mirror of
https://github.com/actions/runner.git
synced 2026-01-07 19:03:09 +08:00
Compare commits
11 Commits
fhammerl/e
...
luketomlin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
534bcec44b | ||
|
|
97d28f7803 | ||
|
|
97c15fd816 | ||
|
|
bb7b1e8259 | ||
|
|
440c81b770 | ||
|
|
9958fc0374 | ||
|
|
81b07eb1c4 | ||
|
|
514ecec5a3 | ||
|
|
128b212b13 | ||
|
|
2dfa28e6e0 | ||
|
|
fd96246580 |
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -131,7 +131,7 @@ jobs:
|
|||||||
file=$(ls)
|
file=$(ls)
|
||||||
sha=$(sha256sum $file | awk '{ print $1 }')
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
echo "Computed sha256: $sha for $file"
|
echo "Computed sha256: $sha for $file"
|
||||||
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
echo "${{matrix.runtime}}-sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
id: sha
|
id: sha
|
||||||
name: Compute SHA256
|
name: Compute SHA256
|
||||||
@@ -140,8 +140,8 @@ jobs:
|
|||||||
file=$(ls)
|
file=$(ls)
|
||||||
sha=$(sha256sum $file | awk '{ print $1 }')
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
echo "Computed sha256: $sha for $file"
|
echo "Computed sha256: $sha for $file"
|
||||||
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
echo "${{matrix.runtime}}-sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
echo "::set-output name=sha256::$sha"
|
echo "sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
id: sha_noexternals
|
id: sha_noexternals
|
||||||
name: Compute SHA256
|
name: Compute SHA256
|
||||||
@@ -150,8 +150,8 @@ jobs:
|
|||||||
file=$(ls)
|
file=$(ls)
|
||||||
sha=$(sha256sum $file | awk '{ print $1 }')
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
echo "Computed sha256: $sha for $file"
|
echo "Computed sha256: $sha for $file"
|
||||||
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
echo "${{matrix.runtime}}-sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
echo "::set-output name=sha256::$sha"
|
echo "sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
id: sha_noruntime
|
id: sha_noruntime
|
||||||
name: Compute SHA256
|
name: Compute SHA256
|
||||||
@@ -160,8 +160,8 @@ jobs:
|
|||||||
file=$(ls)
|
file=$(ls)
|
||||||
sha=$(sha256sum $file | awk '{ print $1 }')
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
echo "Computed sha256: $sha for $file"
|
echo "Computed sha256: $sha for $file"
|
||||||
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
echo "${{matrix.runtime}}-sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
echo "::set-output name=sha256::$sha"
|
echo "sha256=$sha" >> $GITHUB_OUTPUT
|
||||||
shell: bash
|
shell: bash
|
||||||
id: sha_noruntime_noexternals
|
id: sha_noruntime_noexternals
|
||||||
name: Compute SHA256
|
name: Compute SHA256
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:6.0 as build
|
|||||||
|
|
||||||
ARG RUNNER_VERSION
|
ARG RUNNER_VERSION
|
||||||
ARG RUNNER_ARCH="x64"
|
ARG RUNNER_ARCH="x64"
|
||||||
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.2.0
|
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.3.1
|
||||||
ARG DOCKER_VERSION=20.10.23
|
ARG DOCKER_VERSION=20.10.23
|
||||||
|
|
||||||
RUN apt update -y && apt install curl unzip -y
|
RUN apt update -y && apt install curl unzip -y
|
||||||
@@ -46,4 +46,4 @@ COPY --chown=runner:docker --from=build /actions-runner .
|
|||||||
|
|
||||||
RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker
|
RUN install -o root -g root -m 755 docker/* /usr/bin/ && rm -rf docker
|
||||||
|
|
||||||
USER runner
|
USER runner
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
## Features
|
## Features
|
||||||
- Add support for ghe.com domain (#2420)
|
- Support matrix context in output keys (#2477)
|
||||||
- Add docker cli to the runner image. (#2425)
|
- Add update certificates to `./run.sh` if `RUNNER_UPDATE_CA_CERTS` env is set (#2471)
|
||||||
|
- Bypass all proxies for all hosts if `no_proxy='*'` is set (#2395)
|
||||||
|
- Change runner image to make user/folder align with `ubuntu-latest` hosted runner. (#2469)
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Fix URL construction bug for RunService (#2396)
|
- Exit on runner version deprecation error (#2299)
|
||||||
- Defer evaluation of a step's DisplayName until its condition is evaluated. (#2313)
|
- Runner service exit after consecutive re-try exits (#2426)
|
||||||
- Replace '(' and ')' with '[' and '] from OS.Description for fixing User-Agent header validation (#2288)
|
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
- Bump dotnet sdk to latest version. (#2392)
|
- Replace deprecated command with environment file (#2429)
|
||||||
- Start calling run service for job completion (#2412, #2423)
|
- Make requests to `Run` service to renew job request (#2461)
|
||||||
|
- Add job/step log upload to Result service (#2447, #2439)
|
||||||
|
|
||||||
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
|
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
|
||||||
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.
|
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.
|
||||||
|
|||||||
@@ -53,6 +53,33 @@ runWithManualTrap() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateCerts() {
|
||||||
|
local sudo_prefix=""
|
||||||
|
local user_id=`id -u`
|
||||||
|
|
||||||
|
if [ $user_id -ne 0 ]; then
|
||||||
|
if [[ ! -x "$(command -v sudo)" ]]; then
|
||||||
|
echo "Warning: failed to update certificate store: sudo is required but not found"
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
sudo_prefix="sudo"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -x "$(command -v update-ca-certificates)" ]]; then
|
||||||
|
eval $sudo_prefix "update-ca-certificates"
|
||||||
|
elif [[ -x "$(command -v update-ca-trust)" ]]; then
|
||||||
|
eval $sudo_prefix "update-ca-trust"
|
||||||
|
else
|
||||||
|
echo "Warning: failed to update certificate store: update-ca-certificates or update-ca-trust not found. This can happen if you're using a different runner base image."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ ! -z "$RUNNER_UPDATE_CA_CERTS" ]]; then
|
||||||
|
updateCerts
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ -z "$RUNNER_MANUALLY_TRAP_SIG" ]]; then
|
if [[ -z "$RUNNER_MANUALLY_TRAP_SIG" ]]; then
|
||||||
run $*
|
run $*
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -50,6 +50,9 @@ namespace GitHub.Runner.Common
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string MonitorSocketAddress { get; set; }
|
public string MonitorSocketAddress { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public bool UseV2Flow { get; set; }
|
||||||
|
|
||||||
[IgnoreDataMember]
|
[IgnoreDataMember]
|
||||||
public bool IsHostedServer
|
public bool IsHostedServer
|
||||||
{
|
{
|
||||||
|
|||||||
245
src/Runner.Common/RunnerDotcomServer.cs
Normal file
245
src/Runner.Common/RunnerDotcomServer.cs
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.Http.Headers;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common
|
||||||
|
{
|
||||||
|
[ServiceLocator(Default = typeof(RunnerDotcomServer))]
|
||||||
|
public interface IRunnerDotcomServer : IRunnerService
|
||||||
|
{
|
||||||
|
Task<List<TaskAgent>> GetRunnersAsync(int runnerGroupId, string githubUrl, string githubToken, string agentName);
|
||||||
|
|
||||||
|
Task<TaskAgent> AddRunnerAsync(int runnerGroupId, TaskAgent agent, string githubUrl, string githubToken, string publicKey, string hostId);
|
||||||
|
Task<List<TaskAgentPool>> GetRunnerGroupsAsync(string githubUrl, string githubToken);
|
||||||
|
|
||||||
|
string GetGitHubRequestId(HttpResponseHeaders headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RequestType
|
||||||
|
{
|
||||||
|
Get,
|
||||||
|
Post,
|
||||||
|
Patch,
|
||||||
|
Delete
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RunnerDotcomServer : RunnerService, IRunnerDotcomServer
|
||||||
|
{
|
||||||
|
private ITerminal _term;
|
||||||
|
|
||||||
|
public override void Initialize(IHostContext hostContext)
|
||||||
|
{
|
||||||
|
base.Initialize(hostContext);
|
||||||
|
_term = hostContext.GetService<ITerminal>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<List<TaskAgent>> GetRunnersAsync(int runnerGroupId, string githubUrl, string githubToken, string agentName = null)
|
||||||
|
{
|
||||||
|
var githubApiUrl = "";
|
||||||
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
|
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (path.Length == 1)
|
||||||
|
{
|
||||||
|
// org runner
|
||||||
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/orgs/{path[0]}/actions/runner-groups/{runnerGroupId}/runners";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runner-groups/{runnerGroupId}/runners";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (path.Length == 2)
|
||||||
|
{
|
||||||
|
// repo or enterprise runner.
|
||||||
|
if (!string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runner-groups/{runnerGroupId}/runners";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runner-groups/{runnerGroupId}/runners";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"'{githubUrl}' should point to an org or enterprise.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var runnersList = await RetryRequest<ListRunnersResponse>(githubApiUrl, githubToken, RequestType.Get, 3, "Failed to get agents pools");
|
||||||
|
var agents = runnersList.ToTaskAgents();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(agentName))
|
||||||
|
{
|
||||||
|
return agents;
|
||||||
|
}
|
||||||
|
|
||||||
|
return agents.Where(x => string.Equals(x.Name, agentName, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<TaskAgentPool>> GetRunnerGroupsAsync(string githubUrl, string githubToken)
|
||||||
|
{
|
||||||
|
var githubApiUrl = "";
|
||||||
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
|
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (path.Length == 1)
|
||||||
|
{
|
||||||
|
// org runner
|
||||||
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/orgs/{path[0]}/actions/runner-groups";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runner-groups";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (path.Length == 2)
|
||||||
|
{
|
||||||
|
// repo or enterprise runner.
|
||||||
|
if (!string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runner-groups";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runner-groups";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"'{githubUrl}' should point to an org or enterprise.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var agentPools = await RetryRequest<RunnerGroupList>(githubApiUrl, githubToken, RequestType.Get, 3, "Failed to get agents pools");
|
||||||
|
|
||||||
|
return agentPools?.ToAgentPoolList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<TaskAgent> AddRunnerAsync(int runnerGroupId, TaskAgent agent, string githubUrl, string githubToken, string publicKey, string hostId)
|
||||||
|
{
|
||||||
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
|
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
string githubApiUrl;
|
||||||
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/actions/runners/register";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/actions/runners/register";
|
||||||
|
}
|
||||||
|
|
||||||
|
var bodyObject = new Dictionary<string, Object>()
|
||||||
|
{
|
||||||
|
{"url", githubUrl},
|
||||||
|
{"group_id", runnerGroupId},
|
||||||
|
{"name", agent.Name},
|
||||||
|
{"version", agent.Version},
|
||||||
|
{"updates_disabled", agent.DisableUpdate},
|
||||||
|
{"ephemeral", agent.Ephemeral},
|
||||||
|
{"labels", agent.Labels},
|
||||||
|
{"public_key", publicKey},
|
||||||
|
{"host_id", hostId},
|
||||||
|
};
|
||||||
|
|
||||||
|
var body = new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json");
|
||||||
|
|
||||||
|
var runner = await RetryRequest<DistributedTask.WebApi.Runner>(githubApiUrl, githubToken, RequestType.Post, 3, "Failed to add agent", body);
|
||||||
|
agent.Id = runner.Id;
|
||||||
|
agent.Authorization = new TaskAgentAuthorization()
|
||||||
|
{
|
||||||
|
AuthorizationUrl = runner.RunnerAuthorization.AuthorizationUrl,
|
||||||
|
ClientId = new Guid(runner.RunnerAuthorization.ClientId),
|
||||||
|
};
|
||||||
|
return agent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<T> RetryRequest<T>(string githubApiUrl, string githubToken, RequestType requestType, int maxRetryAttemptsCount = 5, string errorMessage = null, StringContent body = null)
|
||||||
|
{
|
||||||
|
int retry = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
retry++;
|
||||||
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
|
{
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("RemoteAuth", githubToken);
|
||||||
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
|
||||||
|
var responseStatus = System.Net.HttpStatusCode.OK;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HttpResponseMessage response = null;
|
||||||
|
if (requestType == RequestType.Get)
|
||||||
|
{
|
||||||
|
response = await httpClient.GetAsync(githubApiUrl);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
response = await httpClient.PostAsync(githubApiUrl, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response != null)
|
||||||
|
{
|
||||||
|
responseStatus = response.StatusCode;
|
||||||
|
var githubRequestId = GetGitHubRequestId(response.Headers);
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Trace.Info($"Http response code: {response.StatusCode} from '{requestType.ToString()} {githubApiUrl}' ({githubRequestId})");
|
||||||
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
return StringUtil.ConvertFromJson<T>(jsonResponse);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_term.WriteError($"Http response code: {response.StatusCode} from '{requestType.ToString()} {githubApiUrl}' (Request Id: {githubRequestId})");
|
||||||
|
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
_term.WriteError(errorResponse);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (retry < maxRetryAttemptsCount && responseStatus != System.Net.HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
Trace.Error($"{errorMessage} -- Atempt: {retry}");
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));
|
||||||
|
Trace.Info($"Retrying in {backOff.Seconds} seconds");
|
||||||
|
await Task.Delay(backOff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetGitHubRequestId(HttpResponseHeaders headers)
|
||||||
|
{
|
||||||
|
if (headers.TryGetValues("x-github-request-id", out var headerValues))
|
||||||
|
{
|
||||||
|
return headerValues.FirstOrDefault();
|
||||||
|
}
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@ using GitHub.Runner.Sdk;
|
|||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.Common.Internal;
|
using GitHub.Services.Common.Internal;
|
||||||
using GitHub.Services.OAuth;
|
using GitHub.Services.OAuth;
|
||||||
|
using GitHub.Services.WebApi.Jwt;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Configuration
|
namespace GitHub.Runner.Listener.Configuration
|
||||||
{
|
{
|
||||||
@@ -31,12 +32,14 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
private IConfigurationStore _store;
|
private IConfigurationStore _store;
|
||||||
private IRunnerServer _runnerServer;
|
private IRunnerServer _runnerServer;
|
||||||
|
private IRunnerDotcomServer _dotcomServer;
|
||||||
private ITerminal _term;
|
private ITerminal _term;
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
_runnerServer = HostContext.GetService<IRunnerServer>();
|
_runnerServer = HostContext.GetService<IRunnerServer>();
|
||||||
|
_dotcomServer = HostContext.GetService<IRunnerDotcomServer>();
|
||||||
Trace.Verbose("Creating _store");
|
Trace.Verbose("Creating _store");
|
||||||
_store = hostContext.GetService<IConfigurationStore>();
|
_store = hostContext.GetService<IConfigurationStore>();
|
||||||
Trace.Verbose("store created");
|
Trace.Verbose("store created");
|
||||||
@@ -113,6 +116,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
ICredentialProvider credProvider = null;
|
ICredentialProvider credProvider = null;
|
||||||
VssCredentials creds = null;
|
VssCredentials creds = null;
|
||||||
_term.WriteSection("Authentication");
|
_term.WriteSection("Authentication");
|
||||||
|
string registerToken = string.Empty;
|
||||||
|
string hostId = string.Empty;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// When testing against a dev deployment of Actions Service, set this environment variable
|
// When testing against a dev deployment of Actions Service, set this environment variable
|
||||||
@@ -130,11 +135,14 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
runnerSettings.GitHubUrl = inputUrl;
|
runnerSettings.GitHubUrl = inputUrl;
|
||||||
var registerToken = await GetRunnerTokenAsync(command, inputUrl, "registration");
|
registerToken = await GetRunnerTokenAsync(command, inputUrl, "registration");
|
||||||
GitHubAuthResult authResult = await GetTenantCredential(inputUrl, registerToken, Constants.RunnerEvent.Register);
|
GitHubAuthResult authResult = await GetTenantCredential(inputUrl, registerToken, Constants.RunnerEvent.Register);
|
||||||
runnerSettings.ServerUrl = authResult.TenantUrl;
|
runnerSettings.ServerUrl = authResult.TenantUrl;
|
||||||
|
runnerSettings.UseV2Flow = authResult.UseV2Flow;
|
||||||
|
_term.WriteLine($"Using V2 flow: {runnerSettings.UseV2Flow}");
|
||||||
creds = authResult.ToVssCredentials();
|
creds = authResult.ToVssCredentials();
|
||||||
Trace.Info("cred retrieved via GitHub auth");
|
Trace.Info("cred retrieved via GitHub auth");
|
||||||
|
hostId = GetHostId(authResult.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -176,9 +184,11 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// We want to use the native CSP of the platform for storage, so we use the RSACSP directly
|
// We want to use the native CSP of the platform for storage, so we use the RSACSP directly
|
||||||
RSAParameters publicKey;
|
RSAParameters publicKey;
|
||||||
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
||||||
|
string publicKeyXML;
|
||||||
using (var rsa = keyManager.CreateKey())
|
using (var rsa = keyManager.CreateKey())
|
||||||
{
|
{
|
||||||
publicKey = rsa.ExportParameters(false);
|
publicKey = rsa.ExportParameters(false);
|
||||||
|
publicKeyXML = rsa.ToXmlString(includePrivateParameters: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_term.WriteSection("Runner Registration");
|
_term.WriteSection("Runner Registration");
|
||||||
@@ -186,9 +196,17 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// If we have more than one runner group available, allow the user to specify which one to be added into
|
// If we have more than one runner group available, allow the user to specify which one to be added into
|
||||||
string poolName = null;
|
string poolName = null;
|
||||||
TaskAgentPool agentPool = null;
|
TaskAgentPool agentPool = null;
|
||||||
List<TaskAgentPool> agentPools = await _runnerServer.GetAgentPoolsAsync();
|
List<TaskAgentPool> agentPools;
|
||||||
TaskAgentPool defaultPool = agentPools?.Where(x => x.IsInternal).FirstOrDefault();
|
if (runnerSettings.UseV2Flow)
|
||||||
|
{
|
||||||
|
agentPools = await _dotcomServer.GetRunnerGroupsAsync(runnerSettings.GitHubUrl, registerToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
agentPools = await _runnerServer.GetAgentPoolsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskAgentPool defaultPool = agentPools?.Where(x => x.IsInternal).FirstOrDefault();
|
||||||
if (agentPools?.Where(x => !x.IsHosted).Count() > 0)
|
if (agentPools?.Where(x => !x.IsHosted).Count() > 0)
|
||||||
{
|
{
|
||||||
poolName = command.GetRunnerGroupName(defaultPool?.Name);
|
poolName = command.GetRunnerGroupName(defaultPool?.Name);
|
||||||
@@ -226,8 +244,16 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
var userLabels = command.GetLabels();
|
var userLabels = command.GetLabels();
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
|
List<TaskAgent> agents;
|
||||||
|
if (runnerSettings.UseV2Flow)
|
||||||
|
{
|
||||||
|
agents = await _dotcomServer.GetRunnersAsync(runnerSettings.PoolId, runnerSettings.GitHubUrl, registerToken, runnerSettings.AgentName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
agents = await _runnerServer.GetAgentsAsync(runnerSettings.PoolId, runnerSettings.AgentName);
|
||||||
|
}
|
||||||
|
|
||||||
var agents = await _runnerServer.GetAgentsAsync(runnerSettings.PoolId, runnerSettings.AgentName);
|
|
||||||
Trace.Verbose("Returns {0} agents", agents.Count);
|
Trace.Verbose("Returns {0} agents", agents.Count);
|
||||||
agent = agents.FirstOrDefault();
|
agent = agents.FirstOrDefault();
|
||||||
if (agent != null)
|
if (agent != null)
|
||||||
@@ -274,7 +300,15 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
agent = await _runnerServer.AddAgentAsync(runnerSettings.PoolId, agent);
|
if (runnerSettings.UseV2Flow)
|
||||||
|
{
|
||||||
|
agent = await _dotcomServer.AddRunnerAsync(runnerSettings.PoolId, agent, runnerSettings.GitHubUrl, registerToken, publicKeyXML, hostId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
agent = await _runnerServer.AddAgentAsync(runnerSettings.PoolId, agent);
|
||||||
|
}
|
||||||
|
|
||||||
if (command.DisableUpdate &&
|
if (command.DisableUpdate &&
|
||||||
command.DisableUpdate != agent.DisableUpdate)
|
command.DisableUpdate != agent.DisableUpdate)
|
||||||
{
|
{
|
||||||
@@ -652,7 +686,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
||||||
responseStatus = response.StatusCode;
|
responseStatus = response.StatusCode;
|
||||||
var githubRequestId = GetGitHubRequestId(response.Headers);
|
var githubRequestId = _dotcomServer.GetGitHubRequestId(response.Headers);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
@@ -715,7 +749,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
||||||
responseStatus = response.StatusCode;
|
responseStatus = response.StatusCode;
|
||||||
var githubRequestId = GetGitHubRequestId(response.Headers);
|
var githubRequestId = _dotcomServer.GetGitHubRequestId(response.Headers);
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
@@ -745,13 +779,11 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetGitHubRequestId(HttpResponseHeaders headers)
|
// Temporary hack for sending legacy host id using v2 flow
|
||||||
|
private string GetHostId(string accessToken)
|
||||||
{
|
{
|
||||||
if (headers.TryGetValues("x-github-request-id", out var headerValues))
|
var claims = JsonWebToken.Create(accessToken).ExtractClaims();
|
||||||
{
|
return claims.FirstOrDefault(x => x.Type == "aud").Value.Split(':').LastOrDefault();
|
||||||
return headerValues.FirstOrDefault();
|
|
||||||
}
|
|
||||||
return string.Empty;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
@@ -20,8 +20,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
public static readonly Dictionary<string, Type> CredentialTypes = new(StringComparer.OrdinalIgnoreCase)
|
public static readonly Dictionary<string, Type> CredentialTypes = new(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
{ Constants.Configuration.OAuth, typeof(OAuthCredential)},
|
{ Constants.Configuration.OAuth, typeof(OAuthCredential) },
|
||||||
{ Constants.Configuration.OAuthAccessToken, typeof(OAuthAccessTokenCredential)},
|
{ Constants.Configuration.OAuthAccessToken, typeof(OAuthAccessTokenCredential) },
|
||||||
};
|
};
|
||||||
|
|
||||||
public ICredentialProvider GetCredentialProvider(string credType)
|
public ICredentialProvider GetCredentialProvider(string credType)
|
||||||
@@ -93,6 +93,9 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
[DataMember(Name = "token")]
|
[DataMember(Name = "token")]
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "use_v2_flow")]
|
||||||
|
public bool UseV2Flow { get; set; }
|
||||||
|
|
||||||
public VssCredentials ToVssCredentials()
|
public VssCredentials ToVssCredentials()
|
||||||
{
|
{
|
||||||
ArgUtil.NotNullOrEmpty(TokenSchema, nameof(TokenSchema));
|
ArgUtil.NotNullOrEmpty(TokenSchema, nameof(TokenSchema));
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ namespace GitHub.Runner.Listener
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_getMessagesTokenSource?.Cancel();
|
_getMessagesTokenSource?.Cancel();
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException)
|
catch (ObjectDisposedException)
|
||||||
{
|
{
|
||||||
Trace.Info("_getMessagesTokenSource is already disposed.");
|
Trace.Info("_getMessagesTokenSource is already disposed.");
|
||||||
@@ -245,6 +245,10 @@ namespace GitHub.Runner.Listener
|
|||||||
_accessTokenRevoked = true;
|
_accessTokenRevoked = true;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
catch (AccessDeniedException e) when (e.InnerException is InvalidTaskAgentVersionException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Trace.Error("Catch exception during get next message.");
|
Trace.Error("Catch exception during get next message.");
|
||||||
@@ -289,7 +293,7 @@ namespace GitHub.Runner.Listener
|
|||||||
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_getMessagesTokenSource.Dispose();
|
_getMessagesTokenSource.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using System.IO;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -58,7 +59,7 @@ namespace GitHub.Runner.Listener
|
|||||||
terminal.WriteLine("This runner version is built for Windows. Please install a correct build for your OS.");
|
terminal.WriteLine("This runner version is built for Windows. Please install a correct build for your OS.");
|
||||||
return Constants.Runner.ReturnCode.TerminatedError;
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
}
|
}
|
||||||
#if ARM64
|
#if ARM64
|
||||||
// A little hacky, but windows gives no way to differentiate between windows 10 and 11.
|
// A little hacky, but windows gives no way to differentiate between windows 10 and 11.
|
||||||
// By default only 11 supports native x64 app emulation on arm, so we only want to support windows 11
|
// By default only 11 supports native x64 app emulation on arm, so we only want to support windows 11
|
||||||
// https://docs.microsoft.com/en-us/windows/arm/overview#build-windows-apps-that-run-on-arm
|
// https://docs.microsoft.com/en-us/windows/arm/overview#build-windows-apps-that-run-on-arm
|
||||||
@@ -69,7 +70,7 @@ namespace GitHub.Runner.Listener
|
|||||||
terminal.WriteLine("Win-arm64 runners require windows 11 or later. Please upgrade your operating system.");
|
terminal.WriteLine("Win-arm64 runners require windows 11 or later. Please upgrade your operating system.");
|
||||||
return Constants.Runner.ReturnCode.TerminatedError;
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
terminal.WriteLine($"Running the runner on this platform is not supported. The current platform is {RuntimeInformation.OSDescription} and it was built for {Constants.Runner.Platform.ToString()}.");
|
terminal.WriteLine($"Running the runner on this platform is not supported. The current platform is {RuntimeInformation.OSDescription} and it was built for {Constants.Runner.Platform.ToString()}.");
|
||||||
@@ -137,6 +138,12 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
catch (AccessDeniedException e) when (e.InnerException is InvalidTaskAgentVersionException)
|
||||||
|
{
|
||||||
|
terminal.WriteError($"An error occured: {e.Message}");
|
||||||
|
trace.Error(e);
|
||||||
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
terminal.WriteError($"An error occurred: {e.Message}");
|
terminal.WriteError($"An error occurred: {e.Message}");
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace GitHub.Runner.Worker
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions, ExecutionContext.ToExpressionState());
|
inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
||||||
}
|
}
|
||||||
|
|
||||||
var userInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
var userInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
@@ -355,7 +355,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
DictionaryContextData expressionValues = ExecutionContext.GetExpressionValues(stepHost);
|
DictionaryContextData expressionValues = ExecutionContext.GetExpressionValues(stepHost);
|
||||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, expressionValues, ExecutionContext.ExpressionFunctions, ExecutionContext.ToExpressionState());
|
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, expressionValues, ExecutionContext.ExpressionFunctions);
|
||||||
|
|
||||||
return inputs;
|
return inputs;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,6 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
githubContext.TryGetValue(PipelineTemplateConstants.Workspace, out var workspace);
|
githubContext.TryGetValue(PipelineTemplateConstants.Workspace, out var workspace);
|
||||||
var workspaceData = workspace as StringContextData;
|
var workspaceData = workspace as StringContextData;
|
||||||
ArgUtil.NotNull(workspaceData, nameof(workspaceData));
|
ArgUtil.NotNull(workspaceData, nameof(workspaceData));
|
||||||
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
|
||||||
|
|
||||||
|
|
||||||
string githubWorkspace = workspaceData.Value;
|
string githubWorkspace = workspaceData.Value;
|
||||||
bool followSymlink = false;
|
bool followSymlink = false;
|
||||||
|
|||||||
@@ -164,14 +164,13 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public Dictionary<String, String> EvaluateStepInputs(
|
public Dictionary<String, String> EvaluateStepInputs(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData,
|
||||||
IList<IFunctionInfo> expressionFunctions,
|
IList<IFunctionInfo> expressionFunctions)
|
||||||
IEnumerable<KeyValuePair<String, Object>> expressionState = null)
|
|
||||||
{
|
{
|
||||||
var result = default(Dictionary<String, String>);
|
var result = default(Dictionary<String, String>);
|
||||||
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
if (token != null && token.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
var context = CreateContext(contextData, expressionFunctions, expressionState);
|
var context = CreateContext(contextData, expressionFunctions);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepWith, token, 0, null, omitHeader: true);
|
token = TemplateEvaluator.Evaluate(context, PipelineTemplateConstants.StepWith, token, 0, null, omitHeader: true);
|
||||||
|
|||||||
@@ -222,6 +222,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
"job-outputs": {
|
"job-outputs": {
|
||||||
|
"context": [
|
||||||
|
"matrix"
|
||||||
|
],
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
"loose-value-type": "string-runner-context"
|
"loose-value-type": "string-runner-context"
|
||||||
|
|||||||
48
src/Sdk/DTWebApi/WebApi/ListRunnersResponse.cs
Normal file
48
src/Sdk/DTWebApi/WebApi/ListRunnersResponse.cs
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GitHub.DistributedTask.WebApi
|
||||||
|
{
|
||||||
|
|
||||||
|
public class ListRunnersResponse
|
||||||
|
{
|
||||||
|
public ListRunnersResponse()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListRunnersResponse(ListRunnersResponse responseToBeCloned)
|
||||||
|
{
|
||||||
|
this.TotalCount = responseToBeCloned.TotalCount;
|
||||||
|
this.Runners = responseToBeCloned.Runners;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("total_count")]
|
||||||
|
public int TotalCount
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("runners")]
|
||||||
|
public List<Runner> Runners
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListRunnersResponse Clone()
|
||||||
|
{
|
||||||
|
return new ListRunnersResponse(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TaskAgent> ToTaskAgents()
|
||||||
|
{
|
||||||
|
return Runners.Select(runner => new TaskAgent() { Name = runner.Name }).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
47
src/Sdk/DTWebApi/WebApi/Runner.cs
Normal file
47
src/Sdk/DTWebApi/WebApi/Runner.cs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
using System;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace GitHub.DistributedTask.WebApi
|
||||||
|
{
|
||||||
|
public class Runner
|
||||||
|
{
|
||||||
|
|
||||||
|
public class Authorization
|
||||||
|
{
|
||||||
|
[JsonProperty("authorization_url")]
|
||||||
|
public Uri AuthorizationUrl
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("client_id")]
|
||||||
|
public string ClientId
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public Int32 Id
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("authorization")]
|
||||||
|
public Authorization RunnerAuthorization
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
internal set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
98
src/Sdk/DTWebApi/WebApi/RunnerGroup.cs
Normal file
98
src/Sdk/DTWebApi/WebApi/RunnerGroup.cs
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GitHub.DistributedTask.WebApi
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// An organization-level grouping of runners.
|
||||||
|
/// </summary>
|
||||||
|
[DataContract]
|
||||||
|
public class RunnerGroup
|
||||||
|
{
|
||||||
|
internal RunnerGroup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RunnerGroup(String name)
|
||||||
|
{
|
||||||
|
this.Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RunnerGroup(RunnerGroup poolToBeCloned)
|
||||||
|
{
|
||||||
|
this.Id = poolToBeCloned.Id;
|
||||||
|
this.IsHosted = poolToBeCloned.IsHosted;
|
||||||
|
this.Name = poolToBeCloned.Name;
|
||||||
|
this.IsDefault = poolToBeCloned.IsDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
[JsonProperty("id")]
|
||||||
|
public Int32 Id
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public String Name
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether or not this pool is internal and can't be modified by users
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
[JsonProperty("default")]
|
||||||
|
public bool IsDefault
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether or not this pool is managed by the service.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
[JsonProperty("is_hosted")]
|
||||||
|
public Boolean IsHosted
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RunnerGroupList
|
||||||
|
{
|
||||||
|
public RunnerGroupList()
|
||||||
|
{
|
||||||
|
this.RunnerGroups = new List<RunnerGroup>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TaskAgentPool> ToAgentPoolList()
|
||||||
|
{
|
||||||
|
var agentPools = this.RunnerGroups.Select(x => new TaskAgentPool(x.Name)
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
IsHosted = x.IsHosted,
|
||||||
|
IsInternal = x.IsDefault
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
return agentPools;
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonProperty("runner_groups")]
|
||||||
|
public List<RunnerGroup> RunnerGroups { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("total_count")]
|
||||||
|
public int Count { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
public class ConfigurationManagerL0
|
public class ConfigurationManagerL0
|
||||||
{
|
{
|
||||||
private Mock<IRunnerServer> _runnerServer;
|
private Mock<IRunnerServer> _runnerServer;
|
||||||
|
private Mock<IRunnerDotcomServer> _dotcomServer;
|
||||||
private Mock<ILocationServer> _locationServer;
|
private Mock<ILocationServer> _locationServer;
|
||||||
private Mock<ICredentialManager> _credMgr;
|
private Mock<ICredentialManager> _credMgr;
|
||||||
private Mock<IPromptManager> _promptManager;
|
private Mock<IPromptManager> _promptManager;
|
||||||
@@ -55,6 +56,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
_store = new Mock<IConfigurationStore>();
|
_store = new Mock<IConfigurationStore>();
|
||||||
_extnMgr = new Mock<IExtensionManager>();
|
_extnMgr = new Mock<IExtensionManager>();
|
||||||
_rsaKeyManager = new Mock<IRSAKeyManager>();
|
_rsaKeyManager = new Mock<IRSAKeyManager>();
|
||||||
|
_dotcomServer = new Mock<IRunnerDotcomServer>();
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
_serviceControlManager = new Mock<IWindowsServiceControlManager>();
|
_serviceControlManager = new Mock<IWindowsServiceControlManager>();
|
||||||
@@ -106,6 +108,10 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
_runnerServer.Setup(x => x.AddAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent));
|
_runnerServer.Setup(x => x.AddAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent));
|
||||||
_runnerServer.Setup(x => x.ReplaceAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent));
|
_runnerServer.Setup(x => x.ReplaceAgentAsync(It.IsAny<int>(), It.IsAny<TaskAgent>())).Returns(Task.FromResult(expectedAgent));
|
||||||
|
|
||||||
|
_dotcomServer.Setup(x => x.GetRunnersAsync(It.IsAny<int>(), It.IsAny<string>(), It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(expectedAgents));
|
||||||
|
_dotcomServer.Setup(x => x.GetRunnerGroupsAsync(It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(expectedPools));
|
||||||
|
_dotcomServer.Setup(x => x.AddRunnerAsync(It.IsAny<int>(), It.IsAny<TaskAgent>(), It.IsAny<string>(), It.IsAny<string>())).Returns(Task.FromResult(expectedAgent));
|
||||||
|
|
||||||
rsa = new RSACryptoServiceProvider(2048);
|
rsa = new RSACryptoServiceProvider(2048);
|
||||||
|
|
||||||
_rsaKeyManager.Setup(x => x.CreateKey()).Returns(rsa);
|
_rsaKeyManager.Setup(x => x.CreateKey()).Returns(rsa);
|
||||||
@@ -119,6 +125,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
tc.SetSingleton<IConfigurationStore>(_store.Object);
|
tc.SetSingleton<IConfigurationStore>(_store.Object);
|
||||||
tc.SetSingleton<IExtensionManager>(_extnMgr.Object);
|
tc.SetSingleton<IExtensionManager>(_extnMgr.Object);
|
||||||
tc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
tc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
|
tc.SetSingleton<IRunnerDotcomServer>(_dotcomServer.Object);
|
||||||
tc.SetSingleton<ILocationServer>(_locationServer.Object);
|
tc.SetSingleton<ILocationServer>(_locationServer.Object);
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
|||||||
@@ -25,25 +25,25 @@ runs:
|
|||||||
- run: exit ${{ inputs.exit-code }}
|
- run: exit ${{ inputs.exit-code }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- run: echo "::set-output name=default::true"
|
- run: echo "default=true" >> $GITHUB_OUTPUT
|
||||||
id: default-conditional
|
id: default-conditional
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- run: echo "::set-output name=success::true"
|
- run: echo "success=true" >> $GITHUB_OUTPUT
|
||||||
id: success-conditional
|
id: success-conditional
|
||||||
shell: bash
|
shell: bash
|
||||||
if: success()
|
if: success()
|
||||||
|
|
||||||
- run: echo "::set-output name=failure::true"
|
- run: echo "failure=true" >> $GITHUB_OUTPUT
|
||||||
id: failure-conditional
|
id: failure-conditional
|
||||||
shell: bash
|
shell: bash
|
||||||
if: failure()
|
if: failure()
|
||||||
|
|
||||||
- run: echo "::set-output name=always::true"
|
- run: echo "always=true" >> $GITHUB_OUTPUT
|
||||||
id: always-conditional
|
id: always-conditional
|
||||||
shell: bash
|
shell: bash
|
||||||
if: always()
|
if: always()
|
||||||
|
|
||||||
- run: echo "failed"
|
- run: echo "failed"
|
||||||
shell: bash
|
shell: bash
|
||||||
if: ${{ inputs.exit-code == 1 && failure() }}
|
if: ${{ inputs.exit-code == 1 && failure() }}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.302.1
|
2.303.0
|
||||||
|
|||||||
Reference in New Issue
Block a user