Compare commits

..

2 Commits

Author SHA1 Message Date
Tatyana Kostromskaya
afb39c9c3c Merge branch 'main' into revert-2918-revert-2844-takost/update-internal-node 2024-05-03 13:17:55 +02:00
Tatyana Kostromskaya
7f9c42fc15 Revert "Revert "Update default version to node20 (#2844)" (#2918)"
This reverts commit 544f19042b.
2024-04-18 12:41:26 +02:00
112 changed files with 602 additions and 1616 deletions

View File

@@ -1,13 +1,13 @@
{
"name": "Actions Runner Devcontainer",
"image": "mcr.microsoft.com/devcontainers/base:noble",
"image": "mcr.microsoft.com/devcontainers/base:focal",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
"ghcr.io/devcontainers/features/dotnet": {
"version": "9.0.100"
"version": "6.0.421"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
"version": "16"
},
"ghcr.io/devcontainers/features/sshd:1": {
"version": "latest"

View File

@@ -5,11 +5,6 @@ updates:
schedule:
interval: "daily"
target-branch: "main"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
target-branch: "main"
- package-ecosystem: "nuget"
directory: "/src"
schedule:

View File

@@ -50,7 +50,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
# Build runner layout
- name: Build & Layout Release
@@ -69,13 +69,13 @@ jobs:
- name: Package Release
if: github.event_name != 'pull_request'
run: |
${{ matrix.devScript }} package Release ${{ matrix.runtime }}
${{ matrix.devScript }} package Release
working-directory: src
# Upload runner package tar.gz/zip as artifact
- name: Publish Artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: runner-package-${{ matrix.runtime }}
path: |

View File

@@ -23,7 +23,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL

View File

@@ -15,7 +15,7 @@ jobs:
DOTNET_CURRENT_MAJOR_MINOR_VERSION: ${{ steps.fetch_current_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_VERSION }}
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Get current major minor version
id: fetch_current_version
shell: bash
@@ -51,7 +51,7 @@ jobs:
run: echo "::error links::feature/dotnet-sdk-upgrade${{ steps.fetch_latest_version.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }} https://github.com/actions/runner/tree/feature/dotnet-sdk-upgrade${{ steps.fetch_latest_version.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}::Branch feature/dotnetsdk-upgrade/${{ steps.fetch_latest_version.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }} already exists. Please take a look and delete that branch if you wish to recreate"
- name: Create a warning annotation if no need to update
if: ${{ steps.fetch_latest_version.outputs.SHOULD_UPDATE == 0 && steps.fetch_latest_version.outputs.BRANCH_EXISTS == 0 }}
run: echo "::warning ::Latest DotNet SDK patch is ${{ steps.fetch_latest_version.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}, and we are on ${{ steps.fetch_current_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_PATCH_VERSION }}. No need to update"
run: echo "::warning ::Latest DotNet SDK patch is ${{ steps.fetch_latest_version.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}, and we are on ${{ steps.fetch_latest_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_PATCH_VERSION }}. No need to update"
- name: Update patch version
if: ${{ steps.fetch_latest_version.outputs.SHOULD_UPDATE == 1 && steps.fetch_latest_version.outputs.BRANCH_EXISTS == 0 }}
shell: bash
@@ -89,7 +89,7 @@ jobs:
if: ${{ needs.dotnet-update.outputs.SHOULD_UPDATE == 1 && needs.dotnet-update.outputs.BRANCH_EXISTS == 0 }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
ref: feature/dotnetsdk-upgrade/${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}
- name: Create Pull Request

24
.github/workflows/lint.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
name: Lint
on:
pull_request:
branches: [ main ]
jobs:
build:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
# Ensure full list of changed files within `super-linter`
fetch-depth: 0
- name: Run linters
uses: github/super-linter@v4
env:
DEFAULT_BRANCH: ${{ github.base_ref }}
EDITORCONFIG_FILE_NAME: .editorconfig
LINTER_RULES_PATH: /src/
VALIDATE_ALL_CODEBASE: false
VALIDATE_CSHARP: true

View File

@@ -20,17 +20,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Compute image version
id: image
uses: actions/github-script@v6
env:
RUNNER_VERSION: ${{ github.event.inputs.runnerVersion }}
with:
script: |
const fs = require('fs');
const inputRunnerVersion = process.env.RUNNER_VERSION;
const inputRunnerVersion = "${{ github.event.inputs.runnerVersion }}"
if (inputRunnerVersion) {
console.log(`Using input runner version ${inputRunnerVersion}`)
core.setOutput('version', inputRunnerVersion);

View File

@@ -11,7 +11,7 @@ jobs:
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
# Make sure ./releaseVersion match ./src/runnerversion
# Query GitHub release ensure version is not used
@@ -87,7 +87,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
# Build runner layout
- name: Build & Layout Release
@@ -117,11 +117,12 @@ jobs:
working-directory: _package
# Upload runner package tar.gz/zip as artifact.
# Since each package name is unique, so we don't need to put ${{matrix}} info into artifact name
- name: Publish Artifact
if: github.event_name != 'pull_request'
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: runner-packages-${{ matrix.runtime }}
name: runner-packages
path: |
_package
@@ -130,43 +131,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
# Download runner package tar.gz/zip produced by 'build' job
- name: Download Artifact (win-x64)
uses: actions/download-artifact@v4
- name: Download Artifact
uses: actions/download-artifact@v1
with:
name: runner-packages-win-x64
path: ./
- name: Download Artifact (win-arm64)
uses: actions/download-artifact@v4
with:
name: runner-packages-win-arm64
path: ./
- name: Download Artifact (osx-x64)
uses: actions/download-artifact@v4
with:
name: runner-packages-osx-x64
path: ./
- name: Download Artifact (osx-arm64)
uses: actions/download-artifact@v4
with:
name: runner-packages-osx-arm64
path: ./
- name: Download Artifact (linux-x64)
uses: actions/download-artifact@v4
with:
name: runner-packages-linux-x64
path: ./
- name: Download Artifact (linux-arm)
uses: actions/download-artifact@v4
with:
name: runner-packages-linux-arm
path: ./
- name: Download Artifact (linux-arm64)
uses: actions/download-artifact@v4
with:
name: runner-packages-linux-arm64
name: runner-packages
path: ./
# Create ReleaseNote file
@@ -296,7 +267,7 @@ jobs:
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v3
- name: Compute image version
id: image

1
.gitignore vendored
View File

@@ -26,5 +26,4 @@ _dotnetsdk
TestResults
TestLogs
.DS_Store
.mono
**/*.DotSettings.user

View File

@@ -41,7 +41,7 @@ To let the runner trusts your CA certificate, you will need to:
- macOS: ![trust ca cert](./../res/macOStrustCA.gif)
- Linux: Refer to the distribution documentation
1. RedHat: https://www.redhat.com/sysadmin/ca-certificates-cli
2. Ubuntu: https://manpages.ubuntu.com/manpages/noble/man8/update-ca-certificates.8.html
2. Ubuntu: http://manpages.ubuntu.com/manpages/focal/man8/update-ca-certificates.8.html
3. Google search: "trust ca certificate on [linux distribution]"
4. If all approaches failed, set environment variable `SSL_CERT_FILE` to the CA bundle `.pem` file we get.
> To verify cert gets installed properly on Linux, you can try use `curl -v https://sitewithsslissue.com` and `pwsh -Command \"Invoke-WebRequest -Uri https://sitewithsslissue.com\"`

View File

@@ -4,7 +4,16 @@
## Supported Distributions and Versions
Please see "[Supported architectures and operating systems for self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#linux)."
x64
- Red Hat Enterprise Linux 7+
- CentOS 7+
- Oracle Linux 7+
- Fedora 29+
- Debian 9+
- Ubuntu 16.04+
- Linux Mint 18+
- openSUSE 15+
- SUSE Enterprise Linux (SLES) 12 SP2+
## Install .Net Core 3.x Linux Dependencies

View File

@@ -4,6 +4,7 @@
## Supported Versions
Please see "[Supported architectures and operating systems for self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#macos)."
- macOS High Sierra (10.13) and later versions
- x64 and arm64 (Apple Silicon)
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)

View File

@@ -2,6 +2,11 @@
## Supported Versions
Please see "[Supported architectures and operating systems for self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners#windows)."
- Windows 7 64-bit
- Windows 8.1 64-bit
- Windows 10 64-bit
- Windows Server 2012 R2 64-bit
- Windows Server 2016 64-bit
- Windows Server 2019 64-bit
## [More .NET Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore30)

View File

@@ -1,12 +1,12 @@
# Source: https://github.com/dotnet/dotnet-docker
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-noble as build
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy as build
ARG TARGETOS
ARG TARGETARCH
ARG RUNNER_VERSION
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.1
ARG DOCKER_VERSION=27.3.1
ARG BUILDX_VERSION=0.18.0
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.0
ARG DOCKER_VERSION=25.0.4
ARG BUILDX_VERSION=0.13.1
RUN apt update -y && apt install curl unzip -y
@@ -32,22 +32,17 @@ RUN export RUNNER_ARCH=${TARGETARCH} \
"https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${TARGETARCH}" \
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
FROM mcr.microsoft.com/dotnet/runtime-deps:9.0-noble
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy
ENV DEBIAN_FRONTEND=noninteractive
ENV RUNNER_MANUALLY_TRAP_SIG=1
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
ENV ImageOS=ubuntu22
# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows
RUN apt update -y \
&& apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \
&& 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 \
&& apt install -y git \
RUN apt-get update -y \
&& apt-get install -y --no-install-recommends \
sudo \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
RUN adduser --disabled-password --gecos "" --uid 1001 runner \

View File

@@ -1,30 +1,8 @@
## What's Changed
* Fix release workflow to use distinct artifact names by @ericsciple in https://github.com/actions/runner/pull/3485
* Update dotnet sdk to latest version @6.0.425 by @github-actions in https://github.com/actions/runner/pull/3433
* add ref and type to job completion in run service by @yaananth in https://github.com/actions/runner/pull/3492
* Remove Broker Migration Message logging by @luketomlinson in https://github.com/actions/runner/pull/3493
* Bump dotnet SDK to dotnet 8. by @TingluoHuang in https://github.com/actions/runner/pull/3500
* Remove dotnet8 compatibility test. by @TingluoHuang in https://github.com/actions/runner/pull/3502
* Remove node16 from the runner. by @TingluoHuang in https://github.com/actions/runner/pull/3503
* send action name for run service by @yaananth in https://github.com/actions/runner/pull/3520
* Handle runner not found by @ericsciple in https://github.com/actions/runner/pull/3536
* Publish job telemetry to run-service. by @TingluoHuang in https://github.com/actions/runner/pull/3545
* Fetch repo-level runner groups from API in v2 flow by @lucavallin in https://github.com/actions/runner/pull/3546
* Allow runner to check service connection in background. by @TingluoHuang in https://github.com/actions/runner/pull/3542
* Expose ENV for cache service v2. by @TingluoHuang in https://github.com/actions/runner/pull/3548
* Update runner docker image. by @TingluoHuang in https://github.com/actions/runner/pull/3511
* Bump Azure.Storage.Blobs from 12.19.1 to 12.23.0 in /src by @dependabot in https://github.com/actions/runner/pull/3549
* fix dotnet-upgrade.yml to print right version by @TingluoHuang in https://github.com/actions/runner/pull/3550
* Update dotnet sdk to latest version @8.0.404 by @github-actions in https://github.com/actions/runner/pull/3552
* Configure dependabot to check github-actions updates by @Goooler in https://github.com/actions/runner/pull/3333
* Bump actions/checkout from 3 to 4 by @dependabot in https://github.com/actions/runner/pull/3556
- Preserve dates when deserializing job message from Run Service by @ericsciple in https://github.com/actions/runner/pull/3269
## New Contributors
* @lucavallin made their first contribution in https://github.com/actions/runner/pull/3546
* @Goooler made their first contribution in https://github.com/actions/runner/pull/3333
**Full Changelog**: https://github.com/actions/runner/compare/v2.320.0...v2.321.0
**Full Changelog**: https://github.com/actions/runner/compare/v2.316.0...v2.316.1
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.
@@ -46,7 +24,9 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
```
## 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.
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.

View File

@@ -0,0 +1 @@
54d95a44d118dba852395991224a6b9c1abe916858c87138656f80c619e85331

View File

@@ -0,0 +1 @@
68015af17f06a824fa478e62ae7393766ce627fd5599ab916432a14656a19a52

View File

@@ -0,0 +1 @@
a2628119ca419cb54e279103ffae7986cdbd0814d57c73ff0dc74c38be08b9ae

View File

@@ -0,0 +1 @@
de71ca09ead807e1a2ce9df0a5b23eb7690cb71fff51169a77e4c3992be53dda

View File

@@ -0,0 +1 @@
d009e05e6b26d614d65be736a15d1bd151932121c16a9ff1b986deadecc982b9

View File

@@ -0,0 +1 @@
f730db39c2305800b4653795360ba9c10c68f384a46b85d808f1f9f0ed3c42e4

View File

@@ -0,0 +1 @@
a35b5722375490e9473cdcccb5e18b41eba3dbf4344fe31abc9821e21f18ea5a

View File

@@ -0,0 +1 @@
4bf3e1af0d482af1b2eaf9f08250248a8c1aea8ec20a3c5be116d58cdd930009

View File

@@ -0,0 +1 @@
ec1719a8cb4d8687328aa64f4aa7c4e3498a715d8939117874782e3e6e63a14b

View File

@@ -0,0 +1 @@
50538de29f173bb73f708c4ed2c8328a62b8795829b97b2a6cb57197e2305287

View File

@@ -0,0 +1 @@
a0a96cbb7593643b69e669bf14d7b29b7f27800b3a00bb3305aebe041456c701

View File

@@ -0,0 +1 @@
6255b22692779467047ecebd60ad46984866d75cdfe10421d593a7b51d620b09

View File

@@ -0,0 +1 @@
6ff1abd055dc35bfbf06f75c2f08908f660346f66ad1d8f81c910068e9ba029d

View File

@@ -0,0 +1 @@
433a6d748742d12abd20dc2a79b62ac3d9718ae47ef26f8e84dc8c180eea3659

View File

@@ -3,10 +3,12 @@ PACKAGERUNTIME=$1
PRECACHE=$2
NODE_URL=https://nodejs.org/dist
UNOFFICIAL_NODE_URL=https://unofficial-builds.nodejs.org/download/release
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
NODE20_VERSION="20.18.0"
NODE16_VERSION="16.20.2"
NODE20_VERSION="20.8.1"
# used only for win-arm64, remove node16 unofficial version when official version is available
NODE16_UNOFFICIAL_VERSION="16.20.0"
get_abs_path() {
# exploits the fact that pwd will print abs path when no args
@@ -137,6 +139,8 @@ function acquireExternalTool() {
# Download the external tools only for Windows.
if [[ "$PACKAGERUNTIME" == "win-x64" || "$PACKAGERUNTIME" == "win-x86" ]]; then
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/$PACKAGERUNTIME/node.exe" node16/bin
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/$PACKAGERUNTIME/node.lib" node16/bin
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.exe" node20/bin
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.lib" node20/bin
if [[ "$PRECACHE" != "" ]]; then
@@ -147,6 +151,8 @@ fi
# Download the external tools only for Windows.
if [[ "$PACKAGERUNTIME" == "win-arm64" ]]; then
# todo: replace these with official release when available
acquireExternalTool "$UNOFFICIAL_NODE_URL/v${NODE16_UNOFFICIAL_VERSION}/$PACKAGERUNTIME/node.exe" node16/bin
acquireExternalTool "$UNOFFICIAL_NODE_URL/v${NODE16_UNOFFICIAL_VERSION}/$PACKAGERUNTIME/node.lib" node16/bin
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.exe" node20/bin
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.lib" node20/bin
if [[ "$PRECACHE" != "" ]]; then
@@ -156,24 +162,30 @@ fi
# Download the external tools only for OSX.
if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-x64.tar.gz" node16 fix_nested_dir
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-darwin-x64.tar.gz" node20 fix_nested_dir
fi
if [[ "$PACKAGERUNTIME" == "osx-arm64" ]]; then
# node.js v12 doesn't support macOS on arm64.
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-arm64.tar.gz" node16 fix_nested_dir
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-darwin-arm64.tar.gz" node20 fix_nested_dir
fi
# Download the external tools for Linux PACKAGERUNTIMEs.
if [[ "$PACKAGERUNTIME" == "linux-x64" ]]; then
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-linux-x64.tar.gz" node16 fix_nested_dir
acquireExternalTool "$NODE_ALPINE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-alpine-x64.tar.gz" node16_alpine
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-linux-x64.tar.gz" node20 fix_nested_dir
acquireExternalTool "$NODE_ALPINE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-alpine-x64.tar.gz" node20_alpine
fi
if [[ "$PACKAGERUNTIME" == "linux-arm64" ]]; then
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-linux-arm64.tar.gz" node16 fix_nested_dir
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-linux-arm64.tar.gz" node20 fix_nested_dir
fi
if [[ "$PACKAGERUNTIME" == "linux-arm" ]]; then
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-linux-armv7l.tar.gz" node16 fix_nested_dir
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-linux-armv7l.tar.gz" node20 fix_nested_dir
fi

View File

@@ -10,7 +10,7 @@ if [ -f ".path" ]; then
echo ".path=${PATH}"
fi
nodever="node20"
nodever=${GITHUB_ACTIONS_RUNNER_FORCED_NODE_VERSION:-node20}
# insert anything to setup env when running as a service
# run the host process which keep the listener alive

View File

@@ -183,19 +183,6 @@ if [[ "$currentplatform" == 'darwin' && restartinteractiverunner -eq 0 ]]; then
fi
fi
# update runsvc.sh
if [ -f "$rootfolder/runsvc.sh" ]
then
date "+[%F %T-%4N] Update runsvc.sh" >> "$logfile" 2>&1
cat "$rootfolder/bin/runsvc.sh" > "$rootfolder/runsvc.sh"
if [ $? -ne 0 ]
then
date "+[%F %T-%4N] Can't update $rootfolder/runsvc.sh using $rootfolder/bin/runsvc.sh" >> "$logfile" 2>&1
mv -fv "$logfile" "$logfile.failed"
exit 1
fi
fi
date "+[%F %T-%4N] Update succeed" >> "$logfile"
touch update.finished

View File

@@ -7,7 +7,6 @@ using GitHub.DistributedTask.Pipelines;
using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Sdk;
using GitHub.Services.Common;
using GitHub.Services.WebApi;
using Sdk.RSWebApi.Contracts;
using Sdk.WebApi.WebApi.RawClient;
@@ -93,7 +92,7 @@ namespace GitHub.Runner.Common
public bool ShouldRetryException(Exception ex)
{
if (ex is AccessDeniedException || ex is RunnerNotFoundException)
if (ex is AccessDeniedException ade && ade.ErrorCode == 1)
{
return false;
}

View File

@@ -159,6 +159,7 @@ namespace GitHub.Runner.Common
public static class Features
{
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
public static readonly string Node16Warning = "DistributedTask.AddWarningToNode16Action";
public static readonly string LogTemplateErrorsAsDebugMessages = "DistributedTask.LogTemplateErrorsAsDebugMessages";
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
public static readonly string AllowRunnerContainerHooks = "DistributedTask.AllowRunnerContainerHooks";
@@ -175,6 +176,14 @@ namespace GitHub.Runner.Common
public static readonly string UnsupportedStopCommandTokenDisabled = "You cannot use a endToken that is an empty string, the string 'pause-logging', or another workflow command. For more information see: https://docs.github.com/actions/learn-github-actions/workflow-commands-for-github-actions#example-stopping-and-starting-workflow-commands or opt into insecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS` environment variable to `true`.";
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
public static readonly string SummaryUploadError = "$GITHUB_STEP_SUMMARY upload aborted, an error occurred when uploading the summary. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
public static readonly string DetectedNodeAfterEndOfLifeMessage = "Node.js 16 actions are deprecated. Please update the following actions to use Node.js 20: {0}. For more information see: https://github.blog/changelog/2023-09-22-github-actions-transitioning-from-node-16-to-node-20/.";
public static readonly string DeprecatedNodeDetectedAfterEndOfLifeActions = "DeprecatedNodeActionsMessageWarnings";
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 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
@@ -245,17 +254,20 @@ namespace GitHub.Runner.Common
public static readonly string RequireJobContainer = "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER";
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
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 readonly string ToolsDirectory = "agent.ToolsDirectory";
// Set this env var to "nodeXY" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
// Set this env var to "node16" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
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 ManualForceActionsToNode20 = "FORCE_JAVASCRIPT_ACTIONS_TO_NODE20";
}
public static class System

View File

@@ -36,7 +36,6 @@ namespace GitHub.Runner.Common
event EventHandler Unloading;
void ShutdownRunner(ShutdownReason reason);
void WritePerfCounter(string counter);
void LoadDefaultUserAgents();
}
public enum StartupType
@@ -68,7 +67,6 @@ namespace GitHub.Runner.Common
private StartupType _startupType;
private string _perfFile;
private RunnerWebProxy _webProxy = new();
private string _hostType = string.Empty;
public event EventHandler Unloading;
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
@@ -80,7 +78,6 @@ namespace GitHub.Runner.Common
{
// Validate args.
ArgUtil.NotNullOrEmpty(hostType, nameof(hostType));
_hostType = hostType;
_loadContext = AssemblyLoadContext.GetLoadContext(typeof(HostContext).GetTypeInfo().Assembly);
_loadContext.Unloading += LoadContext_Unloading;
@@ -199,16 +196,6 @@ namespace GitHub.Runner.Common
}
}
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
{
_trace.Warning($"Runner is running under insecure mode: HTTPS server certificate validation has been turned off by GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY environment variable.");
}
LoadDefaultUserAgents();
}
public void LoadDefaultUserAgents()
{
if (string.IsNullOrEmpty(WebProxy.HttpProxyAddress) && string.IsNullOrEmpty(WebProxy.HttpsProxyAddress))
{
_trace.Info($"No proxy settings were found based on environmental variables (http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY)");
@@ -218,6 +205,11 @@ namespace GitHub.Runner.Common
_userAgents.Add(new ProductInfoHeaderValue("HttpProxyConfigured", bool.TrueString));
}
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
{
_trace.Warning($"Runner is running under insecure mode: HTTPS server certificate validation has been turned off by GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY environment variable.");
}
var credFile = GetConfigFile(WellKnownConfigFile.Credentials);
if (File.Exists(credFile))
{
@@ -252,11 +244,6 @@ namespace GitHub.Runner.Common
_trace.Info($"Adding extra user agent '{extraUserAgentHeader}' to all HTTP requests.");
_userAgents.Add(extraUserAgentHeader);
}
var currentProcess = Process.GetCurrentProcess();
_userAgents.Add(new ProductInfoHeaderValue("Pid", currentProcess.Id.ToString()));
_userAgents.Add(new ProductInfoHeaderValue("CreationTime", Uri.EscapeDataString(DateTime.UtcNow.ToString("O"))));
_userAgents.Add(new ProductInfoHeaderValue($"({_hostType})"));
}
public string GetDirectory(WellKnownDirectory directory)
@@ -629,7 +616,7 @@ namespace GitHub.Runner.Common
payload[0] = Enum.Parse(typeof(GitHub.Services.Common.VssCredentialsType), ((int)payload[0]).ToString());
}
if (payload.Length > 0 && !string.IsNullOrEmpty(eventData.Message))
if (payload.Length > 0)
{
message = String.Format(eventData.Message.Replace("%n", Environment.NewLine), payload);
}

View File

@@ -4,7 +4,6 @@ using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
@@ -180,10 +179,6 @@ namespace GitHub.Runner.Common
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
userAgentValues.AddRange(HostContext.UserAgents);
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
{
this._websocketClient.Options.RemoteCertificateValidationCallback = (_, _, _, _) => true;
}
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
}

View File

@@ -613,7 +613,7 @@ namespace GitHub.Runner.Common
private void SendResultsTelemetry(Exception ex)
{
var issue = new Issue() { Type = IssueType.Warning, Message = $"Caught exception with results. {HostContext.SecretMasker.MaskSecrets(ex.Message)}" };
var issue = new Issue() { Type = IssueType.Warning, Message = $"Caught exception with results. {ex.Message}" };
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.ResultsUploadFailure;
var telemetryRecord = new TimelineRecord()
@@ -709,9 +709,7 @@ namespace GitHub.Runner.Common
{
Trace.Info("Catch exception during update steps, skip update Results.");
Trace.Error(e);
_resultsServiceExceptionsCount++;
// 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;
SendResultsTelemetry(e);

View File

@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Sdk;
using GitHub.Services.Common;
using GitHub.Services.Launch.Client;
using GitHub.Services.WebApi;
namespace GitHub.Runner.Common
{
@@ -24,21 +23,8 @@ namespace GitHub.Runner.Common
public void InitializeLaunchClient(Uri uri, string token)
{
// Using default 100 timeout
RawClientHttpRequestSettings settings = VssUtil.GetHttpRequestSettings(null);
// Create retry handler
IEnumerable<DelegatingHandler> delegatingHandlers = new List<DelegatingHandler>();
if (settings.MaxRetryRequest > 0)
{
delegatingHandlers = new DelegatingHandler[] { new VssHttpRetryMessageHandler(settings.MaxRetryRequest) };
}
// Setup RawHttpMessageHandler without credentials
var httpMessageHandler = new RawHttpMessageHandler(new NoOpCredentials(null), settings);
var pipeline = HttpClientFactory.CreatePipeline(httpMessageHandler, delegatingHandlers);
this._launchClient = new LaunchHttpClient(uri, pipeline, token, disposeHandler: true);
var httpMessageHandler = HostContext.CreateHttpClientHandler();
this._launchClient = new LaunchHttpClient(uri, httpMessageHandler, token, disposeHandler: true);
}
public Task<ActionDownloadInfoCollection> ResolveActionsDownloadInfoAsync(Guid planId, Guid jobId, ActionReferenceList actionReferenceList,

View File

@@ -28,7 +28,6 @@ namespace GitHub.Runner.Common
IList<StepResult> stepResults,
IList<Annotation> jobAnnotations,
string environmentUrl,
IList<Telemetry> telemetry,
CancellationToken token);
Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken token);
@@ -63,10 +62,7 @@ namespace GitHub.Runner.Common
CheckConnection();
return RetryRequest<AgentJobRequestMessage>(
async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, VarUtil.OS, cancellationToken), cancellationToken,
shouldRetry: ex =>
ex is not TaskOrchestrationJobNotFoundException && // HTTP status 404
ex is not TaskOrchestrationJobAlreadyAcquiredException && // HTTP status 409
ex is not TaskOrchestrationJobUnprocessableException); // HTTP status 422
shouldRetry: ex => ex is not TaskOrchestrationJobAlreadyAcquiredException);
}
public Task CompleteJobAsync(
@@ -77,12 +73,11 @@ namespace GitHub.Runner.Common
IList<StepResult> stepResults,
IList<Annotation> jobAnnotations,
string environmentUrl,
IList<Telemetry> telemetry,
CancellationToken cancellationToken)
{
CheckConnection();
return RetryRequest(
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, jobAnnotations, environmentUrl, telemetry, cancellationToken), cancellationToken);
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, jobAnnotations, environmentUrl, cancellationToken), cancellationToken);
}
public Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken cancellationToken)

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Library</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
</PropertyGroup>
@@ -15,11 +15,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.0" />
<PackageReference Include="System.Threading.Channels" Version="9.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@@ -46,11 +46,7 @@ namespace GitHub.Runner.Common
var githubApiUrl = "";
var gitHubUrlBuilder = new UriBuilder(githubUrl);
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
var isOrgRunner = path.Length == 1;
var isRepoOrEnterpriseRunner = path.Length == 2;
var isRepoRunner = isRepoOrEnterpriseRunner && !string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase);
if (isOrgRunner)
if (path.Length == 1)
{
// org runner
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
@@ -62,31 +58,21 @@ namespace GitHub.Runner.Common
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
}
else if (isRepoOrEnterpriseRunner)
else if (path.Length == 2)
{
// Repository runner
if (isRepoRunner)
// repo or enterprise runner.
if (!string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
{
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/repos/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
else
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/repos/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
return null;
}
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
else
{
// Enterprise runner
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
else
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
}
}
else
@@ -104,11 +90,7 @@ namespace GitHub.Runner.Common
var githubApiUrl = "";
var gitHubUrlBuilder = new UriBuilder(githubUrl);
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
var isOrgRunner = path.Length == 1;
var isRepoOrEnterpriseRunner = path.Length == 2;
var isRepoRunner = isRepoOrEnterpriseRunner && !string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase);
if (isOrgRunner)
if (path.Length == 1)
{
// org runner
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
@@ -120,31 +102,21 @@ namespace GitHub.Runner.Common
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runner-groups";
}
}
else if (isRepoOrEnterpriseRunner)
else if (path.Length == 2)
{
// Repository Runner
if (isRepoRunner)
// repo or enterprise runner.
if (!string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
{
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/repos/{path[0]}/{path[1]}/actions/runner-groups";
}
else
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/repos/{path[0]}/{path[1]}/actions/runner-groups";
}
return null;
}
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runner-groups";
}
else
{
// Enterprise Runner
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runner-groups";
}
else
{
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runner-groups";
}
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runner-groups";
}
}
else

View File

@@ -6,7 +6,7 @@ namespace GitHub.Runner.Common.Util
public static class NodeUtil
{
private const string _defaultNodeVersion = "node20";
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node20" });
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16", "node20" });
public static string GetInternalNodeVersion()
{
var forcedInternalNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);

View File

@@ -11,10 +11,9 @@ using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Common;
using GitHub.Runner.Listener.Configuration;
using GitHub.Runner.Sdk;
using GitHub.Runner.Common.Util;
using GitHub.Services.Common;
using GitHub.Runner.Common.Util;
using GitHub.Services.OAuth;
using GitHub.Services.WebApi;
namespace GitHub.Runner.Listener
{
@@ -70,8 +69,7 @@ namespace GitHub.Runner.Listener
Version = BuildConstants.RunnerPackage.Version,
OSDescription = RuntimeInformation.OSDescription,
};
var currentProcess = Process.GetCurrentProcess();
string sessionName = $"{Environment.MachineName ?? "RUNNER"} (PID: {currentProcess.Id})";
string sessionName = $"{Environment.MachineName ?? "RUNNER"}";
var taskAgentSession = new TaskAgentSession(sessionName, agent);
string errorMessage = string.Empty;
@@ -242,10 +240,6 @@ namespace GitHub.Runner.Listener
{
throw;
}
catch (RunnerNotFoundException)
{
throw;
}
catch (Exception ex)
{
Trace.Error("Catch exception during get next message.");
@@ -329,7 +323,6 @@ namespace GitHub.Runner.Listener
ex is TaskAgentPoolNotFoundException ||
ex is TaskAgentSessionExpiredException ||
ex is AccessDeniedException ||
ex is RunnerNotFoundException ||
ex is VssUnauthorizedException)
{
Trace.Info($"Non-retriable exception: {ex.Message}");

View File

@@ -1,5 +1,4 @@
#if OS_WINDOWS
#pragma warning disable CA1416
using System.IO;
using System.Security.Cryptography;
using System.Text;
@@ -85,5 +84,4 @@ namespace GitHub.Runner.Listener.Configuration
}
}
}
#pragma warning restore CA1416
#endif

View File

@@ -1,44 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using GitHub.Runner.Common;
using GitHub.Services.Common;
namespace GitHub.Runner.Listener
{
[ServiceLocator(Default = typeof(ErrorThrottler))]
public interface IErrorThrottler : IRunnerService
{
void Reset();
Task IncrementAndWaitAsync(CancellationToken token);
}
public sealed class ErrorThrottler : RunnerService, IErrorThrottler
{
internal static readonly TimeSpan MinBackoff = TimeSpan.FromSeconds(1);
internal static readonly TimeSpan MaxBackoff = TimeSpan.FromMinutes(1);
internal static readonly TimeSpan BackoffCoefficient = TimeSpan.FromSeconds(1);
private int _count = 0;
public void Reset()
{
_count = 0;
}
public async Task IncrementAndWaitAsync(CancellationToken token)
{
if (++_count <= 1)
{
return;
}
TimeSpan backoff = BackoffTimerHelper.GetExponentialBackoff(
attempt: _count - 2, // 0-based attempt
minBackoff: MinBackoff,
maxBackoff: MaxBackoff,
deltaBackoff: BackoffCoefficient);
Trace.Warning($"Back off {backoff.TotalSeconds} seconds before next attempt. Current consecutive error count: {_count}");
await HostContext.Delay(backoff, token);
}
}
}

View File

@@ -545,36 +545,28 @@ namespace GitHub.Runner.Listener
detailInfo = string.Join(Environment.NewLine, workerOutput);
Trace.Info($"Return code {returnCode} indicate worker encounter an unhandled exception or app crash, attach worker stdout/stderr to JobRequest result.");
try
var jobServer = await InitializeJobServerAsync(systemConnection);
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo };
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
switch (jobServer)
{
var jobServer = await InitializeJobServerAsync(systemConnection);
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo };
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
switch (jobServer)
{
case IJobServer js:
case IJobServer js:
{
await LogWorkerProcessUnhandledException(js, message, unhandledExceptionIssue);
// Go ahead to finish the job with result 'Failed' if the STDERR from worker is System.IO.IOException, since it typically means we are running out of disk space.
if (detailInfo.Contains(typeof(System.IO.IOException).ToString(), StringComparison.OrdinalIgnoreCase))
{
await LogWorkerProcessUnhandledException(js, message, unhandledExceptionIssue);
// Go ahead to finish the job with result 'Failed' if the STDERR from worker is System.IO.IOException, since it typically means we are running out of disk space.
if (detailInfo.Contains(typeof(System.IO.IOException).ToString(), StringComparison.OrdinalIgnoreCase))
{
Trace.Info($"Finish job with result 'Failed' due to IOException.");
await ForceFailJob(js, message);
}
break;
Trace.Info($"Finish job with result 'Failed' due to IOException.");
await ForceFailJob(js, message);
}
case IRunServer rs:
await ForceFailJob(rs, message, unhandledExceptionIssue);
break;
default:
throw new NotSupportedException($"JobServer type '{jobServer.GetType().Name}' is not supported.");
}
}
catch (Exception ex)
{
Trace.Error($"Catch exception during log worker process unhandled exception.");
Trace.Error(ex);
}
case IRunServer rs:
await ForceFailJob(rs, message, unhandledExceptionIssue);
break;
default:
throw new NotSupportedException($"JobServer type '{jobServer.GetType().Name}' is not supported.");
}
}
@@ -1206,7 +1198,7 @@ namespace GitHub.Runner.Listener
jobAnnotations.Add(annotation.Value);
}
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, telemetry: null, CancellationToken.None);
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, CancellationToken.None);
}
catch (Exception ex)
{

View File

@@ -88,8 +88,7 @@ namespace GitHub.Runner.Listener
Version = BuildConstants.RunnerPackage.Version,
OSDescription = RuntimeInformation.OSDescription,
};
var currentProcess = Process.GetCurrentProcess();
string sessionName = $"{Environment.MachineName ?? "RUNNER"} (PID: {currentProcess.Id})";
string sessionName = $"{Environment.MachineName ?? "RUNNER"}";
var taskAgentSession = new TaskAgentSession(sessionName, agent);
string errorMessage = string.Empty;
@@ -264,6 +263,8 @@ namespace GitHub.Runner.Listener
if (message != null && message.MessageType == BrokerMigrationMessage.MessageType)
{
Trace.Info("BrokerMigration message received. Polling Broker for messages...");
var migrationMessage = JsonUtility.FromString<BrokerMigrationMessage>(message.Body);
await _brokerServer.UpdateConnectionIfNeeded(migrationMessage.BrokerBaseUrl, _creds);
@@ -308,10 +309,6 @@ namespace GitHub.Runner.Listener
{
throw;
}
catch (RunnerNotFoundException)
{
throw;
}
catch (Exception ex)
{
Trace.Error("Catch exception during get next message.");
@@ -461,7 +458,6 @@ namespace GitHub.Runner.Listener
ex is TaskAgentPoolNotFoundException ||
ex is TaskAgentSessionExpiredException ||
ex is AccessDeniedException ||
ex is RunnerNotFoundException ||
ex is VssUnauthorizedException)
{
Trace.Info($"Non-retriable exception: {ex.Message}");

View File

@@ -7,7 +7,6 @@ using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using GitHub.DistributedTask.WebApi;
using GitHub.Services.WebApi;
namespace GitHub.Runner.Listener
{
@@ -145,12 +144,6 @@ namespace GitHub.Runner.Listener
trace.Error(e);
return Constants.Runner.ReturnCode.TerminatedError;
}
catch (RunnerNotFoundException e)
{
terminal.WriteError($"An error occurred: {e.Message}");
trace.Error(e);
return Constants.Runner.ReturnCode.TerminatedError;
}
catch (Exception e)
{
terminal.WriteError($"An error occurred: {e.Message}");

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<SelfContained>true</SelfContained>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
@@ -19,11 +18,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.0" />
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.4.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@@ -32,25 +32,10 @@ namespace GitHub.Runner.Listener
private bool _inConfigStage;
private ManualResetEvent _completedCommand = new(false);
// <summary>
// Helps avoid excessive calls to Run Service when encountering non-retriable errors from /acquirejob.
// Normally we rely on the HTTP clients to back off between retry attempts. However, acquiring a job
// involves calls to both Run Serivce and Broker. And Run Service and Broker communicate with each other
// in an async fashion.
//
// When Run Service encounters a non-retriable error, it sends an async message to Broker. The runner will,
// however, immediately call Broker to get the next message. If the async event from Run Service to Broker
// has not yet been processed, the next message from Broker may be the same job message.
//
// The error throttler helps us back off when encountering successive, non-retriable errors from /acquirejob.
// </summary>
private IErrorThrottler _acquireJobThrottler;
public override void Initialize(IHostContext hostContext)
{
base.Initialize(hostContext);
_term = HostContext.GetService<ITerminal>();
_acquireJobThrottler = HostContext.CreateService<IErrorThrottler>();
}
public async Task<int> ExecuteCommand(CommandSettings command)
@@ -228,21 +213,15 @@ namespace GitHub.Runner.Listener
var configFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), config.Key);
var configContent = Convert.FromBase64String(config.Value);
#if OS_WINDOWS
#pragma warning disable CA1416
if (configFile == HostContext.GetConfigFile(WellKnownConfigFile.RSACredentials))
{
configContent = ProtectedData.Protect(configContent, null, DataProtectionScope.LocalMachine);
}
#pragma warning restore CA1416
#endif
File.WriteAllBytes(configFile, configContent);
File.SetAttributes(configFile, File.GetAttributes(configFile) | FileAttributes.Hidden);
Trace.Info($"Saved {configContent.Length} bytes to '{configFile}'.");
}
// make sure we have the right user agent data added from the jitconfig
HostContext.LoadDefaultUserAgents();
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
}
catch (Exception ex)
{
@@ -584,16 +563,13 @@ namespace GitHub.Runner.Listener
await runServer.ConnectAsync(new Uri(messageRef.RunServiceUrl), creds);
try
{
jobRequestMessage = await runServer.GetJobMessageAsync(messageRef.RunnerRequestId, messageQueueLoopTokenSource.Token);
_acquireJobThrottler.Reset();
jobRequestMessage =
await runServer.GetJobMessageAsync(messageRef.RunnerRequestId,
messageQueueLoopTokenSource.Token);
}
catch (Exception ex) when (
ex is TaskOrchestrationJobNotFoundException || // HTTP status 404
ex is TaskOrchestrationJobAlreadyAcquiredException || // HTTP status 409
ex is TaskOrchestrationJobUnprocessableException) // HTTP status 422
catch (TaskOrchestrationJobAlreadyAcquiredException)
{
Trace.Info($"Skipping message Job. {ex.Message}");
await _acquireJobThrottler.IncrementAndWaitAsync(messageQueueLoopTokenSource.Token);
Trace.Info("Job is already acquired, skip this message.");
continue;
}
catch (Exception ex)

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<SelfContained>true</SelfContained>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Library</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<SelfContained>true</SelfContained>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
</PropertyGroup>

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Library</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<SelfContained>true</SelfContained>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
</PropertyGroup>
@@ -15,9 +14,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Text.Encoding.CodePages" Version="9.0.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="System.Threading.Channels" Version="9.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@@ -60,15 +60,5 @@ namespace GitHub.Runner.Sdk
}
return string.Empty;
}
public static string GetVssRequestId(HttpResponseHeaders headers)
{
if (headers != null &&
headers.TryGetValues("x-vss-e2eid", out var headerValues))
{
return headerValues.FirstOrDefault();
}
return string.Empty;
}
}
}

View File

@@ -1102,7 +1102,6 @@ namespace GitHub.Runner.Worker
int timeoutSeconds = 20 * 60;
while (retryCount < 3)
{
string requestId = string.Empty;
using (var actionDownloadTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)))
using (var actionDownloadCancellation = CancellationTokenSource.CreateLinkedTokenSource(actionDownloadTimeout.Token, executionContext.CancellationToken))
{
@@ -1118,7 +1117,7 @@ namespace GitHub.Runner.Worker
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
using (var response = await httpClient.GetAsync(downloadUrl))
{
requestId = UrlUtil.GetGitHubRequestId(response.Headers);
var requestId = UrlUtil.GetGitHubRequestId(response.Headers);
if (!string.IsNullOrEmpty(requestId))
{
Trace.Info($"Request URL: {downloadUrl} X-GitHub-Request-Id: {requestId} Http Status: {response.StatusCode}");
@@ -1156,7 +1155,7 @@ namespace GitHub.Runner.Worker
catch (OperationCanceledException ex) when (!executionContext.CancellationToken.IsCancellationRequested && retryCount >= 2)
{
Trace.Info($"Action download final retry timeout after {timeoutSeconds} seconds.");
throw new TimeoutException($"Action '{downloadUrl}' download has timed out. Error: {ex.Message} {requestId}");
throw new TimeoutException($"Action '{downloadUrl}' download has timed out. Error: {ex.Message}");
}
catch (ActionNotFoundException)
{
@@ -1171,11 +1170,11 @@ namespace GitHub.Runner.Worker
if (actionDownloadTimeout.Token.IsCancellationRequested)
{
// action download didn't finish within timeout
executionContext.Warning($"Action '{downloadUrl}' didn't finish download within {timeoutSeconds} seconds. {requestId}");
executionContext.Warning($"Action '{downloadUrl}' didn't finish download within {timeoutSeconds} seconds.");
}
else
{
executionContext.Warning($"Failed to download action '{downloadUrl}'. Error: {ex.Message} {requestId}");
executionContext.Warning($"Failed to download action '{downloadUrl}'. Error: {ex.Message}");
}
}
}

View File

@@ -83,7 +83,7 @@ namespace GitHub.Runner.Worker
// Initialize
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
void CancelToken();
IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, ActionRunStage stage, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, List<Issue> embeddedIssueCollector = null, CancellationTokenSource cancellationTokenSource = null, Guid embeddedId = default(Guid), string siblingScopeName = null, TimeSpan? timeout = null);
IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, ActionRunStage stage, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null, Guid embeddedId = default(Guid), string siblingScopeName = null, TimeSpan? timeout = null);
IExecutionContext CreateEmbeddedChild(string scopeName, string contextName, Guid embeddedId, ActionRunStage stage, Dictionary<string, string> intraActionState = null, string siblingScopeName = null);
// logging
@@ -135,6 +135,7 @@ namespace GitHub.Runner.Worker
private readonly TimelineRecord _record = new();
private readonly Dictionary<Guid, TimelineRecord> _detailRecords = new();
private readonly List<Issue> _embeddedIssueCollector;
private readonly object _loggerLock = new();
private readonly object _matchersLock = new();
private readonly ExecutionContext _parentExecutionContext;
@@ -153,7 +154,6 @@ namespace GitHub.Runner.Worker
private CancellationTokenSource _cancellationTokenSource;
private TaskCompletionSource<int> _forceCompleted = new();
private bool _throttlingReported = false;
private List<Issue> _embeddedIssueCollector;
// only job level ExecutionContext will track throttling delay.
private long _totalThrottlingDelayInMilliseconds = 0;
@@ -356,7 +356,6 @@ namespace GitHub.Runner.Worker
int? recordOrder = null,
IPagingLogger logger = null,
bool isEmbedded = false,
List<Issue> embeddedIssueCollector = null,
CancellationTokenSource cancellationTokenSource = null,
Guid embeddedId = default(Guid),
string siblingScopeName = null,
@@ -366,10 +365,6 @@ namespace GitHub.Runner.Worker
var child = new ExecutionContext(this, isEmbedded);
child.Initialize(HostContext);
if ((Global.Variables.GetBoolean("RunService.FixEmbeddedIssues") ?? false) && embeddedIssueCollector != null)
{
child._embeddedIssueCollector = embeddedIssueCollector;
}
child.Global = Global;
child.ScopeName = scopeName;
child.ContextName = contextName;
@@ -438,7 +433,7 @@ namespace GitHub.Runner.Worker
Dictionary<string, string> intraActionState = null,
string siblingScopeName = null)
{
return Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, contextName, stage, logger: _logger, isEmbedded: true, embeddedIssueCollector: _embeddedIssueCollector, cancellationTokenSource: null, intraActionState: intraActionState, embeddedId: embeddedId, siblingScopeName: siblingScopeName, timeout: GetRemainingTimeout(), recordOrder: _record.Order);
return Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, contextName, stage, logger: _logger, isEmbedded: true, cancellationTokenSource: null, intraActionState: intraActionState, embeddedId: embeddedId, siblingScopeName: siblingScopeName, timeout: GetRemainingTimeout(), recordOrder: _record.Order);
}
public void Start(string currentOperation = null)
@@ -508,9 +503,6 @@ namespace GitHub.Runner.Worker
Status = _record.State,
Number = _record.Order,
Name = _record.Name,
ActionName = StepTelemetry?.Action,
Ref = StepTelemetry?.Ref,
Type = StepTelemetry?.Type,
StartedAt = _record.StartTime,
CompletedAt = _record.FinishTime,
Annotations = new List<Annotation>()
@@ -528,6 +520,7 @@ namespace GitHub.Runner.Worker
Global.StepsResult.Add(stepResult);
}
if (Root != this)
{
// only dispose TokenSource for step level ExecutionContext
@@ -815,6 +808,11 @@ namespace GitHub.Runner.Worker
Global.Variables = new Variables(HostContext, variables);
if (Global.Variables.GetBoolean("DistributedTask.ForceInternalNodeVersionOnRunnerTo16") ?? false)
{
Environment.SetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion, "node16");
}
// Environment variables shared across all actions
Global.EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer);
@@ -1419,7 +1417,7 @@ namespace GitHub.Runner.Worker
{
if (key == PipelineTemplateConstants.HostWorkspace)
{
// The HostWorkspace context var is excluded so that there is a var that always points to the host path.
// The HostWorkspace context var is excluded so that there is a var that always points to the host path.
// This var can be used to translate back from container paths, e.g. in HashFilesFunction, which always runs on the host machine
continue;
}

View File

@@ -57,13 +57,72 @@ namespace GitHub.Runner.Worker.Handlers
handler = HostContext.CreateService<INodeScriptActionHandler>();
var nodeData = data as NodeJSActionExecutionData;
// With node12 EoL in 04/2022 and node16 EoL in 09/23, we want to execute all JS actions using node20
if (string.Equals(nodeData.NodeVersion, "node12", StringComparison.InvariantCultureIgnoreCase) ||
string.Equals(nodeData.NodeVersion, "node16", StringComparison.InvariantCultureIgnoreCase))
// With node12 EoL in 04/2022, we want to be able to uniformly upgrade all JS actions to node16 from the server
if (string.Equals(nodeData.NodeVersion, "node12", StringComparison.InvariantCultureIgnoreCase))
{
nodeData.NodeVersion = "node20";
var repoAction = action as Pipelines.RepositoryPathReference;
if (repoAction != null)
{
var warningActions = new HashSet<string>();
if (executionContext.Global.Variables.TryGetValue(Constants.Runner.EnforcedNode12DetectedAfterEndOfLifeEnvVariable, out var node16ForceWarnings))
{
warningActions = StringUtil.ConvertFromJson<HashSet<string>>(node16ForceWarnings);
}
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("Node16ForceActionsWarnings", StringUtil.ConvertToJson(warningActions));
}
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;
}
else if (data.ExecutionType == ActionExecutionType.Script)

View File

@@ -72,11 +72,6 @@ namespace GitHub.Runner.Worker.Handlers
Environment["ACTIONS_RESULTS_URL"] = resultsUrl;
}
if (ExecutionContext.Global.Variables.GetBoolean("actions_uses_cache_service_v2") ?? false)
{
Environment["ACTIONS_CACHE_SERVICE_V2"] = bool.TrueString;
}
// Resolve the target script.
string target = null;
if (stage == ActionRunStage.Main)
@@ -98,6 +93,7 @@ namespace GitHub.Runner.Worker.Handlers
ExecutionContext.StepTelemetry.HasPreStep = Data.HasPre;
ExecutionContext.StepTelemetry.HasPostStep = Data.HasPost;
}
ExecutionContext.StepTelemetry.Type = Data.NodeVersion;
ArgUtil.NotNullOrEmpty(target, nameof(target));
target = Path.Combine(ActionDirectory, target);
@@ -110,8 +106,24 @@ namespace GitHub.Runner.Worker.Handlers
workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
}
if (string.Equals(Data.NodeVersion, "node12", StringComparison.OrdinalIgnoreCase) &&
Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.Arm64))
{
ExecutionContext.Output($"The node12 is not supported. Use node16 instead.");
Data.NodeVersion = "node16";
}
string forcedNodeVersion = System.Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedActionsNodeVersion);
if (forcedNodeVersion == "node16" && Data.NodeVersion != "node16")
{
Data.NodeVersion = "node16";
}
if (forcedNodeVersion == "node20" && Data.NodeVersion != "node20")
{
Data.NodeVersion = "node20";
}
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
ExecutionContext.StepTelemetry.Type = nodeRuntimeVersion;
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
// Format the arguments passed to node.
@@ -131,6 +143,28 @@ namespace GitHub.Runner.Worker.Handlers
// Remove environment variable that may cause conflicts with the node within the runner.
Environment.Remove("NODE_ICU_DATA"); // https://github.com/actions/runner/issues/795
if (string.Equals(Data.NodeVersion, Constants.Runner.DeprecatedNodeVersion, StringComparison.OrdinalIgnoreCase) && (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.Node16Warning) ?? false))
{
var repoAction = Action as RepositoryPathReference;
var warningActions = new HashSet<string>();
if (ExecutionContext.Global.Variables.TryGetValue(Constants.Runner.DeprecatedNodeDetectedAfterEndOfLifeActions, out var deprecatedNodeWarnings))
{
warningActions = StringUtil.ConvertFromJson<HashSet<string>>(deprecatedNodeWarnings);
}
if (string.IsNullOrEmpty(repoAction.Name))
{
// local actions don't have a 'Name'
warningActions.Add(repoAction.Path);
}
else
{
warningActions.Add($"{repoAction.Name}/{repoAction.Path ?? string.Empty}".TrimEnd('/') + $"@{repoAction.Ref}");
}
ExecutionContext.Global.Variables.Set(Constants.Runner.DeprecatedNodeDetectedAfterEndOfLifeActions, StringUtil.ConvertToJson(warningActions));
}
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
{

View File

@@ -17,7 +17,6 @@ using GitHub.Runner.Common;
using GitHub.Runner.Common.Util;
using GitHub.Runner.Sdk;
using GitHub.Services.Common;
using Newtonsoft.Json;
using Pipelines = GitHub.DistributedTask.Pipelines;
namespace GitHub.Runner.Worker
@@ -43,13 +42,11 @@ namespace GitHub.Runner.Worker
public sealed class JobExtension : RunnerService, IJobExtension
{
private readonly HashSet<string> _existingProcesses = new(StringComparer.OrdinalIgnoreCase);
private readonly List<Task<CheckResult>> _connectivityCheckTasks = new();
private readonly List<Task<string>> _connectivityCheckTasks = new();
private bool _processCleanup;
private string _processLookupId = $"github_{Guid.NewGuid()}";
private CancellationTokenSource _diskSpaceCheckToken = new();
private Task _diskSpaceCheckTask = null;
private CancellationTokenSource _serviceConnectivityCheckToken = new();
private Task _serviceConnectivityCheckTask = null;
// Download all required actions.
// Make sure all condition inputs are valid.
@@ -402,7 +399,7 @@ namespace GitHub.Runner.Worker
var snapshotOperationProvider = HostContext.GetService<ISnapshotOperationProvider>();
jobContext.RegisterPostJobStep(new JobExtensionRunner(
runAsync: (executionContext, _) => snapshotOperationProvider.CreateSnapshotRequestAsync(executionContext, snapshotRequest),
condition: snapshotRequest.Condition,
condition: $"{PipelineTemplateConstants.Success}()",
displayName: $"Create custom image",
data: null));
}
@@ -457,14 +454,11 @@ namespace GitHub.Runner.Worker
{
foreach (var checkUrl in checkUrls)
{
_connectivityCheckTasks.Add(CheckConnectivity(checkUrl, accessToken: string.Empty, timeoutInSeconds: 5, token: CancellationToken.None));
_connectivityCheckTasks.Add(CheckConnectivity(checkUrl));
}
}
}
Trace.Info($"Start checking service connectivity in background.");
_serviceConnectivityCheckTask = CheckServiceConnectivityAsync(context, _serviceConnectivityCheckToken.Token);
return steps;
}
catch (OperationCanceledException ex) when (jobContext.CancellationToken.IsCancellationRequested)
@@ -698,7 +692,7 @@ namespace GitHub.Runner.Worker
{
var result = await check;
Trace.Info($"Connectivity check result: {result}");
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = $"{result.EndpointUrl}: {result.StatusCode}" });
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = result });
}
}
catch (Exception ex)
@@ -708,22 +702,6 @@ namespace GitHub.Runner.Worker
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = $"Fail to check server connectivity. {ex.Message}" });
}
}
// Collect service connectivity check result
if (_serviceConnectivityCheckTask != null)
{
_serviceConnectivityCheckToken.Cancel();
try
{
await _serviceConnectivityCheckTask;
}
catch (Exception ex)
{
Trace.Error($"Fail to check service connectivity.");
Trace.Error(ex);
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = $"Fail to check service connectivity. {ex.Message}" });
}
}
}
catch (Exception ex)
{
@@ -739,13 +717,11 @@ namespace GitHub.Runner.Worker
}
}
private async Task<CheckResult> CheckConnectivity(string endpointUrl, string accessToken, int timeoutInSeconds, CancellationToken token)
private async Task<string> CheckConnectivity(string endpointUrl)
{
Trace.Info($"Check server connectivity for {endpointUrl}.");
CheckResult result = new CheckResult() { EndpointUrl = endpointUrl };
var stopwatch = Stopwatch.StartNew();
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)))
using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, timeoutTokenSource.Token))
string result = string.Empty;
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
{
try
{
@@ -753,44 +729,21 @@ namespace GitHub.Runner.Worker
using (var httpClient = new HttpClient(httpClientHandler))
{
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
if (!string.IsNullOrEmpty(accessToken))
{
httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
}
var response = await httpClient.GetAsync(endpointUrl, linkedTokenSource.Token);
result.StatusCode = $"{response.StatusCode}";
var githubRequestId = UrlUtil.GetGitHubRequestId(response.Headers);
var vssRequestId = UrlUtil.GetVssRequestId(response.Headers);
if (!string.IsNullOrEmpty(githubRequestId))
{
result.RequestId = githubRequestId;
}
else if (!string.IsNullOrEmpty(vssRequestId))
{
result.RequestId = vssRequestId;
}
var response = await httpClient.GetAsync(endpointUrl, timeoutTokenSource.Token);
result = $"{endpointUrl}: {response.StatusCode}";
}
}
catch (Exception ex) when (ex is OperationCanceledException && token.IsCancellationRequested)
{
Trace.Error($"Request canceled during connectivity check: {ex}");
result.StatusCode = "canceled";
}
catch (Exception ex) when (ex is OperationCanceledException && timeoutTokenSource.IsCancellationRequested)
{
Trace.Error($"Request timeout during connectivity check: {ex}");
result.StatusCode = "timeout";
result = $"{endpointUrl}: timeout";
}
catch (Exception ex)
{
Trace.Error($"Catch exception during connectivity check: {ex}");
result.StatusCode = $"{ex.Message}";
result = $"{endpointUrl}: {ex.Message}";
}
}
stopwatch.Stop();
result.DurationInMs = (int)stopwatch.ElapsedMilliseconds;
return result;
}
@@ -828,84 +781,6 @@ namespace GitHub.Runner.Worker
}
}
private async Task CheckServiceConnectivityAsync(IExecutionContext context, CancellationToken token)
{
var connectionTest = context.Global.Variables.Get(WellKnownDistributedTaskVariables.RunnerServiceConnectivityTest);
if (string.IsNullOrEmpty(connectionTest))
{
return;
}
ServiceConnectivityCheckInput checkConnectivityInfo;
try
{
checkConnectivityInfo = StringUtil.ConvertFromJson<ServiceConnectivityCheckInput>(connectionTest);
}
catch (Exception ex)
{
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.General, Message = $"Fail to parse JSON. {ex.Message}" });
return;
}
if (checkConnectivityInfo == null)
{
return;
}
// make sure interval is at least 10 seconds
checkConnectivityInfo.IntervalInSecond = Math.Max(10, checkConnectivityInfo.IntervalInSecond);
var systemConnection = context.Global.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
var accessToken = systemConnection.Authorization.Parameters[EndpointAuthorizationParameters.AccessToken];
var testResult = new ServiceConnectivityCheckResult();
while (!token.IsCancellationRequested)
{
foreach (var endpoint in checkConnectivityInfo.Endpoints)
{
if (string.IsNullOrEmpty(endpoint.Key) || string.IsNullOrEmpty(endpoint.Value))
{
continue;
}
if (!testResult.EndpointsResult.ContainsKey(endpoint.Key))
{
testResult.EndpointsResult[endpoint.Key] = new List<string>();
}
try
{
var result = await CheckConnectivity(endpoint.Value, accessToken: accessToken, timeoutInSeconds: checkConnectivityInfo.RequestTimeoutInSecond, token);
testResult.EndpointsResult[endpoint.Key].Add($"{result.StartTime:s}: {result.StatusCode} - {result.RequestId} - {result.DurationInMs}ms");
if (!testResult.HasFailure &&
result.StatusCode != "OK" &&
result.StatusCode != "canceled")
{
// track if any endpoint is not reachable
testResult.HasFailure = true;
}
}
catch (Exception ex)
{
testResult.EndpointsResult[endpoint.Key].Add($"{DateTime.UtcNow:s}: {ex.Message}");
}
}
try
{
await Task.Delay(TimeSpan.FromSeconds(checkConnectivityInfo.IntervalInSecond), token);
}
catch (TaskCanceledException)
{
// ignore
}
}
var telemetryData = StringUtil.ConvertToJson(testResult, Formatting.None);
Trace.Verbose($"Connectivity check result: {telemetryData}");
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = telemetryData });
}
private Dictionary<int, Process> SnapshotProcesses()
{
Dictionary<int, Process> snapshot = new();
@@ -937,23 +812,5 @@ namespace GitHub.Runner.Worker
throw new ArgumentException("Jobs without a job container are forbidden on this runner, please add a 'container:' to your job or contact your self-hosted runner administrator.");
}
}
private class CheckResult
{
public CheckResult()
{
StartTime = DateTime.UtcNow;
}
public string EndpointUrl { get; set; }
public DateTime StartTime { get; set; }
public string StatusCode { get; set; }
public string RequestId { get; set; }
public int DurationInMs { get; set; }
}
}
}

View File

@@ -15,7 +15,6 @@ using GitHub.Runner.Common.Util;
using GitHub.Runner.Sdk;
using GitHub.Services.Common;
using GitHub.Services.WebApi;
using Sdk.RSWebApi.Contracts;
using Pipelines = GitHub.DistributedTask.Pipelines;
namespace GitHub.Runner.Worker
@@ -50,8 +49,7 @@ namespace GitHub.Runner.Worker
if (message.Variables.TryGetValue(Constants.Variables.System.OrchestrationId, out VariableValue orchestrationId) &&
!string.IsNullOrEmpty(orchestrationId.Value))
{
// make the orchestration id the first item in the user-agent header to avoid get truncated in server log.
HostContext.UserAgents.Insert(0, new ProductInfoHeaderValue("OrchestrationId", orchestrationId.Value));
HostContext.UserAgents.Add(new ProductInfoHeaderValue("OrchestrationId", orchestrationId.Value));
// make sure orchestration id is in the user-agent header.
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
@@ -280,14 +278,26 @@ namespace GitHub.Runner.Worker
{
jobContext.Debug($"Finishing: {message.JobDisplayName}");
TaskResult result = jobContext.Complete(taskResult);
var jobQueueTelemetry = await ShutdownQueue(throwOnFailure: false);
// include any job telemetry from the background upload process.
if (jobQueueTelemetry?.Count > 0)
if (jobContext.Global.Variables.TryGetValue(Constants.Runner.DeprecatedNodeDetectedAfterEndOfLifeActions, out var deprecatedNodeWarnings))
{
jobContext.Global.JobTelemetry.AddRange(jobQueueTelemetry);
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(deprecatedNodeWarnings));
jobContext.Warning(string.Format(Constants.Runner.DetectedNodeAfterEndOfLifeMessage, actions));
}
if (jobContext.Global.Variables.TryGetValue(Constants.Runner.EnforcedNode12DetectedAfterEndOfLifeEnvVariable, out var node16ForceWarnings))
{
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(node16ForceWarnings));
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);
// Make sure to clean temp after file upload since they may be pending fileupload still use the TEMP dir.
_tempDirectoryManager?.CleanupTempDirectory();
@@ -304,13 +314,6 @@ namespace GitHub.Runner.Worker
environmentUrl = urlStringToken.Value;
}
// Get telemetry
IList<Telemetry> telemetry = null;
if (jobContext.Global.JobTelemetry.Count > 0)
{
telemetry = jobContext.Global.JobTelemetry.Select(x => new Telemetry { Type = x.Type.ToString(), Message = x.Message, }).ToList();
}
Trace.Info($"Raising job completed against run service");
var completeJobRetryLimit = 5;
var exceptions = new List<Exception>();
@@ -318,7 +321,7 @@ namespace GitHub.Runner.Worker
{
try
{
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, jobContext.Global.JobAnnotations, environmentUrl, telemetry, default);
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, jobContext.Global.JobAnnotations, environmentUrl, default);
return result;
}
catch (Exception ex)
@@ -343,14 +346,74 @@ namespace GitHub.Runner.Worker
if (_runnerSettings.DisableUpdate == true)
{
await WarningOutdatedRunnerAsync(jobContext, message, result);
try
{
var currentVersion = new PackageVersion(BuildConstants.RunnerPackage.Version);
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
VssCredentials serverCredential = VssUtil.GetVssCredential(systemConnection);
var runnerServer = HostContext.GetService<IRunnerServer>();
await runnerServer.ConnectAsync(systemConnection.Url, serverCredential);
var serverPackages = await runnerServer.GetPackagesAsync("agent", BuildConstants.RunnerPackage.PackageName, 5, includeToken: false, cancellationToken: CancellationToken.None);
if (serverPackages.Count > 0)
{
serverPackages = serverPackages.OrderByDescending(x => x.Version).ToList();
Trace.Info($"Newer packages {StringUtil.ConvertToJson(serverPackages.Select(x => x.Version.ToString()))}");
var warnOnFailedJob = false; // any minor/patch version behind.
var warnOnOldRunnerVersion = false; // >= 2 minor version behind
if (serverPackages.Any(x => x.Version.CompareTo(currentVersion) > 0))
{
Trace.Info($"Current runner version {currentVersion} is behind the latest runner version {serverPackages[0].Version}.");
warnOnFailedJob = true;
}
if (serverPackages.Where(x => x.Version.Major == currentVersion.Major && x.Version.Minor > currentVersion.Minor).Count() > 1)
{
Trace.Info($"Current runner version {currentVersion} is way behind the latest runner version {serverPackages[0].Version}.");
warnOnOldRunnerVersion = true;
}
if (result == TaskResult.Failed && warnOnFailedJob)
{
jobContext.Warning($"This job failure may be caused by using an out of date self-hosted runner. You are currently using runner version {currentVersion}. Please update to the latest version {serverPackages[0].Version}");
}
else if (warnOnOldRunnerVersion)
{
jobContext.Warning($"This self-hosted runner is currently using runner version {currentVersion}. This version is out of date. Please update to the latest version {serverPackages[0].Version}");
}
}
}
catch (Exception ex)
{
// Ignore any error since suggest runner update is best effort.
Trace.Error($"Caught exception during runner version check: {ex}");
}
}
if (jobContext.Global.Variables.TryGetValue(Constants.Runner.DeprecatedNodeDetectedAfterEndOfLifeActions, out var deprecatedNodeWarnings))
{
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(deprecatedNodeWarnings));
jobContext.Warning(string.Format(Constants.Runner.DetectedNodeAfterEndOfLifeMessage, actions));
}
if (jobContext.Global.Variables.TryGetValue(Constants.Runner.EnforcedNode12DetectedAfterEndOfLifeEnvVariable, out var node16ForceWarnings))
{
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(node16ForceWarnings));
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
{
var jobQueueTelemetry = await ShutdownQueue(throwOnFailure: true);
// include any job telemetry from the background upload process.
if (jobQueueTelemetry?.Count > 0)
if (jobQueueTelemetry.Count > 0)
{
jobContext.Global.JobTelemetry.AddRange(jobQueueTelemetry);
}
@@ -478,52 +541,5 @@ namespace GitHub.Runner.Worker
return Array.Empty<JobTelemetry>();
}
private async Task WarningOutdatedRunnerAsync(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, TaskResult result)
{
try
{
var currentVersion = new PackageVersion(BuildConstants.RunnerPackage.Version);
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
VssCredentials serverCredential = VssUtil.GetVssCredential(systemConnection);
var runnerServer = HostContext.GetService<IRunnerServer>();
await runnerServer.ConnectAsync(systemConnection.Url, serverCredential);
var serverPackages = await runnerServer.GetPackagesAsync("agent", BuildConstants.RunnerPackage.PackageName, 5, includeToken: false, cancellationToken: CancellationToken.None);
if (serverPackages.Count > 0)
{
serverPackages = serverPackages.OrderByDescending(x => x.Version).ToList();
Trace.Info($"Newer packages {StringUtil.ConvertToJson(serverPackages.Select(x => x.Version.ToString()))}");
var warnOnFailedJob = false; // any minor/patch version behind.
var warnOnOldRunnerVersion = false; // >= 2 minor version behind
if (serverPackages.Any(x => x.Version.CompareTo(currentVersion) > 0))
{
Trace.Info($"Current runner version {currentVersion} is behind the latest runner version {serverPackages[0].Version}.");
warnOnFailedJob = true;
}
if (serverPackages.Where(x => x.Version.Major == currentVersion.Major && x.Version.Minor > currentVersion.Minor).Count() > 1)
{
Trace.Info($"Current runner version {currentVersion} is way behind the latest runner version {serverPackages[0].Version}.");
warnOnOldRunnerVersion = true;
}
if (result == TaskResult.Failed && warnOnFailedJob)
{
jobContext.Warning($"This job failure may be caused by using an out of date self-hosted runner. You are currently using runner version {currentVersion}. Please update to the latest version {serverPackages[0].Version}");
}
else if (warnOnOldRunnerVersion)
{
jobContext.Warning($"This self-hosted runner is currently using runner version {currentVersion}. This version is out of date. Please update to the latest version {serverPackages[0].Version}");
}
}
}
catch (Exception ex)
{
// Ignore any error since suggest runner update is best effort.
Trace.Error($"Caught exception during runner version check: {ex}");
}
}
}
}

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Exe</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<SelfContained>true</SelfContained>
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
@@ -19,9 +18,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="9.0.0" />
<PackageReference Include="System.Threading.Channels" Version="9.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
</ItemGroup>

View File

@@ -34,7 +34,6 @@ namespace GitHub.Services.Common
public String PropertyName { get; set; }
[Obsolete]
[SecurityCritical]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{

View File

@@ -127,7 +127,6 @@ namespace GitHub.Services.Common
EventId = (int)info.GetValue("m_eventId", typeof(int));
}
[Obsolete]
[SecurityCritical]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{

View File

@@ -30,7 +30,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
public const String If = "if";
public const String Image = "image";
public const String ImageName = "image-name";
public const String CustomImageVersion = "version";
public const String Include = "include";
public const String Inputs = "inputs";
public const String Job = "job";

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using GitHub.DistributedTask.Expressions2;
using GitHub.DistributedTask.Expressions2.Sdk;
@@ -350,10 +349,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
internal static Snapshot ConvertToJobSnapshotRequest(TemplateContext context, TemplateToken token)
{
string imageName = null;
string version = "1.*";
string versionString = string.Empty;
var condition = $"{PipelineTemplateConstants.Success}()";
if (token is StringToken snapshotStringLiteral)
{
imageName = snapshotStringLiteral.Value;
@@ -364,19 +359,11 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
foreach (var snapshotPropertyPair in snapshotMapping)
{
var propertyName = snapshotPropertyPair.Key.AssertString($"{PipelineTemplateConstants.Snapshot} key");
var propertyValue = snapshotPropertyPair.Value;
switch (propertyName.Value)
{
case PipelineTemplateConstants.ImageName:
imageName = snapshotPropertyPair.Value.AssertString($"{PipelineTemplateConstants.Snapshot} {propertyName}").Value;
break;
case PipelineTemplateConstants.If:
condition = ConvertToIfCondition(context, propertyValue, false);
break;
case PipelineTemplateConstants.CustomImageVersion:
versionString = propertyValue.AssertString($"job {PipelineTemplateConstants.Snapshot} {PipelineTemplateConstants.CustomImageVersion}").Value;
version = IsSnapshotImageVersionValid(versionString) ? versionString : null;
break;
default:
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Snapshot} key");
break;
@@ -389,26 +376,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
return null;
}
return new Snapshot(imageName)
{
Condition = condition,
Version = version
};
}
private static bool IsSnapshotImageVersionValid(string versionString)
{
var versionSegments = versionString.Split(".");
if (versionSegments.Length != 2 ||
!versionSegments[1].Equals("*") ||
!Int32.TryParse(versionSegments[0], NumberStyles.None, CultureInfo.InvariantCulture, result: out int parsedMajor) ||
parsedMajor < 0)
{
return false;
}
return true;
return new Snapshot(imageName);
}
private static ActionStep ConvertToStep(

View File

@@ -1,27 +1,17 @@
using System;
using System.Runtime.Serialization;
using GitHub.DistributedTask.ObjectTemplating.Tokens;
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
namespace GitHub.DistributedTask.Pipelines
{
[DataContract]
public class Snapshot
{
public Snapshot(string imageName, string condition = null, string version = null)
public Snapshot(string imageName)
{
ImageName = imageName;
Condition = condition ?? $"{PipelineTemplateConstants.Success}()";
Version = version ?? "1.*";
}
[DataMember(EmitDefaultValue = false)]
public String ImageName { get; set; }
[DataMember(EmitDefaultValue = false)]
public String Condition { get; set; }
[DataMember(EmitDefaultValue = false)]
public String Version { get; set; }
}
}

View File

@@ -169,28 +169,11 @@
"image-name": {
"type": "non-empty-string",
"required": true
},
"if": "snapshot-if",
"version": {
"type": "non-empty-string",
"required": false
}
}
}
},
"snapshot-if": {
"context": [
"github",
"inputs",
"vars",
"needs",
"strategy",
"matrix"
],
"string": {}
},
"runs-on": {
"context": [
"github",

View File

@@ -1539,26 +1539,6 @@ namespace GitHub.DistributedTask.WebApi
}
}
[Serializable]
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationJobUnprocessableException", "GitHub.DistributedTask.WebApi.TaskOrchestrationJobUnprocessableException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public sealed class TaskOrchestrationJobUnprocessableException : DistributedTaskException
{
public TaskOrchestrationJobUnprocessableException(String message)
: base(message)
{
}
public TaskOrchestrationJobUnprocessableException(String message, Exception innerException)
: base(message, innerException)
{
}
private TaskOrchestrationJobUnprocessableException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
}
[Serializable]
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationPlanSecurityException", "GitHub.DistributedTask.WebApi.TaskOrchestrationPlanSecurityException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public sealed class TaskOrchestrationPlanSecurityException : DistributedTaskException

View File

@@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Newtonsoft.Json;
namespace GitHub.DistributedTask.WebApi
{
[DataContract]
public class ServiceConnectivityCheckInput
{
[JsonConstructor]
public ServiceConnectivityCheckInput()
{
Endpoints = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
}
[DataMember(EmitDefaultValue = false)]
public Dictionary<string, string> Endpoints { get; set; }
[DataMember(EmitDefaultValue = false)]
public int IntervalInSecond { get; set; }
[DataMember(EmitDefaultValue = false)]
public int RequestTimeoutInSecond { get; set; }
}
[DataContract]
public class ServiceConnectivityCheckResult
{
[JsonConstructor]
public ServiceConnectivityCheckResult()
{
EndpointsResult = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
}
[DataMember(Order = 1, EmitDefaultValue = true)]
public bool HasFailure { get; set; }
[DataMember(Order = 2, EmitDefaultValue = false)]
public Dictionary<string, List<string>> EndpointsResult { get; set; }
}
}

View File

@@ -7,6 +7,5 @@ namespace GitHub.DistributedTask.WebApi
public static readonly String JobId = "system.jobId";
public static readonly String RunnerLowDiskspaceThreshold = "system.runner.lowdiskspacethreshold";
public static readonly String RunnerEnvironment = "system.runnerEnvironment";
public static readonly String RunnerServiceConnectivityTest = "system.runner.serviceconnectivitycheckinput";
}
}

View File

@@ -1,20 +0,0 @@
using System.Runtime.Serialization;
namespace GitHub.Actions.RunService.WebApi
{
[DataContract]
public class BrokerError
{
[DataMember(Name = "source", EmitDefaultValue = false)]
public string Source { get; set; }
[DataMember(Name = "errorKind", EmitDefaultValue = false)]
public string ErrorKind { get; set; }
[DataMember(Name = "statusCode", EmitDefaultValue = false)]
public int StatusCode { get; set; }
[DataMember(Name = "errorMessage", EmitDefaultValue = false)]
public string Message { get; set; }
}
}

View File

@@ -1,11 +0,0 @@
using System.Runtime.Serialization;
namespace GitHub.Actions.RunService.WebApi
{
[DataContract]
public class BrokerErrorKind
{
public const string RunnerNotFound = "RunnerNotFound";
public const string RunnerVersionTooOld = "RunnerVersionTooOld";
}
}

View File

@@ -27,9 +27,6 @@ namespace GitHub.Actions.RunService.WebApi
[DataMember(Name = "annotations", EmitDefaultValue = false)]
public IList<Annotation> Annotations { get; set; }
[DataMember(Name = "telemetry", EmitDefaultValue = false)]
public IList<Telemetry> Telemetry { get; set; }
[DataMember(Name = "environmentUrl", EmitDefaultValue = false)]
public string EnvironmentUrl { get; set; }
}

View File

@@ -1,17 +0,0 @@
using System.Runtime.Serialization;
namespace GitHub.Actions.RunService.WebApi
{
[DataContract]
public class RunServiceError
{
[DataMember(Name = "source", EmitDefaultValue = false)]
public string Source { get; set; }
[DataMember(Name = "statusCode", EmitDefaultValue = false)]
public int Code { get; set; }
[DataMember(Name = "errorMessage", EmitDefaultValue = false)]
public string Message { get; set; }
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading.Tasks;
@@ -16,20 +16,9 @@ namespace GitHub.Actions.RunService.WebApi
[DataMember(Name = "number", EmitDefaultValue = false)]
public int? Number { get; set; }
// Example: "Run actions/checkout@v3"
[DataMember(Name = "name", EmitDefaultValue = false)]
public string Name { get; set; }
// Example: "actions/checkout"
[DataMember(Name = "action_name", EmitDefaultValue = false)]
public string ActionName { get; set; }
[DataMember(Name = "ref", EmitDefaultValue = false)]
public string Ref { get; set; }
[DataMember(Name = "type", EmitDefaultValue = false)]
public string Type { get; set; }
[DataMember(Name = "status")]
public TimelineRecordState? Status { get; set; }

View File

@@ -1,20 +0,0 @@
using System.Runtime.Serialization;
namespace Sdk.RSWebApi.Contracts
{
[DataContract]
public struct Telemetry
{
public Telemetry(string message, string type)
{
Message = message;
Type = type;
}
[DataMember(Name = "message", EmitDefaultValue = false)]
public string Message { get; set; }
[DataMember(Name = "type", EmitDefaultValue = false)]
public string Type { get; set; }
}
}

View File

@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
@@ -87,7 +86,6 @@ namespace GitHub.Actions.RunService.WebApi
httpMethod,
requestUri: requestUri,
content: requestContent,
readErrorBody: true,
cancellationToken: cancellationToken);
if (result.IsSuccess)
@@ -95,26 +93,14 @@ namespace GitHub.Actions.RunService.WebApi
return result.Value;
}
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
switch (result.StatusCode)
{
switch ((HttpStatusCode)error.Code)
{
case HttpStatusCode.NotFound:
throw new TaskOrchestrationJobNotFoundException($"Job message not found '{messageId}'. {error.Message}");
case HttpStatusCode.Conflict:
throw new TaskOrchestrationJobAlreadyAcquiredException($"Job message already acquired '{messageId}'. {error.Message}");
case HttpStatusCode.UnprocessableEntity:
throw new TaskOrchestrationJobUnprocessableException($"Unprocessable job '{messageId}'. {error.Message}");
}
}
if (!string.IsNullOrEmpty(result.ErrorBody))
{
throw new Exception($"Failed to get job message: {result.Error}. {Truncate(result.ErrorBody)}");
}
else
{
throw new Exception($"Failed to get job message: {result.Error}");
case HttpStatusCode.NotFound:
throw new TaskOrchestrationJobNotFoundException($"Job message not found: {messageId}");
case HttpStatusCode.Conflict:
throw new TaskOrchestrationJobAlreadyAcquiredException($"Job message already acquired: {messageId}");
default:
throw new Exception($"Failed to get job message: {result.Error}");
}
}
@@ -122,12 +108,11 @@ namespace GitHub.Actions.RunService.WebApi
Uri requestUri,
Guid planId,
Guid jobId,
TaskResult conclusion,
TaskResult result,
Dictionary<String, VariableValue> outputs,
IList<StepResult> stepResults,
IList<Annotation> jobAnnotations,
string environmentUrl,
IList<Telemetry> telemetry,
CancellationToken cancellationToken = default)
{
HttpMethod httpMethod = new HttpMethod("POST");
@@ -135,43 +120,32 @@ namespace GitHub.Actions.RunService.WebApi
{
PlanID = planId,
JobID = jobId,
Conclusion = conclusion,
Conclusion = result,
Outputs = outputs,
StepResults = stepResults,
Annotations = jobAnnotations,
EnvironmentUrl = environmentUrl,
Telemetry = telemetry,
};
requestUri = new Uri(requestUri, "completejob");
var requestContent = new ObjectContent<CompleteJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
var result = await Send2Async(
var response = await SendAsync(
httpMethod,
requestUri,
content: requestContent,
cancellationToken: cancellationToken);
if (result.IsSuccess)
if (response.IsSuccessStatusCode)
{
return;
}
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
switch (response.StatusCode)
{
switch ((HttpStatusCode)error.Code)
{
case HttpStatusCode.NotFound:
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}. {error.Message}");
}
}
if (!string.IsNullOrEmpty(result.ErrorBody))
{
throw new Exception($"Failed to complete job: {result.Error}. {Truncate(result.ErrorBody)}");
}
else
{
throw new Exception($"Failed to complete job: {result.Error}");
case HttpStatusCode.NotFound:
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
default:
throw new Exception($"Failed to complete job: {response.ReasonPhrase}");
}
}
@@ -195,7 +169,6 @@ namespace GitHub.Actions.RunService.WebApi
httpMethod,
requestUri,
content: requestContent,
readErrorBody: true,
cancellationToken: cancellationToken);
if (result.IsSuccess)
@@ -203,22 +176,12 @@ namespace GitHub.Actions.RunService.WebApi
return result.Value;
}
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
switch (result.StatusCode)
{
switch ((HttpStatusCode)error.Code)
{
case HttpStatusCode.NotFound:
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}. {error.Message}");
}
}
if (!string.IsNullOrEmpty(result.ErrorBody))
{
throw new Exception($"Failed to renew job: {result.Error}. {Truncate(result.ErrorBody)}");
}
else
{
throw new Exception($"Failed to renew job: {result.Error}");
case HttpStatusCode.NotFound:
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
default:
throw new Exception($"Failed to renew job: {result.Error}");
}
}
@@ -227,36 +190,5 @@ namespace GitHub.Actions.RunService.WebApi
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
}
private static bool TryParseErrorBody(string errorBody, out RunServiceError error)
{
if (!string.IsNullOrEmpty(errorBody))
{
try
{
error = JsonUtility.FromString<RunServiceError>(errorBody);
if (error?.Source == "actions-run-service")
{
return true;
}
}
catch (Exception)
{
}
}
error = null;
return false;
}
private static string Truncate(string errorBody)
{
if (errorBody.Length > 100)
{
return errorBody.Substring(0, 100) + "[truncated]";
}
return errorBody;
}
}
}

View File

@@ -1,12 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<OutputType>Library</OutputType>
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
<!-- <SelfContained>true</SelfContained> -->
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
<NoWarn>NU1701;NU1603</NoWarn>
<Version>$(Version)</Version>
<DefineConstants>TRACE</DefineConstants>
<LangVersion>8.0</LangVersion>
@@ -14,20 +13,18 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Storage.Blobs" Version="12.23.0" />
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="9.0.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.2.1" />
<PackageReference Include="System.Security.Cryptography.Cng" Version="4.4.0" />
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="4.4.0" />
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
<PackageReference Include="Minimatch" Version="2.0.0" />
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
<PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
<PackageReference Include="System.Formats.Asn1" Version="8.0.1" />
</ItemGroup>
<ItemGroup>

View File

@@ -103,7 +103,6 @@ namespace GitHub.Actions.RunService.WebApi
new HttpMethod("GET"),
requestUri: requestUri,
queryParameters: queryParams,
readErrorBody: true,
cancellationToken: cancellationToken);
if (result.IsSuccess)
@@ -111,23 +110,8 @@ namespace GitHub.Actions.RunService.WebApi
return result.Value;
}
if (TryParseErrorBody(result.ErrorBody, out BrokerError brokerError))
{
switch (brokerError.ErrorKind)
{
case BrokerErrorKind.RunnerNotFound:
throw new RunnerNotFoundException(brokerError.Message);
case BrokerErrorKind.RunnerVersionTooOld:
throw new AccessDeniedException(brokerError.Message)
{
ErrorCode = 1
};
default:
break;
}
}
// temporary back compat
// the only time we throw a `Forbidden` exception from Listener /messages is when the runner is
// disable_update and is too old to poll
if (result.StatusCode == HttpStatusCode.Forbidden)
{
throw new AccessDeniedException($"{result.Error} Runner version v{runnerVersion} is deprecated and cannot receive messages.")
@@ -136,7 +120,7 @@ namespace GitHub.Actions.RunService.WebApi
};
}
throw new Exception($"Failed to get job message. Request to {requestUri} failed with status: {result.StatusCode}. Error message {result.Error}");
throw new Exception($"Failed to get job message: {result.Error}");
}
public async Task<TaskAgentSession> CreateSessionAsync(
@@ -188,26 +172,5 @@ namespace GitHub.Actions.RunService.WebApi
throw new Exception($"Failed to delete broker session: {result.Error}");
}
private static bool TryParseErrorBody(string errorBody, out BrokerError error)
{
if (!string.IsNullOrEmpty(errorBody))
{
try
{
error = JsonUtility.FromString<BrokerError>(errorBody);
if (error?.Source == "actions-broker-listener")
{
return true;
}
}
catch (Exception)
{
}
}
error = null;
return false;
}
}
}

View File

@@ -1,26 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using GitHub.Services.Common;
using GitHub.Services.WebApi;
namespace GitHub.Services.WebApi
{
[Serializable]
public sealed class RunnerNotFoundException : Exception
{
public RunnerNotFoundException()
: base()
{
}
public RunnerNotFoundException(String message)
: base(message)
{
}
public RunnerNotFoundException(String message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@@ -85,7 +85,6 @@ namespace GitHub.Services.OAuth
set;
}
[Obsolete]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
base.GetObjectData(info, context);

View File

@@ -101,55 +101,15 @@ namespace Sdk.WebApi.WebApi
}
}
protected async Task<RawHttpClientResult> Send2Async(
HttpMethod method,
Uri requestUri,
HttpContent content = null,
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
Object userState = null,
CancellationToken cancellationToken = default(CancellationToken))
{
using (var response = await SendAsync(method, requestUri, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
{
if (response.IsSuccessStatusCode)
{
return new RawHttpClientResult(
isSuccess: true,
error: string.Empty,
statusCode: response.StatusCode);
}
else
{
var errorBody = default(string);
try
{
errorBody = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
errorBody = $"Error reading HTTP response body: {ex.Message}";
}
string errorMessage = $"Error: {response.ReasonPhrase}";
return new RawHttpClientResult(
isSuccess: false,
error: errorMessage,
statusCode: response.StatusCode,
errorBody: errorBody);
}
}
}
protected Task<RawHttpClientResult<T>> SendAsync<T>(
HttpMethod method,
Uri requestUri,
HttpContent content = null,
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
Boolean readErrorBody = false,
Object userState = null,
CancellationToken cancellationToken = default(CancellationToken))
{
return SendAsync<T>(method, null, requestUri, content, queryParameters, readErrorBody, userState, cancellationToken);
return SendAsync<T>(method, null, requestUri, content, queryParameters, userState, cancellationToken);
}
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
@@ -158,20 +118,18 @@ namespace Sdk.WebApi.WebApi
Uri requestUri,
HttpContent content = null,
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
Boolean readErrorBody = false,
Object userState = null,
CancellationToken cancellationToken = default(CancellationToken))
{
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
using (HttpRequestMessage requestMessage = CreateRequestMessage(method, additionalHeaders, requestUri, content, queryParameters))
{
return await SendAsync<T>(requestMessage, readErrorBody, userState, cancellationToken).ConfigureAwait(false);
return await SendAsync<T>(requestMessage, userState, cancellationToken).ConfigureAwait(false);
}
}
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
HttpRequestMessage message,
Boolean readErrorBody = false,
Object userState = null,
CancellationToken cancellationToken = default(CancellationToken))
{
@@ -187,21 +145,8 @@ namespace Sdk.WebApi.WebApi
}
else
{
var errorBody = default(string);
if (readErrorBody)
{
try
{
errorBody = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
errorBody = $"Error reading HTTP response body: {ex.Message}";
}
}
string errorMessage = $"Error: {response.ReasonPhrase}";
return RawHttpClientResult<T>.Fail(errorMessage, response.StatusCode, errorBody);
return RawHttpClientResult<T>.Fail(errorMessage, response.StatusCode);
}
}
}

View File

@@ -5,27 +5,15 @@ namespace Sdk.WebApi.WebApi
public class RawHttpClientResult
{
public bool IsSuccess { get; protected set; }
/// <summary>
/// A description of the HTTP status code, like "Error: Unprocessable Entity"
/// </summary>
public string Error { get; protected set; }
/// <summary>
/// The HTTP response body for unsuccessful HTTP status codes, or an error message when reading the response body fails.
/// </summary>
public string ErrorBody { get; protected set; }
public HttpStatusCode StatusCode { get; protected set; }
public bool IsFailure => !IsSuccess;
public RawHttpClientResult(bool isSuccess, string error, HttpStatusCode statusCode, string errorBody = null)
protected RawHttpClientResult(bool isSuccess, string error, HttpStatusCode statusCode)
{
IsSuccess = isSuccess;
Error = error;
StatusCode = statusCode;
ErrorBody = errorBody;
}
}
@@ -33,13 +21,13 @@ namespace Sdk.WebApi.WebApi
{
public T Value { get; private set; }
protected internal RawHttpClientResult(T value, bool isSuccess, string error, HttpStatusCode statusCode, string errorBody)
: base(isSuccess, error, statusCode, errorBody)
protected internal RawHttpClientResult(T value, bool isSuccess, string error, HttpStatusCode statusCode)
: base(isSuccess, error, statusCode)
{
Value = value;
}
public static RawHttpClientResult<T> Fail(string message, HttpStatusCode statusCode, string errorBody) => new RawHttpClientResult<T>(default(T), false, message, statusCode, errorBody);
public static RawHttpClientResult<T> Ok(T value) => new RawHttpClientResult<T>(value, true, string.Empty, HttpStatusCode.OK, null);
public static RawHttpClientResult<T> Fail(string message, HttpStatusCode statusCode) => new RawHttpClientResult<T>(default(T), false, message, statusCode);
public static RawHttpClientResult<T> Ok(T value) => new RawHttpClientResult<T>(value, true, string.Empty, HttpStatusCode.OK);
}
}

View File

@@ -24,7 +24,6 @@ namespace GitHub.Services.WebApi
HttpStatusCode = (HttpStatusCode)info.GetInt32("HttpStatusCode");
}
[Obsolete]
[SecurityCritical]
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{

View File

@@ -68,7 +68,7 @@ namespace GitHub.Runner.Common.Tests
trace.Info("Parsed");
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("Args: {0}", clp.Args.Count);
Assert.Equal(2, clp.Args.Count);
Assert.True(clp.Args.Count == 2);
Assert.True(clp.Args.ContainsKey("arg1"));
Assert.Equal("arg1val", clp.Args["arg1"]);
Assert.True(clp.Args.ContainsKey("arg2"));
@@ -112,7 +112,7 @@ namespace GitHub.Runner.Common.Tests
trace.Info("Parsed");
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("flag2", clp.Flags);
}

View File

@@ -24,7 +24,7 @@ namespace GitHub.Runner.Common.Tests
"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}'");
}
}

View File

@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task CreatesSession()
public async void CreatesSession()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())

View File

@@ -806,7 +806,7 @@ namespace GitHub.Runner.Common.Tests
"test runner" });
// 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}" });
// 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 });
// Assert.
Assert.Equal(0, command.Validate().Count);
Assert.True(command.Validate().Count == 0);
}
}

View File

@@ -190,11 +190,11 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
trace.Info("Configured, verifying all the parameter value");
var s = configManager.LoadSettings();
Assert.NotNull(s);
Assert.Equal(_expectedServerUrl, s.ServerUrl);
Assert.Equal(_expectedAgentName, s.AgentName);
Assert.Equal(_secondRunnerGroupId, s.PoolId);
Assert.Equal(_expectedWorkFolder, s.WorkFolder);
Assert.True(s.Ephemeral);
Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
Assert.True(s.AgentName.Equals(_expectedAgentName));
Assert.True(s.PoolId.Equals(_secondRunnerGroupId));
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
Assert.True(s.Ephemeral.Equals(true));
// 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));
@@ -292,11 +292,11 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
trace.Info("Configured, verifying all the parameter value");
var s = configManager.LoadSettings();
Assert.NotNull(s);
Assert.Equal(_expectedServerUrl, s.ServerUrl);
Assert.Equal(_expectedAgentName, s.AgentName);
Assert.Equal(_secondRunnerGroupId, s.PoolId);
Assert.Equal(_expectedWorkFolder, s.WorkFolder);
Assert.True(s.Ephemeral);
Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
Assert.True(s.AgentName.Equals(_expectedAgentName));
Assert.True(s.PoolId.Equals(_secondRunnerGroupId));
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
Assert.True(s.Ephemeral.Equals(true));
// 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));

View File

@@ -1,213 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using GitHub.DistributedTask.WebApi;
using GitHub.Runner.Listener;
using GitHub.Runner.Listener.Configuration;
using GitHub.Runner.Common.Tests;
using System.Runtime.CompilerServices;
using GitHub.Services.WebApi;
using Moq;
using Xunit;
namespace GitHub.Runner.Common.Tests.Listener
{
public sealed class ErrorThrottlerL0
{
[Theory]
[InlineData(1)]
[InlineData(2)]
[InlineData(3)]
[InlineData(4)]
[InlineData(5)]
[InlineData(6)]
[InlineData(7)]
[InlineData(8)]
public async Task TestIncrementAndWait(int totalAttempts)
{
using (TestHostContext hc = CreateTestContext())
{
// Arrange
var errorThrottler = new ErrorThrottler();
errorThrottler.Initialize(hc);
var eventArgs = new List<DelayEventArgs>();
hc.Delaying += (sender, args) =>
{
eventArgs.Add(args);
};
// Act
for (int attempt = 1; attempt <= totalAttempts; attempt++)
{
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
}
// Assert
Assert.Equal(totalAttempts - 1, eventArgs.Count);
for (int i = 0; i < eventArgs.Count; i++)
{
// Expected milliseconds
int expectedMin;
int expectedMax;
switch (i)
{
case 0:
expectedMin = 1000; // Min backoff
expectedMax = 1000;
break;
case 1:
expectedMin = 1800; // Min + 0.8 * Coefficient
expectedMax = 2200; // Min + 1.2 * Coefficient
break;
case 2:
expectedMin = 3400; // Min + 0.8 * Coefficient * 3
expectedMax = 4600; // Min + 1.2 * Coefficient * 3
break;
case 3:
expectedMin = 6600; // Min + 0.8 * Coefficient * 7
expectedMax = 9400; // Min + 1.2 * Coefficient * 7
break;
case 4:
expectedMin = 13000; // Min + 0.8 * Coefficient * 15
expectedMax = 19000; // Min + 1.2 * Coefficient * 15
break;
case 5:
expectedMin = 25800; // Min + 0.8 * Coefficient * 31
expectedMax = 38200; // Min + 1.2 * Coefficient * 31
break;
case 6:
expectedMin = 51400; // Min + 0.8 * Coefficient * 63
expectedMax = 60000; // Max backoff
break;
case 7:
expectedMin = 60000;
expectedMax = 60000;
break;
default:
throw new NotSupportedException("Unexpected eventArgs count");
}
var actualMilliseconds = eventArgs[i].Delay.TotalMilliseconds;
Assert.True(expectedMin <= actualMilliseconds, $"Unexpected min delay for eventArgs[{i}]. Expected min {expectedMin}, actual {actualMilliseconds}");
Assert.True(expectedMax >= actualMilliseconds, $"Unexpected max delay for eventArgs[{i}]. Expected max {expectedMax}, actual {actualMilliseconds}");
}
}
}
[Fact]
public async Task TestReset()
{
using (TestHostContext hc = CreateTestContext())
{
// Arrange
var errorThrottler = new ErrorThrottler();
errorThrottler.Initialize(hc);
var eventArgs = new List<DelayEventArgs>();
hc.Delaying += (sender, args) =>
{
eventArgs.Add(args);
};
// Act
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
errorThrottler.Reset();
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
// Assert
Assert.Equal(4, eventArgs.Count);
for (int i = 0; i < eventArgs.Count; i++)
{
// Expected milliseconds
int expectedMin;
int expectedMax;
switch (i)
{
case 0:
case 2:
expectedMin = 1000; // Min backoff
expectedMax = 1000;
break;
case 1:
case 3:
expectedMin = 1800; // Min + 0.8 * Coefficient
expectedMax = 2200; // Min + 1.2 * Coefficient
break;
default:
throw new NotSupportedException("Unexpected eventArgs count");
}
var actualMilliseconds = eventArgs[i].Delay.TotalMilliseconds;
Assert.True(expectedMin <= actualMilliseconds, $"Unexpected min delay for eventArgs[{i}]. Expected min {expectedMin}, actual {actualMilliseconds}");
Assert.True(expectedMax >= actualMilliseconds, $"Unexpected max delay for eventArgs[{i}]. Expected max {expectedMax}, actual {actualMilliseconds}");
}
}
}
[Fact]
public async Task TestReceivesCancellationToken()
{
using (TestHostContext hc = CreateTestContext())
{
// Arrange
var errorThrottler = new ErrorThrottler();
errorThrottler.Initialize(hc);
var eventArgs = new List<DelayEventArgs>();
hc.Delaying += (sender, args) =>
{
eventArgs.Add(args);
};
var cancellationTokenSource1 = new CancellationTokenSource();
var cancellationTokenSource2 = new CancellationTokenSource();
var cancellationTokenSource3 = new CancellationTokenSource();
// Act
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource1.Token);
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource2.Token);
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource3.Token);
// Assert
Assert.Equal(2, eventArgs.Count);
Assert.Equal(cancellationTokenSource2.Token, eventArgs[0].Token);
Assert.Equal(cancellationTokenSource3.Token, eventArgs[1].Token);
}
}
[Fact]
public async Task TestReceivesSender()
{
using (TestHostContext hc = CreateTestContext())
{
// Arrange
var errorThrottler = new ErrorThrottler();
errorThrottler.Initialize(hc);
var senders = new List<object>();
hc.Delaying += (sender, args) =>
{
senders.Add(sender);
};
// Act
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
// Assert
Assert.Equal(2, senders.Count);
Assert.Equal(hc, senders[0]);
Assert.Equal(hc, senders[1]);
}
}
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
{
return new TestHostContext(this, testName);
}
}
}

View File

@@ -49,7 +49,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatchesJobRequest()
public async void DispatchesJobRequest()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -99,7 +99,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobRequest()
public async void DispatcherRenewJobRequest()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -157,7 +157,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobRequestStopOnJobNotFoundExceptions()
public async void DispatcherRenewJobRequestStopOnJobNotFoundExceptions()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -216,7 +216,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobOnRunServiceStopOnJobNotFoundExceptions()
public async void DispatcherRenewJobOnRunServiceStopOnJobNotFoundExceptions()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -285,7 +285,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobRequestStopOnJobTokenExpiredExceptions()
public async void DispatcherRenewJobRequestStopOnJobTokenExpiredExceptions()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -344,7 +344,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task RenewJobRequestNewAgentNameUpdatesSettings()
public async void RenewJobRequestNewAgentNameUpdatesSettings()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -401,7 +401,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task RenewJobRequestSameAgentNameIgnored()
public async void RenewJobRequestSameAgentNameIgnored()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -456,7 +456,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task RenewJobRequestNullAgentNameIgnored()
public async void RenewJobRequestNullAgentNameIgnored()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -509,7 +509,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobRequestRecoverFromExceptions()
public async void DispatcherRenewJobRequestRecoverFromExceptions()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -570,7 +570,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobRequestFirstRenewRetrySixTimes()
public async void DispatcherRenewJobRequestFirstRenewRetrySixTimes()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -625,7 +625,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatcherRenewJobRequestStopOnExpiredRequest()
public async void DispatcherRenewJobRequestStopOnExpiredRequest()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -691,7 +691,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DispatchesOneTimeJobRequest()
public async void DispatchesOneTimeJobRequest()
{
//Arrange
using (var hc = new TestHostContext(this))
@@ -734,10 +734,7 @@ namespace GitHub.Runner.Common.Tests.Listener
await jobDispatcher.WaitAsync(CancellationToken.None);
Assert.True(jobDispatcher.RunOnceJobCompleted.Task.IsCompleted, "JobDispatcher should set task complete token for one time agent.");
if (jobDispatcher.RunOnceJobCompleted.Task.IsCompleted)
{
Assert.True(await jobDispatcher.RunOnceJobCompleted.Task, "JobDispatcher should set task complete token to 'TRUE' for one time agent.");
}
Assert.True(jobDispatcher.RunOnceJobCompleted.Task.Result, "JobDispatcher should set task complete token to 'TRUE' for one time agent.");
}
}

View File

@@ -51,7 +51,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task CreatesSession()
public async void CreatesSession()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -95,7 +95,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task CreatesSessionWithBrokerMigration()
public async void CreatesSessionWithBrokerMigration()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -157,7 +157,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DeleteSession()
public async void DeleteSession()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -204,7 +204,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task DeleteSessionWithBrokerMigration()
public async void DeleteSessionWithBrokerMigration()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -281,7 +281,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task GetNextMessage()
public async void GetNextMessage()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -362,7 +362,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task GetNextMessageWithBrokerMigration()
public async void GetNextMessageWithBrokerMigration()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -468,7 +468,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task CreateSessionWithOriginalCredential()
public async void CreateSessionWithOriginalCredential()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())
@@ -513,7 +513,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task SkipDeleteSession_WhenGetNextMessageGetTaskAgentAccessTokenExpiredException()
public async void SkipDeleteSession_WhenGetNextMessageGetTaskAgentAccessTokenExpiredException()
{
using (TestHostContext tc = CreateTestContext())
using (var tokenSource = new CancellationTokenSource())

View File

@@ -23,7 +23,6 @@ namespace GitHub.Runner.Common.Tests.Listener
private Mock<ITerminal> _term;
private Mock<IConfigurationStore> _configStore;
private Mock<ISelfUpdater> _updater;
private Mock<IErrorThrottler> _acquireJobThrottler;
public RunnerL0()
{
@@ -36,7 +35,6 @@ namespace GitHub.Runner.Common.Tests.Listener
_term = new Mock<ITerminal>();
_configStore = new Mock<IConfigurationStore>();
_updater = new Mock<ISelfUpdater>();
_acquireJobThrottler = new Mock<IErrorThrottler>();
}
private Pipelines.AgentJobRequestMessage CreateJobRequestMessage(string jobName)
@@ -57,7 +55,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
//process 2 new job messages, and one cancel message
public async Task TestRunAsync()
public async void TestRunAsync()
{
using (var hc = new TestHostContext(this))
{
@@ -69,7 +67,6 @@ namespace GitHub.Runner.Common.Tests.Listener
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
runner.Initialize(hc);
var settings = new RunnerSettings
{
@@ -129,7 +126,7 @@ namespace GitHub.Runner.Common.Tests.Listener
//wait for the runner to run one job
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
{
@@ -169,7 +166,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[MemberData(nameof(RunAsServiceTestData))]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestExecuteCommandForRunAsService(string[] args, bool configureAsService, Times expectedTimes)
public async void TestExecuteCommandForRunAsService(string[] args, bool configureAsService, Times expectedTimes)
{
using (var hc = new TestHostContext(this))
{
@@ -177,7 +174,6 @@ namespace GitHub.Runner.Common.Tests.Listener
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
var command = new CommandSettings(hc, args);
@@ -201,7 +197,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestMachineProvisionerCLI()
public async void TestMachineProvisionerCLI()
{
using (var hc = new TestHostContext(this))
{
@@ -209,7 +205,6 @@ namespace GitHub.Runner.Common.Tests.Listener
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IMessageListener>(_messageListener.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
var command = new CommandSettings(hc, new[] { "run" });
@@ -235,7 +230,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestRunOnce()
public async void TestRunOnce()
{
using (var hc = new TestHostContext(this))
{
@@ -247,7 +242,6 @@ namespace GitHub.Runner.Common.Tests.Listener
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
runner.Initialize(hc);
var settings = new RunnerSettings
{
@@ -311,11 +305,8 @@ namespace GitHub.Runner.Common.Tests.Listener
await Task.WhenAny(runnerTask, Task.Delay(30000));
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
Assert.False(runnerTask.IsFaulted, runnerTask.Exception?.ToString());
if (runnerTask.IsCompleted)
{
Assert.Equal(Constants.Runner.ReturnCode.Success, await runnerTask);
}
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.Success);
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
@@ -332,7 +323,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestRunOnceOnlyTakeOneJobMessage()
public async void TestRunOnceOnlyTakeOneJobMessage()
{
using (var hc = new TestHostContext(this))
{
@@ -344,7 +335,6 @@ namespace GitHub.Runner.Common.Tests.Listener
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
runner.Initialize(hc);
var settings = new RunnerSettings
{
@@ -416,10 +406,7 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
if (runnerTask.IsCompleted)
{
Assert.Equal(Constants.Runner.ReturnCode.Success, await runnerTask);
}
Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.Success);
_jobDispatcher.Verify(x => x.Run(It.IsAny<Pipelines.AgentJobRequestMessage>(), true), Times.Once(),
$"{nameof(_jobDispatcher.Object.Run)} was not invoked.");
@@ -433,7 +420,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestRunOnceHandleUpdateMessage()
public async void TestRunOnceHandleUpdateMessage()
{
using (var hc = new TestHostContext(this))
{
@@ -446,7 +433,6 @@ namespace GitHub.Runner.Common.Tests.Listener
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.SetSingleton<ISelfUpdater>(_updater.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
runner.Initialize(hc);
var settings = new RunnerSettings
@@ -506,10 +492,7 @@ namespace GitHub.Runner.Common.Tests.Listener
Assert.True(runnerTask.IsCompleted, $"{nameof(runner.ExecuteCommand)} timed out.");
Assert.True(!runnerTask.IsFaulted, runnerTask.Exception?.ToString());
if (runnerTask.IsCompleted)
{
Assert.Equal(Constants.Runner.ReturnCode.RunOnceRunnerUpdating, await runnerTask);
}
Assert.True(runnerTask.Result == Constants.Runner.ReturnCode.RunOnceRunnerUpdating);
_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());
@@ -523,14 +506,13 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestRemoveLocalRunnerConfig()
public async void TestRemoveLocalRunnerConfig()
{
using (var hc = new TestHostContext(this))
{
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
hc.SetSingleton<IPromptManager>(_promptManager.Object);
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
var command = new CommandSettings(hc, new[] { "remove", "--local" });

View File

@@ -78,7 +78,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync()
public async void TestSelfUpdateAsync()
{
try
{
@@ -137,7 +137,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync_NoUpdateOnOldVersion()
public async void TestSelfUpdateAsync_NoUpdateOnOldVersion()
{
try
{
@@ -188,7 +188,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync_DownloadRetry()
public async void TestSelfUpdateAsync_DownloadRetry()
{
try
{
@@ -241,7 +241,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync_ValidateHash()
public async void TestSelfUpdateAsync_ValidateHash()
{
try
{

View File

@@ -74,7 +74,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync()
public async void TestSelfUpdateAsync()
{
try
{
@@ -134,7 +134,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync_DownloadRetry()
public async void TestSelfUpdateAsync_DownloadRetry()
{
try
{
@@ -183,7 +183,7 @@ namespace GitHub.Runner.Common.Tests.Listener
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public async Task TestSelfUpdateAsync_ValidateHash()
public async void TestSelfUpdateAsync_ValidateHash()
{
try
{

View File

@@ -27,9 +27,9 @@ namespace GitHub.Runner.Common.Tests
try
{
#if OS_WINDOWS
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node20\bin\node");
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
#else
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node20/bin/node");
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
hc.EnqueueInstance<IProcessInvoker>(new ProcessInvokerWrapper());
#endif
var startInfo = new ProcessStartInfo(node, "-e \"setTimeout(function(){{}}, 15 * 1000);\"");
@@ -58,7 +58,7 @@ namespace GitHub.Runner.Common.Tests
trace.Error(ex);
}
Assert.Fail("Failed to retrieve process environment variable.");
Assert.True(false, "Fail to retrive process environment variable.");
}
finally
{

View File

@@ -65,14 +65,7 @@ namespace GitHub.Runner.Common.Tests
}
}
if (badCode.Count > 0)
{
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);
}
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)}");
}
[Fact]
@@ -119,14 +112,7 @@ namespace GitHub.Runner.Common.Tests
}
}
if (badCode.Count > 0)
{
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);
}
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)}");
}
[Fact]

View File

@@ -30,11 +30,9 @@ namespace GitHub.Runner.Common.Tests
private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D"));
private StartupType _startupType;
public event EventHandler Unloading;
public event EventHandler<DelayEventArgs> Delaying;
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
public ShutdownReason RunnerShutdownReason { get; private set; }
public ISecretMasker SecretMasker => _secretMasker;
public TestHostContext(object testClass, [CallerMemberName] string testName = "")
{
ArgUtil.NotNull(testClass, nameof(testClass));
@@ -94,14 +92,6 @@ namespace GitHub.Runner.Common.Tests
public async Task Delay(TimeSpan delay, CancellationToken token)
{
// Event callback
EventHandler<DelayEventArgs> handler = Delaying;
if (handler != null)
{
handler(this, new DelayEventArgs(delay, token));
}
// Delay zero
await Task.Delay(TimeSpan.Zero);
}
@@ -370,25 +360,5 @@ namespace GitHub.Runner.Common.Tests
Unloading(this, null);
}
}
public void LoadDefaultUserAgents()
{
return;
}
}
public class DelayEventArgs : EventArgs
{
public DelayEventArgs(
TimeSpan delay,
CancellationToken token)
{
Delay = delay;
Token = token;
}
public TimeSpan Delay { get; }
public CancellationToken Token { get; }
}
}

View File

@@ -38,7 +38,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_DownloadActionFromDotCom_OnPremises_Legacy()
public async void PrepareActions_DownloadActionFromDotCom_OnPremises_Legacy()
{
try
{
@@ -99,7 +99,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_DownloadActionFromDotCom_ZipFileError()
public async void PrepareActions_DownloadActionFromDotCom_ZipFileError()
{
try
{
@@ -156,7 +156,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_DownloadUnknownActionFromGraph_OnPremises_Legacy()
public async void PrepareActions_DownloadUnknownActionFromGraph_OnPremises_Legacy()
{
try
{
@@ -216,7 +216,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_PullImageFromDockerHub()
public async void PrepareActions_PullImageFromDockerHub()
{
try
{
@@ -254,7 +254,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_DownloadActionFromGraph()
public async void PrepareActions_DownloadActionFromGraph()
{
try
{
@@ -296,7 +296,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_DownloadActionFromGraph_UseCache()
public async void PrepareActions_DownloadActionFromGraph_UseCache()
{
try
{
@@ -406,7 +406,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_AlwaysClearActionsCache()
public async void PrepareActions_AlwaysClearActionsCache()
{
try
{
@@ -436,7 +436,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_SkipDownloadActionForSelfRepo()
public async void PrepareActions_SkipDownloadActionForSelfRepo()
{
try
{
@@ -460,7 +460,7 @@ runs:
//Act
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
Assert.Equal(0, steps.Count);
Assert.True(steps.Count == 0);
}
finally
{
@@ -472,7 +472,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithDockerfile()
public async void PrepareActions_RepositoryActionWithDockerfile()
{
try
{
@@ -511,7 +511,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithDockerfileInRelativePath()
public async void PrepareActions_RepositoryActionWithDockerfileInRelativePath()
{
try
{
@@ -552,7 +552,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithActionfile_Dockerfile()
public async void PrepareActions_RepositoryActionWithActionfile_Dockerfile()
{
try
{
@@ -591,7 +591,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithActionfile_DockerfileRelativePath()
public async void PrepareActions_RepositoryActionWithActionfile_DockerfileRelativePath()
{
try
{
@@ -631,7 +631,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithActionfile_DockerHubImage()
public async void PrepareActions_RepositoryActionWithActionfile_DockerHubImage()
{
try
{
@@ -670,7 +670,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithActionYamlFile_DockerHubImage()
public async void PrepareActions_RepositoryActionWithActionYamlFile_DockerHubImage()
{
try
{
@@ -709,7 +709,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithActionfileAndDockerfile()
public async void PrepareActions_RepositoryActionWithActionfileAndDockerfile()
{
try
{
@@ -749,7 +749,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_NotPullOrBuildImagesMultipleTimes()
public async void PrepareActions_NotPullOrBuildImagesMultipleTimes()
{
try
{
@@ -889,7 +889,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithActionfile_Node()
public async void PrepareActions_RepositoryActionWithActionfile_Node()
{
try
{
@@ -915,7 +915,7 @@ runs:
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
// 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
{
@@ -926,7 +926,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithInvalidWrapperActionfile_Node()
public async void PrepareActions_RepositoryActionWithInvalidWrapperActionfile_Node()
{
try
{
@@ -969,7 +969,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_RepositoryActionWithWrapperActionfile_PreSteps()
public async void PrepareActions_RepositoryActionWithWrapperActionfile_PreSteps()
{
try
{
@@ -1024,7 +1024,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_CompositeActionWithActionfile_Node()
public async void PrepareActions_CompositeActionWithActionfile_Node()
{
try
{
@@ -1051,7 +1051,7 @@ runs:
var steps = (await _actionManager.PrepareActionsAsync(_ec.Object, actions)).ContainerSetupSteps;
// 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");
Assert.True(File.Exists(watermarkFile));
// Comes from the composite action
@@ -1067,7 +1067,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_CompositeActionWithActionfile_MaxLimit()
public async void PrepareActions_CompositeActionWithActionfile_MaxLimit()
{
try
{
@@ -1107,7 +1107,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_CompositeActionWithActionfile_CompositePrestepNested()
public async void PrepareActions_CompositeActionWithActionfile_CompositePrestepNested()
{
try
{
@@ -1149,7 +1149,7 @@ runs:
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task PrepareActions_CompositeActionWithActionfile_CompositeContainerNested()
public async void PrepareActions_CompositeActionWithActionfile_CompositeContainerNested()
{
try
{
@@ -1245,7 +1245,7 @@ runs:
// Assert.
Assert.NotNull(definition);
Assert.NotNull(definition.Data);
Assert.Equal(ActionExecutionType.Script, definition.Data.Execution.ExecutionType);
Assert.True(definition.Data.Execution.ExecutionType == ActionExecutionType.Script);
}
finally
{

View File

@@ -11,7 +11,6 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
using Pipelines = GitHub.DistributedTask.Pipelines;
@@ -34,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task MergeDefaultInputs()
public async void MergeDefaultInputs()
{
//Arrange
Setup();
@@ -80,7 +79,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task WriteEventPayload()
public async void WriteEventPayload()
{
//Arrange
Setup();
@@ -320,7 +319,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task WarnInvalidInputs()
public async void WarnInvalidInputs()
{
//Arrange
Setup();
@@ -373,7 +372,7 @@ namespace GitHub.Runner.Common.Tests.Worker
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public async Task SetGitHubContextActionRepoRef()
public async void SetGitHubContextActionRepoRef()
{
//Arrange
Setup();

Some files were not shown because too many files have changed in this diff Show More