mirror of
https://github.com/actions/runner.git
synced 2025-12-11 04:46:58 +00:00
Compare commits
3 Commits
yaananth-p
...
releases/m
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
976290d966 | ||
|
|
1a6dfd0823 | ||
|
|
bc79e859d7 |
@@ -4,7 +4,7 @@
|
|||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
|
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
|
||||||
"ghcr.io/devcontainers/features/dotnet": {
|
"ghcr.io/devcontainers/features/dotnet": {
|
||||||
"version": "6.0.421"
|
"version": "6.0.419"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "16"
|
"version": "16"
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ Runner releases:
|
|||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
We accept contributions in the form of issues and pull requests. The runner typically requires changes across the entire system and we aim for issues in the runner to be entirely self contained and fixable here. Therefore, we will primarily handle bug issues opened in this repo and we kindly request you to create all feature and enhancement requests on the [GitHub Feedback](https://github.com/community/community/discussions/categories/actions-and-packages) page. [Read more about our guidelines here](docs/contribute.md) before contributing.,
|
We accept contributions in the form of issues and pull requests. The runner typically requires changes across the entire system and we aim for issues in the runner to be entirely self contained and fixable here. Therefore, we will primarily handle bug issues opened in this repo and we kindly request you to create all feature and enhancement requests on the [GitHub Feedback](https://github.com/community/community/discussions/categories/actions-and-packages) page. [Read more about our guidelines here](docs/contribute.md) before contributing.
|
||||||
|
|||||||
@@ -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.0
|
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.5.1
|
||||||
ARG DOCKER_VERSION=25.0.4
|
ARG DOCKER_VERSION=25.0.2
|
||||||
ARG BUILDX_VERSION=0.13.1
|
ARG BUILDX_VERSION=0.12.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,20 +1,32 @@
|
|||||||
## What's Changed
|
## What's Changed
|
||||||
|
* Prepare v2.313.0 Release by @luketomlinson in https://github.com/actions/runner/pull/3137
|
||||||
|
* Pass RunnerOS during job acquire. by @TingluoHuang in https://github.com/actions/runner/pull/3140
|
||||||
|
* Process `snapshot` tokens by @davidomid in https://github.com/actions/runner/pull/3135
|
||||||
|
* Update dotnet sdk to latest version @6.0.419 by @github-actions in https://github.com/actions/runner/pull/3158
|
||||||
|
* handle broker run service exception handling by @yaananth in https://github.com/actions/runner/pull/3163
|
||||||
|
* Add a retry logic to docker login operation by @enescakir in https://github.com/actions/runner/pull/3089
|
||||||
|
* Broker fixes for token refreshes and AccessDeniedException by @luketomlinson in https://github.com/actions/runner/pull/3161
|
||||||
|
* Remove USE_BROKER_FLOW by @luketomlinson in https://github.com/actions/runner/pull/3162
|
||||||
|
* Refresh Token for BrokerServer by @luketomlinson in https://github.com/actions/runner/pull/3167
|
||||||
|
* Better step timeout message. by @TingluoHuang in https://github.com/actions/runner/pull/3166
|
||||||
|
* Fix summaries for actions results by @SrRyan in https://github.com/actions/runner/pull/3174
|
||||||
|
|
||||||
- Preserve dates when deserializing job message from Run Service by @ericsciple in https://github.com/actions/runner/pull/3269
|
## New Contributors
|
||||||
|
* @davidomid made their first contribution in https://github.com/actions/runner/pull/3135
|
||||||
|
* @enescakir made their first contribution in https://github.com/actions/runner/pull/3089
|
||||||
|
* @SrRyan made their first contribution in https://github.com/actions/runner/pull/3174
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/actions/runner/compare/v2.316.0...v2.316.1
|
**Full Changelog**: https://github.com/actions/runner/compare/v2.313.0...v2.314.0
|
||||||
|
|
||||||
_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.
|
||||||
See https://docs.github.com/en/enterprise-cloud@latest/actions/hosting-your-own-runners/adding-self-hosted-runners_
|
See https://docs.github.com/en/enterprise-cloud@latest/actions/hosting-your-own-runners/adding-self-hosted-runners_
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
|
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|
||||||
The following snipped needs to be run on `powershell`:
|
The following snipped needs to be run on `powershell`:
|
||||||
|
``` powershell
|
||||||
```powershell
|
|
||||||
# Create a folder under the drive root
|
# Create a folder under the drive root
|
||||||
mkdir \actions-runner ; cd \actions-runner
|
mkdir \actions-runner ; cd \actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -25,14 +37,12 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
|||||||
```
|
```
|
||||||
|
|
||||||
## [Pre-release] Windows arm64
|
## [Pre-release] Windows arm64
|
||||||
|
|
||||||
**Warning:** Windows arm64 runners are currently in preview status and use [unofficial versions of nodejs](https://unofficial-builds.nodejs.org/). They are not intended for production workflows.
|
**Warning:** Windows arm64 runners are currently in preview status and use [unofficial versions of nodejs](https://unofficial-builds.nodejs.org/). They are not intended for production workflows.
|
||||||
|
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|
||||||
The following snipped needs to be run on `powershell`:
|
The following snipped needs to be run on `powershell`:
|
||||||
|
``` powershell
|
||||||
```powershell
|
|
||||||
# Create a folder under the drive root
|
# Create a folder under the drive root
|
||||||
mkdir \actions-runner ; cd \actions-runner
|
mkdir \actions-runner ; cd \actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -44,7 +54,7 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
|||||||
|
|
||||||
## OSX x64
|
## OSX x64
|
||||||
|
|
||||||
```bash
|
``` bash
|
||||||
# Create a folder
|
# Create a folder
|
||||||
mkdir actions-runner && cd actions-runner
|
mkdir actions-runner && cd actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -55,7 +65,7 @@ tar xzf ./actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz
|
|||||||
|
|
||||||
## OSX arm64 (Apple silicon)
|
## OSX arm64 (Apple silicon)
|
||||||
|
|
||||||
```bash
|
``` bash
|
||||||
# Create a folder
|
# Create a folder
|
||||||
mkdir actions-runner && cd actions-runner
|
mkdir actions-runner && cd actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -66,7 +76,7 @@ tar xzf ./actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz
|
|||||||
|
|
||||||
## Linux x64
|
## Linux x64
|
||||||
|
|
||||||
```bash
|
``` bash
|
||||||
# Create a folder
|
# Create a folder
|
||||||
mkdir actions-runner && cd actions-runner
|
mkdir actions-runner && cd actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -77,7 +87,7 @@ tar xzf ./actions-runner-linux-x64-<RUNNER_VERSION>.tar.gz
|
|||||||
|
|
||||||
## Linux arm64
|
## Linux arm64
|
||||||
|
|
||||||
```bash
|
``` bash
|
||||||
# Create a folder
|
# Create a folder
|
||||||
mkdir actions-runner && cd actions-runner
|
mkdir actions-runner && cd actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -88,7 +98,7 @@ tar xzf ./actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz
|
|||||||
|
|
||||||
## Linux arm
|
## Linux arm
|
||||||
|
|
||||||
```bash
|
``` bash
|
||||||
# Create a folder
|
# Create a folder
|
||||||
mkdir actions-runner && cd actions-runner
|
mkdir actions-runner && cd actions-runner
|
||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
@@ -98,7 +108,6 @@ tar xzf ./actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Using your self hosted runner
|
## Using your self hosted runner
|
||||||
|
|
||||||
For additional details about configuring, running, or shutting down the runner please check out our [product docs.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/adding-self-hosted-runners)
|
For additional details about configuring, running, or shutting down the runner please check out our [product docs.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/adding-self-hosted-runners)
|
||||||
|
|
||||||
## SHA-256 Checksums
|
## SHA-256 Checksums
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<Update to ./src/runnerversion when creating release>
|
2.314.1
|
||||||
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
|
||||||
|
|||||||
@@ -114,11 +114,6 @@ var runService = function () {
|
|||||||
);
|
);
|
||||||
stopping = true;
|
stopping = true;
|
||||||
}
|
}
|
||||||
} else if (code === 5) {
|
|
||||||
console.log(
|
|
||||||
"Runner listener exit with Session Conflict error, stop the service, no retry needed."
|
|
||||||
);
|
|
||||||
stopping = true;
|
|
||||||
} else {
|
} else {
|
||||||
var messagePrefix = "Runner listener exit with undefined return code";
|
var messagePrefix = "Runner listener exit with undefined return code";
|
||||||
unknownFailureRetryCount++;
|
unknownFailureRetryCount++;
|
||||||
|
|||||||
@@ -49,10 +49,5 @@ if %ERRORLEVEL% EQU 4 (
|
|||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if %ERRORLEVEL% EQU 5 (
|
|
||||||
echo "Runner listener exit with Session Conflict error, stop the service, no retry needed."
|
|
||||||
exit /b 0
|
|
||||||
)
|
|
||||||
|
|
||||||
echo "Exiting after unknown error code: %ERRORLEVEL%"
|
echo "Exiting after unknown error code: %ERRORLEVEL%"
|
||||||
exit /b 0
|
exit /b 0
|
||||||
@@ -70,9 +70,6 @@ elif [[ $returnCode == 4 ]]; then
|
|||||||
"$DIR"/safe_sleep.sh 1
|
"$DIR"/safe_sleep.sh 1
|
||||||
done
|
done
|
||||||
exit 2
|
exit 2
|
||||||
elif [[ $returnCode == 5 ]]; then
|
|
||||||
echo "Runner listener exit with Session Conflict error, stop the service, no retry needed."
|
|
||||||
exit 0
|
|
||||||
else
|
else
|
||||||
echo "Exiting with unknown error code: ${returnCode}"
|
echo "Exiting with unknown error code: ${returnCode}"
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ runWithManualTrap() {
|
|||||||
cp -f "$DIR"/run-helper.sh.template "$DIR"/run-helper.sh
|
cp -f "$DIR"/run-helper.sh.template "$DIR"/run-helper.sh
|
||||||
"$DIR"/run-helper.sh $* &
|
"$DIR"/run-helper.sh $* &
|
||||||
PID=$!
|
PID=$!
|
||||||
wait $PID
|
wait -f $PID
|
||||||
returnCode=$?
|
returnCode=$?
|
||||||
if [[ $returnCode -eq 2 ]]; then
|
if [[ $returnCode -eq 2 ]]; then
|
||||||
echo "Restarting runner..."
|
echo "Restarting runner..."
|
||||||
@@ -84,4 +84,4 @@ if [[ -z "$RUNNER_MANUALLY_TRAP_SIG" ]]; then
|
|||||||
run $*
|
run $*
|
||||||
else
|
else
|
||||||
runWithManualTrap $*
|
runWithManualTrap $*
|
||||||
fi
|
fi
|
||||||
@@ -20,12 +20,12 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
private bool _hasConnection;
|
private bool _hasConnection;
|
||||||
private VssConnection _connection;
|
private VssConnection _connection;
|
||||||
private ActionsRunServerHttpClient _actionsRunServerClient;
|
private TaskAgentHttpClient _taskAgentClient;
|
||||||
|
|
||||||
public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials)
|
public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials)
|
||||||
{
|
{
|
||||||
_connection = await EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
_connection = await EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||||
_actionsRunServerClient = _connection.GetClient<ActionsRunServerHttpClient>();
|
_taskAgentClient = _connection.GetClient<TaskAgentHttpClient>();
|
||||||
_hasConnection = true;
|
_hasConnection = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ namespace GitHub.Runner.Common
|
|||||||
CheckConnection();
|
CheckConnection();
|
||||||
var jobMessage = RetryRequest<AgentJobRequestMessage>(async () =>
|
var jobMessage = RetryRequest<AgentJobRequestMessage>(async () =>
|
||||||
{
|
{
|
||||||
return await _actionsRunServerClient.GetJobMessageAsync(id, cancellationToken);
|
return await _taskAgentClient.GetJobMessageAsync(id, cancellationToken);
|
||||||
}, cancellationToken);
|
}, cancellationToken);
|
||||||
|
|
||||||
return jobMessage;
|
return jobMessage;
|
||||||
|
|||||||
@@ -153,7 +153,6 @@ namespace GitHub.Runner.Common
|
|||||||
public const int RetryableError = 2;
|
public const int RetryableError = 2;
|
||||||
public const int RunnerUpdating = 3;
|
public const int RunnerUpdating = 3;
|
||||||
public const int RunOnceRunnerUpdating = 4;
|
public const int RunOnceRunnerUpdating = 4;
|
||||||
public const int SessionConflict = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Features
|
public static class Features
|
||||||
@@ -181,9 +180,6 @@ 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 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 class RunnerEvent
|
public static class RunnerEvent
|
||||||
@@ -255,7 +251,6 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
||||||
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
||||||
public static readonly string AllowActionsUseUnsecureNodeVersion = "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION";
|
public static readonly string AllowActionsUseUnsecureNodeVersion = "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION";
|
||||||
public static readonly string ManualForceActionsToNode20 = "FORCE_JAVASCRIPT_ACTIONS_TO_NODE20";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Agent
|
public static class Agent
|
||||||
@@ -267,7 +262,6 @@ namespace GitHub.Runner.Common
|
|||||||
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";
|
||||||
public static readonly string ActionArchiveCacheDirectory = "ACTIONS_RUNNER_ACTION_ARCHIVE_CACHE";
|
public static readonly string ActionArchiveCacheDirectory = "ACTIONS_RUNNER_ACTION_ARCHIVE_CACHE";
|
||||||
public static readonly string ManualForceActionsToNode20 = "FORCE_JAVASCRIPT_ACTIONS_TO_NODE20";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class System
|
public static class System
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace GitHub.Runner.Common
|
|||||||
TaskCompletionSource<int> JobRecordUpdated { get; }
|
TaskCompletionSource<int> JobRecordUpdated { get; }
|
||||||
event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
||||||
Task ShutdownAsync();
|
Task ShutdownAsync();
|
||||||
void Start(Pipelines.AgentJobRequestMessage jobRequest, bool resultsServiceOnly = false);
|
void Start(Pipelines.AgentJobRequestMessage jobRequest, bool resultsServiceOnly = false, bool enableTelemetry = false);
|
||||||
void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber = null);
|
void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber = null);
|
||||||
void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource);
|
void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource);
|
||||||
void QueueResultsUpload(Guid timelineRecordId, string name, string path, string type, bool deleteSource, bool finalize, bool firstBlock, long totalLines);
|
void QueueResultsUpload(Guid timelineRecordId, string name, string path, string type, bool deleteSource, bool finalize, bool firstBlock, long totalLines);
|
||||||
@@ -74,7 +74,6 @@ namespace GitHub.Runner.Common
|
|||||||
private readonly List<JobTelemetry> _jobTelemetries = new();
|
private readonly List<JobTelemetry> _jobTelemetries = new();
|
||||||
private bool _queueInProcess = false;
|
private bool _queueInProcess = false;
|
||||||
private bool _resultsServiceOnly = false;
|
private bool _resultsServiceOnly = false;
|
||||||
private int _resultsServiceExceptionsCount = 0;
|
|
||||||
private Stopwatch _resultsUploadTimer = new();
|
private Stopwatch _resultsUploadTimer = new();
|
||||||
private Stopwatch _actionsUploadTimer = new();
|
private Stopwatch _actionsUploadTimer = new();
|
||||||
|
|
||||||
@@ -105,10 +104,11 @@ namespace GitHub.Runner.Common
|
|||||||
_resultsServer = hostContext.GetService<IResultsServer>();
|
_resultsServer = hostContext.GetService<IResultsServer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(Pipelines.AgentJobRequestMessage jobRequest, bool resultsServiceOnly = false)
|
public void Start(Pipelines.AgentJobRequestMessage jobRequest, bool resultsServiceOnly = false, bool enableTelemetry = false)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
_resultsServiceOnly = resultsServiceOnly;
|
_resultsServiceOnly = resultsServiceOnly;
|
||||||
|
_enableTelemetry = enableTelemetry;
|
||||||
|
|
||||||
var serviceEndPoint = jobRequest.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
var serviceEndPoint = jobRequest.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
@@ -139,12 +139,6 @@ namespace GitHub.Runner.Common
|
|||||||
_resultsClientInitiated = true;
|
_resultsClientInitiated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable telemetry if we have both results service and actions service
|
|
||||||
if (_resultsClientInitiated && !_resultsServiceOnly)
|
|
||||||
{
|
|
||||||
_enableTelemetry = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_queueInProcess)
|
if (_queueInProcess)
|
||||||
{
|
{
|
||||||
Trace.Info("No-opt, all queue process tasks are running.");
|
Trace.Info("No-opt, all queue process tasks are running.");
|
||||||
@@ -580,9 +574,9 @@ namespace GitHub.Runner.Common
|
|||||||
Trace.Info("Catch exception during file upload to results, keep going since the process is best effort.");
|
Trace.Info("Catch exception during file upload to results, keep going since the process is best effort.");
|
||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
errorCount++;
|
errorCount++;
|
||||||
_resultsServiceExceptionsCount++;
|
|
||||||
// If we hit any exceptions uploading to Results, let's skip any additional uploads to Results unless Results is serving logs
|
// 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)
|
if (!_resultsServiceOnly)
|
||||||
{
|
{
|
||||||
_resultsClientInitiated = false;
|
_resultsClientInitiated = false;
|
||||||
SendResultsTelemetry(ex);
|
SendResultsTelemetry(ex);
|
||||||
@@ -709,9 +703,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);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace GitHub.Runner.Listener
|
|||||||
_brokerServer = HostContext.GetService<IBrokerServer>();
|
_brokerServer = HostContext.GetService<IBrokerServer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CreateSessionResult> CreateSessionAsync(CancellationToken token)
|
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ namespace GitHub.Runner.Listener
|
|||||||
encounteringError = false;
|
encounteringError = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateSessionResult.Success;
|
return true;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -123,7 +123,7 @@ namespace GitHub.Runner.Listener
|
|||||||
if (string.Equals(vssOAuthEx.Error, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(vssOAuthEx.Error, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
||||||
return CreateSessionResult.Failure;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether we get 401 because the runner registration already removed by the service.
|
// Check whether we get 401 because the runner registration already removed by the service.
|
||||||
@@ -134,18 +134,14 @@ namespace GitHub.Runner.Listener
|
|||||||
if (string.Equals(authError, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(authError, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
||||||
return CreateSessionResult.Failure;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSessionCreationExceptionRetriable(ex))
|
if (!IsSessionCreationExceptionRetriable(ex))
|
||||||
{
|
{
|
||||||
_term.WriteError($"Failed to create session. {ex.Message}");
|
_term.WriteError($"Failed to create session. {ex.Message}");
|
||||||
if (ex is TaskAgentSessionConflictException)
|
return false;
|
||||||
{
|
|
||||||
return CreateSessionResult.SessionConflict;
|
|
||||||
}
|
|
||||||
return CreateSessionResult.Failure;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!encounteringError) //print the message only on the first error
|
if (!encounteringError) //print the message only on the first error
|
||||||
|
|||||||
@@ -1155,13 +1155,18 @@ namespace GitHub.Runner.Listener
|
|||||||
TimelineRecord jobRecord = timeline.Records.FirstOrDefault(x => x.Id == message.JobId && x.RecordType == "Job");
|
TimelineRecord jobRecord = timeline.Records.FirstOrDefault(x => x.Id == message.JobId && x.RecordType == "Job");
|
||||||
ArgUtil.NotNull(jobRecord, nameof(jobRecord));
|
ArgUtil.NotNull(jobRecord, nameof(jobRecord));
|
||||||
|
|
||||||
|
|
||||||
jobRecord.ErrorCount++;
|
jobRecord.ErrorCount++;
|
||||||
jobRecord.Issues.Add(issue);
|
jobRecord.Issues.Add(issue);
|
||||||
|
|
||||||
Trace.Info("Mark the job as failed since the worker crashed");
|
if (message.Variables.TryGetValue("DistributedTask.MarkJobAsFailedOnWorkerCrash", out var markJobAsFailedOnWorkerCrash) &&
|
||||||
jobRecord.Result = TaskResult.Failed;
|
StringUtil.ConvertToBoolean(markJobAsFailedOnWorkerCrash?.Value))
|
||||||
// mark the job as completed so service will pickup the result
|
{
|
||||||
jobRecord.State = TimelineRecordState.Completed;
|
Trace.Info("Mark the job as failed since the worker crashed");
|
||||||
|
jobRecord.Result = TaskResult.Failed;
|
||||||
|
// mark the job as completed so service will pickup the result
|
||||||
|
jobRecord.State = TimelineRecordState.Completed;
|
||||||
|
}
|
||||||
|
|
||||||
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, new TimelineRecord[] { jobRecord }, CancellationToken.None);
|
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, new TimelineRecord[] { jobRecord }, CancellationToken.None);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,17 +18,10 @@ using GitHub.Services.WebApi;
|
|||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
public enum CreateSessionResult
|
|
||||||
{
|
|
||||||
Success,
|
|
||||||
Failure,
|
|
||||||
SessionConflict
|
|
||||||
}
|
|
||||||
|
|
||||||
[ServiceLocator(Default = typeof(MessageListener))]
|
[ServiceLocator(Default = typeof(MessageListener))]
|
||||||
public interface IMessageListener : IRunnerService
|
public interface IMessageListener : IRunnerService
|
||||||
{
|
{
|
||||||
Task<CreateSessionResult> CreateSessionAsync(CancellationToken token);
|
Task<Boolean> CreateSessionAsync(CancellationToken token);
|
||||||
Task DeleteSessionAsync();
|
Task DeleteSessionAsync();
|
||||||
Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token);
|
Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token);
|
||||||
Task DeleteMessageAsync(TaskAgentMessage message);
|
Task DeleteMessageAsync(TaskAgentMessage message);
|
||||||
@@ -66,7 +59,7 @@ namespace GitHub.Runner.Listener
|
|||||||
_brokerServer = hostContext.GetService<IBrokerServer>();
|
_brokerServer = hostContext.GetService<IBrokerServer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<CreateSessionResult> CreateSessionAsync(CancellationToken token)
|
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
@@ -130,7 +123,7 @@ namespace GitHub.Runner.Listener
|
|||||||
encounteringError = false;
|
encounteringError = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateSessionResult.Success;
|
return true;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
@@ -154,7 +147,7 @@ namespace GitHub.Runner.Listener
|
|||||||
if (string.Equals(vssOAuthEx.Error, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(vssOAuthEx.Error, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
||||||
return CreateSessionResult.Failure;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether we get 401 because the runner registration already removed by the service.
|
// Check whether we get 401 because the runner registration already removed by the service.
|
||||||
@@ -165,18 +158,14 @@ namespace GitHub.Runner.Listener
|
|||||||
if (string.Equals(authError, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(authError, "invalid_client", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
_term.WriteError("Failed to create a session. The runner registration has been deleted from the server, please re-configure. Runner registrations are automatically deleted for runners that have not connected to the service recently.");
|
||||||
return CreateSessionResult.Failure;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsSessionCreationExceptionRetriable(ex))
|
if (!IsSessionCreationExceptionRetriable(ex))
|
||||||
{
|
{
|
||||||
_term.WriteError($"Failed to create session. {ex.Message}");
|
_term.WriteError($"Failed to create session. {ex.Message}");
|
||||||
if (ex is TaskAgentSessionConflictException)
|
return false;
|
||||||
{
|
|
||||||
return CreateSessionResult.SessionConflict;
|
|
||||||
}
|
|
||||||
return CreateSessionResult.Failure;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!encounteringError) //print the message only on the first error
|
if (!encounteringError) //print the message only on the first error
|
||||||
@@ -199,12 +188,12 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
using (var ts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
|
using (var ts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
|
||||||
{
|
{
|
||||||
await _runnerServer.DeleteAgentSessionAsync(_settings.PoolId, _session.SessionId, ts.Token);
|
|
||||||
|
|
||||||
if (_isBrokerSession)
|
if (_isBrokerSession)
|
||||||
{
|
{
|
||||||
await _brokerServer.DeleteSessionAsync(ts.Token);
|
await _brokerServer.DeleteSessionAsync(ts.Token);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
await _runnerServer.DeleteAgentSessionAsync(_settings.PoolId, _session.SessionId, ts.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -236,7 +225,6 @@ namespace GitHub.Runner.Listener
|
|||||||
ArgUtil.NotNull(_settings, nameof(_settings));
|
ArgUtil.NotNull(_settings, nameof(_settings));
|
||||||
bool encounteringError = false;
|
bool encounteringError = false;
|
||||||
int continuousError = 0;
|
int continuousError = 0;
|
||||||
int continuousEmptyMessage = 0;
|
|
||||||
string errorMessage = string.Empty;
|
string errorMessage = string.Empty;
|
||||||
Stopwatch heartbeat = new();
|
Stopwatch heartbeat = new();
|
||||||
heartbeat.Restart();
|
heartbeat.Restart();
|
||||||
@@ -315,7 +303,7 @@ namespace GitHub.Runner.Listener
|
|||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
|
|
||||||
// don't retry if SkipSessionRecover = true, DT service will delete agent session to stop agent from taking more jobs.
|
// don't retry if SkipSessionRecover = true, DT service will delete agent session to stop agent from taking more jobs.
|
||||||
if (ex is TaskAgentSessionExpiredException && !_settings.SkipSessionRecover && (await CreateSessionAsync(token) == CreateSessionResult.Success))
|
if (ex is TaskAgentSessionExpiredException && !_settings.SkipSessionRecover && await CreateSessionAsync(token))
|
||||||
{
|
{
|
||||||
Trace.Info($"{nameof(TaskAgentSessionExpiredException)} received, recovered by recreate session.");
|
Trace.Info($"{nameof(TaskAgentSessionExpiredException)} received, recovered by recreate session.");
|
||||||
}
|
}
|
||||||
@@ -360,27 +348,16 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
if (message == null)
|
if (message == null)
|
||||||
{
|
{
|
||||||
continuousEmptyMessage++;
|
|
||||||
if (heartbeat.Elapsed > TimeSpan.FromMinutes(30))
|
if (heartbeat.Elapsed > TimeSpan.FromMinutes(30))
|
||||||
{
|
{
|
||||||
Trace.Info($"No message retrieved from session '{_session.SessionId}' within last 30 minutes.");
|
Trace.Info($"No message retrieved from session '{_session.SessionId}' within last 30 minutes.");
|
||||||
heartbeat.Restart();
|
heartbeat.Restart();
|
||||||
continuousEmptyMessage = 0;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.Verbose($"No message retrieved from session '{_session.SessionId}'.");
|
Trace.Verbose($"No message retrieved from session '{_session.SessionId}'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (continuousEmptyMessage > 50)
|
|
||||||
{
|
|
||||||
// retried more than 50 times in less than 30mins and still getting empty message
|
|
||||||
// something is not right on the service side, backoff for 15-30s before retry
|
|
||||||
_getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30), _getNextMessageRetryInterval);
|
|
||||||
Trace.Info("Sleeping for {0} seconds before retrying.", _getNextMessageRetryInterval.TotalSeconds);
|
|
||||||
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -359,12 +359,7 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
Trace.Info(nameof(RunAsync));
|
Trace.Info(nameof(RunAsync));
|
||||||
_listener = GetMesageListener(settings);
|
_listener = GetMesageListener(settings);
|
||||||
CreateSessionResult createSessionResult = await _listener.CreateSessionAsync(HostContext.RunnerShutdownToken);
|
if (!await _listener.CreateSessionAsync(HostContext.RunnerShutdownToken))
|
||||||
if (createSessionResult == CreateSessionResult.SessionConflict)
|
|
||||||
{
|
|
||||||
return Constants.Runner.ReturnCode.SessionConflict;
|
|
||||||
}
|
|
||||||
else if (createSessionResult == CreateSessionResult.Failure)
|
|
||||||
{
|
{
|
||||||
return Constants.Runner.ReturnCode.TerminatedError;
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
}
|
}
|
||||||
@@ -572,11 +567,6 @@ namespace GitHub.Runner.Listener
|
|||||||
Trace.Info("Job is already acquired, skip this message.");
|
Trace.Info("Job is already acquired, skip this message.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Error($"Caught exception from acquiring job message: {ex}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
jobDispatcher.Run(jobRequestMessage, runOnce);
|
jobDispatcher.Run(jobRequestMessage, runOnce);
|
||||||
|
|||||||
@@ -459,34 +459,6 @@ namespace GitHub.Runner.Sdk
|
|||||||
File.WriteAllText(path, null);
|
File.WriteAllText(path, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Replaces invalid file name characters with '_'
|
|
||||||
/// </summary>
|
|
||||||
public static string ReplaceInvalidFileNameChars(string fileName)
|
|
||||||
{
|
|
||||||
var result = new StringBuilder();
|
|
||||||
var invalidChars = Path.GetInvalidFileNameChars();
|
|
||||||
|
|
||||||
var current = 0; // Current index
|
|
||||||
while (current < fileName?.Length)
|
|
||||||
{
|
|
||||||
var next = fileName.IndexOfAny(invalidChars, current);
|
|
||||||
if (next >= 0)
|
|
||||||
{
|
|
||||||
result.Append(fileName.Substring(current, next - current));
|
|
||||||
result.Append('_');
|
|
||||||
current = next + 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
result.Append(fileName.Substring(current));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recursively enumerates a directory without following directory reparse points.
|
/// Recursively enumerates a directory without following directory reparse points.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -7,6 +7,129 @@ namespace GitHub.Runner.Sdk
|
|||||||
public static class WhichUtil
|
public static class WhichUtil
|
||||||
{
|
{
|
||||||
public static string Which(string command, bool require = false, ITraceWriter trace = null, string prependPath = null)
|
public static string Which(string command, bool require = false, ITraceWriter trace = null, string prependPath = null)
|
||||||
|
{
|
||||||
|
ArgUtil.NotNullOrEmpty(command, nameof(command));
|
||||||
|
trace?.Info($"Which: '{command}'");
|
||||||
|
if (Path.IsPathFullyQualified(command) && File.Exists(command))
|
||||||
|
{
|
||||||
|
trace?.Info($"Fully qualified path: '{command}'");
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
string path = Environment.GetEnvironmentVariable(PathUtil.PathVariable);
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
trace?.Info("PATH environment variable not defined.");
|
||||||
|
path = path ?? string.Empty;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(prependPath))
|
||||||
|
{
|
||||||
|
path = PathUtil.PrependPath(prependPath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] pathSegments = path.Split(new Char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
for (int i = 0; i < pathSegments.Length; i++)
|
||||||
|
{
|
||||||
|
pathSegments[i] = Environment.ExpandEnvironmentVariables(pathSegments[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string pathSegment in pathSegments)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(pathSegment) && Directory.Exists(pathSegment))
|
||||||
|
{
|
||||||
|
string[] matches = null;
|
||||||
|
#if OS_WINDOWS
|
||||||
|
string pathExt = Environment.GetEnvironmentVariable("PATHEXT");
|
||||||
|
if (string.IsNullOrEmpty(pathExt))
|
||||||
|
{
|
||||||
|
// XP's system default value for PATHEXT system variable
|
||||||
|
pathExt = ".com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh";
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] pathExtSegments = pathExt.Split(new string[] { ";" }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
// if command already has an extension.
|
||||||
|
if (pathExtSegments.Any(ext => command.EndsWith(ext, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
matches = Directory.GetFiles(pathSegment, command);
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException ex)
|
||||||
|
{
|
||||||
|
trace?.Info("Ignore UnauthorizedAccess exception during Which.");
|
||||||
|
trace?.Verbose(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches != null && matches.Length > 0 && IsPathValid(matches.First(), trace))
|
||||||
|
{
|
||||||
|
trace?.Info($"Location: '{matches.First()}'");
|
||||||
|
return matches.First();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string searchPattern;
|
||||||
|
searchPattern = StringUtil.Format($"{command}.*");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
matches = Directory.GetFiles(pathSegment, searchPattern);
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException ex)
|
||||||
|
{
|
||||||
|
trace?.Info("Ignore UnauthorizedAccess exception during Which.");
|
||||||
|
trace?.Verbose(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches != null && matches.Length > 0)
|
||||||
|
{
|
||||||
|
// add extension.
|
||||||
|
for (int i = 0; i < pathExtSegments.Length; i++)
|
||||||
|
{
|
||||||
|
string fullPath = Path.Combine(pathSegment, $"{command}{pathExtSegments[i]}");
|
||||||
|
if (matches.Any(p => p.Equals(fullPath, StringComparison.OrdinalIgnoreCase)) && IsPathValid(fullPath, trace))
|
||||||
|
{
|
||||||
|
trace?.Info($"Location: '{fullPath}'");
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
try
|
||||||
|
{
|
||||||
|
matches = Directory.GetFiles(pathSegment, command);
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException ex)
|
||||||
|
{
|
||||||
|
trace?.Info("Ignore UnauthorizedAccess exception during Which.");
|
||||||
|
trace?.Verbose(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches != null && matches.Length > 0 && IsPathValid(matches.First(), trace))
|
||||||
|
{
|
||||||
|
trace?.Info($"Location: '{matches.First()}'");
|
||||||
|
return matches.First();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
trace?.Info($"{command}: command not found. Make sure '{command}' is installed and its location included in the 'Path' environment variable.");
|
||||||
|
#else
|
||||||
|
trace?.Info($"{command}: command not found. Make sure '{command}' is installed and its location included in the 'PATH' environment variable.");
|
||||||
|
#endif
|
||||||
|
if (require)
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException(
|
||||||
|
message: $"{command}: command not found",
|
||||||
|
fileName: command);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string Which2(string command, bool require = false, ITraceWriter trace = null, string prependPath = null)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNullOrEmpty(command, nameof(command));
|
ArgUtil.NotNullOrEmpty(command, nameof(command));
|
||||||
trace?.Info($"Which2: '{command}'");
|
trace?.Info($"Which2: '{command}'");
|
||||||
|
|||||||
@@ -483,6 +483,10 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
// Load stored Ids for later load actions
|
// Load stored Ids for later load actions
|
||||||
compositeAction.Steps[i].Id = _cachedEmbeddedStepIds[action.Id][i];
|
compositeAction.Steps[i].Id = _cachedEmbeddedStepIds[action.Id][i];
|
||||||
|
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && compositeAction.Steps[i].Reference.Type != Pipelines.ActionSourceType.Script)
|
||||||
|
{
|
||||||
|
throw new Exception("`uses:` keyword is not currently supported.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -699,12 +703,11 @@ namespace GitHub.Runner.Worker
|
|||||||
catch (Exception ex) when (!executionContext.CancellationToken.IsCancellationRequested) // Do not retry if the run is cancelled.
|
catch (Exception ex) when (!executionContext.CancellationToken.IsCancellationRequested) // Do not retry if the run is cancelled.
|
||||||
{
|
{
|
||||||
// UnresolvableActionDownloadInfoException is a 422 client error, don't retry
|
// UnresolvableActionDownloadInfoException is a 422 client error, don't retry
|
||||||
// NonRetryableActionDownloadInfoException is an non-retryable exception from Actions
|
|
||||||
// Some possible cases are:
|
// Some possible cases are:
|
||||||
// * Repo is rate limited
|
// * Repo is rate limited
|
||||||
// * Repo or tag doesn't exist, or isn't public
|
// * Repo or tag doesn't exist, or isn't public
|
||||||
// * Policy validation failed
|
// * Policy validation failed
|
||||||
if (attempt < 3 && !(ex is WebApi.UnresolvableActionDownloadInfoException) && !(ex is WebApi.NonRetryableActionDownloadInfoException))
|
if (attempt < 3 && !(ex is WebApi.UnresolvableActionDownloadInfoException))
|
||||||
{
|
{
|
||||||
executionContext.Output($"Failed to resolve action download info. Error: {ex.Message}");
|
executionContext.Output($"Failed to resolve action download info. Error: {ex.Message}");
|
||||||
executionContext.Debug(ex.ToString());
|
executionContext.Debug(ex.ToString());
|
||||||
@@ -793,39 +796,42 @@ namespace GitHub.Runner.Worker
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var useActionArchiveCache = false;
|
var useActionArchiveCache = false;
|
||||||
var hasActionArchiveCache = false;
|
if (executionContext.Global.Variables.GetBoolean("DistributedTask.UseActionArchiveCache") == true)
|
||||||
var actionArchiveCacheDir = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ActionArchiveCacheDirectory);
|
|
||||||
if (!string.IsNullOrEmpty(actionArchiveCacheDir) &&
|
|
||||||
Directory.Exists(actionArchiveCacheDir))
|
|
||||||
{
|
{
|
||||||
hasActionArchiveCache = true;
|
var hasActionArchiveCache = false;
|
||||||
Trace.Info($"Check if action archive '{downloadInfo.ResolvedNameWithOwner}@{downloadInfo.ResolvedSha}' already exists in cache directory '{actionArchiveCacheDir}'");
|
var actionArchiveCacheDir = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ActionArchiveCacheDirectory);
|
||||||
#if OS_WINDOWS
|
if (!string.IsNullOrEmpty(actionArchiveCacheDir) &&
|
||||||
var cacheArchiveFile = Path.Combine(actionArchiveCacheDir, downloadInfo.ResolvedNameWithOwner.Replace(Path.DirectorySeparatorChar, '_').Replace(Path.AltDirectorySeparatorChar, '_'), $"{downloadInfo.ResolvedSha}.zip");
|
Directory.Exists(actionArchiveCacheDir))
|
||||||
#else
|
|
||||||
var cacheArchiveFile = Path.Combine(actionArchiveCacheDir, downloadInfo.ResolvedNameWithOwner.Replace(Path.DirectorySeparatorChar, '_').Replace(Path.AltDirectorySeparatorChar, '_'), $"{downloadInfo.ResolvedSha}.tar.gz");
|
|
||||||
#endif
|
|
||||||
if (File.Exists(cacheArchiveFile))
|
|
||||||
{
|
{
|
||||||
try
|
hasActionArchiveCache = true;
|
||||||
|
Trace.Info($"Check if action archive '{downloadInfo.ResolvedNameWithOwner}@{downloadInfo.ResolvedSha}' already exists in cache directory '{actionArchiveCacheDir}'");
|
||||||
|
#if OS_WINDOWS
|
||||||
|
var cacheArchiveFile = Path.Combine(actionArchiveCacheDir, downloadInfo.ResolvedNameWithOwner.Replace(Path.DirectorySeparatorChar, '_').Replace(Path.AltDirectorySeparatorChar, '_'), $"{downloadInfo.ResolvedSha}.zip");
|
||||||
|
#else
|
||||||
|
var cacheArchiveFile = Path.Combine(actionArchiveCacheDir, downloadInfo.ResolvedNameWithOwner.Replace(Path.DirectorySeparatorChar, '_').Replace(Path.AltDirectorySeparatorChar, '_'), $"{downloadInfo.ResolvedSha}.tar.gz");
|
||||||
|
#endif
|
||||||
|
if (File.Exists(cacheArchiveFile))
|
||||||
{
|
{
|
||||||
Trace.Info($"Found action archive '{cacheArchiveFile}' in cache directory '{actionArchiveCacheDir}'");
|
try
|
||||||
File.Copy(cacheArchiveFile, archiveFile);
|
{
|
||||||
useActionArchiveCache = true;
|
Trace.Info($"Found action archive '{cacheArchiveFile}' in cache directory '{actionArchiveCacheDir}'");
|
||||||
executionContext.Debug($"Copied action archive '{cacheArchiveFile}' to '{archiveFile}'");
|
File.Copy(cacheArchiveFile, archiveFile);
|
||||||
}
|
useActionArchiveCache = true;
|
||||||
catch (Exception ex)
|
executionContext.Debug($"Copied action archive '{cacheArchiveFile}' to '{archiveFile}'");
|
||||||
{
|
}
|
||||||
Trace.Error($"Failed to copy action archive '{cacheArchiveFile}' to '{archiveFile}'. Error: {ex}");
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error($"Failed to copy action archive '{cacheArchiveFile}' to '{archiveFile}'. Error: {ex}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
executionContext.Global.JobTelemetry.Add(new JobTelemetry()
|
||||||
{
|
{
|
||||||
Type = JobTelemetryType.General,
|
Type = JobTelemetryType.General,
|
||||||
Message = $"Action archive cache usage: {downloadInfo.ResolvedNameWithOwner}@{downloadInfo.ResolvedSha} use cache {useActionArchiveCache} has cache {hasActionArchiveCache}"
|
Message = $"Action archive cache usage: {downloadInfo.ResolvedNameWithOwner}@{downloadInfo.ResolvedSha} use cache {useActionArchiveCache} has cache {hasActionArchiveCache}"
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!useActionArchiveCache)
|
if (!useActionArchiveCache)
|
||||||
{
|
{
|
||||||
@@ -872,9 +878,16 @@ namespace GitHub.Runner.Worker
|
|||||||
int exitCode = await processInvoker.ExecuteAsync(stagingDirectory, tar, $"-xzf \"{archiveFile}\"", null, executionContext.CancellationToken);
|
int exitCode = await processInvoker.ExecuteAsync(stagingDirectory, tar, $"-xzf \"{archiveFile}\"", null, executionContext.CancellationToken);
|
||||||
if (exitCode != 0)
|
if (exitCode != 0)
|
||||||
{
|
{
|
||||||
var fileInfo = new FileInfo(archiveFile);
|
if (executionContext.Global.Variables.GetBoolean("DistributedTask.DetailUntarFailure") == true)
|
||||||
var sha256hash = await IOUtil.GetFileContentSha256HashAsync(archiveFile);
|
{
|
||||||
throw new InvalidActionArchiveException($"Can't use 'tar -xzf' extract archive file: {archiveFile} (SHA256 '{sha256hash}', size '{fileInfo.Length}' bytes, tar outputs '{string.Join(' ', tarOutputs)}'). Action being checked out: {downloadInfo.NameWithOwner}@{downloadInfo.Ref}. return code: {exitCode}.");
|
var fileInfo = new FileInfo(archiveFile);
|
||||||
|
var sha256hash = await IOUtil.GetFileContentSha256HashAsync(archiveFile);
|
||||||
|
throw new InvalidActionArchiveException($"Can't use 'tar -xzf' extract archive file: {archiveFile} (SHA256 '{sha256hash}', size '{fileInfo.Length}' bytes, tar outputs '{string.Join(' ', tarOutputs)}'). Action being checked out: {downloadInfo.NameWithOwner}@{downloadInfo.Ref}. return code: {exitCode}.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidActionArchiveException($"Can't use 'tar -xzf' extract archive file: {archiveFile}. Action being checked out: {downloadInfo.NameWithOwner}@{downloadInfo.Ref}. return code: {exitCode}.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -1018,6 +1031,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var step in compositeAction.Steps)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && step.Reference.Type != Pipelines.ActionSourceType.Script)
|
||||||
|
{
|
||||||
|
throw new Exception("`uses:` keyword is not currently supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
return setupInfo;
|
return setupInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -91,13 +91,13 @@ namespace GitHub.Runner.Worker
|
|||||||
string phaseName = executionContext.Global.Variables.System_PhaseDisplayName ?? "UnknownPhaseName";
|
string phaseName = executionContext.Global.Variables.System_PhaseDisplayName ?? "UnknownPhaseName";
|
||||||
|
|
||||||
// zip the files
|
// zip the files
|
||||||
string diagnosticsZipFileName = $"{buildName}-{IOUtil.ReplaceInvalidFileNameChars(phaseName)}.zip";
|
string diagnosticsZipFileName = $"{buildName}-{phaseName}.zip";
|
||||||
string diagnosticsZipFilePath = Path.Combine(supportRootFolder, diagnosticsZipFileName);
|
string diagnosticsZipFilePath = Path.Combine(supportRootFolder, diagnosticsZipFileName);
|
||||||
ZipFile.CreateFromDirectory(supportFilesFolder, diagnosticsZipFilePath);
|
ZipFile.CreateFromDirectory(supportFilesFolder, diagnosticsZipFilePath);
|
||||||
|
|
||||||
// upload the json metadata file
|
// upload the json metadata file
|
||||||
executionContext.Debug("Uploading diagnostic metadata file.");
|
executionContext.Debug("Uploading diagnostic metadata file.");
|
||||||
string metadataFileName = $"diagnostics-{buildName}-{IOUtil.ReplaceInvalidFileNameChars(phaseName)}.json";
|
string metadataFileName = $"diagnostics-{buildName}-{phaseName}.json";
|
||||||
string metadataFilePath = Path.Combine(supportFilesFolder, metadataFileName);
|
string metadataFilePath = Path.Combine(supportFilesFolder, metadataFileName);
|
||||||
string phaseResult = GetTaskResultAsString(executionContext.Result);
|
string phaseResult = GetTaskResultAsString(executionContext.Result);
|
||||||
|
|
||||||
|
|||||||
@@ -223,10 +223,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
Environment["ACTIONS_CACHE_URL"] = cacheUrl;
|
Environment["ACTIONS_CACHE_URL"] = cacheUrl;
|
||||||
}
|
}
|
||||||
if (systemConnection.Data.TryGetValue("PipelinesServiceUrl", out var pipelinesServiceUrl) && !string.IsNullOrEmpty(pipelinesServiceUrl))
|
|
||||||
{
|
|
||||||
Environment["ACTIONS_RUNTIME_URL"] = pipelinesServiceUrl;
|
|
||||||
}
|
|
||||||
if (systemConnection.Data.TryGetValue("GenerateIdTokenUrl", out var generateIdTokenUrl) && !string.IsNullOrEmpty(generateIdTokenUrl))
|
if (systemConnection.Data.TryGetValue("GenerateIdTokenUrl", out var generateIdTokenUrl) && !string.IsNullOrEmpty(generateIdTokenUrl))
|
||||||
{
|
{
|
||||||
Environment["ACTIONS_ID_TOKEN_REQUEST_URL"] = generateIdTokenUrl;
|
Environment["ACTIONS_ID_TOKEN_REQUEST_URL"] = generateIdTokenUrl;
|
||||||
|
|||||||
@@ -84,45 +84,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
nodeData.NodeVersion = "node16";
|
nodeData.NodeVersion = "node16";
|
||||||
}
|
}
|
||||||
|
|
||||||
var localForceActionsToNode20 = StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable(Constants.Variables.Agent.ManualForceActionsToNode20));
|
|
||||||
executionContext.Global.EnvironmentVariables.TryGetValue(Constants.Variables.Actions.ManualForceActionsToNode20, out var workflowForceActionsToNode20);
|
|
||||||
var enforceNode20Locally = !string.IsNullOrWhiteSpace(workflowForceActionsToNode20) ? StringUtil.ConvertToBoolean(workflowForceActionsToNode20) : localForceActionsToNode20;
|
|
||||||
if (string.Equals(nodeData.NodeVersion, "node16")
|
|
||||||
&& ((executionContext.Global.Variables.GetBoolean("DistributedTask.ForceGithubJavascriptActionsToNode20") ?? false) || enforceNode20Locally))
|
|
||||||
{
|
|
||||||
executionContext.Global.EnvironmentVariables.TryGetValue(Constants.Variables.Actions.AllowActionsUseUnsecureNodeVersion, out var workflowOptOut);
|
|
||||||
var isWorkflowOptOutSet = !string.IsNullOrWhiteSpace(workflowOptOut);
|
|
||||||
var isLocalOptOut = StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowActionsUseUnsecureNodeVersion));
|
|
||||||
bool isOptOut = isWorkflowOptOutSet ? StringUtil.ConvertToBoolean(workflowOptOut) : isLocalOptOut;
|
|
||||||
|
|
||||||
if (!isOptOut)
|
|
||||||
{
|
|
||||||
var repoAction = action as Pipelines.RepositoryPathReference;
|
|
||||||
if (repoAction != null)
|
|
||||||
{
|
|
||||||
var warningActions = new HashSet<string>();
|
|
||||||
if (executionContext.Global.Variables.TryGetValue(Constants.Runner.EnforcedNode16DetectedAfterEndOfLifeEnvVariable, out var node20ForceWarnings))
|
|
||||||
{
|
|
||||||
warningActions = StringUtil.ConvertFromJson<HashSet<string>>(node20ForceWarnings);
|
|
||||||
}
|
|
||||||
|
|
||||||
string repoActionFullName;
|
|
||||||
if (string.IsNullOrEmpty(repoAction.Name))
|
|
||||||
{
|
|
||||||
repoActionFullName = repoAction.Path; // local actions don't have a 'Name'
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
repoActionFullName = $"{repoAction.Name}/{repoAction.Path ?? string.Empty}".TrimEnd('/') + $"@{repoAction.Ref}";
|
|
||||||
}
|
|
||||||
|
|
||||||
warningActions.Add(repoActionFullName);
|
|
||||||
executionContext.Global.Variables.Set(Constants.Runner.EnforcedNode16DetectedAfterEndOfLifeEnvVariable, StringUtil.ConvertToJson(warningActions));
|
|
||||||
}
|
|
||||||
nodeData.NodeVersion = "node20";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
(handler as INodeScriptActionHandler).Data = nodeData;
|
(handler as INodeScriptActionHandler).Data = nodeData;
|
||||||
}
|
}
|
||||||
else if (data.ExecutionType == ActionExecutionType.Script)
|
else if (data.ExecutionType == ActionExecutionType.Script)
|
||||||
|
|||||||
@@ -58,10 +58,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
Environment["ACTIONS_CACHE_URL"] = cacheUrl;
|
Environment["ACTIONS_CACHE_URL"] = cacheUrl;
|
||||||
}
|
}
|
||||||
if (systemConnection.Data.TryGetValue("PipelinesServiceUrl", out var pipelinesServiceUrl) && !string.IsNullOrEmpty(pipelinesServiceUrl))
|
|
||||||
{
|
|
||||||
Environment["ACTIONS_RUNTIME_URL"] = pipelinesServiceUrl;
|
|
||||||
}
|
|
||||||
if (systemConnection.Data.TryGetValue("GenerateIdTokenUrl", out var generateIdTokenUrl) && !string.IsNullOrEmpty(generateIdTokenUrl))
|
if (systemConnection.Data.TryGetValue("GenerateIdTokenUrl", out var generateIdTokenUrl) && !string.IsNullOrEmpty(generateIdTokenUrl))
|
||||||
{
|
{
|
||||||
Environment["ACTIONS_ID_TOKEN_REQUEST_URL"] = generateIdTokenUrl;
|
Environment["ACTIONS_ID_TOKEN_REQUEST_URL"] = generateIdTokenUrl;
|
||||||
@@ -118,11 +114,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
Data.NodeVersion = "node16";
|
Data.NodeVersion = "node16";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forcedNodeVersion == "node20" && Data.NodeVersion != "node20")
|
|
||||||
{
|
|
||||||
Data.NodeVersion = "node20";
|
|
||||||
}
|
|
||||||
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
|
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
|
||||||
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
|
||||||
|
|||||||
@@ -83,19 +83,40 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
shellCommand = "pwsh";
|
shellCommand = "pwsh";
|
||||||
if (validateShellOnHost)
|
if (validateShellOnHost)
|
||||||
{
|
{
|
||||||
shellCommandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which2(shellCommand, require: false, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
|
||||||
|
}
|
||||||
if (string.IsNullOrEmpty(shellCommandPath))
|
if (string.IsNullOrEmpty(shellCommandPath))
|
||||||
{
|
{
|
||||||
shellCommand = "powershell";
|
shellCommand = "powershell";
|
||||||
Trace.Info($"Defaulting to {shellCommand}");
|
Trace.Info($"Defaulting to {shellCommand}");
|
||||||
shellCommandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which2(shellCommand, require: true, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
shellCommand = "sh";
|
shellCommand = "sh";
|
||||||
if (validateShellOnHost)
|
if (validateShellOnHost)
|
||||||
{
|
{
|
||||||
shellCommandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which2("bash", false, Trace, prependPath) ?? WhichUtil.Which2("sh", true, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
|
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
|
||||||
@@ -106,7 +127,14 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
shellCommand = parsed.shellCommand;
|
shellCommand = parsed.shellCommand;
|
||||||
if (validateShellOnHost)
|
if (validateShellOnHost)
|
||||||
{
|
{
|
||||||
shellCommandPath = WhichUtil.Which(parsed.shellCommand, true, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which2(parsed.shellCommand, true, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
shellCommandPath = WhichUtil.Which(parsed.shellCommand, true, Trace, prependPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
argFormat = $"{parsed.shellArgs}".TrimStart();
|
argFormat = $"{parsed.shellArgs}".TrimStart();
|
||||||
@@ -188,17 +216,38 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
shellCommand = "pwsh";
|
shellCommand = "pwsh";
|
||||||
commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which2(shellCommand, require: false, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which(shellCommand, require: false, Trace, prependPath);
|
||||||
|
}
|
||||||
if (string.IsNullOrEmpty(commandPath))
|
if (string.IsNullOrEmpty(commandPath))
|
||||||
{
|
{
|
||||||
shellCommand = "powershell";
|
shellCommand = "powershell";
|
||||||
Trace.Info($"Defaulting to {shellCommand}");
|
Trace.Info($"Defaulting to {shellCommand}");
|
||||||
commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which2(shellCommand, require: true, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which(shellCommand, require: true, Trace, prependPath);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ArgUtil.NotNullOrEmpty(commandPath, "Default Shell");
|
ArgUtil.NotNullOrEmpty(commandPath, "Default Shell");
|
||||||
#else
|
#else
|
||||||
shellCommand = "sh";
|
shellCommand = "sh";
|
||||||
commandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which2("bash", false, Trace, prependPath) ?? WhichUtil.Which2("sh", true, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which("bash", false, Trace, prependPath) ?? WhichUtil.Which("sh", true, Trace, prependPath);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
|
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
|
||||||
}
|
}
|
||||||
@@ -209,7 +258,14 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
if (!IsActionStep && systemShells.Contains(shell))
|
if (!IsActionStep && systemShells.Contains(shell))
|
||||||
{
|
{
|
||||||
shellCommand = shell;
|
shellCommand = shell;
|
||||||
commandPath = WhichUtil.Which(shell, !isContainerStepHost, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which2(shell, !isContainerStepHost, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which(shell, !isContainerStepHost, Trace, prependPath);
|
||||||
|
}
|
||||||
if (shell == "bash")
|
if (shell == "bash")
|
||||||
{
|
{
|
||||||
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat("sh");
|
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat("sh");
|
||||||
@@ -224,7 +280,14 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell);
|
var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell);
|
||||||
shellCommand = parsed.shellCommand;
|
shellCommand = parsed.shellCommand;
|
||||||
// For non-ContainerStepHost, the command must be located on the host by Which
|
// For non-ContainerStepHost, the command must be located on the host by Which
|
||||||
commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
|
if (ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseWhich2") == true)
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which2(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
|
||||||
|
}
|
||||||
argFormat = $"{parsed.shellArgs}".TrimStart();
|
argFormat = $"{parsed.shellArgs}".TrimStart();
|
||||||
if (string.IsNullOrEmpty(argFormat))
|
if (string.IsNullOrEmpty(argFormat))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info("Job ID {0}", message.JobId);
|
Trace.Info("Job ID {0}", message.JobId);
|
||||||
|
|
||||||
DateTime jobStartTimeUtc = DateTime.UtcNow;
|
DateTime jobStartTimeUtc = DateTime.UtcNow;
|
||||||
_runnerSettings = HostContext.GetService<IConfigurationStore>().GetSettings();
|
|
||||||
IRunnerService server = null;
|
IRunnerService server = null;
|
||||||
|
|
||||||
// add orchestration id to useragent for better correlation.
|
// add orchestration id to useragent for better correlation.
|
||||||
@@ -55,6 +54,13 @@ namespace GitHub.Runner.Worker
|
|||||||
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
|
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var jobServerQueueTelemetry = false;
|
||||||
|
if (message.Variables.TryGetValue("DistributedTask.EnableJobServerQueueTelemetry", out VariableValue enableJobServerQueueTelemetry) &&
|
||||||
|
!string.IsNullOrEmpty(enableJobServerQueueTelemetry?.Value))
|
||||||
|
{
|
||||||
|
jobServerQueueTelemetry = StringUtil.ConvertToBoolean(enableJobServerQueueTelemetry.Value);
|
||||||
|
}
|
||||||
|
|
||||||
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||||
if (MessageUtil.IsRunServiceJob(message.MessageType))
|
if (MessageUtil.IsRunServiceJob(message.MessageType))
|
||||||
{
|
{
|
||||||
@@ -76,7 +82,7 @@ namespace GitHub.Runner.Worker
|
|||||||
launchServer.InitializeLaunchClient(new Uri(launchReceiverEndpoint), accessToken);
|
launchServer.InitializeLaunchClient(new Uri(launchReceiverEndpoint), accessToken);
|
||||||
}
|
}
|
||||||
_jobServerQueue = HostContext.GetService<IJobServerQueue>();
|
_jobServerQueue = HostContext.GetService<IJobServerQueue>();
|
||||||
_jobServerQueue.Start(message, resultsServiceOnly: true);
|
_jobServerQueue.Start(message, resultsServiceOnly: true, enableTelemetry: jobServerQueueTelemetry);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -98,7 +104,7 @@ namespace GitHub.Runner.Worker
|
|||||||
VssConnection jobConnection = VssUtil.CreateConnection(jobServerUrl, jobServerCredential, delegatingHandlers);
|
VssConnection jobConnection = VssUtil.CreateConnection(jobServerUrl, jobServerCredential, delegatingHandlers);
|
||||||
await jobServer.ConnectAsync(jobConnection);
|
await jobServer.ConnectAsync(jobConnection);
|
||||||
|
|
||||||
_jobServerQueue.Start(message);
|
_jobServerQueue.Start(message, enableTelemetry: jobServerQueueTelemetry);
|
||||||
server = jobServer;
|
server = jobServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,6 +164,8 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
jobContext.SetRunnerContext("os", VarUtil.OS);
|
jobContext.SetRunnerContext("os", VarUtil.OS);
|
||||||
jobContext.SetRunnerContext("arch", VarUtil.OSArchitecture);
|
jobContext.SetRunnerContext("arch", VarUtil.OSArchitecture);
|
||||||
|
|
||||||
|
_runnerSettings = HostContext.GetService<IConfigurationStore>().GetSettings();
|
||||||
jobContext.SetRunnerContext("name", _runnerSettings.AgentName);
|
jobContext.SetRunnerContext("name", _runnerSettings.AgentName);
|
||||||
|
|
||||||
if (jobContext.Global.Variables.TryGetValue(WellKnownDistributedTaskVariables.RunnerEnvironment, out var runnerEnvironment))
|
if (jobContext.Global.Variables.TryGetValue(WellKnownDistributedTaskVariables.RunnerEnvironment, out var runnerEnvironment))
|
||||||
@@ -290,12 +298,6 @@ namespace GitHub.Runner.Worker
|
|||||||
jobContext.Warning(string.Format(Constants.Runner.EnforcedNode12DetectedAfterEndOfLife, actions));
|
jobContext.Warning(string.Format(Constants.Runner.EnforcedNode12DetectedAfterEndOfLife, actions));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jobContext.Global.Variables.TryGetValue(Constants.Runner.EnforcedNode16DetectedAfterEndOfLifeEnvVariable, out var node20ForceWarnings) && (jobContext.Global.Variables.GetBoolean("DistributedTask.ForceGithubJavascriptActionsToNode20") ?? false))
|
|
||||||
{
|
|
||||||
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(node20ForceWarnings));
|
|
||||||
jobContext.Warning(string.Format(Constants.Runner.EnforcedNode16DetectedAfterEndOfLife, actions));
|
|
||||||
}
|
|
||||||
|
|
||||||
await ShutdownQueue(throwOnFailure: false);
|
await ShutdownQueue(throwOnFailure: false);
|
||||||
|
|
||||||
// Make sure to clean temp after file upload since they may be pending fileupload still use the TEMP dir.
|
// Make sure to clean temp after file upload since they may be pending fileupload still use the TEMP dir.
|
||||||
@@ -403,12 +405,6 @@ namespace GitHub.Runner.Worker
|
|||||||
jobContext.Warning(string.Format(Constants.Runner.EnforcedNode12DetectedAfterEndOfLife, actions));
|
jobContext.Warning(string.Format(Constants.Runner.EnforcedNode12DetectedAfterEndOfLife, actions));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jobContext.Global.Variables.TryGetValue(Constants.Runner.EnforcedNode16DetectedAfterEndOfLifeEnvVariable, out var node20ForceWarnings))
|
|
||||||
{
|
|
||||||
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(node20ForceWarnings));
|
|
||||||
jobContext.Warning(string.Format(Constants.Runner.EnforcedNode16DetectedAfterEndOfLife, actions));
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var jobQueueTelemetry = await ShutdownQueue(throwOnFailure: true);
|
var jobQueueTelemetry = await ShutdownQueue(throwOnFailure: true);
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Services.Common;
|
|
||||||
using GitHub.Services.Common.Diagnostics;
|
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.WebApi
|
|
||||||
{
|
|
||||||
[ResourceArea(TaskResourceIds.AreaId)]
|
|
||||||
public class ActionsRunServerHttpClient : TaskAgentHttpClient
|
|
||||||
{
|
|
||||||
private static readonly JsonSerializerSettings s_serializerSettings;
|
|
||||||
|
|
||||||
static ActionsRunServerHttpClient()
|
|
||||||
{
|
|
||||||
s_serializerSettings = new VssJsonMediaTypeFormatter().SerializerSettings;
|
|
||||||
s_serializerSettings.DateParseHandling = DateParseHandling.None;
|
|
||||||
s_serializerSettings.FloatParseHandling = FloatParseHandling.Double;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionsRunServerHttpClient(
|
|
||||||
Uri baseUrl,
|
|
||||||
VssCredentials credentials)
|
|
||||||
: base(baseUrl, credentials)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionsRunServerHttpClient(
|
|
||||||
Uri baseUrl,
|
|
||||||
VssCredentials credentials,
|
|
||||||
VssHttpRequestSettings settings)
|
|
||||||
: base(baseUrl, credentials, settings)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionsRunServerHttpClient(
|
|
||||||
Uri baseUrl,
|
|
||||||
VssCredentials credentials,
|
|
||||||
params DelegatingHandler[] handlers)
|
|
||||||
: base(baseUrl, credentials, handlers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionsRunServerHttpClient(
|
|
||||||
Uri baseUrl,
|
|
||||||
VssCredentials credentials,
|
|
||||||
VssHttpRequestSettings settings,
|
|
||||||
params DelegatingHandler[] handlers)
|
|
||||||
: base(baseUrl, credentials, settings, handlers)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public ActionsRunServerHttpClient(
|
|
||||||
Uri baseUrl,
|
|
||||||
HttpMessageHandler pipeline,
|
|
||||||
Boolean disposeHandler)
|
|
||||||
: base(baseUrl, pipeline, disposeHandler)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<Pipelines.AgentJobRequestMessage> GetJobMessageAsync(
|
|
||||||
string messageId,
|
|
||||||
object userState = null,
|
|
||||||
CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
HttpMethod httpMethod = new HttpMethod("GET");
|
|
||||||
Guid locationId = new Guid("25adab70-1379-4186-be8e-b643061ebe3a");
|
|
||||||
object routeValues = new { messageId = messageId };
|
|
||||||
|
|
||||||
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
|
||||||
httpMethod,
|
|
||||||
locationId,
|
|
||||||
routeValues: routeValues,
|
|
||||||
version: new ApiResourceVersion(6.0, 1),
|
|
||||||
userState: userState,
|
|
||||||
cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task<T> ReadJsonContentAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2498,25 +2498,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Serializable]
|
|
||||||
public class NonRetryableActionDownloadInfoException : DistributedTaskException
|
|
||||||
{
|
|
||||||
public NonRetryableActionDownloadInfoException(String message)
|
|
||||||
: base(message)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public NonRetryableActionDownloadInfoException(String message, Exception innerException)
|
|
||||||
: base(message, innerException)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected NonRetryableActionDownloadInfoException(SerializationInfo info, StreamingContext context)
|
|
||||||
: base(info, context)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
public sealed class FailedToResolveActionDownloadInfoException : DistributedTaskException
|
public sealed class FailedToResolveActionDownloadInfoException : DistributedTaskException
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -141,6 +141,24 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
return ReplaceAgentAsync(poolId, agent.Id, agent, userState, cancellationToken);
|
return ReplaceAgentAsync(poolId, agent.Id, agent, userState, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<Pipelines.AgentJobRequestMessage> GetJobMessageAsync(
|
||||||
|
string messageId,
|
||||||
|
object userState = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
HttpMethod httpMethod = new HttpMethod("GET");
|
||||||
|
Guid locationId = new Guid("25adab70-1379-4186-be8e-b643061ebe3a");
|
||||||
|
object routeValues = new { messageId = messageId };
|
||||||
|
|
||||||
|
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
||||||
|
httpMethod,
|
||||||
|
locationId,
|
||||||
|
routeValues: routeValues,
|
||||||
|
version: new ApiResourceVersion(6.0, 1),
|
||||||
|
userState: userState,
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
protected Task<T> SendAsync<T>(
|
protected Task<T> SendAsync<T>(
|
||||||
HttpMethod method,
|
HttpMethod method,
|
||||||
Guid locationId,
|
Guid locationId,
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.OAuth;
|
using GitHub.Services.OAuth;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Sdk.RSWebApi.Contracts;
|
using Sdk.RSWebApi.Contracts;
|
||||||
using Sdk.WebApi.WebApi;
|
using Sdk.WebApi.WebApi;
|
||||||
|
|
||||||
@@ -17,15 +16,6 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
{
|
{
|
||||||
public class RunServiceHttpClient : RawHttpClientBase
|
public class RunServiceHttpClient : RawHttpClientBase
|
||||||
{
|
{
|
||||||
private static readonly JsonSerializerSettings s_serializerSettings;
|
|
||||||
|
|
||||||
static RunServiceHttpClient()
|
|
||||||
{
|
|
||||||
s_serializerSettings = new VssJsonMediaTypeFormatter().SerializerSettings;
|
|
||||||
s_serializerSettings.DateParseHandling = DateParseHandling.None;
|
|
||||||
s_serializerSettings.FloatParseHandling = FloatParseHandling.Double;
|
|
||||||
}
|
|
||||||
|
|
||||||
public RunServiceHttpClient(
|
public RunServiceHttpClient(
|
||||||
Uri baseUrl,
|
Uri baseUrl,
|
||||||
VssOAuthCredential credentials)
|
VssOAuthCredential credentials)
|
||||||
@@ -184,11 +174,5 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
throw new Exception($"Failed to renew job: {result.Error}");
|
throw new Exception($"Failed to renew job: {result.Error}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override async Task<T> ReadJsonContentAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken))
|
|
||||||
{
|
|
||||||
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
|
||||||
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,11 +56,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
BrokerMessageListener listener = new();
|
BrokerMessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
trace.Info("result: {0}", result);
|
trace.Info("result: {0}", result);
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
_brokerServer
|
_brokerServer
|
||||||
.Verify(x => x.CreateSessionAsync(
|
.Verify(x => x.CreateSessionAsync(
|
||||||
It.Is<TaskAgentSession>(y => y != null),
|
It.Is<TaskAgentSession>(y => y != null),
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,11 +75,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
trace.Info("result: {0}", result);
|
trace.Info("result: {0}", result);
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.CreateAgentSessionAsync(
|
.Verify(x => x.CreateAgentSessionAsync(
|
||||||
_settings.PoolId,
|
_settings.PoolId,
|
||||||
@@ -135,11 +135,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
trace.Info("result: {0}", result);
|
trace.Info("result: {0}", result);
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.CreateAgentSessionAsync(
|
.Verify(x => x.CreateAgentSessionAsync(
|
||||||
@@ -185,8 +185,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Setup(x => x.DeleteAgentSessionAsync(
|
.Setup(x => x.DeleteAgentSessionAsync(
|
||||||
@@ -245,10 +245,10 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
trace.Info("result: {0}", result);
|
trace.Info("result: {0}", result);
|
||||||
|
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.CreateAgentSessionAsync(
|
.Verify(x => x.CreateAgentSessionAsync(
|
||||||
@@ -272,7 +272,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
//Assert
|
//Assert
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.DeleteAgentSessionAsync(
|
.Verify(x => x.DeleteAgentSessionAsync(
|
||||||
_settings.PoolId, expectedBrokerSession.SessionId, It.IsAny<CancellationToken>()), Times.Once());
|
_settings.PoolId, expectedSession.SessionId, It.IsAny<CancellationToken>()), Times.Never());
|
||||||
_brokerServer
|
_brokerServer
|
||||||
.Verify(x => x.DeleteSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
|
.Verify(x => x.DeleteSessionAsync(It.IsAny<CancellationToken>()), Times.Once());
|
||||||
}
|
}
|
||||||
@@ -309,8 +309,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
|
|
||||||
var arMessages = new TaskAgentMessage[]
|
var arMessages = new TaskAgentMessage[]
|
||||||
{
|
{
|
||||||
@@ -390,8 +390,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
|
|
||||||
var brokerMigrationMesage = new BrokerMigrationMessage(new Uri("https://actions.broker.com"));
|
var brokerMigrationMesage = new BrokerMigrationMessage(new Uri("https://actions.broker.com"));
|
||||||
|
|
||||||
@@ -497,11 +497,11 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
trace.Info("result: {0}", result);
|
trace.Info("result: {0}", result);
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.CreateAgentSessionAsync(
|
.Verify(x => x.CreateAgentSessionAsync(
|
||||||
_settings.PoolId,
|
_settings.PoolId,
|
||||||
@@ -541,8 +541,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
MessageListener listener = new();
|
MessageListener listener = new();
|
||||||
listener.Initialize(tc);
|
listener.Initialize(tc);
|
||||||
|
|
||||||
CreateSessionResult result = await listener.CreateSessionAsync(tokenSource.Token);
|
bool result = await listener.CreateSessionAsync(tokenSource.Token);
|
||||||
Assert.Equal(CreateSessionResult.Success, result);
|
Assert.True(result);
|
||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Setup(x => x.GetAgentMessageAsync(
|
.Setup(x => x.GetAgentMessageAsync(
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_configurationManager.Setup(x => x.IsConfigured())
|
_configurationManager.Setup(x => x.IsConfigured())
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(Task.FromResult<CreateSessionResult>(CreateSessionResult.Success));
|
.Returns(Task.FromResult<bool>(true));
|
||||||
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(async () =>
|
.Returns(async () =>
|
||||||
{
|
{
|
||||||
@@ -126,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
|
||||||
{
|
{
|
||||||
@@ -184,7 +184,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_configStore.Setup(x => x.IsServiceConfigured()).Returns(configureAsService);
|
_configStore.Setup(x => x.IsServiceConfigured()).Returns(configureAsService);
|
||||||
|
|
||||||
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(Task.FromResult<CreateSessionResult>(CreateSessionResult.Failure));
|
.Returns(Task.FromResult(false));
|
||||||
|
|
||||||
var runner = new Runner.Listener.Runner();
|
var runner = new Runner.Listener.Runner();
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
@@ -217,7 +217,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
.Returns(false);
|
.Returns(false);
|
||||||
|
|
||||||
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(Task.FromResult<CreateSessionResult>(CreateSessionResult.Failure));
|
.Returns(Task.FromResult(false));
|
||||||
|
|
||||||
var runner = new Runner.Listener.Runner();
|
var runner = new Runner.Listener.Runner();
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
@@ -263,7 +263,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_configurationManager.Setup(x => x.IsConfigured())
|
_configurationManager.Setup(x => x.IsConfigured())
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(Task.FromResult<CreateSessionResult>(CreateSessionResult.Success));
|
.Returns(Task.FromResult<bool>(true));
|
||||||
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(async () =>
|
.Returns(async () =>
|
||||||
{
|
{
|
||||||
@@ -305,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.");
|
||||||
@@ -366,7 +363,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_configurationManager.Setup(x => x.IsConfigured())
|
_configurationManager.Setup(x => x.IsConfigured())
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(Task.FromResult<CreateSessionResult>(CreateSessionResult.Success));
|
.Returns(Task.FromResult<bool>(true));
|
||||||
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(async () =>
|
.Returns(async () =>
|
||||||
{
|
{
|
||||||
@@ -409,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.");
|
||||||
@@ -464,7 +458,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_configurationManager.Setup(x => x.IsConfigured())
|
_configurationManager.Setup(x => x.IsConfigured())
|
||||||
.Returns(true);
|
.Returns(true);
|
||||||
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.CreateSessionAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(Task.FromResult<CreateSessionResult>(CreateSessionResult.Success));
|
.Returns(Task.FromResult<bool>(true));
|
||||||
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
_messageListener.Setup(x => x.GetNextMessageAsync(It.IsAny<CancellationToken>()))
|
||||||
.Returns(async () =>
|
.Returns(async () =>
|
||||||
{
|
{
|
||||||
@@ -498,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());
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -960,33 +960,6 @@ namespace GitHub.Runner.Common.Tests.Util
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public void ReplaceInvalidFileNameChars()
|
|
||||||
{
|
|
||||||
Assert.Equal(string.Empty, IOUtil.ReplaceInvalidFileNameChars(null));
|
|
||||||
Assert.Equal(string.Empty, IOUtil.ReplaceInvalidFileNameChars(string.Empty));
|
|
||||||
Assert.Equal("hello.txt", IOUtil.ReplaceInvalidFileNameChars("hello.txt"));
|
|
||||||
#if OS_WINDOWS
|
|
||||||
// Refer https://github.com/dotnet/runtime/blob/ce84f1d8a3f12711bad678a33efbc37b461f684f/src/libraries/System.Private.CoreLib/src/System/IO/Path.Windows.cs#L15
|
|
||||||
Assert.Equal(
|
|
||||||
"1_ 2_ 3_ 4_ 5_ 6_ 7_ 8_ 9_ 10_ 11_ 12_ 13_ 14_ 15_ 16_ 17_ 18_ 19_ 20_ 21_ 22_ 23_ 24_ 25_ 26_ 27_ 28_ 29_ 30_ 31_ 32_ 33_ 34_ 35_ 36_ 37_ 38_ 39_ 40_ 41_",
|
|
||||||
IOUtil.ReplaceInvalidFileNameChars($"1\" 2< 3> 4| 5\0 6{(char)1} 7{(char)2} 8{(char)3} 9{(char)4} 10{(char)5} 11{(char)6} 12{(char)7} 13{(char)8} 14{(char)9} 15{(char)10} 16{(char)11} 17{(char)12} 18{(char)13} 19{(char)14} 20{(char)15} 21{(char)16} 22{(char)17} 23{(char)18} 24{(char)19} 25{(char)20} 26{(char)21} 27{(char)22} 28{(char)23} 29{(char)24} 30{(char)25} 31{(char)26} 32{(char)27} 33{(char)28} 34{(char)29} 35{(char)30} 36{(char)31} 37: 38* 39? 40\\ 41/"));
|
|
||||||
#else
|
|
||||||
// Refer https://github.com/dotnet/runtime/blob/ce84f1d8a3f12711bad678a33efbc37b461f684f/src/libraries/System.Private.CoreLib/src/System/IO/Path.Unix.cs#L12
|
|
||||||
Assert.Equal("1_ 2_", IOUtil.ReplaceInvalidFileNameChars("1\0 2/"));
|
|
||||||
#endif
|
|
||||||
Assert.Equal("_leading", IOUtil.ReplaceInvalidFileNameChars("/leading"));
|
|
||||||
Assert.Equal("__consecutive leading", IOUtil.ReplaceInvalidFileNameChars("//consecutive leading"));
|
|
||||||
Assert.Equal("trailing_", IOUtil.ReplaceInvalidFileNameChars("trailing/"));
|
|
||||||
Assert.Equal("consecutive trailing__", IOUtil.ReplaceInvalidFileNameChars("consecutive trailing//"));
|
|
||||||
Assert.Equal("middle_middle", IOUtil.ReplaceInvalidFileNameChars("middle/middle"));
|
|
||||||
Assert.Equal("consecutive middle__consecutive middle", IOUtil.ReplaceInvalidFileNameChars("consecutive middle//consecutive middle"));
|
|
||||||
Assert.Equal("_leading_middle_trailing_", IOUtil.ReplaceInvalidFileNameChars("/leading/middle/trailing/"));
|
|
||||||
Assert.Equal("__consecutive leading__consecutive middle__consecutive trailing__", IOUtil.ReplaceInvalidFileNameChars("//consecutive leading//consecutive middle//consecutive trailing//"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task CreateDirectoryReparsePoint(IHostContext context, string link, string target)
|
private static async Task CreateDirectoryReparsePoint(IHostContext context, string link, string target)
|
||||||
{
|
{
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
|||||||
@@ -212,5 +212,210 @@ namespace GitHub.Runner.Common.Tests.Util
|
|||||||
File.Delete(brokenSymlink);
|
File.Delete(brokenSymlink);
|
||||||
Environment.SetEnvironmentVariable(PathUtil.PathVariable, oldValue);
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, oldValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void UseWhich2FindGit()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = new(this))
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
string gitPath = WhichUtil.Which2("git", trace: trace);
|
||||||
|
|
||||||
|
trace.Info($"Which(\"git\") returns: {gitPath ?? string.Empty}");
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.True(!string.IsNullOrEmpty(gitPath) && File.Exists(gitPath), $"Unable to find Git through: {nameof(WhichUtil.Which)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void Which2ReturnsNullWhenNotFound()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = new(this))
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
string nosuch = WhichUtil.Which2("no-such-file-cf7e351f", trace: trace);
|
||||||
|
|
||||||
|
trace.Info($"result: {nosuch ?? string.Empty}");
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.True(string.IsNullOrEmpty(nosuch), "Path should not be resolved");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void Which2ThrowsWhenRequireAndNotFound()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = new(this))
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
WhichUtil.Which2("no-such-file-cf7e351f", require: true, trace: trace);
|
||||||
|
throw new Exception("which should have thrown");
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
Assert.Equal("no-such-file-cf7e351f", ex.FileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void Which2HandleFullyQualifiedPath()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = new(this))
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
var gitPath = WhichUtil.Which2("git", require: true, trace: trace);
|
||||||
|
var gitPath2 = WhichUtil.Which2(gitPath, require: true, trace: trace);
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.Equal(gitPath, gitPath2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void Which2HandlesSymlinkToTargetFullPath()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using TestHostContext hc = new TestHostContext(this);
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
string oldValue = Environment.GetEnvironmentVariable(PathUtil.PathVariable);
|
||||||
|
#if OS_WINDOWS
|
||||||
|
string newValue = oldValue + @$";{Path.GetTempPath()}";
|
||||||
|
string symlinkName = $"symlink-{Guid.NewGuid()}";
|
||||||
|
string symlink = Path.GetTempPath() + $"{symlinkName}.exe";
|
||||||
|
string target = Path.GetTempPath() + $"target-{Guid.NewGuid()}.exe";
|
||||||
|
#else
|
||||||
|
string newValue = oldValue + @$":{Path.GetTempPath()}";
|
||||||
|
string symlinkName = $"symlink-{Guid.NewGuid()}";
|
||||||
|
string symlink = Path.GetTempPath() + $"{symlinkName}";
|
||||||
|
string target = Path.GetTempPath() + $"target-{Guid.NewGuid()}";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, newValue);
|
||||||
|
|
||||||
|
|
||||||
|
using (File.Create(target))
|
||||||
|
{
|
||||||
|
File.CreateSymbolicLink(symlink, target);
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
var result = WhichUtil.Which2(symlinkName, require: true, trace: trace);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(!string.IsNullOrEmpty(result) && File.Exists(result), $"Unable to find symlink through: {nameof(WhichUtil.Which)}");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
File.Delete(symlink);
|
||||||
|
File.Delete(target);
|
||||||
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, oldValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void Which2HandlesSymlinkToTargetRelativePath()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using TestHostContext hc = new TestHostContext(this);
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
string oldValue = Environment.GetEnvironmentVariable(PathUtil.PathVariable);
|
||||||
|
#if OS_WINDOWS
|
||||||
|
string newValue = oldValue + @$";{Path.GetTempPath()}";
|
||||||
|
string symlinkName = $"symlink-{Guid.NewGuid()}";
|
||||||
|
string symlink = Path.GetTempPath() + $"{symlinkName}.exe";
|
||||||
|
string targetName = $"target-{Guid.NewGuid()}.exe";
|
||||||
|
string target = Path.GetTempPath() + targetName;
|
||||||
|
#else
|
||||||
|
string newValue = oldValue + @$":{Path.GetTempPath()}";
|
||||||
|
string symlinkName = $"symlink-{Guid.NewGuid()}";
|
||||||
|
string symlink = Path.GetTempPath() + $"{symlinkName}";
|
||||||
|
string targetName = $"target-{Guid.NewGuid()}";
|
||||||
|
string target = Path.GetTempPath() + targetName;
|
||||||
|
#endif
|
||||||
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, newValue);
|
||||||
|
|
||||||
|
|
||||||
|
using (File.Create(target))
|
||||||
|
{
|
||||||
|
File.CreateSymbolicLink(symlink, targetName);
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
var result = WhichUtil.Which2(symlinkName, require: true, trace: trace);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(!string.IsNullOrEmpty(result) && File.Exists(result), $"Unable to find {symlinkName} through: {nameof(WhichUtil.Which)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
File.Delete(symlink);
|
||||||
|
File.Delete(target);
|
||||||
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, oldValue);
|
||||||
|
|
||||||
|
}
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Common")]
|
||||||
|
public void Which2ThrowsWhenSymlinkBroken()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
using TestHostContext hc = new TestHostContext(this);
|
||||||
|
Tracing trace = hc.GetTrace();
|
||||||
|
string oldValue = Environment.GetEnvironmentVariable(PathUtil.PathVariable);
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
string newValue = oldValue + @$";{Path.GetTempPath()}";
|
||||||
|
string brokenSymlinkName = $"broken-symlink-{Guid.NewGuid()}";
|
||||||
|
string brokenSymlink = Path.GetTempPath() + $"{brokenSymlinkName}.exe";
|
||||||
|
#else
|
||||||
|
string newValue = oldValue + @$":{Path.GetTempPath()}";
|
||||||
|
string brokenSymlinkName = $"broken-symlink-{Guid.NewGuid()}";
|
||||||
|
string brokenSymlink = Path.GetTempPath() + $"{brokenSymlinkName}";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
string target = "no-such-file-cf7e351f";
|
||||||
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, newValue);
|
||||||
|
|
||||||
|
File.CreateSymbolicLink(brokenSymlink, target);
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
var exception = Assert.Throws<FileNotFoundException>(() => WhichUtil.Which2(brokenSymlinkName, require: true, trace: trace));
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(brokenSymlinkName, exception.FileName);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
File.Delete(brokenSymlink);
|
||||||
|
Environment.SetEnvironmentVariable(PathUtil.PathVariable, oldValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,6 +382,8 @@ runs:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_ec.Object.Global.Variables.Set("DistributedTask.UseActionArchiveCache", bool.TrueString);
|
||||||
|
|
||||||
//Act
|
//Act
|
||||||
await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
await _actionManager.PrepareActionsAsync(_ec.Object, actions);
|
||||||
|
|
||||||
@@ -460,7 +462,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 +917,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 +1053,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 +1247,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
|
||||||
{
|
{
|
||||||
@@ -2373,6 +2375,10 @@ runs:
|
|||||||
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
||||||
_ec.Setup(x => x.Root).Returns(new GitHub.Runner.Worker.ExecutionContext());
|
_ec.Setup(x => x.Root).Returns(new GitHub.Runner.Worker.ExecutionContext());
|
||||||
var variables = new Dictionary<string, VariableValue>();
|
var variables = new Dictionary<string, VariableValue>();
|
||||||
|
if (enableComposite)
|
||||||
|
{
|
||||||
|
variables["DistributedTask.EnableCompositeActions"] = "true";
|
||||||
|
}
|
||||||
_ec.Object.Global.Variables = new Variables(_hc, variables);
|
_ec.Object.Global.Variables = new Variables(_hc, variables);
|
||||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
||||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
|||||||
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
||||||
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
||||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||||
DOTNETSDK_VERSION="6.0.421"
|
DOTNETSDK_VERSION="6.0.419"
|
||||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||||
RUNNER_VERSION=$(cat runnerversion)
|
RUNNER_VERSION=$(cat runnerversion)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "6.0.421"
|
"version": "6.0.419"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.316.1
|
2.314.1
|
||||||
|
|||||||
Reference in New Issue
Block a user