mirror of
https://github.com/actions/runner.git
synced 2025-12-11 04:46:58 +00:00
Compare commits
11 Commits
users/thbo
...
users/eric
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ecc737c6b | ||
|
|
ece9b6d04b | ||
|
|
7a18d3001d | ||
|
|
02639a2092 | ||
|
|
a727194742 | ||
|
|
a9c58d7398 | ||
|
|
e15414eb5e | ||
|
|
4ab1e645c3 | ||
|
|
584f6b6ca3 | ||
|
|
abc65839f3 | ||
|
|
06292aa118 |
61
docs/adrs/0263-proxy-support.md
Normal file
61
docs/adrs/0263-proxy-support.md
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
# ADR 263: Self Hosted Runner Proxies
|
||||||
|
**Date**: 2019-11-13
|
||||||
|
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
- Proxy support is required for some enterprises and organizations to start using their own self hosted runners
|
||||||
|
- While there is not a standard convention, many applications support setting proxies via the environmental variables `http_proxy`, `https_proxy`, `no_proxy`, such as curl, wget, perl, python, docker, git, R, ect
|
||||||
|
- Some of these applications use `HTTPS_PROXY` versus `https_proxy`, but most understand or primarily support the lowercase variant
|
||||||
|
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
We will update the Runner to use the conventional environment variables for proxies: `http_proxy`, `https_proxy` and `no_proxy` if they are set.
|
||||||
|
These are described in detail below:
|
||||||
|
- `https_proxy` a proxy URL for all https traffic. It may contain basic authentication credentials. For example:
|
||||||
|
- http://proxy.com
|
||||||
|
- http://127.0.0.1:8080
|
||||||
|
- http://user:password@proxy.com
|
||||||
|
- `http_proxy` a proxy URL for all http traffic. It may contain basic authentication credentials. For example:
|
||||||
|
- http://proxy.com
|
||||||
|
- http://127.0.0.1:8080
|
||||||
|
- http://user:password@proxy.com
|
||||||
|
- `no_proxy` a comma seperated list of hosts that should not use the proxy. An optional port may be specified
|
||||||
|
- `google.com`
|
||||||
|
- `yahoo.com:443`
|
||||||
|
- `google.com,bing.com`
|
||||||
|
|
||||||
|
We won't use `http_proxy` for https traffic when `https_proxy` is not set, this behavior lines up with any libcurl based tools (curl, git) and wget.
|
||||||
|
Otherwise action authors and workflow users need to adjust to differences between the runner proxy convention, and tools used by their actions and scripts.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
Customer set `http_proxy=http://127.0.0.1:8888` and configure the runner against `https://github.com/owner/repo`, with the `https_proxy` -> `http_proxy` fallback, the runner will connect to server without any problem. However, if user runs `git push` to `https://github.com/owner/repo`, `git` won't use the proxy since it require `https_proxy` to be set for any https traffic.
|
||||||
|
|
||||||
|
> `golang`, `node.js` and other dev tools from the linux community use `http_proxy` for both http and https traffic base on my research.
|
||||||
|
|
||||||
|
A majority of our users are using Linux where these variables are commonly required to be set by various programs. By reading these values, we simplify the process for self hosted runners to set up proxy, and expose it in a way users are already familiar with.
|
||||||
|
|
||||||
|
A password provided for a proxy will be masked in the logs.
|
||||||
|
|
||||||
|
We will support the lowercase and uppercase variants, with lowercase taking priority if both are set.
|
||||||
|
|
||||||
|
### No Proxy Format
|
||||||
|
|
||||||
|
While exact implementations are different per application on handle `no_proxy` env, most applications accept a comma separated list of hosts. Some accept wildcard characters (*). We are going to do exact case-insentive matches, and not support wildcards at this time.
|
||||||
|
For example:
|
||||||
|
- example.com will match example.com, foo.example.com, foo.bar.example.com
|
||||||
|
- foo.example.com will match bar.foo.example.com and foo.example.com
|
||||||
|
|
||||||
|
We will not support IP addresses for `no_proxy`, only hostnames.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
1. Enterprises and organizations needing proxy support will be able to embrace self hosted runners
|
||||||
|
2. Users will need to set these environmental variables before configuring the runner in order to use a proxy when configuring
|
||||||
|
3. The runner will read from the environmental variables during config and runtime and use the provided proxy if it exists
|
||||||
|
4. Users may need to pass these environmental variables into other applications if they do not natively take these variables
|
||||||
|
5. Action authors may need to update their workflows to react to the these environment variables
|
||||||
|
6. We will document the way of setting environmental variables for runners using the environmental variables and how the runner uses them
|
||||||
|
7. Like all other secrets, users will be able to relatively easily figure out proxy password if they can modify a workflow file running on a self hosted machine
|
||||||
@@ -9,26 +9,27 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
private static readonly EscapeMapping[] _escapeMappings = new[]
|
private static readonly EscapeMapping[] _escapeMappings = new[]
|
||||||
{
|
{
|
||||||
new EscapeMapping(token: "%", replacement: "%25"),
|
|
||||||
new EscapeMapping(token: ";", replacement: "%3B"),
|
new EscapeMapping(token: ";", replacement: "%3B"),
|
||||||
new EscapeMapping(token: "\r", replacement: "%0D"),
|
new EscapeMapping(token: "\r", replacement: "%0D"),
|
||||||
new EscapeMapping(token: "\n", replacement: "%0A"),
|
new EscapeMapping(token: "\n", replacement: "%0A"),
|
||||||
new EscapeMapping(token: "]", replacement: "%5D"),
|
new EscapeMapping(token: "]", replacement: "%5D"),
|
||||||
|
new EscapeMapping(token: "%", replacement: "%25"),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly EscapeMapping[] _escapeDataMappings = new[]
|
private static readonly EscapeMapping[] _escapeDataMappings = new[]
|
||||||
{
|
{
|
||||||
new EscapeMapping(token: "\r", replacement: "%0D"),
|
new EscapeMapping(token: "\r", replacement: "%0D"),
|
||||||
new EscapeMapping(token: "\n", replacement: "%0A"),
|
new EscapeMapping(token: "\n", replacement: "%0A"),
|
||||||
|
new EscapeMapping(token: "%", replacement: "%25"),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static readonly EscapeMapping[] _escapePropertyMappings = new[]
|
private static readonly EscapeMapping[] _escapePropertyMappings = new[]
|
||||||
{
|
{
|
||||||
new EscapeMapping(token: "%", replacement: "%25"),
|
|
||||||
new EscapeMapping(token: "\r", replacement: "%0D"),
|
new EscapeMapping(token: "\r", replacement: "%0D"),
|
||||||
new EscapeMapping(token: "\n", replacement: "%0A"),
|
new EscapeMapping(token: "\n", replacement: "%0A"),
|
||||||
new EscapeMapping(token: ":", replacement: "%3A"),
|
new EscapeMapping(token: ":", replacement: "%3A"),
|
||||||
new EscapeMapping(token: ",", replacement: "%2C"),
|
new EscapeMapping(token: ",", replacement: "%2C"),
|
||||||
|
new EscapeMapping(token: "%", replacement: "%25"),
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly Dictionary<string, string> _properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
private readonly Dictionary<string, string> _properties = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
private Guid _timelineId;
|
private Guid _timelineId;
|
||||||
private Guid _timelineRecordId;
|
private Guid _timelineRecordId;
|
||||||
private string _pageId;
|
|
||||||
private FileStream _pageData;
|
private FileStream _pageData;
|
||||||
private StreamWriter _pageWriter;
|
private StreamWriter _pageWriter;
|
||||||
private int _byteCount;
|
private int _byteCount;
|
||||||
@@ -40,7 +39,6 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
_totalLines = 0;
|
_totalLines = 0;
|
||||||
_pageId = Guid.NewGuid().ToString();
|
|
||||||
_pagesFolder = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Diag), PagingFolder);
|
_pagesFolder = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Diag), PagingFolder);
|
||||||
_jobServerQueue = HostContext.GetService<IJobServerQueue>();
|
_jobServerQueue = HostContext.GetService<IJobServerQueue>();
|
||||||
Directory.CreateDirectory(_pagesFolder);
|
Directory.CreateDirectory(_pagesFolder);
|
||||||
@@ -102,7 +100,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
EndPage();
|
EndPage();
|
||||||
_byteCount = 0;
|
_byteCount = 0;
|
||||||
_dataFileName = Path.Combine(_pagesFolder, $"{_pageId}_{++_pageCount}.log");
|
_dataFileName = Path.Combine(_pagesFolder, $"{_timelineRecordId}_{++_pageCount}.log");
|
||||||
_pageData = new FileStream(_dataFileName, FileMode.CreateNew);
|
_pageData = new FileStream(_dataFileName, FileMode.CreateNew);
|
||||||
_pageWriter = new StreamWriter(_pageData, System.Text.Encoding.UTF8);
|
_pageWriter = new StreamWriter(_pageData, System.Text.Encoding.UTF8);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Util
|
namespace GitHub.Runner.Common.Util
|
||||||
@@ -75,5 +76,29 @@ namespace GitHub.Runner.Common.Util
|
|||||||
throw new NotSupportedException(result.ToString());
|
throw new NotSupportedException(result.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static StringContextData ToContextData(this TaskResult result)
|
||||||
|
{
|
||||||
|
string str;
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case TaskResult.Succeeded:
|
||||||
|
str = "success";
|
||||||
|
break;
|
||||||
|
case TaskResult.Failed:
|
||||||
|
str = "failure";
|
||||||
|
break;
|
||||||
|
case TaskResult.Canceled:
|
||||||
|
str = "cancelled";
|
||||||
|
break;
|
||||||
|
case TaskResult.Skipped:
|
||||||
|
str = "skipped";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException($"Unexpected task result '{result}' when converting to context data");
|
||||||
|
}
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -568,6 +568,10 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
Trace.Info("worker process has been killed.");
|
Trace.Info("worker process has been killed.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When worker doesn't exit within cancel timeout, the runner will kill the worker process and worker won't finish upload job logs.
|
||||||
|
// The runner will try to upload these logs at this time.
|
||||||
|
await TryUploadUnfinishedLogs(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
Trace.Info($"finish job request for job {message.JobId} with result: {resultOnAbandonOrCancel}");
|
Trace.Info($"finish job request for job {message.JobId} with result: {resultOnAbandonOrCancel}");
|
||||||
@@ -712,6 +716,116 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Best effort upload any logs for this job.
|
||||||
|
private async Task TryUploadUnfinishedLogs(Pipelines.AgentJobRequestMessage message)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
|
||||||
|
var logFolder = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Diag), PagingLogger.PagingFolder);
|
||||||
|
if (!Directory.Exists(logFolder))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var logs = Directory.GetFiles(logFolder);
|
||||||
|
if (logs.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var systemConnection = message.Resources.Endpoints.SingleOrDefault(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection));
|
||||||
|
ArgUtil.NotNull(systemConnection, nameof(systemConnection));
|
||||||
|
|
||||||
|
var jobServer = HostContext.GetService<IJobServer>();
|
||||||
|
VssCredentials jobServerCredential = VssUtil.GetVssCredential(systemConnection);
|
||||||
|
VssConnection jobConnection = VssUtil.CreateConnection(systemConnection.Url, jobServerCredential);
|
||||||
|
|
||||||
|
await jobServer.ConnectAsync(jobConnection);
|
||||||
|
|
||||||
|
var timeline = await jobServer.GetTimelineAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, CancellationToken.None);
|
||||||
|
|
||||||
|
var updatedRecords = new List<TimelineRecord>();
|
||||||
|
var logPages = new Dictionary<Guid, Dictionary<int, string>>();
|
||||||
|
var logRecords = new Dictionary<Guid, TimelineRecord>();
|
||||||
|
foreach (var log in logs)
|
||||||
|
{
|
||||||
|
var logName = Path.GetFileNameWithoutExtension(log);
|
||||||
|
var logPageSeperator = logName.IndexOf('_');
|
||||||
|
var logRecordId = Guid.Empty;
|
||||||
|
var pageNumber = 0;
|
||||||
|
if (logPageSeperator < 0)
|
||||||
|
{
|
||||||
|
Trace.Warning($"log file '{log}' doesn't follow naming convension 'GUID_INT'.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!Guid.TryParse(logName.Substring(0, logPageSeperator), out logRecordId))
|
||||||
|
{
|
||||||
|
Trace.Warning($"log file '{log}' doesn't follow naming convension 'GUID_INT'.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!int.TryParse(logName.Substring(logPageSeperator + 1), out pageNumber))
|
||||||
|
{
|
||||||
|
Trace.Warning($"log file '{log}' doesn't follow naming convension 'GUID_INT'.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var record = timeline.Records.FirstOrDefault(x => x.Id == logRecordId);
|
||||||
|
if (record != null)
|
||||||
|
{
|
||||||
|
if (!logPages.ContainsKey(record.Id))
|
||||||
|
{
|
||||||
|
logPages[record.Id] = new Dictionary<int, string>();
|
||||||
|
logRecords[record.Id] = record;
|
||||||
|
}
|
||||||
|
|
||||||
|
logPages[record.Id][pageNumber] = log;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var pages in logPages)
|
||||||
|
{
|
||||||
|
var record = logRecords[pages.Key];
|
||||||
|
if (record.Log == null)
|
||||||
|
{
|
||||||
|
// Create the log
|
||||||
|
record.Log = await jobServer.CreateLogAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, new TaskLog(String.Format(@"logs\{0:D}", record.Id)), default(CancellationToken));
|
||||||
|
|
||||||
|
// Need to post timeline record updates to reflect the log creation
|
||||||
|
updatedRecords.Add(record.Clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 1; i <= pages.Value.Count; i++)
|
||||||
|
{
|
||||||
|
var logFile = pages.Value[i];
|
||||||
|
// Upload the contents
|
||||||
|
using (FileStream fs = File.Open(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||||
|
{
|
||||||
|
var logUploaded = await jobServer.AppendLogContentAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, record.Log.Id, fs, default(CancellationToken));
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info($"Uploaded unfinished log '{logFile}' for current job.");
|
||||||
|
IOUtil.DeleteFile(logFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updatedRecords.Count > 0)
|
||||||
|
{
|
||||||
|
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, updatedRecords, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Ignore any error during log upload since it's best effort
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: We need send detailInfo back to DT in order to add an issue for the job
|
// TODO: We need send detailInfo back to DT in order to add an issue for the job
|
||||||
private async Task CompleteJobRequestAsync(int poolId, Pipelines.AgentJobRequestMessage message, Guid lockToken, TaskResult result, string detailInfo = null)
|
private async Task CompleteJobRequestAsync(int poolId, Pipelines.AgentJobRequestMessage message, Guid lockToken, TaskResult result, string detailInfo = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ namespace GitHub.Runner.Worker
|
|||||||
if (actionDefinition.Execution == null)
|
if (actionDefinition.Execution == null)
|
||||||
{
|
{
|
||||||
executionContext.Debug($"Loaded action.yml file: {StringUtil.ConvertToJson(actionDefinition)}");
|
executionContext.Debug($"Loaded action.yml file: {StringUtil.ConvertToJson(actionDefinition)}");
|
||||||
throw new ArgumentException($"Top level 'run:' section is required for {manifestFile}");
|
throw new ArgumentException($"Top level 'runs:' section is required for {manifestFile}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Container
|
namespace GitHub.Runner.Worker.Container
|
||||||
{
|
{
|
||||||
@@ -19,7 +19,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
|
|
||||||
public ContainerInfo()
|
public ContainerInfo()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ContainerInfo(IHostContext hostContext, Pipelines.JobContainer container, bool isJobContainer = true, string networkAlias = null)
|
public ContainerInfo(IHostContext hostContext, Pipelines.JobContainer container, bool isJobContainer = true, string networkAlias = null)
|
||||||
|
|||||||
@@ -61,16 +61,11 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
var path = "/proc/1/cgroup";
|
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
||||||
// OSX does not have this file, but you cannot run OSX as a base image for docker containers currently.
|
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||||
if (File.Exists(path))
|
|
||||||
{
|
{
|
||||||
var initProcessCgroup = File.ReadLines(path);
|
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||||
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -342,6 +342,12 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
_logger.End();
|
_logger.End();
|
||||||
|
|
||||||
|
// update context
|
||||||
|
if (!string.IsNullOrEmpty(ContextName))
|
||||||
|
{
|
||||||
|
StepsContext.SetConclusion(ScopeName, ContextName, Result.Value.ToContextData());
|
||||||
|
}
|
||||||
|
|
||||||
return Result.Value;
|
return Result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,8 +189,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
container.ContainerEnvironmentVariables[variable.Key] = container.TranslateToContainerPath(variable.Value);
|
container.ContainerEnvironmentVariables[variable.Key] = container.TranslateToContainerPath(variable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager, container))
|
||||||
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager, container))
|
||||||
{
|
{
|
||||||
var runExitCode = await dockerManger.DockerRun(ExecutionContext, container, stdoutManager.OnDataReceived, stderrManager.OnDataReceived);
|
var runExitCode = await dockerManger.DockerRun(ExecutionContext, container, stdoutManager.OnDataReceived, stderrManager.OnDataReceived);
|
||||||
if (runExitCode != 0)
|
if (runExitCode != 0)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Worker.Container;
|
||||||
using DTWebApi = GitHub.DistributedTask.WebApi;
|
using DTWebApi = GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
@@ -17,6 +18,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
private const string _timeoutKey = "GITHUB_ACTIONS_RUNNER_ISSUE_MATCHER_TIMEOUT";
|
private const string _timeoutKey = "GITHUB_ACTIONS_RUNNER_ISSUE_MATCHER_TIMEOUT";
|
||||||
private static readonly Regex _colorCodeRegex = new Regex(@"\x0033\[[0-9;]*m?", RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
private static readonly Regex _colorCodeRegex = new Regex(@"\x0033\[[0-9;]*m?", RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||||
private readonly IActionCommandManager _commandManager;
|
private readonly IActionCommandManager _commandManager;
|
||||||
|
private readonly ContainerInfo _container;
|
||||||
private readonly IExecutionContext _executionContext;
|
private readonly IExecutionContext _executionContext;
|
||||||
private readonly int _failsafe = 50;
|
private readonly int _failsafe = 50;
|
||||||
private readonly object _matchersLock = new object();
|
private readonly object _matchersLock = new object();
|
||||||
@@ -25,10 +27,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Mapping that indicates whether a directory belongs to the workflow repository
|
// Mapping that indicates whether a directory belongs to the workflow repository
|
||||||
private readonly Dictionary<string, string> _directoryMap = new Dictionary<string, string>();
|
private readonly Dictionary<string, string> _directoryMap = new Dictionary<string, string>();
|
||||||
|
|
||||||
public OutputManager(IExecutionContext executionContext, IActionCommandManager commandManager)
|
public OutputManager(IExecutionContext executionContext, IActionCommandManager commandManager, ContainerInfo container = null)
|
||||||
{
|
{
|
||||||
_executionContext = executionContext;
|
_executionContext = executionContext;
|
||||||
_commandManager = commandManager;
|
_commandManager = commandManager;
|
||||||
|
_container = container ?? executionContext.Container;
|
||||||
|
|
||||||
// Recursion failsafe (test override)
|
// Recursion failsafe (test override)
|
||||||
var failsafeString = Environment.GetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE");
|
var failsafeString = Environment.GetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE");
|
||||||
@@ -257,6 +260,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
if (!string.IsNullOrWhiteSpace(match.File))
|
if (!string.IsNullOrWhiteSpace(match.File))
|
||||||
{
|
{
|
||||||
var file = match.File;
|
var file = match.File;
|
||||||
|
var translate = _container != null;
|
||||||
|
|
||||||
// Root using fromPath
|
// Root using fromPath
|
||||||
if (!string.IsNullOrWhiteSpace(match.FromPath) && !Path.IsPathFullyQualified(file))
|
if (!string.IsNullOrWhiteSpace(match.FromPath) && !Path.IsPathFullyQualified(file))
|
||||||
@@ -275,11 +279,19 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
ArgUtil.NotNullOrEmpty(workspace, "workspace");
|
ArgUtil.NotNullOrEmpty(workspace, "workspace");
|
||||||
|
|
||||||
file = Path.Combine(workspace, file);
|
file = Path.Combine(workspace, file);
|
||||||
|
translate = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove relative pathing and normalize slashes
|
// Remove relative pathing and normalize slashes
|
||||||
file = Path.GetFullPath(file);
|
file = Path.GetFullPath(file);
|
||||||
|
|
||||||
|
// Translate to host
|
||||||
|
if (translate)
|
||||||
|
{
|
||||||
|
file = _container.TranslateToHostPath(file);
|
||||||
|
file = Path.GetFullPath(file);
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether the file exists
|
// Check whether the file exists
|
||||||
if (File.Exists(file))
|
if (File.Exists(file))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -107,6 +107,11 @@ namespace GitHub.Runner.Worker
|
|||||||
return await CompleteJobAsync(jobServer, jobContext, message, TaskResult.Failed);
|
return await CompleteJobAsync(jobServer, jobContext, message, TaskResult.Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (jobContext.WriteDebug)
|
||||||
|
{
|
||||||
|
jobContext.SetRunnerContext("debug", "1");
|
||||||
|
}
|
||||||
|
|
||||||
jobContext.SetRunnerContext("os", VarUtil.OS);
|
jobContext.SetRunnerContext("os", VarUtil.OS);
|
||||||
|
|
||||||
string toolsDirectory = HostContext.GetDirectory(WellKnownDirectory.Tools);
|
string toolsDirectory = HostContext.GetDirectory(WellKnownDirectory.Tools);
|
||||||
|
|||||||
@@ -56,13 +56,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetResult(
|
public void SetConclusion(
|
||||||
string scopeName,
|
string scopeName,
|
||||||
string stepName,
|
string stepName,
|
||||||
string result)
|
StringContextData conclusion)
|
||||||
{
|
{
|
||||||
var step = GetStep(scopeName, stepName);
|
var step = GetStep(scopeName, stepName);
|
||||||
step["result"] = new StringContextData(result);
|
step["conclusion"] = conclusion;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DictionaryContextData GetStep(string scopeName, string stepName)
|
private DictionaryContextData GetStep(string scopeName, string stepName)
|
||||||
|
|||||||
@@ -154,6 +154,11 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
|
|
||||||
if (value is StringToken containerLiteral)
|
if (value is StringToken containerLiteral)
|
||||||
{
|
{
|
||||||
|
if (String.IsNullOrEmpty(containerLiteral.Value))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
result.Image = containerLiteral.Value;
|
result.Image = containerLiteral.Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -472,7 +472,7 @@
|
|||||||
"matrix"
|
"matrix"
|
||||||
],
|
],
|
||||||
"one-of": [
|
"one-of": [
|
||||||
"non-empty-string",
|
"string",
|
||||||
"container-mapping"
|
"container-mapping"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -497,10 +497,22 @@
|
|||||||
],
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
"loose-value-type": "container"
|
"loose-value-type": "services-container"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"services-container": {
|
||||||
|
"context": [
|
||||||
|
"github",
|
||||||
|
"strategy",
|
||||||
|
"matrix"
|
||||||
|
],
|
||||||
|
"one-of": [
|
||||||
|
"non-empty-string",
|
||||||
|
"container-mapping"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
"container-env": {
|
"container-env": {
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
using System.IO;
|
||||||
using System.IO;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using System;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests
|
namespace GitHub.Runner.Common.Tests
|
||||||
{
|
{
|
||||||
@@ -21,9 +20,16 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
return projectDir;
|
return projectDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetTestFilePath([CallerFilePath] string path = null)
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
public static string GetSrcPath()
|
public static string GetSrcPath()
|
||||||
{
|
{
|
||||||
string srcDir = Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR");
|
string L0dir = Path.GetDirectoryName(GetTestFilePath());
|
||||||
|
string testDir = Path.GetDirectoryName(L0dir);
|
||||||
|
string srcDir = Path.GetDirectoryName(testDir);
|
||||||
ArgUtil.Directory(srcDir, nameof(srcDir));
|
ArgUtil.Directory(srcDir, nameof(srcDir));
|
||||||
Assert.Equal(Src, Path.GetFileName(srcDir));
|
Assert.Equal(Src, Path.GetFileName(srcDir));
|
||||||
return srcDir;
|
return srcDir;
|
||||||
|
|||||||
@@ -202,5 +202,20 @@ namespace GitHub.Runner.Common.Tests.Util
|
|||||||
Assert.Equal(TaskResult.Skipped, merged);
|
Assert.Equal(TaskResult.Skipped, merged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void ToContextData()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using (TestHostContext hc = new TestHostContext(this))
|
||||||
|
{
|
||||||
|
Assert.Equal("success", TaskResult.Succeeded.ToContextData().ToString());
|
||||||
|
Assert.Equal("failure", TaskResult.Failed.ToContextData().ToString());
|
||||||
|
Assert.Equal("cancelled", TaskResult.Canceled.ToContextData().ToString());
|
||||||
|
Assert.Equal("skipped", TaskResult.Skipped.ToContextData().ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,19 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Assert.True(ActionCommand.TryParse(message, commands, out verify));
|
Assert.True(ActionCommand.TryParse(message, commands, out verify));
|
||||||
Assert.True(IsEqualCommand(hc, test, verify));
|
Assert.True(IsEqualCommand(hc, test, verify));
|
||||||
|
|
||||||
|
message = "";
|
||||||
|
test = null;
|
||||||
|
verify = null;
|
||||||
|
//##[do-something k1=%253B=%250D=%250A=%255D;]%253B-%250D-%250A-%255D
|
||||||
|
message = "##[do-something k1=%253B=%250D=%250A=%255D;]%253B-%250D-%250A-%255D";
|
||||||
|
test = new ActionCommand("do-something")
|
||||||
|
{
|
||||||
|
Data = "%3B-%0D-%0A-%5D",
|
||||||
|
};
|
||||||
|
test.Properties.Add("k1", "%3B=%0D=%0A=%5D");
|
||||||
|
Assert.True(ActionCommand.TryParse(message, commands, out verify));
|
||||||
|
Assert.True(IsEqualCommand(hc, test, verify));
|
||||||
|
|
||||||
message = "";
|
message = "";
|
||||||
test = null;
|
test = null;
|
||||||
verify = null;
|
verify = null;
|
||||||
@@ -109,7 +122,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
message = "";
|
message = "";
|
||||||
test = null;
|
test = null;
|
||||||
verify = null;
|
verify = null;
|
||||||
//::do-something k1=%3B=%0D=%0A=%5D;::%3B-%0D-%0A-%5D
|
//::do-something k1=;=%2C=%0D=%0A=]=%3A,::;-%0D-%0A-]-:-,
|
||||||
message = "::do-something k1=;=%2C=%0D=%0A=]=%3A,::;-%0D-%0A-]-:-,";
|
message = "::do-something k1=;=%2C=%0D=%0A=]=%3A,::;-%0D-%0A-]-:-,";
|
||||||
test = new ActionCommand("do-something")
|
test = new ActionCommand("do-something")
|
||||||
{
|
{
|
||||||
@@ -119,6 +132,19 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Assert.True(ActionCommand.TryParseV2(message, commands, out verify));
|
Assert.True(ActionCommand.TryParseV2(message, commands, out verify));
|
||||||
Assert.True(IsEqualCommand(hc, test, verify));
|
Assert.True(IsEqualCommand(hc, test, verify));
|
||||||
|
|
||||||
|
message = "";
|
||||||
|
test = null;
|
||||||
|
verify = null;
|
||||||
|
//::do-something k1=;=%252C=%250D=%250A=]=%253A,::;-%250D-%250A-]-:-,
|
||||||
|
message = "::do-something k1=;=%252C=%250D=%250A=]=%253A,::;-%250D-%250A-]-:-,";
|
||||||
|
test = new ActionCommand("do-something")
|
||||||
|
{
|
||||||
|
Data = ";-%0D-%0A-]-:-,",
|
||||||
|
};
|
||||||
|
test.Properties.Add("k1", ";=%2C=%0D=%0A=]=%3A");
|
||||||
|
Assert.True(ActionCommand.TryParseV2(message, commands, out verify));
|
||||||
|
Assert.True(IsEqualCommand(hc, test, verify));
|
||||||
|
|
||||||
message = "";
|
message = "";
|
||||||
test = null;
|
test = null;
|
||||||
verify = null;
|
verify = null;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile));
|
Directory.CreateDirectory(Path.GetDirectoryName(watermarkFile));
|
||||||
File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString());
|
File.WriteAllText(watermarkFile, DateTime.UtcNow.ToString());
|
||||||
Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist"));
|
Directory.CreateDirectory(Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist"));
|
||||||
File.Copy(Path.Combine(Environment.GetEnvironmentVariable("GITHUB_RUNNER_SRC_DIR"), "Test", TestDataFolderName, "dockerfileaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml"));
|
File.Copy(Path.Combine(TestUtil.GetSrcPath(), "Test", TestDataFolderName, "dockerfileaction.yml"), Path.Combine(Path.GetDirectoryName(watermarkFile), "notexist", "action.yml"));
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Threading.Tasks;
|
|||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
|
using GitHub.Runner.Worker.Container;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -748,6 +749,130 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Environment.SetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE", "");
|
Environment.SetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OS_LINUX
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void MatcherFile_JobContainer()
|
||||||
|
{
|
||||||
|
var matchers = new IssueMatchersConfig
|
||||||
|
{
|
||||||
|
Matchers =
|
||||||
|
{
|
||||||
|
new IssueMatcherConfig
|
||||||
|
{
|
||||||
|
Owner = "my-matcher-1",
|
||||||
|
Patterns = new[]
|
||||||
|
{
|
||||||
|
new IssuePatternConfig
|
||||||
|
{
|
||||||
|
Pattern = @"(.+): (.+)",
|
||||||
|
File = 1,
|
||||||
|
Message = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var container = new ContainerInfo();
|
||||||
|
using (var hostContext = Setup(matchers: matchers, jobContainer: container))
|
||||||
|
using (_outputManager)
|
||||||
|
{
|
||||||
|
// Setup github.workspace, github.repository
|
||||||
|
var workDirectory = hostContext.GetDirectory(WellKnownDirectory.Work);
|
||||||
|
ArgUtil.NotNullOrEmpty(workDirectory, nameof(workDirectory));
|
||||||
|
Directory.CreateDirectory(workDirectory);
|
||||||
|
var workspaceDirectory = Path.Combine(workDirectory, "workspace");
|
||||||
|
Directory.CreateDirectory(workspaceDirectory);
|
||||||
|
_executionContext.Setup(x => x.GetGitHubContext("workspace")).Returns(workspaceDirectory);
|
||||||
|
_executionContext.Setup(x => x.GetGitHubContext("repository")).Returns("my-org/workflow-repo");
|
||||||
|
|
||||||
|
// Setup a git repository
|
||||||
|
await CreateRepository(hostContext, workspaceDirectory, "https://github.com/my-org/workflow-repo");
|
||||||
|
|
||||||
|
// Create test files
|
||||||
|
var file = Path.Combine(workspaceDirectory, "some-file.txt");
|
||||||
|
File.WriteAllText(file, "");
|
||||||
|
|
||||||
|
// Add translation path
|
||||||
|
container.AddPathTranslateMapping(workspaceDirectory, "/container/path/to/workspace");
|
||||||
|
|
||||||
|
// Process
|
||||||
|
Process($"/container/path/to/workspace/some-file.txt: some error 1");
|
||||||
|
Process($"some-file.txt: some error 2");
|
||||||
|
|
||||||
|
Assert.Equal(2, _issues.Count);
|
||||||
|
|
||||||
|
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
||||||
|
Assert.Equal("some-file.txt", _issues[0].Item1.Data["file"]);
|
||||||
|
|
||||||
|
Assert.Equal("some error 2", _issues[1].Item1.Message);
|
||||||
|
Assert.Equal("some-file.txt", _issues[1].Item1.Data["file"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async void MatcherFile_StepContainer()
|
||||||
|
{
|
||||||
|
var matchers = new IssueMatchersConfig
|
||||||
|
{
|
||||||
|
Matchers =
|
||||||
|
{
|
||||||
|
new IssueMatcherConfig
|
||||||
|
{
|
||||||
|
Owner = "my-matcher-1",
|
||||||
|
Patterns = new[]
|
||||||
|
{
|
||||||
|
new IssuePatternConfig
|
||||||
|
{
|
||||||
|
Pattern = @"(.+): (.+)",
|
||||||
|
File = 1,
|
||||||
|
Message = 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
var container = new ContainerInfo();
|
||||||
|
using (var hostContext = Setup(matchers: matchers, stepContainer: container))
|
||||||
|
using (_outputManager)
|
||||||
|
{
|
||||||
|
// Setup github.workspace, github.repository
|
||||||
|
var workDirectory = hostContext.GetDirectory(WellKnownDirectory.Work);
|
||||||
|
ArgUtil.NotNullOrEmpty(workDirectory, nameof(workDirectory));
|
||||||
|
Directory.CreateDirectory(workDirectory);
|
||||||
|
var workspaceDirectory = Path.Combine(workDirectory, "workspace");
|
||||||
|
Directory.CreateDirectory(workspaceDirectory);
|
||||||
|
_executionContext.Setup(x => x.GetGitHubContext("workspace")).Returns(workspaceDirectory);
|
||||||
|
_executionContext.Setup(x => x.GetGitHubContext("repository")).Returns("my-org/workflow-repo");
|
||||||
|
|
||||||
|
// Setup a git repository
|
||||||
|
await CreateRepository(hostContext, workspaceDirectory, "https://github.com/my-org/workflow-repo");
|
||||||
|
|
||||||
|
// Create test files
|
||||||
|
var file = Path.Combine(workspaceDirectory, "some-file.txt");
|
||||||
|
File.WriteAllText(file, "");
|
||||||
|
|
||||||
|
// Add translation path
|
||||||
|
container.AddPathTranslateMapping(workspaceDirectory, "/container/path/to/workspace");
|
||||||
|
|
||||||
|
// Process
|
||||||
|
Process($"/container/path/to/workspace/some-file.txt: some error 1");
|
||||||
|
Process($"some-file.txt: some error 2");
|
||||||
|
|
||||||
|
Assert.Equal(2, _issues.Count);
|
||||||
|
|
||||||
|
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
||||||
|
Assert.Equal("some-file.txt", _issues[0].Item1.Data["file"]);
|
||||||
|
|
||||||
|
Assert.Equal("some error 2", _issues[1].Item1.Message);
|
||||||
|
Assert.Equal("some-file.txt", _issues[1].Item1.Data["file"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -806,7 +931,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
private TestHostContext Setup(
|
private TestHostContext Setup(
|
||||||
[CallerMemberName] string name = "",
|
[CallerMemberName] string name = "",
|
||||||
IssueMatchersConfig matchers = null)
|
IssueMatchersConfig matchers = null,
|
||||||
|
ContainerInfo jobContainer = null,
|
||||||
|
ContainerInfo stepContainer = null)
|
||||||
{
|
{
|
||||||
matchers?.Validate();
|
matchers?.Validate();
|
||||||
|
|
||||||
@@ -824,6 +951,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
.Returns(true);
|
.Returns(true);
|
||||||
_executionContext.Setup(x => x.Variables)
|
_executionContext.Setup(x => x.Variables)
|
||||||
.Returns(_variables);
|
.Returns(_variables);
|
||||||
|
_executionContext.Setup(x => x.Container)
|
||||||
|
.Returns(jobContainer);
|
||||||
_executionContext.Setup(x => x.GetMatchers())
|
_executionContext.Setup(x => x.GetMatchers())
|
||||||
.Returns(matchers?.Matchers ?? new List<IssueMatcherConfig>());
|
.Returns(matchers?.Matchers ?? new List<IssueMatcherConfig>());
|
||||||
_executionContext.Setup(x => x.Add(It.IsAny<OnMatcherChanged>()))
|
_executionContext.Setup(x => x.Add(It.IsAny<OnMatcherChanged>()))
|
||||||
@@ -856,7 +985,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
_outputManager = new OutputManager(_executionContext.Object, _commandManager.Object);
|
_outputManager = new OutputManager(_executionContext.Object, _commandManager.Object, stepContainer);
|
||||||
return hostContext;
|
return hostContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,8 +137,6 @@ function runtest ()
|
|||||||
ulimit -n 1024
|
ulimit -n 1024
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export GITHUB_RUNNER_SRC_DIR=${SCRIPT_DIR}
|
|
||||||
|
|
||||||
dotnet msbuild -t:test -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed "failed tests"
|
dotnet msbuild -t:test -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed "failed tests"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user