mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
6 Commits
sample
...
releases/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1413297394 | ||
|
|
6a063ae7be | ||
|
|
76bb4961fb | ||
|
|
bf3d32e631 | ||
|
|
11aa006d30 | ||
|
|
586c8a7fa5 |
@@ -1,12 +1,12 @@
|
||||
## Features
|
||||
- Set Default shell to powershell for windows runners (#135)
|
||||
- Use Powershell as fallback if Powershell Core is not available for default shell on windows (#142)
|
||||
- N/A
|
||||
|
||||
## Bugs
|
||||
- Removed unintended additional fields on error and warning commands (#137)
|
||||
- Reverted removal of additional fields error and warning fields (#147)
|
||||
- Actions cache would incorrectly cache the action if the tag was updated (#148)
|
||||
|
||||
## Misc
|
||||
- N/A
|
||||
- Updated to .NET Core 3.0 (#127)
|
||||
|
||||
## Agent Downloads
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ namespace GitHub.Runner.Common
|
||||
Add<T>(extensions, "GitHub.Runner.Worker.DebugCommandExtension, Runner.Worker");
|
||||
Add<T>(extensions, "GitHub.Runner.Worker.GroupCommandExtension, Runner.Worker");
|
||||
Add<T>(extensions, "GitHub.Runner.Worker.EndGroupCommandExtension, Runner.Worker");
|
||||
Add<T>(extensions, "GitHub.Runner.Worker.EchoCommandExtension, Runner.Worker");
|
||||
break;
|
||||
default:
|
||||
// This should never happen.
|
||||
|
||||
@@ -236,15 +236,15 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
// try upload all files for the first time.
|
||||
UploadResult uploadResult = await ParallelUploadAsync(context, files, maxConcurrentUploads, _uploadCancellationTokenSource.Token);
|
||||
|
||||
if (uploadResult.RetryFiles.Count == 0)
|
||||
if (uploadResult.FailedFiles.Count == 0)
|
||||
{
|
||||
// all files have been upload succeed.
|
||||
context.Output("File upload complete.");
|
||||
context.Output("File upload succeed.");
|
||||
return uploadResult.TotalFileSizeUploaded;
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Output($"{uploadResult.RetryFiles.Count} files failed to upload, retry these files after a minute.");
|
||||
context.Output($"{uploadResult.FailedFiles.Count} files failed to upload, retry these files after a minute.");
|
||||
}
|
||||
|
||||
// Delay 1 min then retry failed files.
|
||||
@@ -255,13 +255,13 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
}
|
||||
|
||||
// Retry upload all failed files.
|
||||
context.Output($"Start retry {uploadResult.RetryFiles.Count} failed files upload.");
|
||||
UploadResult retryUploadResult = await ParallelUploadAsync(context, uploadResult.RetryFiles, maxConcurrentUploads, _uploadCancellationTokenSource.Token);
|
||||
context.Output($"Start retry {uploadResult.FailedFiles.Count} failed files upload.");
|
||||
UploadResult retryUploadResult = await ParallelUploadAsync(context, uploadResult.FailedFiles, maxConcurrentUploads, _uploadCancellationTokenSource.Token);
|
||||
|
||||
if (retryUploadResult.RetryFiles.Count == 0)
|
||||
if (retryUploadResult.FailedFiles.Count == 0)
|
||||
{
|
||||
// all files have been upload succeed after retry.
|
||||
context.Output("File upload complete after retry.");
|
||||
context.Output("File upload succeed after retry.");
|
||||
return uploadResult.TotalFileSizeUploaded + retryUploadResult.TotalFileSizeUploaded;
|
||||
}
|
||||
else
|
||||
@@ -465,61 +465,75 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
using (FileStream fs = File.Open(fileToUpload, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||
{
|
||||
string itemPath = (_containerPath.TrimEnd('/') + "/" + fileToUpload.Remove(0, _sourceParentDirectory.Length + 1)).Replace('\\', '/');
|
||||
bool failAndExit = false;
|
||||
uploadTimer.Restart();
|
||||
bool catchExceptionDuringUpload = false;
|
||||
HttpResponseMessage response = null;
|
||||
try
|
||||
{
|
||||
uploadTimer.Restart();
|
||||
using (HttpResponseMessage response = await _fileContainerHttpClient.UploadFileAsync(_containerId, itemPath, fs, _projectId, cancellationToken: token, chunkSize: 4 * 1024 * 1024))
|
||||
{
|
||||
if (response == null || response.StatusCode != HttpStatusCode.Created)
|
||||
{
|
||||
context.Output($"Unable to copy file to server StatusCode={response?.StatusCode}: {response?.ReasonPhrase}. Source file path: {fileToUpload}. Target server path: {itemPath}");
|
||||
|
||||
if (response?.StatusCode == HttpStatusCode.Conflict)
|
||||
{
|
||||
// fail upload task but continue with any other files
|
||||
context.Error($"Error '{fileToUpload}' has already been uploaded.");
|
||||
}
|
||||
else if (_fileContainerHttpClient.IsFastFailResponse(response))
|
||||
{
|
||||
// Fast fail: we received an http status code where we should abandon our efforts
|
||||
context.Output($"Cannot continue uploading files, so draining upload queue of {_fileUploadQueue.Count} items.");
|
||||
DrainUploadQueue(context);
|
||||
failedFiles.Clear();
|
||||
failAndExit = true;
|
||||
throw new UploadFailedException($"Critical failure uploading '{fileToUpload}'");
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Debug($"Adding '{fileToUpload}' to retry list.");
|
||||
failedFiles.Add(fileToUpload);
|
||||
}
|
||||
throw new UploadFailedException($"Http failure response '{response?.StatusCode}': '{response?.ReasonPhrase}' while uploading '{fileToUpload}'");
|
||||
}
|
||||
|
||||
uploadTimer.Stop();
|
||||
context.Debug($"File: '{fileToUpload}' took {uploadTimer.ElapsedMilliseconds} milliseconds to finish upload");
|
||||
uploadedSize += fs.Length;
|
||||
OutputLogForFile(context, fileToUpload, $"Detail upload trace for file: {itemPath}", context.Debug);
|
||||
}
|
||||
response = await _fileContainerHttpClient.UploadFileAsync(_containerId, itemPath, fs, _projectId, cancellationToken: token, chunkSize: 4 * 1024 * 1024);
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
context.Output($"File upload has been cancelled during upload file: '{fileToUpload}'.");
|
||||
if (response != null)
|
||||
{
|
||||
response.Dispose();
|
||||
response = null;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
catchExceptionDuringUpload = true;
|
||||
context.Output($"Fail to upload '{fileToUpload}' due to '{ex.Message}'.");
|
||||
context.Output(ex.ToString());
|
||||
}
|
||||
|
||||
OutputLogForFile(context, fileToUpload, $"Detail upload trace for file that fail to upload: {itemPath}", context.Output);
|
||||
|
||||
if (failAndExit)
|
||||
uploadTimer.Stop();
|
||||
if (catchExceptionDuringUpload || (response != null && response.StatusCode != HttpStatusCode.Created))
|
||||
{
|
||||
if (response != null)
|
||||
{
|
||||
context.Debug("Exiting upload.");
|
||||
throw;
|
||||
context.Output($"Unable to copy file to server StatusCode={response.StatusCode}: {response.ReasonPhrase}. Source file path: {fileToUpload}. Target server path: {itemPath}");
|
||||
}
|
||||
|
||||
// output detail upload trace for the file.
|
||||
ConcurrentQueue<string> logQueue;
|
||||
if (_fileUploadTraceLog.TryGetValue(itemPath, out logQueue))
|
||||
{
|
||||
context.Output($"Detail upload trace for file that fail to upload: {itemPath}");
|
||||
string message;
|
||||
while (logQueue.TryDequeue(out message))
|
||||
{
|
||||
context.Output(message);
|
||||
}
|
||||
}
|
||||
|
||||
// tracking file that failed to upload.
|
||||
failedFiles.Add(fileToUpload);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Debug($"File: '{fileToUpload}' took {uploadTimer.ElapsedMilliseconds} milliseconds to finish upload");
|
||||
uploadedSize += fs.Length;
|
||||
// debug detail upload trace for the file.
|
||||
ConcurrentQueue<string> logQueue;
|
||||
if (_fileUploadTraceLog.TryGetValue(itemPath, out logQueue))
|
||||
{
|
||||
context.Debug($"Detail upload trace for file: {itemPath}");
|
||||
string message;
|
||||
while (logQueue.TryDequeue(out message))
|
||||
{
|
||||
context.Debug(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
response.Dispose();
|
||||
response = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,30 +590,6 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
}
|
||||
}
|
||||
|
||||
private void DrainUploadQueue(RunnerActionPluginExecutionContext context)
|
||||
{
|
||||
while (_fileUploadQueue.TryDequeue(out string fileToUpload))
|
||||
{
|
||||
context.Debug($"Clearing upload queue: '{fileToUpload}'");
|
||||
Interlocked.Increment(ref _uploadFilesProcessed);
|
||||
}
|
||||
}
|
||||
|
||||
private void OutputLogForFile(RunnerActionPluginExecutionContext context, string itemPath, string logDescription, Action<string> log)
|
||||
{
|
||||
// output detail upload trace for the file.
|
||||
ConcurrentQueue<string> logQueue;
|
||||
if (_fileUploadTraceLog.TryGetValue(itemPath, out logQueue))
|
||||
{
|
||||
log(logDescription);
|
||||
string message;
|
||||
while (logQueue.TryDequeue(out message))
|
||||
{
|
||||
log(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadFileTraceReportReceived(object sender, ReportTraceEventArgs e)
|
||||
{
|
||||
ConcurrentQueue<string> logQueue = _fileUploadTraceLog.GetOrAdd(e.File, new ConcurrentQueue<string>());
|
||||
@@ -617,22 +607,22 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
{
|
||||
public UploadResult()
|
||||
{
|
||||
RetryFiles = new List<string>();
|
||||
FailedFiles = new List<string>();
|
||||
TotalFileSizeUploaded = 0;
|
||||
}
|
||||
|
||||
public UploadResult(List<string> retryFiles, long totalFileSizeUploaded)
|
||||
public UploadResult(List<string> failedFiles, long totalFileSizeUploaded)
|
||||
{
|
||||
RetryFiles = retryFiles ?? new List<string>();
|
||||
FailedFiles = failedFiles;
|
||||
TotalFileSizeUploaded = totalFileSizeUploaded;
|
||||
}
|
||||
public List<string> RetryFiles { get; set; }
|
||||
public List<string> FailedFiles { get; set; }
|
||||
|
||||
public long TotalFileSizeUploaded { get; set; }
|
||||
|
||||
public void AddUploadResult(UploadResult resultToAdd)
|
||||
{
|
||||
this.RetryFiles.AddRange(resultToAdd.RetryFiles);
|
||||
this.FailedFiles.AddRange(resultToAdd.FailedFiles);
|
||||
this.TotalFileSizeUploaded += resultToAdd.TotalFileSizeUploaded;
|
||||
}
|
||||
}
|
||||
@@ -667,19 +657,4 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
this.FailedFiles.AddRange(resultToAdd.FailedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
public class UploadFailedException : Exception
|
||||
{
|
||||
public UploadFailedException()
|
||||
: base()
|
||||
{ }
|
||||
|
||||
public UploadFailedException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public UploadFailedException(string message, Exception inner)
|
||||
: base(message, inner)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -74,22 +74,17 @@ namespace GitHub.Runner.Plugins.Artifact
|
||||
context.Output($"Uploading artifact '{artifactName}' from '{fullPath}' for run #{buildId}");
|
||||
|
||||
FileContainerServer fileContainerHelper = new FileContainerServer(context.VssConnection, projectId, containerId, artifactName);
|
||||
long size = await fileContainerHelper.CopyToContainerAsync(context, fullPath, token);
|
||||
var propertiesDictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
try
|
||||
{
|
||||
long size = await fileContainerHelper.CopyToContainerAsync(context, fullPath, token);
|
||||
propertiesDictionary.Add("artifactsize", size.ToString());
|
||||
context.Output($"Uploaded '{size}' bytes from '{fullPath}' to server");
|
||||
}
|
||||
// if any of the results were successful, make sure to attach them to the build
|
||||
finally
|
||||
{
|
||||
string fileContainerFullPath = StringUtil.Format($"#/{containerId}/{artifactName}");
|
||||
BuildServer buildHelper = new BuildServer(context.VssConnection);
|
||||
string jobId = context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.JobId).Value ?? string.Empty;
|
||||
var artifact = await buildHelper.AssociateArtifact(projectId, buildId, jobId, artifactName, ArtifactResourceTypes.Container, fileContainerFullPath, propertiesDictionary, token);
|
||||
context.Output($"Associated artifact {artifactName} ({artifact.Id}) with run #{buildId}");
|
||||
}
|
||||
propertiesDictionary.Add("artifactsize", size.ToString());
|
||||
|
||||
string fileContainerFullPath = StringUtil.Format($"#/{containerId}/{artifactName}");
|
||||
context.Output($"Uploaded '{fullPath}' to server");
|
||||
|
||||
BuildServer buildHelper = new BuildServer(context.VssConnection);
|
||||
string jobId = context.Variables.GetValueOrDefault(WellKnownDistributedTaskVariables.JobId).Value ?? string.Empty;
|
||||
var artifact = await buildHelper.AssociateArtifact(projectId, buildId, jobId, artifactName, ArtifactResourceTypes.Container, fileContainerFullPath, propertiesDictionary, token);
|
||||
context.Output($"Associated artifact {artifactName} ({artifact.Id}) with run #{buildId}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,35 +107,26 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
else if (_commandExtensions.TryGetValue(actionCommand.Command, out IActionCommandExtension extension))
|
||||
{
|
||||
bool commandHasBeenOutput = false;
|
||||
|
||||
bool omitEcho;
|
||||
try
|
||||
{
|
||||
if (context.EchoOnActionCommand)
|
||||
{
|
||||
context.Output(input);
|
||||
context.Debug($"Processing command '{actionCommand.Command}'");
|
||||
commandHasBeenOutput = true;
|
||||
}
|
||||
|
||||
extension.ProcessCommand(context, input, actionCommand);
|
||||
|
||||
if (context.EchoOnActionCommand)
|
||||
{
|
||||
context.Debug($"Processed command '{actionCommand.Command}' successfully");
|
||||
}
|
||||
extension.ProcessCommand(context, input, actionCommand, out omitEcho);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!commandHasBeenOutput)
|
||||
{
|
||||
context.Output(input);
|
||||
}
|
||||
|
||||
omitEcho = true;
|
||||
context.Output(input);
|
||||
context.Error($"Unable to process command '{input}' successfully.");
|
||||
context.Error(ex);
|
||||
context.CommandResult = TaskResult.Failed;
|
||||
}
|
||||
|
||||
if (!omitEcho)
|
||||
{
|
||||
context.Output(input);
|
||||
context.Debug($"Processed command");
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -152,7 +143,7 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
string Command { get; }
|
||||
|
||||
void ProcessCommand(IExecutionContext context, string line, ActionCommand command);
|
||||
void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho);
|
||||
}
|
||||
|
||||
public sealed class InternalPluginSetRepoPathCommandExtension : RunnerService, IActionCommandExtension
|
||||
@@ -161,7 +152,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
if (!command.Properties.TryGetValue(SetRepoPathCommandProperties.repoFullName, out string repoFullName) || string.IsNullOrEmpty(repoFullName))
|
||||
{
|
||||
@@ -175,6 +166,8 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
var directoryManager = HostContext.GetService<IPipelineDirectoryManager>();
|
||||
var trackingConfig = directoryManager.UpdateRepositoryDirectory(context, repoFullName, command.Data, StringUtil.ConvertToBoolean(workspaceRepo));
|
||||
|
||||
omitEcho = true;
|
||||
}
|
||||
|
||||
private static class SetRepoPathCommandProperties
|
||||
@@ -190,7 +183,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
if (!command.Properties.TryGetValue(SetEnvCommandProperties.Name, out string envName) || string.IsNullOrEmpty(envName))
|
||||
{
|
||||
@@ -199,7 +192,9 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
context.EnvironmentVariables[envName] = command.Data;
|
||||
context.SetEnvContext(envName, command.Data);
|
||||
context.Output(line);
|
||||
context.Debug($"{envName}='{command.Data}'");
|
||||
omitEcho = true;
|
||||
}
|
||||
|
||||
private static class SetEnvCommandProperties
|
||||
@@ -214,7 +209,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
if (!command.Properties.TryGetValue(SetOutputCommandProperties.Name, out string outputName) || string.IsNullOrEmpty(outputName))
|
||||
{
|
||||
@@ -222,7 +217,9 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
|
||||
context.SetOutput(outputName, command.Data, out var reference);
|
||||
context.Output(line);
|
||||
context.Debug($"{reference}='{command.Data}'");
|
||||
omitEcho = true;
|
||||
}
|
||||
|
||||
private static class SetOutputCommandProperties
|
||||
@@ -237,7 +234,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
if (!command.Properties.TryGetValue(SaveStateCommandProperties.Name, out string stateName) || string.IsNullOrEmpty(stateName))
|
||||
{
|
||||
@@ -246,6 +243,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
context.IntraActionState[stateName] = command.Data;
|
||||
context.Debug($"Save intra-action state {stateName} = {command.Data}");
|
||||
omitEcho = true;
|
||||
}
|
||||
|
||||
private static class SaveStateCommandProperties
|
||||
@@ -260,17 +258,19 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(command.Data))
|
||||
{
|
||||
context.Warning("Can't add secret mask for empty string in ##[add-mask] command.");
|
||||
context.Warning("Can't add secret mask for empty string.");
|
||||
}
|
||||
else
|
||||
{
|
||||
HostContext.SecretMasker.AddValue(command.Data);
|
||||
Trace.Info($"Add new secret mask with length of {command.Data.Length}");
|
||||
}
|
||||
|
||||
omitEcho = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,11 +280,12 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
ArgUtil.NotNullOrEmpty(command.Data, "path");
|
||||
context.PrependPath.RemoveAll(x => string.Equals(x, command.Data, StringComparison.CurrentCulture));
|
||||
context.PrependPath.Add(command.Data);
|
||||
omitEcho = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,8 +295,9 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
omitEcho = false;
|
||||
var file = command.Data;
|
||||
|
||||
// File is required
|
||||
@@ -340,22 +342,23 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
omitEcho = false;
|
||||
command.Properties.TryGetValue(RemoveMatcherCommandProperties.Owner, out string owner);
|
||||
var file = command.Data;
|
||||
|
||||
// Owner and file are mutually exclusive
|
||||
if (!string.IsNullOrEmpty(owner) && !string.IsNullOrEmpty(file))
|
||||
{
|
||||
context.Warning("Either specify an owner name or a file path in ##[remove-matcher] command. Both values cannot be set.");
|
||||
context.Warning("Either specify a matcher owner name or a file path. Both values cannot be set.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Owner or file is required
|
||||
if (string.IsNullOrEmpty(owner) && string.IsNullOrEmpty(file))
|
||||
{
|
||||
context.Warning("Either an owner name or a file path must be specified in ##[remove-matcher] command.");
|
||||
context.Warning("Either a matcher owner name or a file path must be specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -407,8 +410,9 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
omitEcho = true;
|
||||
context.Debug(command.Data);
|
||||
}
|
||||
}
|
||||
@@ -434,8 +438,13 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
omitEcho = true;
|
||||
command.Properties.TryGetValue(IssueCommandProperties.File, out string file);
|
||||
command.Properties.TryGetValue(IssueCommandProperties.Line, out string line);
|
||||
command.Properties.TryGetValue(IssueCommandProperties.Column, out string column);
|
||||
|
||||
Issue issue = new Issue()
|
||||
{
|
||||
Category = "General",
|
||||
@@ -443,8 +452,54 @@ namespace GitHub.Runner.Worker
|
||||
Message = command.Data
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(file))
|
||||
{
|
||||
issue.Category = "Code";
|
||||
|
||||
if (context.Container != null)
|
||||
{
|
||||
// Translate file path back from container path
|
||||
file = context.Container.TranslateToHostPath(file);
|
||||
command.Properties[IssueCommandProperties.File] = file;
|
||||
}
|
||||
|
||||
// Get the values that represent the server path given a local path
|
||||
string repoName = context.GetGitHubContext("repository");
|
||||
var repoPath = context.GetGitHubContext("workspace");
|
||||
|
||||
string relativeSourcePath = IOUtil.MakeRelative(file, repoPath);
|
||||
if (!string.Equals(relativeSourcePath, file, IOUtil.FilePathStringComparison))
|
||||
{
|
||||
// add repo info
|
||||
if (!string.IsNullOrEmpty(repoName))
|
||||
{
|
||||
command.Properties["repo"] = repoName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(relativeSourcePath))
|
||||
{
|
||||
// replace sourcePath with the new relative path
|
||||
// prefer `/` on all platforms
|
||||
command.Properties[IssueCommandProperties.File] = relativeSourcePath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var property in command.Properties)
|
||||
{
|
||||
issue.Data[property.Key] = property.Value;
|
||||
}
|
||||
|
||||
context.AddIssue(issue);
|
||||
}
|
||||
|
||||
private static class IssueCommandProperties
|
||||
{
|
||||
public const String File = "file";
|
||||
public const String Line = "line";
|
||||
public const String Column = "col";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public sealed class GroupCommandExtension : GroupingCommandExtension
|
||||
@@ -462,37 +517,11 @@ namespace GitHub.Runner.Worker
|
||||
public abstract string Command { get; }
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, out bool omitEcho)
|
||||
{
|
||||
var data = this is GroupCommandExtension ? command.Data : string.Empty;
|
||||
context.Output($"##[{Command}]{data}");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class EchoCommandExtension : RunnerService, IActionCommandExtension
|
||||
{
|
||||
public string Command => "echo";
|
||||
|
||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||
|
||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command)
|
||||
{
|
||||
ArgUtil.NotNullOrEmpty(command.Data, "value");
|
||||
|
||||
switch (command.Data.Trim().ToUpperInvariant())
|
||||
{
|
||||
case "ON":
|
||||
context.EchoOnActionCommand = true;
|
||||
context.Debug("Setting echo command value to 'on'");
|
||||
break;
|
||||
case "OFF":
|
||||
context.EchoOnActionCommand = false;
|
||||
context.Debug("Setting echo command value to 'off'");
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Invalid echo command value. Possible values can be: 'on', 'off'. Current value is: '{command.Data}'.");
|
||||
break;
|
||||
}
|
||||
omitEcho = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,9 @@ namespace GitHub.Runner.Worker
|
||||
executionContext.Warning("The 'PREVIEW_ACTION_TOKEN' secret is depreciated. Please remove it from the repository's secrets");
|
||||
}
|
||||
|
||||
// Clear the cache (local runner)
|
||||
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
||||
|
||||
foreach (var action in actions)
|
||||
{
|
||||
if (action.Reference.Type == Pipelines.ActionSourceType.ContainerRegistry)
|
||||
@@ -445,7 +448,7 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure we get an clean folder ready to use.
|
||||
// make sure we get a clean folder ready to use.
|
||||
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
|
||||
Directory.CreateDirectory(destDirectory);
|
||||
executionContext.Output($"Download action repository '{repositoryReference.Name}@{repositoryReference.Ref}'");
|
||||
|
||||
@@ -12,14 +12,14 @@ using GitHub.Services.WebApi;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using Newtonsoft.Json;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Worker
|
||||
{
|
||||
@@ -62,8 +62,6 @@ namespace GitHub.Runner.Worker
|
||||
// Only job level ExecutionContext has PostJobSteps
|
||||
Stack<IStep> PostJobSteps { get; }
|
||||
|
||||
bool EchoOnActionCommand { get; set; }
|
||||
|
||||
// Initialize
|
||||
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
|
||||
void CancelToken();
|
||||
@@ -155,8 +153,6 @@ namespace GitHub.Runner.Worker
|
||||
// Only job level ExecutionContext has PostJobSteps
|
||||
public Stack<IStep> PostJobSteps { get; private set; }
|
||||
|
||||
public bool EchoOnActionCommand { get; set; }
|
||||
|
||||
|
||||
public TaskResult? Result
|
||||
{
|
||||
@@ -296,7 +292,6 @@ namespace GitHub.Runner.Worker
|
||||
child.PrependPath = PrependPath;
|
||||
child.Container = Container;
|
||||
child.ServiceContainers = ServiceContainers;
|
||||
child.EchoOnActionCommand = EchoOnActionCommand;
|
||||
|
||||
if (recordOrder != null)
|
||||
{
|
||||
@@ -709,9 +704,6 @@ namespace GitHub.Runner.Worker
|
||||
_logger = HostContext.CreateService<IPagingLogger>();
|
||||
_logger.Setup(_mainTimelineId, _record.Id);
|
||||
|
||||
// Initialize 'echo on action command success' property, default to false, unless Step_Debug is set
|
||||
EchoOnActionCommand = Variables.Step_Debug ?? false;
|
||||
|
||||
// Verbosity (from GitHub.Step_Debug).
|
||||
WriteDebug = Variables.Step_Debug ?? false;
|
||||
|
||||
|
||||
@@ -397,11 +397,6 @@ namespace GitHub.Services.FileContainer.Client
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (IsFastFailResponse(response))
|
||||
{
|
||||
FileUploadTrace(itemPath, $"Chunk '{currentChunk}' attempt '{attempt}' of file '{itemPath}' received non-success status code {response.StatusCode} for sending request and cannot continue.");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileUploadTrace(itemPath, $"Chunk '{currentChunk}' attempt '{attempt}' of file '{itemPath}' received non-success status code {response.StatusCode} for sending request.");
|
||||
@@ -543,17 +538,6 @@ namespace GitHub.Services.FileContainer.Client
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
public bool IsFastFailResponse(HttpResponseMessage response)
|
||||
{
|
||||
int statusCode = (int)response?.StatusCode;
|
||||
return statusCode >= 400 && statusCode <= 499;
|
||||
}
|
||||
|
||||
protected override bool ShouldThrowError(HttpResponseMessage response)
|
||||
{
|
||||
return !response.IsSuccessStatusCode && !IsFastFailResponse(response);
|
||||
}
|
||||
|
||||
private async Task<HttpResponseMessage> ContainerGetRequestAsync(
|
||||
Int64 containerId,
|
||||
String itemPath,
|
||||
|
||||
@@ -5,7 +5,6 @@ using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Worker;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Common.Tests.Worker
|
||||
{
|
||||
@@ -147,159 +146,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "##[set-env name=foo]bar"));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void EchoProcessCommand()
|
||||
{
|
||||
using (TestHostContext _hc = new TestHostContext(this))
|
||||
{
|
||||
var extensionManager = new Mock<IExtensionManager>();
|
||||
var echoCommand = new EchoCommandExtension();
|
||||
echoCommand.Initialize(_hc);
|
||||
|
||||
extensionManager.Setup(x => x.GetExtensions<IActionCommandExtension>())
|
||||
.Returns(new List<IActionCommandExtension>() { echoCommand });
|
||||
_hc.SetSingleton<IExtensionManager>(extensionManager.Object);
|
||||
|
||||
Mock<IExecutionContext> _ec = new Mock<IExecutionContext>();
|
||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns((string tag, string line) =>
|
||||
{
|
||||
_hc.GetTrace().Info($"{tag} {line}");
|
||||
return 1;
|
||||
});
|
||||
|
||||
_ec.SetupAllProperties();
|
||||
|
||||
ActionCommandManager commandManager = new ActionCommandManager();
|
||||
commandManager.Initialize(_hc);
|
||||
|
||||
Assert.False(_ec.Object.EchoOnActionCommand);
|
||||
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "::echo::on"));
|
||||
Assert.True(_ec.Object.EchoOnActionCommand);
|
||||
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "::echo::off"));
|
||||
Assert.False(_ec.Object.EchoOnActionCommand);
|
||||
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "::echo::ON"));
|
||||
Assert.True(_ec.Object.EchoOnActionCommand);
|
||||
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "::echo::Off "));
|
||||
Assert.False(_ec.Object.EchoOnActionCommand);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void EchoProcessCommandDebugOn()
|
||||
{
|
||||
using (TestHostContext _hc = new TestHostContext(this))
|
||||
{
|
||||
// Set up a few things
|
||||
// 1. Job request message (with ACTIONS_STEP_DEBUG = true)
|
||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||
TimelineReference timeline = new TimelineReference();
|
||||
JobEnvironment environment = new JobEnvironment();
|
||||
environment.SystemConnection = new ServiceEndpoint();
|
||||
List<TaskInstance> tasks = new List<TaskInstance>();
|
||||
Guid JobId = Guid.NewGuid();
|
||||
string jobName = "some job name";
|
||||
var jobRequest = Pipelines.AgentJobRequestMessageUtil.Convert(new AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, environment, tasks));
|
||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||
{
|
||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||
Id = "github",
|
||||
Version = "sha1"
|
||||
});
|
||||
jobRequest.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||
jobRequest.Variables["ACTIONS_STEP_DEBUG"] = "true";
|
||||
|
||||
// Some service dependencies
|
||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||
|
||||
_hc.SetSingleton(jobServerQueue.Object);
|
||||
|
||||
var extensionManager = new Mock<IExtensionManager>();
|
||||
var echoCommand = new EchoCommandExtension();
|
||||
echoCommand.Initialize(_hc);
|
||||
|
||||
extensionManager.Setup(x => x.GetExtensions<IActionCommandExtension>())
|
||||
.Returns(new List<IActionCommandExtension>() { echoCommand });
|
||||
_hc.SetSingleton<IExtensionManager>(extensionManager.Object);
|
||||
|
||||
var configurationStore = new Mock<IConfigurationStore>();
|
||||
configurationStore.Setup(x => x.GetSettings()).Returns(new RunnerSettings());
|
||||
_hc.SetSingleton(configurationStore.Object);
|
||||
|
||||
var pagingLogger = new Mock<IPagingLogger>();
|
||||
_hc.EnqueueInstance(pagingLogger.Object);
|
||||
|
||||
ActionCommandManager commandManager = new ActionCommandManager();
|
||||
commandManager.Initialize(_hc);
|
||||
|
||||
var _ec = new Runner.Worker.ExecutionContext();
|
||||
_ec.Initialize(_hc);
|
||||
|
||||
// Initialize the job (to exercise logic that sets EchoOnActionCommand)
|
||||
_ec.InitializeJob(jobRequest, System.Threading.CancellationToken.None);
|
||||
|
||||
_ec.Complete();
|
||||
|
||||
Assert.True(_ec.EchoOnActionCommand);
|
||||
|
||||
Assert.True(commandManager.TryProcessCommand(_ec, "::echo::off"));
|
||||
Assert.False(_ec.EchoOnActionCommand);
|
||||
|
||||
Assert.True(commandManager.TryProcessCommand(_ec, "::echo::on"));
|
||||
Assert.True(_ec.EchoOnActionCommand);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void EchoProcessCommandInvalid()
|
||||
{
|
||||
using (TestHostContext _hc = new TestHostContext(this))
|
||||
{
|
||||
var extensionManager = new Mock<IExtensionManager>();
|
||||
var echoCommand = new EchoCommandExtension();
|
||||
echoCommand.Initialize(_hc);
|
||||
|
||||
extensionManager.Setup(x => x.GetExtensions<IActionCommandExtension>())
|
||||
.Returns(new List<IActionCommandExtension>() { echoCommand });
|
||||
_hc.SetSingleton<IExtensionManager>(extensionManager.Object);
|
||||
|
||||
Mock<IExecutionContext> _ec = new Mock<IExecutionContext>();
|
||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||
.Returns((string tag, string line) =>
|
||||
{
|
||||
_hc.GetTrace().Info($"{tag} {line}");
|
||||
return 1;
|
||||
});
|
||||
|
||||
_ec.SetupAllProperties();
|
||||
|
||||
ActionCommandManager commandManager = new ActionCommandManager();
|
||||
commandManager.Initialize(_hc);
|
||||
|
||||
// Echo commands below are considered "processed", but are invalid
|
||||
// 1. Invalid echo value
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "::echo::invalid"));
|
||||
Assert.Equal(TaskResult.Failed, _ec.Object.CommandResult);
|
||||
Assert.False(_ec.Object.EchoOnActionCommand);
|
||||
|
||||
// 2. No value
|
||||
Assert.True(commandManager.TryProcessCommand(_ec.Object, "::echo::"));
|
||||
Assert.Equal(TaskResult.Failed, _ec.Object.CommandResult);
|
||||
Assert.False(_ec.Object.EchoOnActionCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,6 +233,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
@@ -272,6 +273,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Teardown();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
@@ -306,6 +308,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
#if OS_LINUX
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
@@ -772,6 +775,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Teardown();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.159.2
|
||||
2.160.0
|
||||
Reference in New Issue
Block a user