mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
2 Commits
v2.319.1
...
revert-291
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
afb39c9c3c | ||
|
|
7f9c42fc15 |
4
.github/workflows/publish-image.yml
vendored
4
.github/workflows/publish-image.yml
vendored
@@ -25,12 +25,10 @@ jobs:
|
|||||||
- name: Compute image version
|
- name: Compute image version
|
||||||
id: image
|
id: image
|
||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v6
|
||||||
env:
|
|
||||||
RUNNER_VERSION: ${{ github.event.inputs.runnerVersion }}
|
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const inputRunnerVersion = process.env.RUNNER_VERSION;
|
const inputRunnerVersion = "${{ github.event.inputs.runnerVersion }}"
|
||||||
if (inputRunnerVersion) {
|
if (inputRunnerVersion) {
|
||||||
console.log(`Using input runner version ${inputRunnerVersion}`)
|
console.log(`Using input runner version ${inputRunnerVersion}`)
|
||||||
core.setOutput('version', inputRunnerVersion);
|
core.setOutput('version', inputRunnerVersion);
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
||||||
|
|
||||||
The runner carries its own copy of node.js executable under `<runner_root>/externals/node16/`.
|
The runner carries its own copy of node.js executable under `<runner_root>/externals/node20/`.
|
||||||
|
|
||||||
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node16/`.
|
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node20/`.
|
||||||
|
|
||||||
> Not the `node` from `$PATH`
|
> Not the `node` from `$PATH`
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,16 @@
|
|||||||
|
|
||||||
## Supported Distributions and Versions
|
## Supported Distributions and Versions
|
||||||
|
|
||||||
Please see "[Supported architectures and operating systems for self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#linux)."
|
x64
|
||||||
|
- Red Hat Enterprise Linux 7+
|
||||||
|
- CentOS 7+
|
||||||
|
- Oracle Linux 7+
|
||||||
|
- Fedora 29+
|
||||||
|
- Debian 9+
|
||||||
|
- Ubuntu 16.04+
|
||||||
|
- Linux Mint 18+
|
||||||
|
- openSUSE 15+
|
||||||
|
- SUSE Enterprise Linux (SLES) 12 SP2+
|
||||||
|
|
||||||
## Install .Net Core 3.x Linux Dependencies
|
## Install .Net Core 3.x Linux Dependencies
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
Please see "[Supported architectures and operating systems for self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#macos)."
|
- macOS High Sierra (10.13) and later versions
|
||||||
|
- x64 and arm64 (Apple Silicon)
|
||||||
|
|
||||||
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)
|
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
Please see "[Supported architectures and operating systems for self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#windows)."
|
- Windows 7 64-bit
|
||||||
|
- Windows 8.1 64-bit
|
||||||
|
- Windows 10 64-bit
|
||||||
|
- Windows Server 2012 R2 64-bit
|
||||||
|
- Windows Server 2016 64-bit
|
||||||
|
- Windows Server 2019 64-bit
|
||||||
|
|
||||||
## [More .NET Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore30)
|
## [More .NET Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore30)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy as build
|
|||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG RUNNER_VERSION
|
ARG RUNNER_VERSION
|
||||||
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.1
|
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.0
|
||||||
ARG DOCKER_VERSION=27.1.1
|
ARG DOCKER_VERSION=25.0.4
|
||||||
ARG BUILDX_VERSION=0.16.2
|
ARG BUILDX_VERSION=0.13.1
|
||||||
|
|
||||||
RUN apt update -y && apt install curl unzip -y
|
RUN apt update -y && apt install curl unzip -y
|
||||||
|
|
||||||
@@ -39,15 +39,12 @@ ENV RUNNER_MANUALLY_TRAP_SIG=1
|
|||||||
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
|
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
|
||||||
ENV ImageOS=ubuntu22
|
ENV ImageOS=ubuntu22
|
||||||
|
|
||||||
# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows
|
RUN apt-get update -y \
|
||||||
RUN apt update -y \
|
&& apt-get install -y --no-install-recommends \
|
||||||
&& apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common \
|
sudo \
|
||||||
|
lsb-release \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Configure git-core/ppa based on guidance here: https://git-scm.com/download/linux
|
|
||||||
RUN add-apt-repository ppa:git-core/ppa \
|
|
||||||
&& apt update -y
|
|
||||||
|
|
||||||
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
|
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
|
||||||
&& groupadd docker --gid 123 \
|
&& groupadd docker --gid 123 \
|
||||||
&& usermod -aG sudo runner \
|
&& usermod -aG sudo runner \
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
## What's Changed
|
## What's Changed
|
||||||
|
|
||||||
- .NET 8 compat test adjustments: 1) do not trim SDK, 2) support pattern to match output, 3) modify output truncation length https://github.com/actions/runner/pull/3427
|
- Preserve dates when deserializing job message from Run Service by @ericsciple in https://github.com/actions/runner/pull/3269
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/actions/runner/compare/v2.319.0...v2.319.1
|
**Full Changelog**: https://github.com/actions/runner/compare/v2.316.0...v2.316.1
|
||||||
|
|
||||||
_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.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.319.1
|
<Update to ./src/runnerversion when creating release>
|
||||||
|
|||||||
1
src/Misc/contentHash/dotnetRuntime/linux-arm
Normal file
1
src/Misc/contentHash/dotnetRuntime/linux-arm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
54d95a44d118dba852395991224a6b9c1abe916858c87138656f80c619e85331
|
||||||
1
src/Misc/contentHash/dotnetRuntime/linux-arm64
Normal file
1
src/Misc/contentHash/dotnetRuntime/linux-arm64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
68015af17f06a824fa478e62ae7393766ce627fd5599ab916432a14656a19a52
|
||||||
1
src/Misc/contentHash/dotnetRuntime/linux-x64
Normal file
1
src/Misc/contentHash/dotnetRuntime/linux-x64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
a2628119ca419cb54e279103ffae7986cdbd0814d57c73ff0dc74c38be08b9ae
|
||||||
1
src/Misc/contentHash/dotnetRuntime/osx-arm64
Normal file
1
src/Misc/contentHash/dotnetRuntime/osx-arm64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
de71ca09ead807e1a2ce9df0a5b23eb7690cb71fff51169a77e4c3992be53dda
|
||||||
1
src/Misc/contentHash/dotnetRuntime/osx-x64
Normal file
1
src/Misc/contentHash/dotnetRuntime/osx-x64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
d009e05e6b26d614d65be736a15d1bd151932121c16a9ff1b986deadecc982b9
|
||||||
1
src/Misc/contentHash/dotnetRuntime/win-arm64
Normal file
1
src/Misc/contentHash/dotnetRuntime/win-arm64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
f730db39c2305800b4653795360ba9c10c68f384a46b85d808f1f9f0ed3c42e4
|
||||||
1
src/Misc/contentHash/dotnetRuntime/win-x64
Normal file
1
src/Misc/contentHash/dotnetRuntime/win-x64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
a35b5722375490e9473cdcccb5e18b41eba3dbf4344fe31abc9821e21f18ea5a
|
||||||
1
src/Misc/contentHash/externals/linux-arm
vendored
Normal file
1
src/Misc/contentHash/externals/linux-arm
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
4bf3e1af0d482af1b2eaf9f08250248a8c1aea8ec20a3c5be116d58cdd930009
|
||||||
1
src/Misc/contentHash/externals/linux-arm64
vendored
Normal file
1
src/Misc/contentHash/externals/linux-arm64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ec1719a8cb4d8687328aa64f4aa7c4e3498a715d8939117874782e3e6e63a14b
|
||||||
1
src/Misc/contentHash/externals/linux-x64
vendored
Normal file
1
src/Misc/contentHash/externals/linux-x64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
50538de29f173bb73f708c4ed2c8328a62b8795829b97b2a6cb57197e2305287
|
||||||
1
src/Misc/contentHash/externals/osx-arm64
vendored
Normal file
1
src/Misc/contentHash/externals/osx-arm64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
a0a96cbb7593643b69e669bf14d7b29b7f27800b3a00bb3305aebe041456c701
|
||||||
1
src/Misc/contentHash/externals/osx-x64
vendored
Normal file
1
src/Misc/contentHash/externals/osx-x64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
6255b22692779467047ecebd60ad46984866d75cdfe10421d593a7b51d620b09
|
||||||
1
src/Misc/contentHash/externals/win-arm64
vendored
Normal file
1
src/Misc/contentHash/externals/win-arm64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
6ff1abd055dc35bfbf06f75c2f08908f660346f66ad1d8f81c910068e9ba029d
|
||||||
1
src/Misc/contentHash/externals/win-x64
vendored
Normal file
1
src/Misc/contentHash/externals/win-x64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
433a6d748742d12abd20dc2a79b62ac3d9718ae47ef26f8e84dc8c180eea3659
|
||||||
@@ -5,11 +5,10 @@ PRECACHE=$2
|
|||||||
NODE_URL=https://nodejs.org/dist
|
NODE_URL=https://nodejs.org/dist
|
||||||
UNOFFICIAL_NODE_URL=https://unofficial-builds.nodejs.org/download/release
|
UNOFFICIAL_NODE_URL=https://unofficial-builds.nodejs.org/download/release
|
||||||
NODE_ALPINE_URL=https://github.com/actions/alpine_nodejs/releases/download
|
NODE_ALPINE_URL=https://github.com/actions/alpine_nodejs/releases/download
|
||||||
# When you update Node versions you must also create a new release of alpine_nodejs at that updated version.
|
|
||||||
# Follow the instructions here: https://github.com/actions/alpine_nodejs?tab=readme-ov-file#getting-started
|
|
||||||
NODE16_VERSION="16.20.2"
|
NODE16_VERSION="16.20.2"
|
||||||
NODE20_VERSION="20.13.1"
|
NODE20_VERSION="20.8.1"
|
||||||
NODE16_UNOFFICIAL_VERSION="16.20.0" # used only for win-arm64, remove node16 unofficial version when official version is available
|
# used only for win-arm64, remove node16 unofficial version when official version is available
|
||||||
|
NODE16_UNOFFICIAL_VERSION="16.20.0"
|
||||||
|
|
||||||
get_abs_path() {
|
get_abs_path() {
|
||||||
# exploits the fact that pwd will print abs path when no args
|
# exploits the fact that pwd will print abs path when no args
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ if [ -f ".path" ]; then
|
|||||||
echo ".path=${PATH}"
|
echo ".path=${PATH}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nodever=${GITHUB_ACTIONS_RUNNER_FORCED_NODE_VERSION:-node16}
|
nodever=${GITHUB_ACTIONS_RUNNER_FORCED_NODE_VERSION:-node20}
|
||||||
|
|
||||||
# insert anything to setup env when running as a service
|
# insert anything to setup env when running as a service
|
||||||
# run the host process which keep the listener alive
|
# run the host process which keep the listener alive
|
||||||
|
|||||||
@@ -135,12 +135,17 @@ if [[ "$currentplatform" == 'darwin' && restartinteractiverunner -eq 0 ]]; then
|
|||||||
then
|
then
|
||||||
# inspect the open file handles to find the node process
|
# inspect the open file handles to find the node process
|
||||||
# we can't actually inspect the process using ps because it uses relative paths and doesn't follow symlinks
|
# we can't actually inspect the process using ps because it uses relative paths and doesn't follow symlinks
|
||||||
nodever="node16"
|
nodever="node20"
|
||||||
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node12
|
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node16
|
||||||
then
|
then
|
||||||
nodever="node12"
|
nodever="node16"
|
||||||
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
|
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node12
|
||||||
|
then
|
||||||
|
nodever="node12"
|
||||||
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $? -eq 0 && -n "$path" ]]
|
if [[ $? -eq 0 && -n "$path" ]]
|
||||||
then
|
then
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string DeprecatedNodeVersion = "node16";
|
public static readonly string DeprecatedNodeVersion = "node16";
|
||||||
public static readonly string EnforcedNode12DetectedAfterEndOfLife = "The following actions uses node12 which is deprecated and will be forced to run on node16: {0}. For more info: https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/";
|
public static readonly string EnforcedNode12DetectedAfterEndOfLife = "The following actions uses node12 which is deprecated and will be forced to run on node16: {0}. For more info: https://github.blog/changelog/2023-06-13-github-actions-all-actions-will-run-on-node16-instead-of-node12-by-default/";
|
||||||
public static readonly string EnforcedNode12DetectedAfterEndOfLifeEnvVariable = "Node16ForceActionsWarnings";
|
public static readonly string EnforcedNode12DetectedAfterEndOfLifeEnvVariable = "Node16ForceActionsWarnings";
|
||||||
public static readonly string EnforcedNode16DetectedAfterEndOfLife = "The following actions use a deprecated Node.js version and will be forced to run on node20: {0}. For more info: https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/";
|
public static readonly string EnforcedNode16DetectedAfterEndOfLife = "The following actions uses Node.js version which is deprecated and will be forced to run on node20: {0}. For more info: https://github.blog/changelog/2024-03-07-github-actions-all-actions-will-run-on-node20-instead-of-node16-by-default/";
|
||||||
public static readonly string EnforcedNode16DetectedAfterEndOfLifeEnvVariable = "Node20ForceActionsWarnings";
|
public static readonly string EnforcedNode16DetectedAfterEndOfLifeEnvVariable = "Node20ForceActionsWarnings";
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -262,7 +262,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
||||||
|
|
||||||
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
// Set this env var to "node16" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
||||||
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
||||||
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
||||||
public static readonly string PrintLogToStdout = "ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT";
|
public static readonly string PrintLogToStdout = "ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT";
|
||||||
@@ -280,10 +280,6 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string PhaseDisplayName = "system.phaseDisplayName";
|
public static readonly string PhaseDisplayName = "system.phaseDisplayName";
|
||||||
public static readonly string JobRequestType = "system.jobRequestType";
|
public static readonly string JobRequestType = "system.jobRequestType";
|
||||||
public static readonly string OrchestrationId = "system.orchestrationId";
|
public static readonly string OrchestrationId = "system.orchestrationId";
|
||||||
public static readonly string TestDotNet8Compatibility = "system.testDotNet8Compatibility";
|
|
||||||
public static readonly string DotNet8CompatibilityOutputLength = "system.dotNet8CompatibilityOutputLength";
|
|
||||||
public static readonly string DotNet8CompatibilityOutputPattern = "system.dotNet8CompatibilityOutputPattern";
|
|
||||||
public static readonly string DotNet8CompatibilityWarning = "system.dotNet8CompatibilityWarning";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Net.Security;
|
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -180,10 +179,6 @@ namespace GitHub.Runner.Common
|
|||||||
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
|
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
|
||||||
userAgentValues.AddRange(HostContext.UserAgents);
|
userAgentValues.AddRange(HostContext.UserAgents);
|
||||||
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
|
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
|
||||||
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
|
|
||||||
{
|
|
||||||
this._websocketClient.Options.RemoteCertificateValidationCallback = (_, _, _, _) => true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -613,7 +613,7 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
private void SendResultsTelemetry(Exception ex)
|
private void SendResultsTelemetry(Exception ex)
|
||||||
{
|
{
|
||||||
var issue = new Issue() { Type = IssueType.Warning, Message = $"Caught exception with results. {HostContext.SecretMasker.MaskSecrets(ex.Message)}" };
|
var issue = new Issue() { Type = IssueType.Warning, Message = $"Caught exception with results. {ex.Message}" };
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.ResultsUploadFailure;
|
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.ResultsUploadFailure;
|
||||||
|
|
||||||
var telemetryRecord = new TimelineRecord()
|
var telemetryRecord = new TimelineRecord()
|
||||||
@@ -709,9 +709,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
Trace.Info("Catch exception during update steps, skip update Results.");
|
Trace.Info("Catch exception during update steps, skip update Results.");
|
||||||
Trace.Error(e);
|
Trace.Error(e);
|
||||||
_resultsServiceExceptionsCount++;
|
if (!_resultsServiceOnly)
|
||||||
// If we hit any exceptions uploading to Results, let's skip any additional uploads to Results unless Results is serving logs
|
|
||||||
if (!_resultsServiceOnly && _resultsServiceExceptionsCount > 3)
|
|
||||||
{
|
{
|
||||||
_resultsClientInitiated = false;
|
_resultsClientInitiated = false;
|
||||||
SendResultsTelemetry(e);
|
SendResultsTelemetry(e);
|
||||||
|
|||||||
@@ -62,10 +62,7 @@ namespace GitHub.Runner.Common
|
|||||||
CheckConnection();
|
CheckConnection();
|
||||||
return RetryRequest<AgentJobRequestMessage>(
|
return RetryRequest<AgentJobRequestMessage>(
|
||||||
async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, VarUtil.OS, cancellationToken), cancellationToken,
|
async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, VarUtil.OS, cancellationToken), cancellationToken,
|
||||||
shouldRetry: ex =>
|
shouldRetry: ex => ex is not TaskOrchestrationJobAlreadyAcquiredException);
|
||||||
ex is not TaskOrchestrationJobNotFoundException && // HTTP status 404
|
|
||||||
ex is not TaskOrchestrationJobAlreadyAcquiredException && // HTTP status 409
|
|
||||||
ex is not TaskOrchestrationJobUnprocessableException); // HTTP status 422
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task CompleteJobAsync(
|
public Task CompleteJobAsync(
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace GitHub.Runner.Common.Util
|
|||||||
{
|
{
|
||||||
public static class NodeUtil
|
public static class NodeUtil
|
||||||
{
|
{
|
||||||
private const string _defaultNodeVersion = "node16";
|
private const string _defaultNodeVersion = "node20";
|
||||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16", "node20" });
|
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16", "node20" });
|
||||||
public static string GetInternalNodeVersion()
|
public static string GetInternalNodeVersion()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Services.Common;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
|
||||||
{
|
|
||||||
[ServiceLocator(Default = typeof(ErrorThrottler))]
|
|
||||||
public interface IErrorThrottler : IRunnerService
|
|
||||||
{
|
|
||||||
void Reset();
|
|
||||||
Task IncrementAndWaitAsync(CancellationToken token);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ErrorThrottler : RunnerService, IErrorThrottler
|
|
||||||
{
|
|
||||||
internal static readonly TimeSpan MinBackoff = TimeSpan.FromSeconds(1);
|
|
||||||
internal static readonly TimeSpan MaxBackoff = TimeSpan.FromMinutes(1);
|
|
||||||
internal static readonly TimeSpan BackoffCoefficient = TimeSpan.FromSeconds(1);
|
|
||||||
private int _count = 0;
|
|
||||||
|
|
||||||
public void Reset()
|
|
||||||
{
|
|
||||||
_count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task IncrementAndWaitAsync(CancellationToken token)
|
|
||||||
{
|
|
||||||
if (++_count <= 1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeSpan backoff = BackoffTimerHelper.GetExponentialBackoff(
|
|
||||||
attempt: _count - 2, // 0-based attempt
|
|
||||||
minBackoff: MinBackoff,
|
|
||||||
maxBackoff: MaxBackoff,
|
|
||||||
deltaBackoff: BackoffCoefficient);
|
|
||||||
Trace.Warning($"Back off {backoff.TotalSeconds} seconds before next attempt. Current consecutive error count: {_count}");
|
|
||||||
await HostContext.Delay(backoff, token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,25 +32,10 @@ namespace GitHub.Runner.Listener
|
|||||||
private bool _inConfigStage;
|
private bool _inConfigStage;
|
||||||
private ManualResetEvent _completedCommand = new(false);
|
private ManualResetEvent _completedCommand = new(false);
|
||||||
|
|
||||||
// <summary>
|
|
||||||
// Helps avoid excessive calls to Run Service when encountering non-retriable errors from /acquirejob.
|
|
||||||
// Normally we rely on the HTTP clients to back off between retry attempts. However, acquiring a job
|
|
||||||
// involves calls to both Run Serivce and Broker. And Run Service and Broker communicate with each other
|
|
||||||
// in an async fashion.
|
|
||||||
//
|
|
||||||
// When Run Service encounters a non-retriable error, it sends an async message to Broker. The runner will,
|
|
||||||
// however, immediately call Broker to get the next message. If the async event from Run Service to Broker
|
|
||||||
// has not yet been processed, the next message from Broker may be the same job message.
|
|
||||||
//
|
|
||||||
// The error throttler helps us back off when encountering successive, non-retriable errors from /acquirejob.
|
|
||||||
// </summary>
|
|
||||||
private IErrorThrottler _acquireJobThrottler;
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
_term = HostContext.GetService<ITerminal>();
|
_term = HostContext.GetService<ITerminal>();
|
||||||
_acquireJobThrottler = HostContext.CreateService<IErrorThrottler>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> ExecuteCommand(CommandSettings command)
|
public async Task<int> ExecuteCommand(CommandSettings command)
|
||||||
@@ -578,16 +563,13 @@ namespace GitHub.Runner.Listener
|
|||||||
await runServer.ConnectAsync(new Uri(messageRef.RunServiceUrl), creds);
|
await runServer.ConnectAsync(new Uri(messageRef.RunServiceUrl), creds);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
jobRequestMessage = await runServer.GetJobMessageAsync(messageRef.RunnerRequestId, messageQueueLoopTokenSource.Token);
|
jobRequestMessage =
|
||||||
_acquireJobThrottler.Reset();
|
await runServer.GetJobMessageAsync(messageRef.RunnerRequestId,
|
||||||
|
messageQueueLoopTokenSource.Token);
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (
|
catch (TaskOrchestrationJobAlreadyAcquiredException)
|
||||||
ex is TaskOrchestrationJobNotFoundException || // HTTP status 404
|
|
||||||
ex is TaskOrchestrationJobAlreadyAcquiredException || // HTTP status 409
|
|
||||||
ex is TaskOrchestrationJobUnprocessableException) // HTTP status 422
|
|
||||||
{
|
{
|
||||||
Trace.Info($"Skipping message Job. {ex.Message}");
|
Trace.Info("Job is already acquired, skip this message.");
|
||||||
await _acquireJobThrottler.IncrementAndWaitAsync(messageQueueLoopTokenSource.Token);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -837,7 +837,6 @@ namespace GitHub.Runner.Worker
|
|||||||
// Actions environment
|
// Actions environment
|
||||||
ActionsEnvironment = message.ActionsEnvironment;
|
ActionsEnvironment = message.ActionsEnvironment;
|
||||||
|
|
||||||
|
|
||||||
// Service container info
|
// Service container info
|
||||||
Global.ServiceContainers = new List<ContainerInfo>();
|
Global.ServiceContainers = new List<ContainerInfo>();
|
||||||
|
|
||||||
|
|||||||
@@ -127,10 +127,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check OS warning
|
|
||||||
var osWarningChecker = HostContext.GetService<IOSWarningChecker>();
|
|
||||||
await osWarningChecker.CheckOSAsync(context);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var tokenPermissions = jobContext.Global.Variables.Get("system.github.token.permissions") ?? "";
|
var tokenPermissions = jobContext.Global.Variables.Get("system.github.token.permissions") ?? "";
|
||||||
|
|||||||
@@ -1,110 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
|
||||||
{
|
|
||||||
[ServiceLocator(Default = typeof(OSWarningChecker))]
|
|
||||||
public interface IOSWarningChecker : IRunnerService
|
|
||||||
{
|
|
||||||
Task CheckOSAsync(IExecutionContext context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class OSWarningChecker : RunnerService, IOSWarningChecker
|
|
||||||
{
|
|
||||||
private static TimeSpan s_regexTimeout = TimeSpan.FromSeconds(1);
|
|
||||||
|
|
||||||
public async Task CheckOSAsync(IExecutionContext context)
|
|
||||||
{
|
|
||||||
ArgUtil.NotNull(context, nameof(context));
|
|
||||||
if (!context.Global.Variables.System_TestDotNet8Compatibility)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Output("Testing runner upgrade compatibility");
|
|
||||||
List<string> output = new();
|
|
||||||
object outputLock = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using (var process = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
process.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stdout)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(stdout.Data))
|
|
||||||
{
|
|
||||||
lock (outputLock)
|
|
||||||
{
|
|
||||||
output.Add(stdout.Data);
|
|
||||||
Trace.Info(stdout.Data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
process.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stderr)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(stderr.Data))
|
|
||||||
{
|
|
||||||
lock (outputLock)
|
|
||||||
{
|
|
||||||
output.Add(stderr.Data);
|
|
||||||
Trace.Error(stderr.Data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
using (var cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(10)))
|
|
||||||
{
|
|
||||||
int exitCode = await process.ExecuteAsync(
|
|
||||||
workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
|
|
||||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "testDotNet8Compatibility", $"TestDotNet8Compatibility{IOUtil.ExeExtension}"),
|
|
||||||
arguments: string.Empty,
|
|
||||||
environment: null,
|
|
||||||
cancellationToken: cancellationTokenSource.Token);
|
|
||||||
|
|
||||||
var outputStr = string.Join("\n", output).Trim();
|
|
||||||
if (exitCode != 0 || !string.Equals(outputStr, "Hello from .NET 8!", StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
var pattern = context.Global.Variables.System_DotNet8CompatibilityOutputPattern;
|
|
||||||
if (!string.IsNullOrEmpty(pattern))
|
|
||||||
{
|
|
||||||
var regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant, s_regexTimeout);
|
|
||||||
if (!regex.IsMatch(outputStr))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var warningMessage = context.Global.Variables.System_DotNet8CompatibilityWarning;
|
|
||||||
if (!string.IsNullOrEmpty(warningMessage))
|
|
||||||
{
|
|
||||||
context.Warning(warningMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $".NET 8 OS compatibility test failed with exit code '{exitCode}' and output: {GetShortOutput(context, output)}" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Error("An error occurred while testing .NET 8 compatibility'");
|
|
||||||
Trace.Error(ex);
|
|
||||||
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $".NET 8 OS compatibility test encountered exception type '{ex.GetType().FullName}', message: '{ex.Message}', process output: '{GetShortOutput(context, output)}'" });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GetShortOutput(IExecutionContext context, List<string> output)
|
|
||||||
{
|
|
||||||
var length = context.Global.Variables.System_DotNet8CompatibilityOutputLength ?? 200;
|
|
||||||
var outputStr = string.Join("\n", output).Trim();
|
|
||||||
return outputStr.Length > length ? string.Concat(outputStr.Substring(0, length), "[...]") : outputStr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -72,16 +72,8 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public bool? Step_Debug => GetBoolean(Constants.Variables.Actions.StepDebug);
|
public bool? Step_Debug => GetBoolean(Constants.Variables.Actions.StepDebug);
|
||||||
|
|
||||||
public string System_DotNet8CompatibilityWarning => Get(Constants.Variables.System.DotNet8CompatibilityWarning);
|
|
||||||
|
|
||||||
public string System_DotNet8CompatibilityOutputPattern => Get(Constants.Variables.System.DotNet8CompatibilityOutputPattern);
|
|
||||||
|
|
||||||
public int? System_DotNet8CompatibilityOutputLength => GetInt(Constants.Variables.System.DotNet8CompatibilityOutputLength);
|
|
||||||
|
|
||||||
public string System_PhaseDisplayName => Get(Constants.Variables.System.PhaseDisplayName);
|
public string System_PhaseDisplayName => Get(Constants.Variables.System.PhaseDisplayName);
|
||||||
|
|
||||||
public bool System_TestDotNet8Compatibility => GetBoolean(Constants.Variables.System.TestDotNet8Compatibility) ?? false;
|
|
||||||
|
|
||||||
public string Get(string name)
|
public string Get(string name)
|
||||||
{
|
{
|
||||||
Variable variable;
|
Variable variable;
|
||||||
|
|||||||
@@ -1539,26 +1539,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationJobUnprocessableException", "GitHub.DistributedTask.WebApi.TaskOrchestrationJobUnprocessableException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
|
||||||
public sealed class TaskOrchestrationJobUnprocessableException : DistributedTaskException
|
|
||||||
{
|
|
||||||
public TaskOrchestrationJobUnprocessableException(String message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public TaskOrchestrationJobUnprocessableException(String message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private TaskOrchestrationJobUnprocessableException(SerializationInfo info, StreamingContext context)
|
|
||||||
: base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationPlanSecurityException", "GitHub.DistributedTask.WebApi.TaskOrchestrationPlanSecurityException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationPlanSecurityException", "GitHub.DistributedTask.WebApi.TaskOrchestrationPlanSecurityException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
||||||
public sealed class TaskOrchestrationPlanSecurityException : DistributedTaskException
|
public sealed class TaskOrchestrationPlanSecurityException : DistributedTaskException
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace GitHub.Actions.RunService.WebApi
|
|
||||||
{
|
|
||||||
[DataContract]
|
|
||||||
public class RunServiceError
|
|
||||||
{
|
|
||||||
[DataMember(Name = "source", EmitDefaultValue = false)]
|
|
||||||
public string Source { get; set; }
|
|
||||||
|
|
||||||
[DataMember(Name = "statusCode", EmitDefaultValue = false)]
|
|
||||||
public int Code { get; set; }
|
|
||||||
|
|
||||||
[DataMember(Name = "errorMessage", EmitDefaultValue = false)]
|
|
||||||
public string Message { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -86,7 +86,6 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri: requestUri,
|
requestUri: requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
readErrorBody: true,
|
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
@@ -94,35 +93,14 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
return result.Value;
|
return result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
|
|
||||||
{
|
|
||||||
switch ((HttpStatusCode)error.Code)
|
|
||||||
{
|
|
||||||
case HttpStatusCode.NotFound:
|
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job message not found '{messageId}'. {error.Message}");
|
|
||||||
case HttpStatusCode.Conflict:
|
|
||||||
throw new TaskOrchestrationJobAlreadyAcquiredException($"Job message already acquired '{messageId}'. {error.Message}");
|
|
||||||
case HttpStatusCode.UnprocessableEntity:
|
|
||||||
throw new TaskOrchestrationJobUnprocessableException($"Unprocessable job '{messageId}'. {error.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary back compat
|
|
||||||
switch (result.StatusCode)
|
switch (result.StatusCode)
|
||||||
{
|
{
|
||||||
case HttpStatusCode.NotFound:
|
case HttpStatusCode.NotFound:
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job message not found: {messageId}");
|
throw new TaskOrchestrationJobNotFoundException($"Job message not found: {messageId}");
|
||||||
case HttpStatusCode.Conflict:
|
case HttpStatusCode.Conflict:
|
||||||
throw new TaskOrchestrationJobAlreadyAcquiredException($"Job message already acquired: {messageId}");
|
throw new TaskOrchestrationJobAlreadyAcquiredException($"Job message already acquired: {messageId}");
|
||||||
}
|
default:
|
||||||
|
throw new Exception($"Failed to get job message: {result.Error}");
|
||||||
if (!string.IsNullOrEmpty(result.ErrorBody))
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to get job message: {result.Error}. {Truncate(result.ErrorBody)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to get job message: {result.Error}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +108,7 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
Guid planId,
|
Guid planId,
|
||||||
Guid jobId,
|
Guid jobId,
|
||||||
TaskResult conclusion,
|
TaskResult result,
|
||||||
Dictionary<String, VariableValue> outputs,
|
Dictionary<String, VariableValue> outputs,
|
||||||
IList<StepResult> stepResults,
|
IList<StepResult> stepResults,
|
||||||
IList<Annotation> jobAnnotations,
|
IList<Annotation> jobAnnotations,
|
||||||
@@ -142,7 +120,7 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
{
|
{
|
||||||
PlanID = planId,
|
PlanID = planId,
|
||||||
JobID = jobId,
|
JobID = jobId,
|
||||||
Conclusion = conclusion,
|
Conclusion = result,
|
||||||
Outputs = outputs,
|
Outputs = outputs,
|
||||||
StepResults = stepResults,
|
StepResults = stepResults,
|
||||||
Annotations = jobAnnotations,
|
Annotations = jobAnnotations,
|
||||||
@@ -152,39 +130,22 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
requestUri = new Uri(requestUri, "completejob");
|
requestUri = new Uri(requestUri, "completejob");
|
||||||
|
|
||||||
var requestContent = new ObjectContent<CompleteJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
|
var requestContent = new ObjectContent<CompleteJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
|
||||||
var result = await Send2Async(
|
var response = await SendAsync(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri,
|
requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
if (result.IsSuccess)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
|
switch (response.StatusCode)
|
||||||
{
|
|
||||||
switch ((HttpStatusCode)error.Code)
|
|
||||||
{
|
|
||||||
case HttpStatusCode.NotFound:
|
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}. {error.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary back compat
|
|
||||||
switch (result.StatusCode)
|
|
||||||
{
|
{
|
||||||
case HttpStatusCode.NotFound:
|
case HttpStatusCode.NotFound:
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
|
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
|
||||||
}
|
default:
|
||||||
|
throw new Exception($"Failed to complete job: {response.ReasonPhrase}");
|
||||||
if (!string.IsNullOrEmpty(result.ErrorBody))
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to complete job: {result.Error}. {Truncate(result.ErrorBody)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to complete job: {result.Error}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +169,6 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri,
|
requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
readErrorBody: true,
|
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
@@ -216,29 +176,12 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
return result.Value;
|
return result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
|
|
||||||
{
|
|
||||||
switch ((HttpStatusCode)error.Code)
|
|
||||||
{
|
|
||||||
case HttpStatusCode.NotFound:
|
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}. {error.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temporary back compat
|
|
||||||
switch (result.StatusCode)
|
switch (result.StatusCode)
|
||||||
{
|
{
|
||||||
case HttpStatusCode.NotFound:
|
case HttpStatusCode.NotFound:
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
|
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
|
||||||
}
|
default:
|
||||||
|
throw new Exception($"Failed to renew job: {result.Error}");
|
||||||
if (!string.IsNullOrEmpty(result.ErrorBody))
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to renew job: {result.Error}. {Truncate(result.ErrorBody)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to renew job: {result.Error}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,36 +190,5 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||||
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryParseErrorBody(string errorBody, out RunServiceError error)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(errorBody))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
error = JsonUtility.FromString<RunServiceError>(errorBody);
|
|
||||||
if (error?.Source == "actions-run-service")
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
error = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string Truncate(string errorBody)
|
|
||||||
{
|
|
||||||
if (errorBody.Length > 100)
|
|
||||||
{
|
|
||||||
return errorBody.Substring(0, 100) + "[truncated]";
|
|
||||||
}
|
|
||||||
|
|
||||||
return errorBody;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,55 +101,15 @@ namespace Sdk.WebApi.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<RawHttpClientResult> Send2Async(
|
|
||||||
HttpMethod method,
|
|
||||||
Uri requestUri,
|
|
||||||
HttpContent content = null,
|
|
||||||
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
|
||||||
Object userState = null,
|
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
using (var response = await SendAsync(method, requestUri, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
|
|
||||||
{
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
return new RawHttpClientResult(
|
|
||||||
isSuccess: true,
|
|
||||||
error: string.Empty,
|
|
||||||
statusCode: response.StatusCode);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var errorBody = default(string);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
errorBody = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
errorBody = $"Error reading HTTP response body: {ex.Message}";
|
|
||||||
}
|
|
||||||
|
|
||||||
string errorMessage = $"Error: {response.ReasonPhrase}";
|
|
||||||
return new RawHttpClientResult(
|
|
||||||
isSuccess: false,
|
|
||||||
error: errorMessage,
|
|
||||||
statusCode: response.StatusCode,
|
|
||||||
errorBody: errorBody);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Task<RawHttpClientResult<T>> SendAsync<T>(
|
protected Task<RawHttpClientResult<T>> SendAsync<T>(
|
||||||
HttpMethod method,
|
HttpMethod method,
|
||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
HttpContent content = null,
|
HttpContent content = null,
|
||||||
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
||||||
Boolean readErrorBody = false,
|
|
||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return SendAsync<T>(method, null, requestUri, content, queryParameters, readErrorBody, userState, cancellationToken);
|
return SendAsync<T>(method, null, requestUri, content, queryParameters, userState, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
||||||
@@ -158,20 +118,18 @@ namespace Sdk.WebApi.WebApi
|
|||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
HttpContent content = null,
|
HttpContent content = null,
|
||||||
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
||||||
Boolean readErrorBody = false,
|
|
||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||||
using (HttpRequestMessage requestMessage = CreateRequestMessage(method, additionalHeaders, requestUri, content, queryParameters))
|
using (HttpRequestMessage requestMessage = CreateRequestMessage(method, additionalHeaders, requestUri, content, queryParameters))
|
||||||
{
|
{
|
||||||
return await SendAsync<T>(requestMessage, readErrorBody, userState, cancellationToken).ConfigureAwait(false);
|
return await SendAsync<T>(requestMessage, userState, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
||||||
HttpRequestMessage message,
|
HttpRequestMessage message,
|
||||||
Boolean readErrorBody = false,
|
|
||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
@@ -187,21 +145,8 @@ namespace Sdk.WebApi.WebApi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var errorBody = default(string);
|
|
||||||
if (readErrorBody)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
errorBody = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
errorBody = $"Error reading HTTP response body: {ex.Message}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string errorMessage = $"Error: {response.ReasonPhrase}";
|
string errorMessage = $"Error: {response.ReasonPhrase}";
|
||||||
return RawHttpClientResult<T>.Fail(errorMessage, response.StatusCode, errorBody);
|
return RawHttpClientResult<T>.Fail(errorMessage, response.StatusCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,27 +5,15 @@ namespace Sdk.WebApi.WebApi
|
|||||||
public class RawHttpClientResult
|
public class RawHttpClientResult
|
||||||
{
|
{
|
||||||
public bool IsSuccess { get; protected set; }
|
public bool IsSuccess { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A description of the HTTP status code, like "Error: Unprocessable Entity"
|
|
||||||
/// </summary>
|
|
||||||
public string Error { get; protected set; }
|
public string Error { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The HTTP response body for unsuccessful HTTP status codes, or an error message when reading the response body fails.
|
|
||||||
/// </summary>
|
|
||||||
public string ErrorBody { get; protected set; }
|
|
||||||
|
|
||||||
public HttpStatusCode StatusCode { get; protected set; }
|
public HttpStatusCode StatusCode { get; protected set; }
|
||||||
|
|
||||||
public bool IsFailure => !IsSuccess;
|
public bool IsFailure => !IsSuccess;
|
||||||
|
|
||||||
public RawHttpClientResult(bool isSuccess, string error, HttpStatusCode statusCode, string errorBody = null)
|
protected RawHttpClientResult(bool isSuccess, string error, HttpStatusCode statusCode)
|
||||||
{
|
{
|
||||||
IsSuccess = isSuccess;
|
IsSuccess = isSuccess;
|
||||||
Error = error;
|
Error = error;
|
||||||
StatusCode = statusCode;
|
StatusCode = statusCode;
|
||||||
ErrorBody = errorBody;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,13 +21,13 @@ namespace Sdk.WebApi.WebApi
|
|||||||
{
|
{
|
||||||
public T Value { get; private set; }
|
public T Value { get; private set; }
|
||||||
|
|
||||||
protected internal RawHttpClientResult(T value, bool isSuccess, string error, HttpStatusCode statusCode, string errorBody)
|
protected internal RawHttpClientResult(T value, bool isSuccess, string error, HttpStatusCode statusCode)
|
||||||
: base(isSuccess, error, statusCode, errorBody)
|
: base(isSuccess, error, statusCode)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RawHttpClientResult<T> Fail(string message, HttpStatusCode statusCode, string errorBody) => new RawHttpClientResult<T>(default(T), false, message, statusCode, errorBody);
|
public static RawHttpClientResult<T> Fail(string message, HttpStatusCode statusCode) => new RawHttpClientResult<T>(default(T), false, message, statusCode);
|
||||||
public static RawHttpClientResult<T> Ok(T value) => new RawHttpClientResult<T>(value, true, string.Empty, HttpStatusCode.OK, null);
|
public static RawHttpClientResult<T> Ok(T value) => new RawHttpClientResult<T>(value, true, string.Empty, HttpStatusCode.OK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
trace.Info("Parsed");
|
trace.Info("Parsed");
|
||||||
|
|
||||||
trace.Info("Commands: {0}", clp.Commands.Count);
|
trace.Info("Commands: {0}", clp.Commands.Count);
|
||||||
Assert.Equal(2, clp.Commands.Count);
|
Assert.True(clp.Commands.Count == 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
trace.Info("Parsed");
|
trace.Info("Parsed");
|
||||||
|
|
||||||
trace.Info("Args: {0}", clp.Args.Count);
|
trace.Info("Args: {0}", clp.Args.Count);
|
||||||
Assert.Equal(2, clp.Args.Count);
|
Assert.True(clp.Args.Count == 2);
|
||||||
Assert.True(clp.Args.ContainsKey("arg1"));
|
Assert.True(clp.Args.ContainsKey("arg1"));
|
||||||
Assert.Equal("arg1val", clp.Args["arg1"]);
|
Assert.Equal("arg1val", clp.Args["arg1"]);
|
||||||
Assert.True(clp.Args.ContainsKey("arg2"));
|
Assert.True(clp.Args.ContainsKey("arg2"));
|
||||||
@@ -112,7 +112,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
trace.Info("Parsed");
|
trace.Info("Parsed");
|
||||||
|
|
||||||
trace.Info("Args: {0}", clp.Flags.Count);
|
trace.Info("Args: {0}", clp.Flags.Count);
|
||||||
Assert.Equal(2, clp.Flags.Count);
|
Assert.True(clp.Flags.Count == 2);
|
||||||
Assert.Contains("flag1", clp.Flags);
|
Assert.Contains("flag1", clp.Flags);
|
||||||
Assert.Contains("flag2", clp.Flags);
|
Assert.Contains("flag2", clp.Flags);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
"osx-arm64"
|
"osx-arm64"
|
||||||
};
|
};
|
||||||
|
|
||||||
Assert.Equal(40, BuildConstants.Source.CommitHash.Length);
|
Assert.True(BuildConstants.Source.CommitHash.Length == 40, $"CommitHash should be SHA-1 hash {BuildConstants.Source.CommitHash}");
|
||||||
Assert.True(validPackageNames.Contains(BuildConstants.RunnerPackage.PackageName), $"PackageName should be one of the following '{string.Join(", ", validPackageNames)}', current PackageName is '{BuildConstants.RunnerPackage.PackageName}'");
|
Assert.True(validPackageNames.Contains(BuildConstants.RunnerPackage.PackageName), $"PackageName should be one of the following '{string.Join(", ", validPackageNames)}', current PackageName is '{BuildConstants.RunnerPackage.PackageName}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -806,7 +806,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
"test runner" });
|
"test runner" });
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(0, command.Validate().Count);
|
Assert.True(command.Validate().Count == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -844,7 +844,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(0, command.Validate().Count);
|
Assert.True(command.Validate().Count == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,7 +874,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(0, command.Validate().Count);
|
Assert.True(command.Validate().Count == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,11 +190,11 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
trace.Info("Configured, verifying all the parameter value");
|
trace.Info("Configured, verifying all the parameter value");
|
||||||
var s = configManager.LoadSettings();
|
var s = configManager.LoadSettings();
|
||||||
Assert.NotNull(s);
|
Assert.NotNull(s);
|
||||||
Assert.Equal(_expectedServerUrl, s.ServerUrl);
|
Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
|
||||||
Assert.Equal(_expectedAgentName, s.AgentName);
|
Assert.True(s.AgentName.Equals(_expectedAgentName));
|
||||||
Assert.Equal(_secondRunnerGroupId, s.PoolId);
|
Assert.True(s.PoolId.Equals(_secondRunnerGroupId));
|
||||||
Assert.Equal(_expectedWorkFolder, s.WorkFolder);
|
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
|
||||||
Assert.True(s.Ephemeral);
|
Assert.True(s.Ephemeral.Equals(true));
|
||||||
|
|
||||||
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
||||||
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
||||||
@@ -292,11 +292,11 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
trace.Info("Configured, verifying all the parameter value");
|
trace.Info("Configured, verifying all the parameter value");
|
||||||
var s = configManager.LoadSettings();
|
var s = configManager.LoadSettings();
|
||||||
Assert.NotNull(s);
|
Assert.NotNull(s);
|
||||||
Assert.Equal(_expectedServerUrl, s.ServerUrl);
|
Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
|
||||||
Assert.Equal(_expectedAgentName, s.AgentName);
|
Assert.True(s.AgentName.Equals(_expectedAgentName));
|
||||||
Assert.Equal(_secondRunnerGroupId, s.PoolId);
|
Assert.True(s.PoolId.Equals(_secondRunnerGroupId));
|
||||||
Assert.Equal(_expectedWorkFolder, s.WorkFolder);
|
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
|
||||||
Assert.True(s.Ephemeral);
|
Assert.True(s.Ephemeral.Equals(true));
|
||||||
|
|
||||||
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
||||||
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
_runnerServer.Verify(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.Is<TaskAgentPoolType>(p => p == TaskAgentPoolType.Automation)), Times.Exactly(2));
|
||||||
|
|||||||
@@ -1,213 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Listener;
|
|
||||||
using GitHub.Runner.Listener.Configuration;
|
|
||||||
using GitHub.Runner.Common.Tests;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using Moq;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Listener
|
|
||||||
{
|
|
||||||
public sealed class ErrorThrottlerL0
|
|
||||||
{
|
|
||||||
[Theory]
|
|
||||||
[InlineData(1)]
|
|
||||||
[InlineData(2)]
|
|
||||||
[InlineData(3)]
|
|
||||||
[InlineData(4)]
|
|
||||||
[InlineData(5)]
|
|
||||||
[InlineData(6)]
|
|
||||||
[InlineData(7)]
|
|
||||||
[InlineData(8)]
|
|
||||||
public async void TestIncrementAndWait(int totalAttempts)
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var errorThrottler = new ErrorThrottler();
|
|
||||||
errorThrottler.Initialize(hc);
|
|
||||||
var eventArgs = new List<DelayEventArgs>();
|
|
||||||
hc.Delaying += (sender, args) =>
|
|
||||||
{
|
|
||||||
eventArgs.Add(args);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
for (int attempt = 1; attempt <= totalAttempts; attempt++)
|
|
||||||
{
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(totalAttempts - 1, eventArgs.Count);
|
|
||||||
for (int i = 0; i < eventArgs.Count; i++)
|
|
||||||
{
|
|
||||||
// Expected milliseconds
|
|
||||||
int expectedMin;
|
|
||||||
int expectedMax;
|
|
||||||
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
expectedMin = 1000; // Min backoff
|
|
||||||
expectedMax = 1000;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
expectedMin = 1800; // Min + 0.8 * Coefficient
|
|
||||||
expectedMax = 2200; // Min + 1.2 * Coefficient
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
expectedMin = 3400; // Min + 0.8 * Coefficient * 3
|
|
||||||
expectedMax = 4600; // Min + 1.2 * Coefficient * 3
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
expectedMin = 6600; // Min + 0.8 * Coefficient * 7
|
|
||||||
expectedMax = 9400; // Min + 1.2 * Coefficient * 7
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
expectedMin = 13000; // Min + 0.8 * Coefficient * 15
|
|
||||||
expectedMax = 19000; // Min + 1.2 * Coefficient * 15
|
|
||||||
break;
|
|
||||||
case 5:
|
|
||||||
expectedMin = 25800; // Min + 0.8 * Coefficient * 31
|
|
||||||
expectedMax = 38200; // Min + 1.2 * Coefficient * 31
|
|
||||||
break;
|
|
||||||
case 6:
|
|
||||||
expectedMin = 51400; // Min + 0.8 * Coefficient * 63
|
|
||||||
expectedMax = 60000; // Max backoff
|
|
||||||
break;
|
|
||||||
case 7:
|
|
||||||
expectedMin = 60000;
|
|
||||||
expectedMax = 60000;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException("Unexpected eventArgs count");
|
|
||||||
}
|
|
||||||
|
|
||||||
var actualMilliseconds = eventArgs[i].Delay.TotalMilliseconds;
|
|
||||||
Assert.True(expectedMin <= actualMilliseconds, $"Unexpected min delay for eventArgs[{i}]. Expected min {expectedMin}, actual {actualMilliseconds}");
|
|
||||||
Assert.True(expectedMax >= actualMilliseconds, $"Unexpected max delay for eventArgs[{i}]. Expected max {expectedMax}, actual {actualMilliseconds}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestReset()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var errorThrottler = new ErrorThrottler();
|
|
||||||
errorThrottler.Initialize(hc);
|
|
||||||
var eventArgs = new List<DelayEventArgs>();
|
|
||||||
hc.Delaying += (sender, args) =>
|
|
||||||
{
|
|
||||||
eventArgs.Add(args);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
errorThrottler.Reset();
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(4, eventArgs.Count);
|
|
||||||
for (int i = 0; i < eventArgs.Count; i++)
|
|
||||||
{
|
|
||||||
// Expected milliseconds
|
|
||||||
int expectedMin;
|
|
||||||
int expectedMax;
|
|
||||||
|
|
||||||
switch (i)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
case 2:
|
|
||||||
expectedMin = 1000; // Min backoff
|
|
||||||
expectedMax = 1000;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
case 3:
|
|
||||||
expectedMin = 1800; // Min + 0.8 * Coefficient
|
|
||||||
expectedMax = 2200; // Min + 1.2 * Coefficient
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new NotSupportedException("Unexpected eventArgs count");
|
|
||||||
}
|
|
||||||
|
|
||||||
var actualMilliseconds = eventArgs[i].Delay.TotalMilliseconds;
|
|
||||||
Assert.True(expectedMin <= actualMilliseconds, $"Unexpected min delay for eventArgs[{i}]. Expected min {expectedMin}, actual {actualMilliseconds}");
|
|
||||||
Assert.True(expectedMax >= actualMilliseconds, $"Unexpected max delay for eventArgs[{i}]. Expected max {expectedMax}, actual {actualMilliseconds}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestReceivesCancellationToken()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var errorThrottler = new ErrorThrottler();
|
|
||||||
errorThrottler.Initialize(hc);
|
|
||||||
var eventArgs = new List<DelayEventArgs>();
|
|
||||||
hc.Delaying += (sender, args) =>
|
|
||||||
{
|
|
||||||
eventArgs.Add(args);
|
|
||||||
};
|
|
||||||
var cancellationTokenSource1 = new CancellationTokenSource();
|
|
||||||
var cancellationTokenSource2 = new CancellationTokenSource();
|
|
||||||
var cancellationTokenSource3 = new CancellationTokenSource();
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource1.Token);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource2.Token);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource3.Token);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(2, eventArgs.Count);
|
|
||||||
Assert.Equal(cancellationTokenSource2.Token, eventArgs[0].Token);
|
|
||||||
Assert.Equal(cancellationTokenSource3.Token, eventArgs[1].Token);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public async void TestReceivesSender()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
// Arrange
|
|
||||||
var errorThrottler = new ErrorThrottler();
|
|
||||||
errorThrottler.Initialize(hc);
|
|
||||||
var senders = new List<object>();
|
|
||||||
hc.Delaying += (sender, args) =>
|
|
||||||
{
|
|
||||||
senders.Add(sender);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Act
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
Assert.Equal(2, senders.Count);
|
|
||||||
Assert.Equal(hc, senders[0]);
|
|
||||||
Assert.Equal(hc, senders[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
|
||||||
{
|
|
||||||
return new TestHostContext(this, testName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -734,10 +734,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
await jobDispatcher.WaitAsync(CancellationToken.None);
|
await jobDispatcher.WaitAsync(CancellationToken.None);
|
||||||
|
|
||||||
Assert.True(jobDispatcher.RunOnceJobCompleted.Task.IsCompleted, "JobDispatcher should set task complete token for one time agent.");
|
Assert.True(jobDispatcher.RunOnceJobCompleted.Task.IsCompleted, "JobDispatcher should set task complete token for one time agent.");
|
||||||
if (jobDispatcher.RunOnceJobCompleted.Task.IsCompleted)
|
Assert.True(jobDispatcher.RunOnceJobCompleted.Task.Result, "JobDispatcher should set task complete token to 'TRUE' for one time agent.");
|
||||||
{
|
|
||||||
Assert.True(await jobDispatcher.RunOnceJobCompleted.Task, "JobDispatcher should set task complete token to 'TRUE' for one time agent.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
private Mock<ITerminal> _term;
|
private Mock<ITerminal> _term;
|
||||||
private Mock<IConfigurationStore> _configStore;
|
private Mock<IConfigurationStore> _configStore;
|
||||||
private Mock<ISelfUpdater> _updater;
|
private Mock<ISelfUpdater> _updater;
|
||||||
private Mock<IErrorThrottler> _acquireJobThrottler;
|
|
||||||
|
|
||||||
public RunnerL0()
|
public RunnerL0()
|
||||||
{
|
{
|
||||||
@@ -36,7 +35,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_term = new Mock<ITerminal>();
|
_term = new Mock<ITerminal>();
|
||||||
_configStore = new Mock<IConfigurationStore>();
|
_configStore = new Mock<IConfigurationStore>();
|
||||||
_updater = new Mock<ISelfUpdater>();
|
_updater = new Mock<ISelfUpdater>();
|
||||||
_acquireJobThrottler = new Mock<IErrorThrottler>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pipelines.AgentJobRequestMessage CreateJobRequestMessage(string jobName)
|
private Pipelines.AgentJobRequestMessage CreateJobRequestMessage(string jobName)
|
||||||
@@ -69,7 +67,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
@@ -129,7 +126,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
//wait for the runner to run one job
|
//wait for the runner to run one job
|
||||||
if (!await signalWorkerComplete.WaitAsync(2000))
|
if (!await signalWorkerComplete.WaitAsync(2000))
|
||||||
{
|
{
|
||||||
Assert.Fail($"{nameof(_messageListener.Object.GetNextMessageAsync)} was not invoked.");
|
Assert.True(false, $"{nameof(_messageListener.Object.GetNextMessageAsync)} was not invoked.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -177,7 +174,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
|
|
||||||
var command = new CommandSettings(hc, args);
|
var command = new CommandSettings(hc, args);
|
||||||
|
|
||||||
@@ -209,7 +205,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
|
|
||||||
var command = new CommandSettings(hc, new[] { "run" });
|
var command = new CommandSettings(hc, new[] { "run" });
|
||||||
|
|
||||||
@@ -247,7 +242,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
@@ -311,11 +305,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
await Task.WhenAny(runnerTask, Task.Delay(30000));
|
await Task.WhenAny(runnerTask, Task.Delay(30000));
|
||||||
|
|
||||||
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
|
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
|
||||||
Assert.False(runnerTask.IsFaulted, runnerTask.Exception?.ToString());
|
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
|
||||||
if (runnerTask.IsCompleted)
|
Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.Success);
|
||||||
{
|
|
||||||
Assert.Equal(Constants.Runner.ReturnCode.Success, await runnerTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
|
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
|
||||||
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
|
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
|
||||||
@@ -344,7 +335,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
@@ -416,10 +406,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
|
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
|
||||||
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
|
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
|
||||||
if (runnerTask.IsCompleted)
|
Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.Success);
|
||||||
{
|
|
||||||
Assert.Equal(Constants.Runner.ReturnCode.Success, await runnerTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
|
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
|
||||||
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
|
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
|
||||||
@@ -446,7 +433,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.SetSingleton<ISelfUpdater>(_updater.Object);
|
hc.SetSingleton<ISelfUpdater>(_updater.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
|
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
@@ -506,10 +492,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
|
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
|
||||||
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
|
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
|
||||||
if (runnerTask.IsCompleted)
|
Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.RunOnceRunnerUpdating);
|
||||||
{
|
|
||||||
Assert.Equal(Constants.Runner.ReturnCode.RunOnceRunnerUpdating, await runnerTask);
|
|
||||||
}
|
|
||||||
|
|
||||||
_updater.Verify(x => x.SelfUpdate(It.IsAny<AgentRefreshMessage>(), It.IsAny<IJobDispatcher>(), false, It.IsAny<CancellationToken>()), Times.Once);
|
_updater.Verify(x => x.SelfUpdate(It.IsAny<AgentRefreshMessage>(), It.IsAny<IJobDispatcher>(), false, It.IsAny<CancellationToken>()), Times.Once);
|
||||||
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Never());
|
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Never());
|
||||||
@@ -530,7 +513,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
|
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
|
||||||
|
|
||||||
var command = new CommandSettings(hc, new[] { "remove", "--local" });
|
var command = new CommandSettings(hc, new[] { "remove", "--local" });
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
trace.Error(ex);
|
trace.Error(ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.Fail("Failed to retrieve process environment variable.");
|
Assert.True(false, "Fail to retrive process environment variable.");
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -65,14 +65,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badCode.Count > 0)
|
Assert.True(badCode.Count == 0, $"The following code is using Raw HttpClientHandler() which will not follow the proxy setting agent have. Please use HostContext.CreateHttpClientHandler() instead.\n {string.Join("\n", badCode)}");
|
||||||
{
|
|
||||||
Assert.Fail($"The following code is using Raw HttpClientHandler() which will not follow the proxy setting agent have. Please use HostContext.CreateHttpClientHandler() instead.\n {string.Join("\n", badCode)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.True(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -119,14 +112,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (badCode.Count > 0)
|
Assert.True(badCode.Count == 0, $"The following code is using Raw HttpClient() which will not follow the proxy setting agent have. Please use New HttpClient(HostContext.CreateHttpClientHandler()) instead.\n {string.Join("\n", badCode)}");
|
||||||
{
|
|
||||||
Assert.Fail($"The following code is using Raw HttpClient() which will not follow the proxy setting agent have. Please use New HttpClient(HostContext.CreateHttpClientHandler()) instead.\n {string.Join("\n", badCode)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.True(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -30,11 +30,9 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D"));
|
private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D"));
|
||||||
private StartupType _startupType;
|
private StartupType _startupType;
|
||||||
public event EventHandler Unloading;
|
public event EventHandler Unloading;
|
||||||
public event EventHandler<DelayEventArgs> Delaying;
|
|
||||||
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
||||||
public ShutdownReason RunnerShutdownReason { get; private set; }
|
public ShutdownReason RunnerShutdownReason { get; private set; }
|
||||||
public ISecretMasker SecretMasker => _secretMasker;
|
public ISecretMasker SecretMasker => _secretMasker;
|
||||||
|
|
||||||
public TestHostContext(object testClass, [CallerMemberName] string testName = "")
|
public TestHostContext(object testClass, [CallerMemberName] string testName = "")
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(testClass, nameof(testClass));
|
ArgUtil.NotNull(testClass, nameof(testClass));
|
||||||
@@ -94,14 +92,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
|
|
||||||
public async Task Delay(TimeSpan delay, CancellationToken token)
|
public async Task Delay(TimeSpan delay, CancellationToken token)
|
||||||
{
|
{
|
||||||
// Event callback
|
|
||||||
EventHandler<DelayEventArgs> handler = Delaying;
|
|
||||||
if (handler != null)
|
|
||||||
{
|
|
||||||
handler(this, new DelayEventArgs(delay, token));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delay zero
|
|
||||||
await Task.Delay(TimeSpan.Zero);
|
await Task.Delay(TimeSpan.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,19 +361,4 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DelayEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public DelayEventArgs(
|
|
||||||
TimeSpan delay,
|
|
||||||
CancellationToken token)
|
|
||||||
{
|
|
||||||
Delay = delay;
|
|
||||||
Token = token;
|
|
||||||
}
|
|
||||||
|
|
||||||
public TimeSpan Delay { get; }
|
|
||||||
|
|
||||||
public CancellationToken Token { get; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ runs:
|
|||||||
//Act
|
//Act
|
||||||
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
Assert.Equal(0, steps.Count);
|
Assert.True(steps.Count == 0);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -915,7 +915,7 @@ runs:
|
|||||||
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
// node.js based action doesn't need any extra steps to build/pull containers.
|
// node.js based action doesn't need any extra steps to build/pull containers.
|
||||||
Assert.Equal(0, steps.Count);
|
Assert.True(steps.Count == 0);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -1051,7 +1051,7 @@ runs:
|
|||||||
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
|
||||||
|
|
||||||
// node.js based action doesn't need any extra steps to build/pull containers.
|
// node.js based action doesn't need any extra steps to build/pull containers.
|
||||||
Assert.Equal(0, steps.Count);
|
Assert.True(steps.Count == 0);
|
||||||
var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang/runner_L0", "CompositeBasic.completed");
|
var watermarkFile = Path.Combine(_hc.GetDirectory(WellKnownDirectory.Actions), "TingluoHuang/runner_L0", "CompositeBasic.completed");
|
||||||
Assert.True(File.Exists(watermarkFile));
|
Assert.True(File.Exists(watermarkFile));
|
||||||
// Comes from the composite action
|
// Comes from the composite action
|
||||||
@@ -1245,7 +1245,7 @@ runs:
|
|||||||
// Assert.
|
// Assert.
|
||||||
Assert.NotNull(definition);
|
Assert.NotNull(definition);
|
||||||
Assert.NotNull(definition.Data);
|
Assert.NotNull(definition.Data);
|
||||||
Assert.Equal(ActionExecutionType.Script, definition.Data.Execution.ExecutionType);
|
Assert.True(definition.Data.Execution.ExecutionType == ActionExecutionType.Script);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -140,7 +140,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
hc.SetSingleton(_diagnosticLogManager.Object);
|
hc.SetSingleton(_diagnosticLogManager.Object);
|
||||||
hc.SetSingleton(_jobHookProvider.Object);
|
hc.SetSingleton(_jobHookProvider.Object);
|
||||||
hc.SetSingleton(_snapshotOperationProvider.Object);
|
hc.SetSingleton(_snapshotOperationProvider.Object);
|
||||||
hc.SetSingleton(new Mock<IOSWarningChecker>().Object);
|
|
||||||
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // JobExecutionContext
|
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // JobExecutionContext
|
||||||
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // job start hook
|
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // job start hook
|
||||||
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // Initial Job
|
hc.EnqueueInstance<IPagingLogger>(_logger.Object); // Initial Job
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
||||||
<PackageReference Include="xunit" Version="2.7.1" />
|
<PackageReference Include="xunit" Version="2.4.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||||
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.4.0" />
|
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.4.0" />
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace TestDotNet8Compatibility
|
|
||||||
{
|
|
||||||
public static class Program
|
|
||||||
{
|
|
||||||
public static int Main(string[] args)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Hello from .NET 8!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
|
||||||
<OutputType>Exe</OutputType>
|
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
|
||||||
<SelfContained>true</SelfContained>
|
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
|
||||||
<Version>$(Version)</Version>
|
|
||||||
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
|
||||||
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="14.0" DefaultTargets="Build"
|
|
||||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectFiles Include="TestDotNet8Compatibility.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Target Name="Build">
|
|
||||||
<MSBuild Targets="Restore" Projects="@(ProjectFiles)" StopOnFirstFailure="true" />
|
|
||||||
<MSBuild Targets="Publish" Projects="@(ProjectFiles)" BuildInParallel="false" StopOnFirstFailure="true" Properties="Configuration=$(BUILDCONFIG);PackageRuntime=$(PackageRuntime);Version=$(RunnerVersion);RuntimeIdentifier=$(PackageRuntime);PublishDir=$(MSBuildProjectDirectory)/../../_layout/bin/testDotNet8Compatibility" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="Clean">
|
|
||||||
<RemoveDir Directories="$(MSBuildProjectDirectory)/../../_layout/bin/testDotNet8Compatibility" />
|
|
||||||
<RemoveDir Directories="TestDotNet8Compatibility/bin" />
|
|
||||||
<RemoveDir Directories="TestDotNet8Compatibility/obj" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="Layout" DependsOnTargets="Clean;Build">
|
|
||||||
</Target>
|
|
||||||
</Project>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"sdk": {
|
|
||||||
"version": "8.0.303"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
54
src/dev.sh
54
src/dev.sh
@@ -19,8 +19,6 @@ PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
|||||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||||
DOTNETSDK_VERSION="6.0.421"
|
DOTNETSDK_VERSION="6.0.421"
|
||||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||||
DOTNET8SDK_VERSION="8.0.303"
|
|
||||||
DOTNET8SDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNET8SDK_VERSION"
|
|
||||||
RUNNER_VERSION=$(cat runnerversion)
|
RUNNER_VERSION=$(cat runnerversion)
|
||||||
|
|
||||||
pushd "$SCRIPT_DIR"
|
pushd "$SCRIPT_DIR"
|
||||||
@@ -127,19 +125,6 @@ function build ()
|
|||||||
{
|
{
|
||||||
heading "Building ..."
|
heading "Building ..."
|
||||||
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
||||||
|
|
||||||
# Build TestDotNet8Compatibility
|
|
||||||
heading "Building .NET 8 compatibility test"
|
|
||||||
echo "Prepend ${DOTNET8SDK_INSTALLDIR} to %PATH%" # Prepend .NET 8 SDK to PATH
|
|
||||||
PATH_BAK=$PATH
|
|
||||||
export PATH=${DOTNET8SDK_INSTALLDIR}:$PATH
|
|
||||||
pushd "$SCRIPT_DIR/TestDotNet8Compatibility" > /dev/null # Working directory
|
|
||||||
pwd
|
|
||||||
echo "Dotnet 8 SDK Version"
|
|
||||||
dotnet --version
|
|
||||||
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
|
||||||
popd > /dev/null # Restore working directory
|
|
||||||
export PATH=$PATH_BAK # Restore PATH
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function layout ()
|
function layout ()
|
||||||
@@ -158,18 +143,6 @@ function layout ()
|
|||||||
|
|
||||||
heading "Setup externals folder for $RUNTIME_ID runner's layout"
|
heading "Setup externals folder for $RUNTIME_ID runner's layout"
|
||||||
bash ./Misc/externals.sh $RUNTIME_ID || checkRC externals.sh
|
bash ./Misc/externals.sh $RUNTIME_ID || checkRC externals.sh
|
||||||
|
|
||||||
# Build TestDotNet8Compatibility
|
|
||||||
echo "Prepend ${DOTNET8SDK_INSTALLDIR} to %PATH%" # Prepend .NET 8 SDK to PATH
|
|
||||||
PATH_BAK=$PATH
|
|
||||||
export PATH=${DOTNET8SDK_INSTALLDIR}:$PATH
|
|
||||||
pushd "$SCRIPT_DIR/TestDotNet8Compatibility" > /dev/null # Working directory
|
|
||||||
heading "Dotnet 8 SDK Version"
|
|
||||||
dotnet --version
|
|
||||||
heading "Building .NET 8 compatibility test"
|
|
||||||
dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
|
||||||
popd > /dev/null # Restore working directory
|
|
||||||
export PATH=$PATH_BAK # Restore PATH
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function runtest ()
|
function runtest ()
|
||||||
@@ -226,7 +199,6 @@ function package ()
|
|||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Install .NET SDK
|
|
||||||
if [[ (! -d "${DOTNETSDK_INSTALLDIR}") || (! -e "${DOTNETSDK_INSTALLDIR}/.${DOTNETSDK_VERSION}") || (! -e "${DOTNETSDK_INSTALLDIR}/dotnet") ]]; then
|
if [[ (! -d "${DOTNETSDK_INSTALLDIR}") || (! -e "${DOTNETSDK_INSTALLDIR}/.${DOTNETSDK_VERSION}") || (! -e "${DOTNETSDK_INSTALLDIR}/dotnet") ]]; then
|
||||||
|
|
||||||
# Download dotnet SDK to ../_dotnetsdk directory
|
# Download dotnet SDK to ../_dotnetsdk directory
|
||||||
@@ -252,32 +224,6 @@ if [[ (! -d "${DOTNETSDK_INSTALLDIR}") || (! -e "${DOTNETSDK_INSTALLDIR}/.${DOTN
|
|||||||
echo "${DOTNETSDK_VERSION}" > "${DOTNETSDK_INSTALLDIR}/.${DOTNETSDK_VERSION}"
|
echo "${DOTNETSDK_VERSION}" > "${DOTNETSDK_INSTALLDIR}/.${DOTNETSDK_VERSION}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Install .NET 8 SDK
|
|
||||||
if [[ (! -d "${DOTNET8SDK_INSTALLDIR}") || (! -e "${DOTNET8SDK_INSTALLDIR}/.${DOTNET8SDK_VERSION}") || (! -e "${DOTNET8SDK_INSTALLDIR}/dotnet") ]]; then
|
|
||||||
|
|
||||||
# Download dotnet 8 SDK to ../_dotnetsdk directory
|
|
||||||
heading "Ensure Dotnet 8 SDK"
|
|
||||||
|
|
||||||
# _dotnetsdk
|
|
||||||
# \1.0.x
|
|
||||||
# \dotnet
|
|
||||||
# \.1.0.x
|
|
||||||
echo "Download dotnet8sdk into ${DOTNET8SDK_INSTALLDIR}"
|
|
||||||
rm -Rf "${DOTNETSDK_DIR}"
|
|
||||||
|
|
||||||
# run dotnet-install.ps1 on windows, dotnet-install.sh on linux
|
|
||||||
if [[ ("$CURRENT_PLATFORM" == "windows") ]]; then
|
|
||||||
echo "Convert ${DOTNET8SDK_INSTALLDIR} to Windows style path"
|
|
||||||
sdkinstallwindow_path=${DOTNET8SDK_INSTALLDIR:1}
|
|
||||||
sdkinstallwindow_path=${sdkinstallwindow_path:0:1}:${sdkinstallwindow_path:1}
|
|
||||||
$POWERSHELL -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "& \"./Misc/dotnet-install.ps1\" -Version ${DOTNET8SDK_VERSION} -InstallDir \"${sdkinstallwindow_path}\" -NoPath; exit \$LastExitCode;" || checkRC dotnet-install.ps1
|
|
||||||
else
|
|
||||||
bash ./Misc/dotnet-install.sh --version ${DOTNET8SDK_VERSION} --install-dir "${DOTNET8SDK_INSTALLDIR}" --no-path || checkRC dotnet-install.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "${DOTNET8SDK_VERSION}" > "${DOTNET8SDK_INSTALLDIR}/.${DOTNET8SDK_VERSION}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Prepend ${DOTNETSDK_INSTALLDIR} to %PATH%"
|
echo "Prepend ${DOTNETSDK_INSTALLDIR} to %PATH%"
|
||||||
export PATH=${DOTNETSDK_INSTALLDIR}:$PATH
|
export PATH=${DOTNETSDK_INSTALLDIR}:$PATH
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.319.1
|
2.316.1
|
||||||
|
|||||||
Reference in New Issue
Block a user