-
Notifications
You must be signed in to change notification settings - Fork 957
/
RepositoryPlugin.cs
172 lines (156 loc) · 8.38 KB
/
RepositoryPlugin.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
using System;
using System.Threading;
using System.Threading.Tasks;
using GitHub.Runner.Sdk;
using Pipelines = GitHub.DistributedTask.Pipelines;
using System.IO;
using System.Text.RegularExpressions;
using GitHub.DistributedTask.Pipelines.Expressions;
using System.Text;
namespace GitHub.Runner.Plugins.Repository.v1_0
{
public class CheckoutTask : IRunnerActionPlugin
{
private readonly Regex _validSha1 = new(@"\b[0-9a-f]{40}\b", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled, TimeSpan.FromSeconds(2));
public async Task RunAsync(RunnerActionPluginExecutionContext executionContext, CancellationToken token)
{
string runnerWorkspace = executionContext.GetRunnerContext("workspace");
ArgUtil.Directory(runnerWorkspace, nameof(runnerWorkspace));
string tempDirectory = executionContext.GetRunnerContext("temp");
ArgUtil.Directory(tempDirectory, nameof(tempDirectory));
var repoFullName = executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Repository);
if (string.IsNullOrEmpty(repoFullName))
{
repoFullName = executionContext.GetGitHubContext("repository");
}
var repoFullNameSplit = repoFullName.Split("/", StringSplitOptions.RemoveEmptyEntries);
if (repoFullNameSplit.Length != 2)
{
throw new ArgumentOutOfRangeException(repoFullName);
}
string expectRepoPath;
var path = executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Path);
if (!string.IsNullOrEmpty(path))
{
expectRepoPath = IOUtil.ResolvePath(runnerWorkspace, path);
if (!expectRepoPath.StartsWith(runnerWorkspace.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar) + Path.DirectorySeparatorChar))
{
throw new ArgumentException($"Input path '{path}' should resolve to a directory under '{runnerWorkspace}', current resolved path '{expectRepoPath}'.");
}
}
else
{
// When repository doesn't has path set, default to sources directory 1/repoName
expectRepoPath = Path.Combine(runnerWorkspace, repoFullNameSplit[1]);
}
var workspaceRepo = executionContext.GetGitHubContext("repository");
// for self repository, we need to let the worker knows where it is after checkout.
if (string.Equals(workspaceRepo, repoFullName, StringComparison.OrdinalIgnoreCase))
{
var workspaceRepoPath = executionContext.GetGitHubContext("workspace");
executionContext.Debug($"Repository requires to be placed at '{expectRepoPath}', current location is '{workspaceRepoPath}'");
if (!string.Equals(workspaceRepoPath.Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), expectRepoPath.Trim(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), IOUtil.FilePathStringComparison))
{
executionContext.Output($"Repository is current at '{workspaceRepoPath}', move to '{expectRepoPath}'.");
var count = 1;
var staging = Path.Combine(tempDirectory, $"_{count}");
while (Directory.Exists(staging))
{
count++;
staging = Path.Combine(tempDirectory, $"_{count}");
}
try
{
executionContext.Debug($"Move existing repository '{workspaceRepoPath}' to '{expectRepoPath}' via staging directory '{staging}'.");
IOUtil.MoveDirectory(workspaceRepoPath, expectRepoPath, staging, CancellationToken.None);
}
catch (Exception ex)
{
executionContext.Debug("Catch exception during repository move.");
executionContext.Debug(ex.ToString());
executionContext.Warning("Unable move and reuse existing repository to required location.");
IOUtil.DeleteDirectory(expectRepoPath, CancellationToken.None);
}
executionContext.Output($"Repository will locate at '{expectRepoPath}'.");
}
executionContext.Debug($"Update workspace repository location.");
executionContext.SetRepositoryPath(repoFullName, expectRepoPath, true);
}
string sourceBranch;
string sourceVersion;
string refInput = executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Ref);
if (string.IsNullOrEmpty(refInput))
{
sourceBranch = executionContext.GetGitHubContext("ref");
sourceVersion = executionContext.GetGitHubContext("sha");
}
else
{
sourceBranch = refInput;
sourceVersion = executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Version); // version get removed when checkout move to repo in the graph
if (string.IsNullOrEmpty(sourceVersion) && RegexUtility.IsMatch(sourceBranch, WellKnownRegularExpressions.SHA1))
{
sourceVersion = sourceBranch;
// If Ref is a SHA and the repo is self, we need to use github.ref as source branch since it might be refs/pull/*
if (string.Equals(workspaceRepo, repoFullName, StringComparison.OrdinalIgnoreCase))
{
sourceBranch = executionContext.GetGitHubContext("ref");
}
else
{
sourceBranch = "refs/heads/master";
}
}
}
bool clean = StringUtil.ConvertToBoolean(executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Clean), true);
string submoduleInput = executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Submodules);
int fetchDepth = 0;
if (!int.TryParse(executionContext.GetInput("fetch-depth"), out fetchDepth) || fetchDepth < 0)
{
fetchDepth = 0;
}
bool gitLfsSupport = StringUtil.ConvertToBoolean(executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Lfs));
string accessToken = executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Token);
if (string.IsNullOrEmpty(accessToken))
{
accessToken = executionContext.GetGitHubContext("token");
}
// register problem matcher
string problemMatcher = @"
{
""problemMatcher"": [
{
""owner"": ""checkout-git"",
""pattern"": [
{
""regexp"": ""^fatal: (.*)$"",
""message"": 1
}
]
}
]
}";
string matcherFile = Path.Combine(tempDirectory, $"git_{Guid.NewGuid()}.json");
File.WriteAllText(matcherFile, problemMatcher, new UTF8Encoding(false));
executionContext.Output($"##[add-matcher]{matcherFile}");
try
{
await new GitHubSourceProvider().GetSourceAsync(executionContext,
expectRepoPath,
repoFullName,
sourceBranch,
sourceVersion,
clean,
submoduleInput,
fetchDepth,
gitLfsSupport,
accessToken,
token);
}
finally
{
executionContext.Output("##[remove-matcher owner=checkout-git]");
}
}
}
}