mirror of
https://github.com/actions/runner.git
synced 2025-12-10 12:36:23 +00:00
Compare commits
67 Commits
feature/do
...
v2.322.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0edc478ca7 | ||
|
|
fccbe8fb0b | ||
|
|
e3bc10a931 | ||
|
|
ba50bf6482 | ||
|
|
8eef71d93d | ||
|
|
7ae9fc03a2 | ||
|
|
8e97ad4d86 | ||
|
|
aa76aa476f | ||
|
|
0738df9702 | ||
|
|
8bf52ffe7d | ||
|
|
9df3fc825d | ||
|
|
fde5227fbf | ||
|
|
27f6ca8177 | ||
|
|
078eb3b381 | ||
|
|
c46dac6736 | ||
|
|
e640a9fef3 | ||
|
|
6d266a7c44 | ||
|
|
4700649bb5 | ||
|
|
27580ef8de | ||
|
|
6c94f78f37 | ||
|
|
074d9c0922 | ||
|
|
59f2be2158 | ||
|
|
1e1f7845fa | ||
|
|
694ae12b23 | ||
|
|
d16fb2c593 | ||
|
|
d37a7ae14d | ||
|
|
6ef5803f24 | ||
|
|
2c03d74f11 | ||
|
|
3d34a3c6d6 | ||
|
|
59ec9b4139 | ||
|
|
4a99838fa2 | ||
|
|
af8dee51e1 | ||
|
|
9b3b554758 | ||
|
|
4d8402c260 | ||
|
|
aa0ee2bf64 | ||
|
|
dcc64fead2 | ||
|
|
149123c232 | ||
|
|
e292ec220e | ||
|
|
3696b7d89f | ||
|
|
6d7446a45e | ||
|
|
ddf41af767 | ||
|
|
0b0cb5520d | ||
|
|
4c0a43f0e4 | ||
|
|
65764d9ddc | ||
|
|
36c66c8083 | ||
|
|
99b464e102 | ||
|
|
e1fa1fcbc3 | ||
|
|
2979fbad94 | ||
|
|
a77fe8a53f | ||
|
|
7e84ae0b30 | ||
|
|
fb6d1adb43 | ||
|
|
7303cb5673 | ||
|
|
43d67e46db | ||
|
|
ae04147f96 | ||
|
|
12506842c0 | ||
|
|
2190396357 | ||
|
|
41bc0da6fe | ||
|
|
2a7f327d93 | ||
|
|
dbcaa7cf3d | ||
|
|
8df87a82b0 | ||
|
|
70746ff593 | ||
|
|
054fc2e046 | ||
|
|
ecb732eaf4 | ||
|
|
3dab1f1fb0 | ||
|
|
8f1c723ba0 | ||
|
|
1e74a8137b | ||
|
|
3f28dd845f |
@@ -4,10 +4,10 @@
|
|||||||
"features": {
|
"features": {
|
||||||
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
|
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
|
||||||
"ghcr.io/devcontainers/features/dotnet": {
|
"ghcr.io/devcontainers/features/dotnet": {
|
||||||
"version": "6.0.421"
|
"version": "8.0.405"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
"ghcr.io/devcontainers/features/node:1": {
|
||||||
"version": "16"
|
"version": "20"
|
||||||
},
|
},
|
||||||
"ghcr.io/devcontainers/features/sshd:1": {
|
"ghcr.io/devcontainers/features/sshd:1": {
|
||||||
"version": "latest"
|
"version": "latest"
|
||||||
|
|||||||
5
.github/dependabot.yml
vendored
5
.github/dependabot.yml
vendored
@@ -5,6 +5,11 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
target-branch: "main"
|
target-branch: "main"
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
target-branch: "main"
|
||||||
- package-ecosystem: "nuget"
|
- package-ecosystem: "nuget"
|
||||||
directory: "/src"
|
directory: "/src"
|
||||||
schedule:
|
schedule:
|
||||||
|
|||||||
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
|||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Build runner layout
|
# Build runner layout
|
||||||
- name: Build & Layout Release
|
- name: Build & Layout Release
|
||||||
@@ -69,13 +69,13 @@ jobs:
|
|||||||
- name: Package Release
|
- name: Package Release
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
run: |
|
run: |
|
||||||
${{ matrix.devScript }} package Release
|
${{ matrix.devScript }} package Release ${{ matrix.runtime }}
|
||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
# Upload runner package tar.gz/zip as artifact
|
# Upload runner package tar.gz/zip as artifact
|
||||||
- name: Publish Artifact
|
- name: Publish Artifact
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: runner-package-${{ matrix.runtime }}
|
name: runner-package-${{ matrix.runtime }}
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
6
.github/workflows/codeql.yml
vendored
6
.github/workflows/codeql.yml
vendored
@@ -23,11 +23,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
# Override language selection by uncommenting this and choosing your languages
|
# Override language selection by uncommenting this and choosing your languages
|
||||||
# with:
|
# with:
|
||||||
# languages: go, javascript, csharp, python, cpp, java
|
# languages: go, javascript, csharp, python, cpp, java
|
||||||
@@ -38,4 +38,4 @@ jobs:
|
|||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
|||||||
6
.github/workflows/dotnet-upgrade.yml
vendored
6
.github/workflows/dotnet-upgrade.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
DOTNET_CURRENT_MAJOR_MINOR_VERSION: ${{ steps.fetch_current_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_VERSION }}
|
DOTNET_CURRENT_MAJOR_MINOR_VERSION: ${{ steps.fetch_current_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_VERSION }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Get current major minor version
|
- name: Get current major minor version
|
||||||
id: fetch_current_version
|
id: fetch_current_version
|
||||||
shell: bash
|
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"
|
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
|
- 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 }}
|
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_latest_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_current_version.outputs.DOTNET_CURRENT_MAJOR_MINOR_PATCH_VERSION }}. No need to update"
|
||||||
- name: Update patch version
|
- name: Update patch version
|
||||||
if: ${{ steps.fetch_latest_version.outputs.SHOULD_UPDATE == 1 && steps.fetch_latest_version.outputs.BRANCH_EXISTS == 0 }}
|
if: ${{ steps.fetch_latest_version.outputs.SHOULD_UPDATE == 1 && steps.fetch_latest_version.outputs.BRANCH_EXISTS == 0 }}
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -89,7 +89,7 @@ jobs:
|
|||||||
if: ${{ needs.dotnet-update.outputs.SHOULD_UPDATE == 1 && needs.dotnet-update.outputs.BRANCH_EXISTS == 0 }}
|
if: ${{ needs.dotnet-update.outputs.SHOULD_UPDATE == 1 && needs.dotnet-update.outputs.BRANCH_EXISTS == 0 }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
ref: feature/dotnetsdk-upgrade/${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}
|
ref: feature/dotnetsdk-upgrade/${{ needs.dotnet-update.outputs.DOTNET_LATEST_MAJOR_MINOR_PATCH_VERSION }}
|
||||||
- name: Create Pull Request
|
- name: Create Pull Request
|
||||||
|
|||||||
24
.github/workflows/lint.yml
vendored
24
.github/workflows/lint.yml
vendored
@@ -1,24 +0,0 @@
|
|||||||
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
|
|
||||||
8
.github/workflows/publish-image.yml
vendored
8
.github/workflows/publish-image.yml
vendored
@@ -20,15 +20,17 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Compute image version
|
- name: Compute image version
|
||||||
id: image
|
id: image
|
||||||
uses: actions/github-script@v6
|
uses: actions/github-script@v6
|
||||||
|
env:
|
||||||
|
RUNNER_VERSION: ${{ github.event.inputs.runnerVersion }}
|
||||||
with:
|
with:
|
||||||
script: |
|
script: |
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const inputRunnerVersion = "${{ github.event.inputs.runnerVersion }}"
|
const inputRunnerVersion = process.env.RUNNER_VERSION;
|
||||||
if (inputRunnerVersion) {
|
if (inputRunnerVersion) {
|
||||||
console.log(`Using input runner version ${inputRunnerVersion}`)
|
console.log(`Using input runner version ${inputRunnerVersion}`)
|
||||||
core.setOutput('version', inputRunnerVersion);
|
core.setOutput('version', inputRunnerVersion);
|
||||||
@@ -39,7 +41,7 @@ jobs:
|
|||||||
core.setOutput('version', runnerVersion);
|
core.setOutput('version', runnerVersion);
|
||||||
|
|
||||||
- name: Setup Docker buildx
|
- name: Setup Docker buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Log into registry ${{ env.REGISTRY }}
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
|
|||||||
51
.github/workflows/release.yml
vendored
51
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
|||||||
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Make sure ./releaseVersion match ./src/runnerversion
|
# Make sure ./releaseVersion match ./src/runnerversion
|
||||||
# Query GitHub release ensure version is not used
|
# Query GitHub release ensure version is not used
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Build runner layout
|
# Build runner layout
|
||||||
- name: Build & Layout Release
|
- name: Build & Layout Release
|
||||||
@@ -117,12 +117,11 @@ jobs:
|
|||||||
working-directory: _package
|
working-directory: _package
|
||||||
|
|
||||||
# Upload runner package tar.gz/zip as artifact.
|
# 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
|
- name: Publish Artifact
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: runner-packages
|
name: runner-packages-${{ matrix.runtime }}
|
||||||
path: |
|
path: |
|
||||||
_package
|
_package
|
||||||
|
|
||||||
@@ -131,13 +130,43 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
# Download runner package tar.gz/zip produced by 'build' job
|
# Download runner package tar.gz/zip produced by 'build' job
|
||||||
- name: Download Artifact
|
- name: Download Artifact (win-x64)
|
||||||
uses: actions/download-artifact@v1
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: runner-packages
|
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
|
||||||
path: ./
|
path: ./
|
||||||
|
|
||||||
# Create ReleaseNote file
|
# Create ReleaseNote file
|
||||||
@@ -267,7 +296,7 @@ jobs:
|
|||||||
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
|
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Compute image version
|
- name: Compute image version
|
||||||
id: image
|
id: image
|
||||||
@@ -280,7 +309,7 @@ jobs:
|
|||||||
core.setOutput('version', runnerVersion);
|
core.setOutput('version', runnerVersion);
|
||||||
|
|
||||||
- name: Setup Docker buildx
|
- name: Setup Docker buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Log into registry ${{ env.REGISTRY }}
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -26,4 +26,5 @@ _dotnetsdk
|
|||||||
TestResults
|
TestResults
|
||||||
TestLogs
|
TestLogs
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
.mono
|
||||||
**/*.DotSettings.user
|
**/*.DotSettings.user
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
||||||
|
|
||||||
The runner carries its own copy of node.js executable under `<runner_root>/externals/node16/`.
|
The runner carries its own copy of node.js executable under `<runner_root>/externals/node20/`.
|
||||||
|
|
||||||
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node16/`.
|
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node20/`.
|
||||||
|
|
||||||
> Not the `node` from `$PATH`
|
> Not the `node` from `$PATH`
|
||||||
|
|
||||||
|
|||||||
@@ -4,16 +4,7 @@
|
|||||||
|
|
||||||
## Supported Distributions and Versions
|
## Supported Distributions and Versions
|
||||||
|
|
||||||
x64
|
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)."
|
||||||
- Red Hat Enterprise Linux 7+
|
|
||||||
- CentOS 7+
|
|
||||||
- Oracle Linux 7+
|
|
||||||
- Fedora 29+
|
|
||||||
- Debian 9+
|
|
||||||
- Ubuntu 16.04+
|
|
||||||
- Linux Mint 18+
|
|
||||||
- openSUSE 15+
|
|
||||||
- SUSE Enterprise Linux (SLES) 12 SP2+
|
|
||||||
|
|
||||||
## Install .Net Core 3.x Linux Dependencies
|
## Install .Net Core 3.x Linux Dependencies
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
- macOS High Sierra (10.13) and later 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)."
|
||||||
- x64 and arm64 (Apple Silicon)
|
|
||||||
|
|
||||||
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)
|
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
- Windows 7 64-bit
|
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 8.1 64-bit
|
|
||||||
- Windows 10 64-bit
|
|
||||||
- Windows Server 2012 R2 64-bit
|
|
||||||
- Windows Server 2016 64-bit
|
|
||||||
- Windows Server 2019 64-bit
|
|
||||||
|
|
||||||
## [More .NET Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore30)
|
## [More .NET Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/windows-prerequisites?tabs=netcore30)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
# Source: https://github.com/dotnet/dotnet-docker
|
# Source: https://github.com/dotnet/dotnet-docker
|
||||||
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy as build
|
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy as build
|
||||||
|
|
||||||
ARG TARGETOS
|
ARG TARGETOS
|
||||||
ARG TARGETARCH
|
ARG TARGETARCH
|
||||||
ARG RUNNER_VERSION
|
ARG RUNNER_VERSION
|
||||||
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.0
|
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.6.1
|
||||||
ARG DOCKER_VERSION=25.0.5
|
ARG DOCKER_VERSION=27.4.1
|
||||||
ARG BUILDX_VERSION=0.13.2
|
ARG BUILDX_VERSION=0.19.3
|
||||||
|
|
||||||
RUN apt update -y && apt install curl unzip -y
|
RUN apt update -y && apt install curl unzip -y
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ RUN export RUNNER_ARCH=${TARGETARCH} \
|
|||||||
"https://github.com/docker/buildx/releases/download/v${BUILDX_VERSION}/buildx-v${BUILDX_VERSION}.linux-${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
|
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-buildx
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-jammy
|
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0-jammy
|
||||||
|
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
ENV RUNNER_MANUALLY_TRAP_SIG=1
|
ENV RUNNER_MANUALLY_TRAP_SIG=1
|
||||||
@@ -41,12 +41,14 @@ ENV ImageOS=ubuntu22
|
|||||||
|
|
||||||
# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows
|
# 'gpg-agent' and 'software-properties-common' are needed for the 'add-apt-repository' command that follows
|
||||||
RUN apt update -y \
|
RUN apt update -y \
|
||||||
&& apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common \
|
&& apt install -y --no-install-recommends sudo lsb-release gpg-agent software-properties-common curl jq unzip \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Configure git-core/ppa based on guidance here: https://git-scm.com/download/linux
|
# Configure git-core/ppa based on guidance here: https://git-scm.com/download/linux
|
||||||
RUN add-apt-repository ppa:git-core/ppa \
|
RUN add-apt-repository ppa:git-core/ppa \
|
||||||
&& apt update -y
|
&& apt update -y \
|
||||||
|
&& apt install -y git \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
|
RUN adduser --disabled-password --gecos "" --uid 1001 runner \
|
||||||
&& groupadd docker --gid 123 \
|
&& groupadd docker --gid 123 \
|
||||||
|
|||||||
@@ -1,12 +1,23 @@
|
|||||||
## What's Changed
|
## What's Changed
|
||||||
|
* Fix name of generated of artifact builds from GitHub workflow for arm artifacts by @satmandu in https://github.com/actions/runner/pull/3568
|
||||||
|
* Ignore error when fail to report worker crash. by @TingluoHuang in https://github.com/actions/runner/pull/3588
|
||||||
|
* Fix null ref in 'OnEventWritten()' by @TingluoHuang in https://github.com/actions/runner/pull/3593
|
||||||
|
* Send stepNumber for annotation to run-service by @TingluoHuang in https://github.com/actions/runner/pull/3614
|
||||||
|
* Enable nuget audit. by @TingluoHuang in https://github.com/actions/runner/pull/3615
|
||||||
|
* Update dotnet install script. by @TingluoHuang in https://github.com/actions/runner/pull/3659
|
||||||
|
* Print immutable action package details in set up job logs by @heavymachinery in https://github.com/actions/runner/pull/3645
|
||||||
|
* Update dotnet sdk to latest version @8.0.405 by @github-actions in https://github.com/actions/runner/pull/3666
|
||||||
|
* Upgrade `buildx` from `0.18.0` to `0.19.3` (critical CVE) by @MPV in https://github.com/actions/runner/pull/3647
|
||||||
|
* Upgrade `docker` from `27.3.1` to `27.4.1` by @MPV in https://github.com/actions/runner/pull/3648
|
||||||
|
* Bump Microsoft.NET.Test.Sdk from 17.8.0 to 17.12.0 in /src by @dependabot in https://github.com/actions/runner/pull/3584
|
||||||
|
* Bump docker/setup-buildx-action from 2 to 3 by @dependabot in https://github.com/actions/runner/pull/3564
|
||||||
|
* Bump github/codeql-action from 2 to 3 by @dependabot in https://github.com/actions/runner/pull/3555
|
||||||
|
* Bump Moq from 4.20.70 to 4.20.72 in /src by @dependabot in https://github.com/actions/runner/pull/3672
|
||||||
|
|
||||||
- Do not give up when uploading steps metadata by @yacaovsnc in https://github.com/actions/runner/pull/3280
|
## New Contributors
|
||||||
- Upgrade node20 to 20.13.1 by @pje in https://github.com/actions/runner/pull/3284
|
* @satmandu made their first contribution in https://github.com/actions/runner/pull/3568
|
||||||
- Delete all the contentHash files by @pje in https://github.com/actions/runner/pull/3285
|
|
||||||
- Make it easy to install `git` on an Action Runner Image by @jww3 in https://github.com/actions/runner/pull/3273
|
|
||||||
- Install `gpg-agent` during actions/runner container image build by @jww3 in https://github.com/actions/runner/pull/3294
|
|
||||||
|
|
||||||
**Full Changelog**: https://github.com/actions/runner/compare/v2.316.1...v2.317.0
|
**Full Changelog**: https://github.com/actions/runner/compare/v2.321.0...v2.322.0
|
||||||
|
|
||||||
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
|
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
|
||||||
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.
|
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.
|
||||||
@@ -28,9 +39,7 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
|||||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
|
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
|
||||||
```
|
```
|
||||||
|
|
||||||
## [Pre-release] Windows arm64
|
## 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.
|
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.
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<Update to ./src/runnerversion when creating release>
|
2.322.0
|
||||||
|
|||||||
@@ -57,4 +57,13 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- Enable NuGet package auditing -->
|
||||||
|
<NuGetAudit>true</NuGetAudit>
|
||||||
|
<!-- Audit direct and transitive packages -->
|
||||||
|
<NuGetAuditMode>all</NuGetAuditMode>
|
||||||
|
<!-- Report low, moderate, high and critical advisories -->
|
||||||
|
<NuGetAuditLevel>moderate</NuGetAuditLevel>
|
||||||
|
</PropertyGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
1488
src/Misc/dotnet-install.ps1
vendored
1488
src/Misc/dotnet-install.ps1
vendored
File diff suppressed because it is too large
Load Diff
1254
src/Misc/dotnet-install.sh
vendored
1254
src/Misc/dotnet-install.sh
vendored
File diff suppressed because it is too large
Load Diff
@@ -3,13 +3,10 @@ PACKAGERUNTIME=$1
|
|||||||
PRECACHE=$2
|
PRECACHE=$2
|
||||||
|
|
||||||
NODE_URL=https://nodejs.org/dist
|
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
|
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.
|
# 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
|
# Follow the instructions here: https://github.com/actions/alpine_nodejs?tab=readme-ov-file#getting-started
|
||||||
NODE16_VERSION="16.20.2"
|
NODE20_VERSION="20.18.0"
|
||||||
NODE20_VERSION="20.13.1"
|
|
||||||
NODE16_UNOFFICIAL_VERSION="16.20.0" # used only for win-arm64, remove node16 unofficial version when official version is available
|
|
||||||
|
|
||||||
get_abs_path() {
|
get_abs_path() {
|
||||||
# exploits the fact that pwd will print abs path when no args
|
# exploits the fact that pwd will print abs path when no args
|
||||||
@@ -140,8 +137,6 @@ function acquireExternalTool() {
|
|||||||
|
|
||||||
# Download the external tools only for Windows.
|
# Download the external tools only for Windows.
|
||||||
if [[ "$PACKAGERUNTIME" == "win-x64" || "$PACKAGERUNTIME" == "win-x86" ]]; then
|
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.exe" node20/bin
|
||||||
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.lib" node20/bin
|
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.lib" node20/bin
|
||||||
if [[ "$PRECACHE" != "" ]]; then
|
if [[ "$PRECACHE" != "" ]]; then
|
||||||
@@ -152,8 +147,6 @@ fi
|
|||||||
# Download the external tools only for Windows.
|
# Download the external tools only for Windows.
|
||||||
if [[ "$PACKAGERUNTIME" == "win-arm64" ]]; then
|
if [[ "$PACKAGERUNTIME" == "win-arm64" ]]; then
|
||||||
# todo: replace these with official release when available
|
# 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.exe" node20/bin
|
||||||
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.lib" node20/bin
|
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/$PACKAGERUNTIME/node.lib" node20/bin
|
||||||
if [[ "$PRECACHE" != "" ]]; then
|
if [[ "$PRECACHE" != "" ]]; then
|
||||||
@@ -163,30 +156,24 @@ fi
|
|||||||
|
|
||||||
# Download the external tools only for OSX.
|
# Download the external tools only for OSX.
|
||||||
if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
|
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
|
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-darwin-x64.tar.gz" node20 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$PACKAGERUNTIME" == "osx-arm64" ]]; then
|
if [[ "$PACKAGERUNTIME" == "osx-arm64" ]]; then
|
||||||
# node.js v12 doesn't support macOS on arm64.
|
# 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
|
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-darwin-arm64.tar.gz" node20 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Download the external tools for Linux PACKAGERUNTIMEs.
|
# Download the external tools for Linux PACKAGERUNTIMEs.
|
||||||
if [[ "$PACKAGERUNTIME" == "linux-x64" ]]; then
|
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_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
|
acquireExternalTool "$NODE_ALPINE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-alpine-x64.tar.gz" node20_alpine
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$PACKAGERUNTIME" == "linux-arm64" ]]; then
|
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
|
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-linux-arm64.tar.gz" node20 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$PACKAGERUNTIME" == "linux-arm" ]]; then
|
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
|
acquireExternalTool "$NODE_URL/v${NODE20_VERSION}/node-v${NODE20_VERSION}-linux-armv7l.tar.gz" node20 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ if [ -f ".path" ]; then
|
|||||||
echo ".path=${PATH}"
|
echo ".path=${PATH}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
nodever=${GITHUB_ACTIONS_RUNNER_FORCED_NODE_VERSION:-node16}
|
nodever="node20"
|
||||||
|
|
||||||
# insert anything to setup env when running as a service
|
# insert anything to setup env when running as a service
|
||||||
# run the host process which keep the listener alive
|
# run the host process which keep the listener alive
|
||||||
|
|||||||
@@ -135,12 +135,17 @@ if [[ "$currentplatform" == 'darwin' && restartinteractiverunner -eq 0 ]]; then
|
|||||||
then
|
then
|
||||||
# inspect the open file handles to find the node process
|
# inspect the open file handles to find the node process
|
||||||
# we can't actually inspect the process using ps because it uses relative paths and doesn't follow symlinks
|
# we can't actually inspect the process using ps because it uses relative paths and doesn't follow symlinks
|
||||||
nodever="node16"
|
nodever="node20"
|
||||||
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node12
|
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node16
|
||||||
then
|
then
|
||||||
nodever="node12"
|
nodever="node16"
|
||||||
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
|
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node12
|
||||||
|
then
|
||||||
|
nodever="node12"
|
||||||
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
if [[ $? -eq 0 && -n "$path" ]]
|
if [[ $? -eq 0 && -n "$path" ]]
|
||||||
then
|
then
|
||||||
@@ -178,6 +183,19 @@ if [[ "$currentplatform" == 'darwin' && restartinteractiverunner -eq 0 ]]; then
|
|||||||
fi
|
fi
|
||||||
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"
|
date "+[%F %T-%4N] Update succeed" >> "$logfile"
|
||||||
|
|
||||||
touch update.finished
|
touch update.finished
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using GitHub.DistributedTask.Pipelines;
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
using Sdk.RSWebApi.Contracts;
|
using Sdk.RSWebApi.Contracts;
|
||||||
using Sdk.WebApi.WebApi.RawClient;
|
using Sdk.WebApi.WebApi.RawClient;
|
||||||
|
|
||||||
@@ -92,7 +93,7 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
public bool ShouldRetryException(Exception ex)
|
public bool ShouldRetryException(Exception ex)
|
||||||
{
|
{
|
||||||
if (ex is AccessDeniedException ade && ade.ErrorCode == 1)
|
if (ex is AccessDeniedException || ex is RunnerNotFoundException)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -159,7 +159,6 @@ namespace GitHub.Runner.Common
|
|||||||
public static class Features
|
public static class Features
|
||||||
{
|
{
|
||||||
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
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 LogTemplateErrorsAsDebugMessages = "DistributedTask.LogTemplateErrorsAsDebugMessages";
|
||||||
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
||||||
public static readonly string AllowRunnerContainerHooks = "DistributedTask.AllowRunnerContainerHooks";
|
public static readonly string AllowRunnerContainerHooks = "DistributedTask.AllowRunnerContainerHooks";
|
||||||
@@ -176,14 +175,6 @@ 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 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 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 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
|
public static class RunnerEvent
|
||||||
@@ -254,20 +245,17 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string RequireJobContainer = "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER";
|
public static readonly string RequireJobContainer = "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER";
|
||||||
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
||||||
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
||||||
public static readonly string AllowActionsUseUnsecureNodeVersion = "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION";
|
|
||||||
public static readonly string ManualForceActionsToNode20 = "FORCE_JAVASCRIPT_ACTIONS_TO_NODE20";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Agent
|
public static class Agent
|
||||||
{
|
{
|
||||||
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
||||||
|
|
||||||
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
// Set this env var to "nodeXY" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
||||||
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
||||||
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
||||||
public static readonly string PrintLogToStdout = "ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT";
|
public static readonly string PrintLogToStdout = "ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT";
|
||||||
public static readonly string ActionArchiveCacheDirectory = "ACTIONS_RUNNER_ACTION_ARCHIVE_CACHE";
|
public static readonly string ActionArchiveCacheDirectory = "ACTIONS_RUNNER_ACTION_ARCHIVE_CACHE";
|
||||||
public static readonly string ManualForceActionsToNode20 = "FORCE_JAVASCRIPT_ACTIONS_TO_NODE20";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class System
|
public static class System
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ namespace GitHub.Runner.Common
|
|||||||
event EventHandler Unloading;
|
event EventHandler Unloading;
|
||||||
void ShutdownRunner(ShutdownReason reason);
|
void ShutdownRunner(ShutdownReason reason);
|
||||||
void WritePerfCounter(string counter);
|
void WritePerfCounter(string counter);
|
||||||
|
void LoadDefaultUserAgents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum StartupType
|
public enum StartupType
|
||||||
@@ -67,6 +68,7 @@ namespace GitHub.Runner.Common
|
|||||||
private StartupType _startupType;
|
private StartupType _startupType;
|
||||||
private string _perfFile;
|
private string _perfFile;
|
||||||
private RunnerWebProxy _webProxy = new();
|
private RunnerWebProxy _webProxy = new();
|
||||||
|
private string _hostType = string.Empty;
|
||||||
|
|
||||||
public event EventHandler Unloading;
|
public event EventHandler Unloading;
|
||||||
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
||||||
@@ -78,6 +80,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
// Validate args.
|
// Validate args.
|
||||||
ArgUtil.NotNullOrEmpty(hostType, nameof(hostType));
|
ArgUtil.NotNullOrEmpty(hostType, nameof(hostType));
|
||||||
|
_hostType = hostType;
|
||||||
|
|
||||||
_loadContext = AssemblyLoadContext.GetLoadContext(typeof(HostContext).GetTypeInfo().Assembly);
|
_loadContext = AssemblyLoadContext.GetLoadContext(typeof(HostContext).GetTypeInfo().Assembly);
|
||||||
_loadContext.Unloading += LoadContext_Unloading;
|
_loadContext.Unloading += LoadContext_Unloading;
|
||||||
@@ -196,6 +199,16 @@ 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))
|
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)");
|
_trace.Info($"No proxy settings were found based on environmental variables (http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY)");
|
||||||
@@ -205,11 +218,6 @@ namespace GitHub.Runner.Common
|
|||||||
_userAgents.Add(new ProductInfoHeaderValue("HttpProxyConfigured", bool.TrueString));
|
_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);
|
var credFile = GetConfigFile(WellKnownConfigFile.Credentials);
|
||||||
if (File.Exists(credFile))
|
if (File.Exists(credFile))
|
||||||
{
|
{
|
||||||
@@ -244,6 +252,11 @@ namespace GitHub.Runner.Common
|
|||||||
_trace.Info($"Adding extra user agent '{extraUserAgentHeader}' to all HTTP requests.");
|
_trace.Info($"Adding extra user agent '{extraUserAgentHeader}' to all HTTP requests.");
|
||||||
_userAgents.Add(extraUserAgentHeader);
|
_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)
|
public string GetDirectory(WellKnownDirectory directory)
|
||||||
@@ -616,7 +629,7 @@ namespace GitHub.Runner.Common
|
|||||||
payload[0] = Enum.Parse(typeof(GitHub.Services.Common.VssCredentialsType), ((int)payload[0]).ToString());
|
payload[0] = Enum.Parse(typeof(GitHub.Services.Common.VssCredentialsType), ((int)payload[0]).ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.Length > 0)
|
if (payload.Length > 0 && !string.IsNullOrEmpty(eventData.Message))
|
||||||
{
|
{
|
||||||
message = String.Format(eventData.Message.Replace("%n", Environment.NewLine), payload);
|
message = String.Format(eventData.Message.Replace("%n", Environment.NewLine), payload);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
using System.Net.Security;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -179,6 +180,10 @@ namespace GitHub.Runner.Common
|
|||||||
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
|
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
|
||||||
userAgentValues.AddRange(HostContext.UserAgents);
|
userAgentValues.AddRange(HostContext.UserAgents);
|
||||||
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
|
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
|
||||||
|
{
|
||||||
|
this._websocketClient.Options.RemoteCertificateValidationCallback = (_, _, _, _) => true;
|
||||||
|
}
|
||||||
|
|
||||||
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.Launch.Client;
|
using GitHub.Services.Launch.Client;
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
@@ -23,8 +24,21 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
public void InitializeLaunchClient(Uri uri, string token)
|
public void InitializeLaunchClient(Uri uri, string token)
|
||||||
{
|
{
|
||||||
var httpMessageHandler = HostContext.CreateHttpClientHandler();
|
// Using default 100 timeout
|
||||||
this._launchClient = new LaunchHttpClient(uri, httpMessageHandler, token, disposeHandler: true);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<ActionDownloadInfoCollection> ResolveActionsDownloadInfoAsync(Guid planId, Guid jobId, ActionReferenceList actionReferenceList,
|
public Task<ActionDownloadInfoCollection> ResolveActionsDownloadInfoAsync(Guid planId, Guid jobId, ActionReferenceList actionReferenceList,
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ namespace GitHub.Runner.Common
|
|||||||
IList<StepResult> stepResults,
|
IList<StepResult> stepResults,
|
||||||
IList<Annotation> jobAnnotations,
|
IList<Annotation> jobAnnotations,
|
||||||
string environmentUrl,
|
string environmentUrl,
|
||||||
|
IList<Telemetry> telemetry,
|
||||||
CancellationToken token);
|
CancellationToken token);
|
||||||
|
|
||||||
Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken token);
|
Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken token);
|
||||||
@@ -62,7 +63,10 @@ namespace GitHub.Runner.Common
|
|||||||
CheckConnection();
|
CheckConnection();
|
||||||
return RetryRequest<AgentJobRequestMessage>(
|
return RetryRequest<AgentJobRequestMessage>(
|
||||||
async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, VarUtil.OS, cancellationToken), cancellationToken,
|
async () => await _runServiceHttpClient.GetJobMessageAsync(requestUri, id, VarUtil.OS, cancellationToken), cancellationToken,
|
||||||
shouldRetry: ex => ex is not TaskOrchestrationJobAlreadyAcquiredException);
|
shouldRetry: ex =>
|
||||||
|
ex is not TaskOrchestrationJobNotFoundException && // HTTP status 404
|
||||||
|
ex is not TaskOrchestrationJobAlreadyAcquiredException && // HTTP status 409
|
||||||
|
ex is not TaskOrchestrationJobUnprocessableException); // HTTP status 422
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task CompleteJobAsync(
|
public Task CompleteJobAsync(
|
||||||
@@ -73,11 +77,12 @@ namespace GitHub.Runner.Common
|
|||||||
IList<StepResult> stepResults,
|
IList<StepResult> stepResults,
|
||||||
IList<Annotation> jobAnnotations,
|
IList<Annotation> jobAnnotations,
|
||||||
string environmentUrl,
|
string environmentUrl,
|
||||||
|
IList<Telemetry> telemetry,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
return RetryRequest(
|
return RetryRequest(
|
||||||
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, jobAnnotations, environmentUrl, cancellationToken), cancellationToken);
|
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, result, outputs, stepResults, jobAnnotations, environmentUrl, telemetry, cancellationToken), cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken cancellationToken)
|
public Task<RenewJobResponse> RenewJobAsync(Guid planId, Guid jobId, CancellationToken cancellationToken)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -15,11 +15,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
|
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -46,7 +46,11 @@ namespace GitHub.Runner.Common
|
|||||||
var githubApiUrl = "";
|
var githubApiUrl = "";
|
||||||
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (path.Length == 1)
|
var isOrgRunner = path.Length == 1;
|
||||||
|
var isRepoOrEnterpriseRunner = path.Length == 2;
|
||||||
|
var isRepoRunner = isRepoOrEnterpriseRunner && !string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (isOrgRunner)
|
||||||
{
|
{
|
||||||
// org runner
|
// org runner
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
@@ -58,21 +62,31 @@ namespace GitHub.Runner.Common
|
|||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (path.Length == 2)
|
else if (isRepoOrEnterpriseRunner)
|
||||||
{
|
{
|
||||||
// repo or enterprise runner.
|
// Repository runner
|
||||||
if (!string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
|
if (isRepoRunner)
|
||||||
{
|
{
|
||||||
return null;
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
}
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/repos/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
}
|
||||||
{
|
else
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/repos/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runners?name={Uri.EscapeDataString(agentName)}";
|
// 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)}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -90,7 +104,11 @@ namespace GitHub.Runner.Common
|
|||||||
var githubApiUrl = "";
|
var githubApiUrl = "";
|
||||||
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
var path = gitHubUrlBuilder.Path.Split('/', '\\', StringSplitOptions.RemoveEmptyEntries);
|
||||||
if (path.Length == 1)
|
var isOrgRunner = path.Length == 1;
|
||||||
|
var isRepoOrEnterpriseRunner = path.Length == 2;
|
||||||
|
var isRepoRunner = isRepoOrEnterpriseRunner && !string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (isOrgRunner)
|
||||||
{
|
{
|
||||||
// org runner
|
// org runner
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
@@ -102,21 +120,31 @@ namespace GitHub.Runner.Common
|
|||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runner-groups";
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runner-groups";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (path.Length == 2)
|
else if (isRepoOrEnterpriseRunner)
|
||||||
{
|
{
|
||||||
// repo or enterprise runner.
|
// Repository Runner
|
||||||
if (!string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
|
if (isRepoRunner)
|
||||||
{
|
{
|
||||||
return null;
|
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
||||||
}
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/repos/{path[0]}/{path[1]}/actions/runner-groups";
|
||||||
if (UrlUtil.IsHostedServer(gitHubUrlBuilder))
|
}
|
||||||
{
|
else
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{path[0]}/{path[1]}/actions/runner-groups";
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/repos/{path[0]}/{path[1]}/actions/runner-groups";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{path[0]}/{path[1]}/actions/runner-groups";
|
// 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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ namespace GitHub.Runner.Common.Util
|
|||||||
{
|
{
|
||||||
public static class NodeUtil
|
public static class NodeUtil
|
||||||
{
|
{
|
||||||
private const string _defaultNodeVersion = "node16";
|
private const string _defaultNodeVersion = "node20";
|
||||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16", "node20" });
|
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node20" });
|
||||||
public static string GetInternalNodeVersion()
|
public static string GetInternalNodeVersion()
|
||||||
{
|
{
|
||||||
var forcedInternalNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
var forcedInternalNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Listener.Configuration;
|
using GitHub.Runner.Listener.Configuration;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.OAuth;
|
using GitHub.Services.OAuth;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -69,7 +70,8 @@ namespace GitHub.Runner.Listener
|
|||||||
Version = BuildConstants.RunnerPackage.Version,
|
Version = BuildConstants.RunnerPackage.Version,
|
||||||
OSDescription = RuntimeInformation.OSDescription,
|
OSDescription = RuntimeInformation.OSDescription,
|
||||||
};
|
};
|
||||||
string sessionName = $"{Environment.MachineName ?? "RUNNER"}";
|
var currentProcess = Process.GetCurrentProcess();
|
||||||
|
string sessionName = $"{Environment.MachineName ?? "RUNNER"} (PID: {currentProcess.Id})";
|
||||||
var taskAgentSession = new TaskAgentSession(sessionName, agent);
|
var taskAgentSession = new TaskAgentSession(sessionName, agent);
|
||||||
|
|
||||||
string errorMessage = string.Empty;
|
string errorMessage = string.Empty;
|
||||||
@@ -240,6 +242,10 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
catch (RunnerNotFoundException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Trace.Error("Catch exception during get next message.");
|
Trace.Error("Catch exception during get next message.");
|
||||||
@@ -323,6 +329,7 @@ namespace GitHub.Runner.Listener
|
|||||||
ex is TaskAgentPoolNotFoundException ||
|
ex is TaskAgentPoolNotFoundException ||
|
||||||
ex is TaskAgentSessionExpiredException ||
|
ex is TaskAgentSessionExpiredException ||
|
||||||
ex is AccessDeniedException ||
|
ex is AccessDeniedException ||
|
||||||
|
ex is RunnerNotFoundException ||
|
||||||
ex is VssUnauthorizedException)
|
ex is VssUnauthorizedException)
|
||||||
{
|
{
|
||||||
Trace.Info($"Non-retriable exception: {ex.Message}");
|
Trace.Info($"Non-retriable exception: {ex.Message}");
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -84,4 +85,5 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
44
src/Runner.Listener/ErrorThrottler.cs
Normal file
44
src/Runner.Listener/ErrorThrottler.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -545,28 +545,36 @@ namespace GitHub.Runner.Listener
|
|||||||
detailInfo = string.Join(Environment.NewLine, workerOutput);
|
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.");
|
Trace.Info($"Return code {returnCode} indicate worker encounter an unhandled exception or app crash, attach worker stdout/stderr to JobRequest result.");
|
||||||
|
|
||||||
var jobServer = await InitializeJobServerAsync(systemConnection);
|
try
|
||||||
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo };
|
|
||||||
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
|
|
||||||
switch (jobServer)
|
|
||||||
{
|
{
|
||||||
case IJobServer js:
|
var jobServer = await InitializeJobServerAsync(systemConnection);
|
||||||
{
|
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = detailInfo };
|
||||||
await LogWorkerProcessUnhandledException(js, message, unhandledExceptionIssue);
|
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
|
||||||
// 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.
|
switch (jobServer)
|
||||||
if (detailInfo.Contains(typeof(System.IO.IOException).ToString(), StringComparison.OrdinalIgnoreCase))
|
{
|
||||||
|
case IJobServer js:
|
||||||
{
|
{
|
||||||
Trace.Info($"Finish job with result 'Failed' due to IOException.");
|
await LogWorkerProcessUnhandledException(js, message, unhandledExceptionIssue);
|
||||||
await ForceFailJob(js, message);
|
// 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;
|
||||||
|
}
|
||||||
|
case IRunServer rs:
|
||||||
|
await ForceFailJob(rs, message, unhandledExceptionIssue);
|
||||||
break;
|
break;
|
||||||
}
|
default:
|
||||||
case IRunServer rs:
|
throw new NotSupportedException($"JobServer type '{jobServer.GetType().Name}' is not supported.");
|
||||||
await ForceFailJob(rs, message, unhandledExceptionIssue);
|
}
|
||||||
break;
|
}
|
||||||
default:
|
catch (Exception ex)
|
||||||
throw new NotSupportedException($"JobServer type '{jobServer.GetType().Name}' is not supported.");
|
{
|
||||||
|
Trace.Error($"Catch exception during log worker process unhandled exception.");
|
||||||
|
Trace.Error(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1198,7 +1206,7 @@ namespace GitHub.Runner.Listener
|
|||||||
jobAnnotations.Add(annotation.Value);
|
jobAnnotations.Add(annotation.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, CancellationToken.None);
|
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, TaskResult.Failed, outputs: null, stepResults: null, jobAnnotations: jobAnnotations, environmentUrl: null, telemetry: null, CancellationToken.None);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ namespace GitHub.Runner.Listener
|
|||||||
Version = BuildConstants.RunnerPackage.Version,
|
Version = BuildConstants.RunnerPackage.Version,
|
||||||
OSDescription = RuntimeInformation.OSDescription,
|
OSDescription = RuntimeInformation.OSDescription,
|
||||||
};
|
};
|
||||||
string sessionName = $"{Environment.MachineName ?? "RUNNER"}";
|
var currentProcess = Process.GetCurrentProcess();
|
||||||
|
string sessionName = $"{Environment.MachineName ?? "RUNNER"} (PID: {currentProcess.Id})";
|
||||||
var taskAgentSession = new TaskAgentSession(sessionName, agent);
|
var taskAgentSession = new TaskAgentSession(sessionName, agent);
|
||||||
|
|
||||||
string errorMessage = string.Empty;
|
string errorMessage = string.Empty;
|
||||||
@@ -263,8 +264,6 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
if (message != null && message.MessageType == BrokerMigrationMessage.MessageType)
|
if (message != null && message.MessageType == BrokerMigrationMessage.MessageType)
|
||||||
{
|
{
|
||||||
Trace.Info("BrokerMigration message received. Polling Broker for messages...");
|
|
||||||
|
|
||||||
var migrationMessage = JsonUtility.FromString<BrokerMigrationMessage>(message.Body);
|
var migrationMessage = JsonUtility.FromString<BrokerMigrationMessage>(message.Body);
|
||||||
|
|
||||||
await _brokerServer.UpdateConnectionIfNeeded(migrationMessage.BrokerBaseUrl, _creds);
|
await _brokerServer.UpdateConnectionIfNeeded(migrationMessage.BrokerBaseUrl, _creds);
|
||||||
@@ -309,6 +308,10 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
catch (RunnerNotFoundException)
|
||||||
|
{
|
||||||
|
throw;
|
||||||
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Trace.Error("Catch exception during get next message.");
|
Trace.Error("Catch exception during get next message.");
|
||||||
@@ -458,6 +461,7 @@ namespace GitHub.Runner.Listener
|
|||||||
ex is TaskAgentPoolNotFoundException ||
|
ex is TaskAgentPoolNotFoundException ||
|
||||||
ex is TaskAgentSessionExpiredException ||
|
ex is TaskAgentSessionExpiredException ||
|
||||||
ex is AccessDeniedException ||
|
ex is AccessDeniedException ||
|
||||||
|
ex is RunnerNotFoundException ||
|
||||||
ex is VssUnauthorizedException)
|
ex is VssUnauthorizedException)
|
||||||
{
|
{
|
||||||
Trace.Info($"Non-retriable exception: {ex.Message}");
|
Trace.Info($"Non-retriable exception: {ex.Message}");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Reflection;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -144,6 +145,12 @@ namespace GitHub.Runner.Listener
|
|||||||
trace.Error(e);
|
trace.Error(e);
|
||||||
return Constants.Runner.ReturnCode.TerminatedError;
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
terminal.WriteError($"An error occurred: {e.Message}");
|
terminal.WriteError($"An error occurred: {e.Message}");
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
||||||
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
||||||
@@ -18,11 +19,11 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.4.0" />
|
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -32,10 +32,25 @@ namespace GitHub.Runner.Listener
|
|||||||
private bool _inConfigStage;
|
private bool _inConfigStage;
|
||||||
private ManualResetEvent _completedCommand = new(false);
|
private ManualResetEvent _completedCommand = new(false);
|
||||||
|
|
||||||
|
// <summary>
|
||||||
|
// Helps avoid excessive calls to Run Service when encountering non-retriable errors from /acquirejob.
|
||||||
|
// Normally we rely on the HTTP clients to back off between retry attempts. However, acquiring a job
|
||||||
|
// involves calls to both Run Serivce and Broker. And Run Service and Broker communicate with each other
|
||||||
|
// in an async fashion.
|
||||||
|
//
|
||||||
|
// When Run Service encounters a non-retriable error, it sends an async message to Broker. The runner will,
|
||||||
|
// however, immediately call Broker to get the next message. If the async event from Run Service to Broker
|
||||||
|
// has not yet been processed, the next message from Broker may be the same job message.
|
||||||
|
//
|
||||||
|
// The error throttler helps us back off when encountering successive, non-retriable errors from /acquirejob.
|
||||||
|
// </summary>
|
||||||
|
private IErrorThrottler _acquireJobThrottler;
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
_term = HostContext.GetService<ITerminal>();
|
_term = HostContext.GetService<ITerminal>();
|
||||||
|
_acquireJobThrottler = HostContext.CreateService<IErrorThrottler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> ExecuteCommand(CommandSettings command)
|
public async Task<int> ExecuteCommand(CommandSettings command)
|
||||||
@@ -213,15 +228,21 @@ namespace GitHub.Runner.Listener
|
|||||||
var configFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), config.Key);
|
var configFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), config.Key);
|
||||||
var configContent = Convert.FromBase64String(config.Value);
|
var configContent = Convert.FromBase64String(config.Value);
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
if (configFile == HostContext.GetConfigFile(WellKnownConfigFile.RSACredentials))
|
if (configFile == HostContext.GetConfigFile(WellKnownConfigFile.RSACredentials))
|
||||||
{
|
{
|
||||||
configContent = ProtectedData.Protect(configContent, null, DataProtectionScope.LocalMachine);
|
configContent = ProtectedData.Protect(configContent, null, DataProtectionScope.LocalMachine);
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
#endif
|
#endif
|
||||||
File.WriteAllBytes(configFile, configContent);
|
File.WriteAllBytes(configFile, configContent);
|
||||||
File.SetAttributes(configFile, File.GetAttributes(configFile) | FileAttributes.Hidden);
|
File.SetAttributes(configFile, File.GetAttributes(configFile) | FileAttributes.Hidden);
|
||||||
Trace.Info($"Saved {configContent.Length} bytes to '{configFile}'.");
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -563,13 +584,16 @@ namespace GitHub.Runner.Listener
|
|||||||
await runServer.ConnectAsync(new Uri(messageRef.RunServiceUrl), creds);
|
await runServer.ConnectAsync(new Uri(messageRef.RunServiceUrl), creds);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
jobRequestMessage =
|
jobRequestMessage = await runServer.GetJobMessageAsync(messageRef.RunnerRequestId, messageQueueLoopTokenSource.Token);
|
||||||
await runServer.GetJobMessageAsync(messageRef.RunnerRequestId,
|
_acquireJobThrottler.Reset();
|
||||||
messageQueueLoopTokenSource.Token);
|
|
||||||
}
|
}
|
||||||
catch (TaskOrchestrationJobAlreadyAcquiredException)
|
catch (Exception ex) when (
|
||||||
|
ex is TaskOrchestrationJobNotFoundException || // HTTP status 404
|
||||||
|
ex is TaskOrchestrationJobAlreadyAcquiredException || // HTTP status 409
|
||||||
|
ex is TaskOrchestrationJobUnprocessableException) // HTTP status 422
|
||||||
{
|
{
|
||||||
Trace.Info("Job is already acquired, skip this message.");
|
Trace.Info($"Skipping message Job. {ex.Message}");
|
||||||
|
await _acquireJobThrottler.IncrementAndWaitAsync(messageQueueLoopTokenSource.Token);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
||||||
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
@@ -14,9 +15,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
|
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -60,5 +60,15 @@ namespace GitHub.Runner.Sdk
|
|||||||
}
|
}
|
||||||
return string.Empty;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -775,7 +775,19 @@ namespace GitHub.Runner.Worker
|
|||||||
// make sure we get a clean folder ready to use.
|
// make sure we get a clean folder ready to use.
|
||||||
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
|
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
|
||||||
Directory.CreateDirectory(destDirectory);
|
Directory.CreateDirectory(destDirectory);
|
||||||
executionContext.Output($"Download action repository '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}' (SHA:{downloadInfo.ResolvedSha})");
|
|
||||||
|
if (downloadInfo.PackageDetails != null)
|
||||||
|
{
|
||||||
|
executionContext.Output($"##[group]Download immutable action package '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}'");
|
||||||
|
executionContext.Output($"Version: {downloadInfo.PackageDetails.Version}");
|
||||||
|
executionContext.Output($"Digest: {downloadInfo.PackageDetails.ManifestDigest}");
|
||||||
|
executionContext.Output($"Source commit SHA: {downloadInfo.ResolvedSha}");
|
||||||
|
executionContext.Output("##[endgroup]");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
executionContext.Output($"Download action repository '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}' (SHA:{downloadInfo.ResolvedSha})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//download and extract action in a temp folder and rename it on success
|
//download and extract action in a temp folder and rename it on success
|
||||||
@@ -1102,6 +1114,7 @@ namespace GitHub.Runner.Worker
|
|||||||
int timeoutSeconds = 20 * 60;
|
int timeoutSeconds = 20 * 60;
|
||||||
while (retryCount < 3)
|
while (retryCount < 3)
|
||||||
{
|
{
|
||||||
|
string requestId = string.Empty;
|
||||||
using (var actionDownloadTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)))
|
using (var actionDownloadTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)))
|
||||||
using (var actionDownloadCancellation = CancellationTokenSource.CreateLinkedTokenSource(actionDownloadTimeout.Token, executionContext.CancellationToken))
|
using (var actionDownloadCancellation = CancellationTokenSource.CreateLinkedTokenSource(actionDownloadTimeout.Token, executionContext.CancellationToken))
|
||||||
{
|
{
|
||||||
@@ -1117,7 +1130,7 @@ namespace GitHub.Runner.Worker
|
|||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
using (var response = await httpClient.GetAsync(downloadUrl))
|
using (var response = await httpClient.GetAsync(downloadUrl))
|
||||||
{
|
{
|
||||||
var requestId = UrlUtil.GetGitHubRequestId(response.Headers);
|
requestId = UrlUtil.GetGitHubRequestId(response.Headers);
|
||||||
if (!string.IsNullOrEmpty(requestId))
|
if (!string.IsNullOrEmpty(requestId))
|
||||||
{
|
{
|
||||||
Trace.Info($"Request URL: {downloadUrl} X-GitHub-Request-Id: {requestId} Http Status: {response.StatusCode}");
|
Trace.Info($"Request URL: {downloadUrl} X-GitHub-Request-Id: {requestId} Http Status: {response.StatusCode}");
|
||||||
@@ -1155,7 +1168,7 @@ namespace GitHub.Runner.Worker
|
|||||||
catch (OperationCanceledException ex) when (!executionContext.CancellationToken.IsCancellationRequested && retryCount >= 2)
|
catch (OperationCanceledException ex) when (!executionContext.CancellationToken.IsCancellationRequested && retryCount >= 2)
|
||||||
{
|
{
|
||||||
Trace.Info($"Action download final retry timeout after {timeoutSeconds} seconds.");
|
Trace.Info($"Action download final retry timeout after {timeoutSeconds} seconds.");
|
||||||
throw new TimeoutException($"Action '{downloadUrl}' download has timed out. Error: {ex.Message}");
|
throw new TimeoutException($"Action '{downloadUrl}' download has timed out. Error: {ex.Message} {requestId}");
|
||||||
}
|
}
|
||||||
catch (ActionNotFoundException)
|
catch (ActionNotFoundException)
|
||||||
{
|
{
|
||||||
@@ -1170,11 +1183,11 @@ namespace GitHub.Runner.Worker
|
|||||||
if (actionDownloadTimeout.Token.IsCancellationRequested)
|
if (actionDownloadTimeout.Token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
// action download didn't finish within timeout
|
// action download didn't finish within timeout
|
||||||
executionContext.Warning($"Action '{downloadUrl}' didn't finish download within {timeoutSeconds} seconds.");
|
executionContext.Warning($"Action '{downloadUrl}' didn't finish download within {timeoutSeconds} seconds. {requestId}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
executionContext.Warning($"Failed to download action '{downloadUrl}'. Error: {ex.Message}");
|
executionContext.Warning($"Failed to download action '{downloadUrl}'. Error: {ex.Message} {requestId}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// Initialize
|
// Initialize
|
||||||
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
|
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
|
||||||
void CancelToken();
|
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, 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, List<Issue> embeddedIssueCollector = null, 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);
|
IExecutionContext CreateEmbeddedChild(string scopeName, string contextName, Guid embeddedId, ActionRunStage stage, Dictionary<string, string> intraActionState = null, string siblingScopeName = null);
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
@@ -135,7 +135,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
private readonly TimelineRecord _record = new();
|
private readonly TimelineRecord _record = new();
|
||||||
private readonly Dictionary<Guid, TimelineRecord> _detailRecords = new();
|
private readonly Dictionary<Guid, TimelineRecord> _detailRecords = new();
|
||||||
private readonly List<Issue> _embeddedIssueCollector;
|
|
||||||
private readonly object _loggerLock = new();
|
private readonly object _loggerLock = new();
|
||||||
private readonly object _matchersLock = new();
|
private readonly object _matchersLock = new();
|
||||||
private readonly ExecutionContext _parentExecutionContext;
|
private readonly ExecutionContext _parentExecutionContext;
|
||||||
@@ -154,6 +153,7 @@ namespace GitHub.Runner.Worker
|
|||||||
private CancellationTokenSource _cancellationTokenSource;
|
private CancellationTokenSource _cancellationTokenSource;
|
||||||
private TaskCompletionSource<int> _forceCompleted = new();
|
private TaskCompletionSource<int> _forceCompleted = new();
|
||||||
private bool _throttlingReported = false;
|
private bool _throttlingReported = false;
|
||||||
|
private List<Issue> _embeddedIssueCollector;
|
||||||
|
|
||||||
// only job level ExecutionContext will track throttling delay.
|
// only job level ExecutionContext will track throttling delay.
|
||||||
private long _totalThrottlingDelayInMilliseconds = 0;
|
private long _totalThrottlingDelayInMilliseconds = 0;
|
||||||
@@ -356,6 +356,7 @@ namespace GitHub.Runner.Worker
|
|||||||
int? recordOrder = null,
|
int? recordOrder = null,
|
||||||
IPagingLogger logger = null,
|
IPagingLogger logger = null,
|
||||||
bool isEmbedded = false,
|
bool isEmbedded = false,
|
||||||
|
List<Issue> embeddedIssueCollector = null,
|
||||||
CancellationTokenSource cancellationTokenSource = null,
|
CancellationTokenSource cancellationTokenSource = null,
|
||||||
Guid embeddedId = default(Guid),
|
Guid embeddedId = default(Guid),
|
||||||
string siblingScopeName = null,
|
string siblingScopeName = null,
|
||||||
@@ -365,6 +366,10 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
var child = new ExecutionContext(this, isEmbedded);
|
var child = new ExecutionContext(this, isEmbedded);
|
||||||
child.Initialize(HostContext);
|
child.Initialize(HostContext);
|
||||||
|
if ((Global.Variables.GetBoolean("RunService.FixEmbeddedIssues") ?? false) && embeddedIssueCollector != null)
|
||||||
|
{
|
||||||
|
child._embeddedIssueCollector = embeddedIssueCollector;
|
||||||
|
}
|
||||||
child.Global = Global;
|
child.Global = Global;
|
||||||
child.ScopeName = scopeName;
|
child.ScopeName = scopeName;
|
||||||
child.ContextName = contextName;
|
child.ContextName = contextName;
|
||||||
@@ -433,7 +438,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Dictionary<string, string> intraActionState = null,
|
Dictionary<string, string> intraActionState = null,
|
||||||
string siblingScopeName = null)
|
string siblingScopeName = null)
|
||||||
{
|
{
|
||||||
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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(string currentOperation = null)
|
public void Start(string currentOperation = null)
|
||||||
@@ -503,6 +508,9 @@ namespace GitHub.Runner.Worker
|
|||||||
Status = _record.State,
|
Status = _record.State,
|
||||||
Number = _record.Order,
|
Number = _record.Order,
|
||||||
Name = _record.Name,
|
Name = _record.Name,
|
||||||
|
ActionName = StepTelemetry?.Action,
|
||||||
|
Ref = StepTelemetry?.Ref,
|
||||||
|
Type = StepTelemetry?.Type,
|
||||||
StartedAt = _record.StartTime,
|
StartedAt = _record.StartTime,
|
||||||
CompletedAt = _record.FinishTime,
|
CompletedAt = _record.FinishTime,
|
||||||
Annotations = new List<Annotation>()
|
Annotations = new List<Annotation>()
|
||||||
@@ -520,7 +528,6 @@ namespace GitHub.Runner.Worker
|
|||||||
Global.StepsResult.Add(stepResult);
|
Global.StepsResult.Add(stepResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Root != this)
|
if (Root != this)
|
||||||
{
|
{
|
||||||
// only dispose TokenSource for step level ExecutionContext
|
// only dispose TokenSource for step level ExecutionContext
|
||||||
@@ -808,11 +815,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
Global.Variables = new Variables(HostContext, variables);
|
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
|
// Environment variables shared across all actions
|
||||||
Global.EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer);
|
Global.EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer);
|
||||||
|
|
||||||
@@ -837,7 +839,6 @@ namespace GitHub.Runner.Worker
|
|||||||
// Actions environment
|
// Actions environment
|
||||||
ActionsEnvironment = message.ActionsEnvironment;
|
ActionsEnvironment = message.ActionsEnvironment;
|
||||||
|
|
||||||
|
|
||||||
// Service container info
|
// Service container info
|
||||||
Global.ServiceContainers = new List<ContainerInfo>();
|
Global.ServiceContainers = new List<ContainerInfo>();
|
||||||
|
|
||||||
@@ -1418,7 +1419,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
if (key == PipelineTemplateConstants.HostWorkspace)
|
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
|
// This var can be used to translate back from container paths, e.g. in HashFilesFunction, which always runs on the host machine
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,72 +57,13 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
handler = HostContext.CreateService<INodeScriptActionHandler>();
|
handler = HostContext.CreateService<INodeScriptActionHandler>();
|
||||||
var nodeData = data as NodeJSActionExecutionData;
|
var nodeData = data as NodeJSActionExecutionData;
|
||||||
|
|
||||||
// With node12 EoL in 04/2022, we want to be able to uniformly upgrade all JS actions to node16 from the server
|
// 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))
|
if (string.Equals(nodeData.NodeVersion, "node12", StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
string.Equals(nodeData.NodeVersion, "node16", StringComparison.InvariantCultureIgnoreCase))
|
||||||
{
|
{
|
||||||
var repoAction = action as Pipelines.RepositoryPathReference;
|
nodeData.NodeVersion = "node20";
|
||||||
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;
|
(handler as INodeScriptActionHandler).Data = nodeData;
|
||||||
}
|
}
|
||||||
else if (data.ExecutionType == ActionExecutionType.Script)
|
else if (data.ExecutionType == ActionExecutionType.Script)
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
Environment["ACTIONS_RESULTS_URL"] = resultsUrl;
|
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.
|
// Resolve the target script.
|
||||||
string target = null;
|
string target = null;
|
||||||
if (stage == ActionRunStage.Main)
|
if (stage == ActionRunStage.Main)
|
||||||
@@ -93,7 +98,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
ExecutionContext.StepTelemetry.HasPreStep = Data.HasPre;
|
ExecutionContext.StepTelemetry.HasPreStep = Data.HasPre;
|
||||||
ExecutionContext.StepTelemetry.HasPostStep = Data.HasPost;
|
ExecutionContext.StepTelemetry.HasPostStep = Data.HasPost;
|
||||||
}
|
}
|
||||||
ExecutionContext.StepTelemetry.Type = Data.NodeVersion;
|
|
||||||
|
|
||||||
ArgUtil.NotNullOrEmpty(target, nameof(target));
|
ArgUtil.NotNullOrEmpty(target, nameof(target));
|
||||||
target = Path.Combine(ActionDirectory, target);
|
target = Path.Combine(ActionDirectory, target);
|
||||||
@@ -106,24 +110,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
|
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);
|
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}");
|
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
|
||||||
// Format the arguments passed to node.
|
// Format the arguments passed to node.
|
||||||
@@ -143,28 +131,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Remove environment variable that may cause conflicts with the node within the runner.
|
// 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
|
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 stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||||
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ using GitHub.Runner.Common;
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
@@ -42,11 +43,13 @@ namespace GitHub.Runner.Worker
|
|||||||
public sealed class JobExtension : RunnerService, IJobExtension
|
public sealed class JobExtension : RunnerService, IJobExtension
|
||||||
{
|
{
|
||||||
private readonly HashSet<string> _existingProcesses = new(StringComparer.OrdinalIgnoreCase);
|
private readonly HashSet<string> _existingProcesses = new(StringComparer.OrdinalIgnoreCase);
|
||||||
private readonly List<Task<string>> _connectivityCheckTasks = new();
|
private readonly List<Task<CheckResult>> _connectivityCheckTasks = new();
|
||||||
private bool _processCleanup;
|
private bool _processCleanup;
|
||||||
private string _processLookupId = $"github_{Guid.NewGuid()}";
|
private string _processLookupId = $"github_{Guid.NewGuid()}";
|
||||||
private CancellationTokenSource _diskSpaceCheckToken = new();
|
private CancellationTokenSource _diskSpaceCheckToken = new();
|
||||||
private Task _diskSpaceCheckTask = null;
|
private Task _diskSpaceCheckTask = null;
|
||||||
|
private CancellationTokenSource _serviceConnectivityCheckToken = new();
|
||||||
|
private Task _serviceConnectivityCheckTask = null;
|
||||||
|
|
||||||
// Download all required actions.
|
// Download all required actions.
|
||||||
// Make sure all condition inputs are valid.
|
// Make sure all condition inputs are valid.
|
||||||
@@ -399,7 +402,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var snapshotOperationProvider = HostContext.GetService<ISnapshotOperationProvider>();
|
var snapshotOperationProvider = HostContext.GetService<ISnapshotOperationProvider>();
|
||||||
jobContext.RegisterPostJobStep(new JobExtensionRunner(
|
jobContext.RegisterPostJobStep(new JobExtensionRunner(
|
||||||
runAsync: (executionContext, _) => snapshotOperationProvider.CreateSnapshotRequestAsync(executionContext, snapshotRequest),
|
runAsync: (executionContext, _) => snapshotOperationProvider.CreateSnapshotRequestAsync(executionContext, snapshotRequest),
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
condition: snapshotRequest.Condition,
|
||||||
displayName: $"Create custom image",
|
displayName: $"Create custom image",
|
||||||
data: null));
|
data: null));
|
||||||
}
|
}
|
||||||
@@ -454,11 +457,14 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
foreach (var checkUrl in checkUrls)
|
foreach (var checkUrl in checkUrls)
|
||||||
{
|
{
|
||||||
_connectivityCheckTasks.Add(CheckConnectivity(checkUrl));
|
_connectivityCheckTasks.Add(CheckConnectivity(checkUrl, accessToken: string.Empty, timeoutInSeconds: 5, token: CancellationToken.None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Trace.Info($"Start checking service connectivity in background.");
|
||||||
|
_serviceConnectivityCheckTask = CheckServiceConnectivityAsync(context, _serviceConnectivityCheckToken.Token);
|
||||||
|
|
||||||
return steps;
|
return steps;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException ex) when (jobContext.CancellationToken.IsCancellationRequested)
|
catch (OperationCanceledException ex) when (jobContext.CancellationToken.IsCancellationRequested)
|
||||||
@@ -692,7 +698,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
var result = await check;
|
var result = await check;
|
||||||
Trace.Info($"Connectivity check result: {result}");
|
Trace.Info($"Connectivity check result: {result}");
|
||||||
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = result });
|
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = $"{result.EndpointUrl}: {result.StatusCode}" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -702,6 +708,22 @@ namespace GitHub.Runner.Worker
|
|||||||
context.Global.JobTelemetry.Add(new JobTelemetry() { Type = JobTelemetryType.ConnectivityCheck, Message = $"Fail to check server connectivity. {ex.Message}" });
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -717,11 +739,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> CheckConnectivity(string endpointUrl)
|
private async Task<CheckResult> CheckConnectivity(string endpointUrl, string accessToken, int timeoutInSeconds, CancellationToken token)
|
||||||
{
|
{
|
||||||
Trace.Info($"Check server connectivity for {endpointUrl}.");
|
Trace.Info($"Check server connectivity for {endpointUrl}.");
|
||||||
string result = string.Empty;
|
CheckResult result = new CheckResult() { EndpointUrl = endpointUrl };
|
||||||
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(5)))
|
var stopwatch = Stopwatch.StartNew();
|
||||||
|
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutInSeconds)))
|
||||||
|
using (var linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, timeoutTokenSource.Token))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -729,21 +753,44 @@ namespace GitHub.Runner.Worker
|
|||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
{
|
{
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
var response = await httpClient.GetAsync(endpointUrl, timeoutTokenSource.Token);
|
if (!string.IsNullOrEmpty(accessToken))
|
||||||
result = $"{endpointUrl}: {response.StatusCode}";
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
catch (Exception ex) when (ex is OperationCanceledException && timeoutTokenSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Trace.Error($"Request timeout during connectivity check: {ex}");
|
Trace.Error($"Request timeout during connectivity check: {ex}");
|
||||||
result = $"{endpointUrl}: timeout";
|
result.StatusCode = "timeout";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Trace.Error($"Catch exception during connectivity check: {ex}");
|
Trace.Error($"Catch exception during connectivity check: {ex}");
|
||||||
result = $"{endpointUrl}: {ex.Message}";
|
result.StatusCode = $"{ex.Message}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stopwatch.Stop();
|
||||||
|
result.DurationInMs = (int)stopwatch.ElapsedMilliseconds;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -781,6 +828,84 @@ 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()
|
private Dictionary<int, Process> SnapshotProcesses()
|
||||||
{
|
{
|
||||||
Dictionary<int, Process> snapshot = new();
|
Dictionary<int, Process> snapshot = new();
|
||||||
@@ -812,5 +937,23 @@ 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.");
|
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; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using GitHub.Runner.Common.Util;
|
|||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
|
using Sdk.RSWebApi.Contracts;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
@@ -49,7 +50,8 @@ namespace GitHub.Runner.Worker
|
|||||||
if (message.Variables.TryGetValue(Constants.Variables.System.OrchestrationId, out VariableValue orchestrationId) &&
|
if (message.Variables.TryGetValue(Constants.Variables.System.OrchestrationId, out VariableValue orchestrationId) &&
|
||||||
!string.IsNullOrEmpty(orchestrationId.Value))
|
!string.IsNullOrEmpty(orchestrationId.Value))
|
||||||
{
|
{
|
||||||
HostContext.UserAgents.Add(new ProductInfoHeaderValue("OrchestrationId", 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));
|
||||||
|
|
||||||
// make sure orchestration id is in the user-agent header.
|
// make sure orchestration id is in the user-agent header.
|
||||||
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
|
VssUtil.InitializeVssClientSettings(HostContext.UserAgents, HostContext.WebProxy);
|
||||||
@@ -278,26 +280,14 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
jobContext.Debug($"Finishing: {message.JobDisplayName}");
|
jobContext.Debug($"Finishing: {message.JobDisplayName}");
|
||||||
TaskResult result = jobContext.Complete(taskResult);
|
TaskResult result = jobContext.Complete(taskResult);
|
||||||
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 jobQueueTelemetry = await ShutdownQueue(throwOnFailure: false);
|
||||||
|
// include any job telemetry from the background upload process.
|
||||||
|
if (jobQueueTelemetry?.Count > 0)
|
||||||
{
|
{
|
||||||
var actions = string.Join(", ", StringUtil.ConvertFromJson<HashSet<string>>(node16ForceWarnings));
|
jobContext.Global.JobTelemetry.AddRange(jobQueueTelemetry);
|
||||||
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.
|
// Make sure to clean temp after file upload since they may be pending fileupload still use the TEMP dir.
|
||||||
_tempDirectoryManager?.CleanupTempDirectory();
|
_tempDirectoryManager?.CleanupTempDirectory();
|
||||||
|
|
||||||
@@ -314,6 +304,13 @@ namespace GitHub.Runner.Worker
|
|||||||
environmentUrl = urlStringToken.Value;
|
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");
|
Trace.Info($"Raising job completed against run service");
|
||||||
var completeJobRetryLimit = 5;
|
var completeJobRetryLimit = 5;
|
||||||
var exceptions = new List<Exception>();
|
var exceptions = new List<Exception>();
|
||||||
@@ -321,7 +318,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, jobContext.Global.JobAnnotations, environmentUrl, default);
|
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, result, jobContext.JobOutputs, jobContext.Global.StepsResult, jobContext.Global.JobAnnotations, environmentUrl, telemetry, default);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -346,74 +343,14 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (_runnerSettings.DisableUpdate == true)
|
if (_runnerSettings.DisableUpdate == true)
|
||||||
{
|
{
|
||||||
try
|
await WarningOutdatedRunnerAsync(jobContext, message, result);
|
||||||
{
|
|
||||||
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
|
try
|
||||||
{
|
{
|
||||||
var jobQueueTelemetry = await ShutdownQueue(throwOnFailure: true);
|
var jobQueueTelemetry = await ShutdownQueue(throwOnFailure: true);
|
||||||
// include any job telemetry from the background upload process.
|
// include any job telemetry from the background upload process.
|
||||||
if (jobQueueTelemetry.Count > 0)
|
if (jobQueueTelemetry?.Count > 0)
|
||||||
{
|
{
|
||||||
jobContext.Global.JobTelemetry.AddRange(jobQueueTelemetry);
|
jobContext.Global.JobTelemetry.AddRange(jobQueueTelemetry);
|
||||||
}
|
}
|
||||||
@@ -541,5 +478,52 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
return Array.Empty<JobTelemetry>();
|
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}");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
||||||
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
||||||
@@ -18,9 +19,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="8.0.0" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
|
<PackageReference Include="System.Threading.Channels" Version="8.0.0" />
|
||||||
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ namespace GitHub.Services.Common
|
|||||||
|
|
||||||
public String PropertyName { get; set; }
|
public String PropertyName { get; set; }
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
[SecurityCritical]
|
[SecurityCritical]
|
||||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ namespace GitHub.Services.Common
|
|||||||
EventId = (int)info.GetValue("m_eventId", typeof(int));
|
EventId = (int)info.GetValue("m_eventId", typeof(int));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
[SecurityCritical]
|
[SecurityCritical]
|
||||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String If = "if";
|
public const String If = "if";
|
||||||
public const String Image = "image";
|
public const String Image = "image";
|
||||||
public const String ImageName = "image-name";
|
public const String ImageName = "image-name";
|
||||||
|
public const String CustomImageVersion = "version";
|
||||||
public const String Include = "include";
|
public const String Include = "include";
|
||||||
public const String Inputs = "inputs";
|
public const String Inputs = "inputs";
|
||||||
public const String Job = "job";
|
public const String Job = "job";
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.Expressions2;
|
using GitHub.DistributedTask.Expressions2;
|
||||||
using GitHub.DistributedTask.Expressions2.Sdk;
|
using GitHub.DistributedTask.Expressions2.Sdk;
|
||||||
@@ -349,6 +350,10 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
internal static Snapshot ConvertToJobSnapshotRequest(TemplateContext context, TemplateToken token)
|
internal static Snapshot ConvertToJobSnapshotRequest(TemplateContext context, TemplateToken token)
|
||||||
{
|
{
|
||||||
string imageName = null;
|
string imageName = null;
|
||||||
|
string version = "1.*";
|
||||||
|
string versionString = string.Empty;
|
||||||
|
var condition = $"{PipelineTemplateConstants.Success}()";
|
||||||
|
|
||||||
if (token is StringToken snapshotStringLiteral)
|
if (token is StringToken snapshotStringLiteral)
|
||||||
{
|
{
|
||||||
imageName = snapshotStringLiteral.Value;
|
imageName = snapshotStringLiteral.Value;
|
||||||
@@ -359,11 +364,19 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
foreach (var snapshotPropertyPair in snapshotMapping)
|
foreach (var snapshotPropertyPair in snapshotMapping)
|
||||||
{
|
{
|
||||||
var propertyName = snapshotPropertyPair.Key.AssertString($"{PipelineTemplateConstants.Snapshot} key");
|
var propertyName = snapshotPropertyPair.Key.AssertString($"{PipelineTemplateConstants.Snapshot} key");
|
||||||
|
var propertyValue = snapshotPropertyPair.Value;
|
||||||
switch (propertyName.Value)
|
switch (propertyName.Value)
|
||||||
{
|
{
|
||||||
case PipelineTemplateConstants.ImageName:
|
case PipelineTemplateConstants.ImageName:
|
||||||
imageName = snapshotPropertyPair.Value.AssertString($"{PipelineTemplateConstants.Snapshot} {propertyName}").Value;
|
imageName = snapshotPropertyPair.Value.AssertString($"{PipelineTemplateConstants.Snapshot} {propertyName}").Value;
|
||||||
break;
|
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:
|
default:
|
||||||
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Snapshot} key");
|
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Snapshot} key");
|
||||||
break;
|
break;
|
||||||
@@ -376,7 +389,26 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Snapshot(imageName);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionStep ConvertToStep(
|
private static ActionStep ConvertToStep(
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.Pipelines
|
namespace GitHub.DistributedTask.Pipelines
|
||||||
{
|
{
|
||||||
[DataContract]
|
[DataContract]
|
||||||
public class Snapshot
|
public class Snapshot
|
||||||
{
|
{
|
||||||
public Snapshot(string imageName)
|
public Snapshot(string imageName, string condition = null, string version = null)
|
||||||
{
|
{
|
||||||
ImageName = imageName;
|
ImageName = imageName;
|
||||||
|
Condition = condition ?? $"{PipelineTemplateConstants.Success}()";
|
||||||
|
Version = version ?? "1.*";
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public String ImageName { get; set; }
|
public String ImageName { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public String Condition { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public String Version { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,11 +169,28 @@
|
|||||||
"image-name": {
|
"image-name": {
|
||||||
"type": "non-empty-string",
|
"type": "non-empty-string",
|
||||||
"required": true
|
"required": true
|
||||||
|
},
|
||||||
|
"if": "snapshot-if",
|
||||||
|
"version": {
|
||||||
|
"type": "non-empty-string",
|
||||||
|
"required": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"snapshot-if": {
|
||||||
|
"context": [
|
||||||
|
"github",
|
||||||
|
"inputs",
|
||||||
|
"vars",
|
||||||
|
"needs",
|
||||||
|
"strategy",
|
||||||
|
"matrix"
|
||||||
|
],
|
||||||
|
"string": {}
|
||||||
|
},
|
||||||
|
|
||||||
"runs-on": {
|
"runs-on": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public ActionDownloadAuthentication Authentication { get; set; }
|
public ActionDownloadAuthentication Authentication { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public ActionDownloadPackageDetails PackageDetails { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string NameWithOwner { get; set; }
|
public string NameWithOwner { get; set; }
|
||||||
|
|
||||||
@@ -37,4 +40,14 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public class ActionDownloadPackageDetails
|
||||||
|
{
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public string ManifestDigest { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1539,6 +1539,26 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationJobUnprocessableException", "GitHub.DistributedTask.WebApi.TaskOrchestrationJobUnprocessableException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
||||||
|
public sealed class TaskOrchestrationJobUnprocessableException : DistributedTaskException
|
||||||
|
{
|
||||||
|
public TaskOrchestrationJobUnprocessableException(String message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public TaskOrchestrationJobUnprocessableException(String message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private TaskOrchestrationJobUnprocessableException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Serializable]
|
[Serializable]
|
||||||
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationPlanSecurityException", "GitHub.DistributedTask.WebApi.TaskOrchestrationPlanSecurityException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
[ExceptionMapping("0.0", "3.0", "TaskOrchestrationPlanSecurityException", "GitHub.DistributedTask.WebApi.TaskOrchestrationPlanSecurityException, GitHub.DistributedTask.WebApi, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
|
||||||
public sealed class TaskOrchestrationPlanSecurityException : DistributedTaskException
|
public sealed class TaskOrchestrationPlanSecurityException : DistributedTaskException
|
||||||
|
|||||||
42
src/Sdk/DTWebApi/WebApi/ServiceConnectivityCheck.cs
Normal file
42
src/Sdk/DTWebApi/WebApi/ServiceConnectivityCheck.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,5 +7,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
public static readonly String JobId = "system.jobId";
|
public static readonly String JobId = "system.jobId";
|
||||||
public static readonly String RunnerLowDiskspaceThreshold = "system.runner.lowdiskspacethreshold";
|
public static readonly String RunnerLowDiskspaceThreshold = "system.runner.lowdiskspacethreshold";
|
||||||
public static readonly String RunnerEnvironment = "system.runnerEnvironment";
|
public static readonly String RunnerEnvironment = "system.runnerEnvironment";
|
||||||
|
public static readonly String RunnerServiceConnectivityTest = "system.runner.serviceconnectivitycheckinput";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,5 +31,8 @@ namespace Sdk.RSWebApi.Contracts
|
|||||||
|
|
||||||
[DataMember(Name = "endColumn", EmitDefaultValue = false)]
|
[DataMember(Name = "endColumn", EmitDefaultValue = false)]
|
||||||
public long EndColumn;
|
public long EndColumn;
|
||||||
|
|
||||||
|
[DataMember(Name = "stepNumber", EmitDefaultValue = false)]
|
||||||
|
public long StepNumber;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
src/Sdk/RSWebApi/Contracts/BrokerError.cs
Normal file
20
src/Sdk/RSWebApi/Contracts/BrokerError.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Sdk/RSWebApi/Contracts/BrokerErrorKind.cs
Normal file
11
src/Sdk/RSWebApi/Contracts/BrokerErrorKind.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace GitHub.Actions.RunService.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public class BrokerErrorKind
|
||||||
|
{
|
||||||
|
public const string RunnerNotFound = "RunnerNotFound";
|
||||||
|
public const string RunnerVersionTooOld = "RunnerVersionTooOld";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,6 +27,9 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
[DataMember(Name = "annotations", EmitDefaultValue = false)]
|
[DataMember(Name = "annotations", EmitDefaultValue = false)]
|
||||||
public IList<Annotation> Annotations { get; set; }
|
public IList<Annotation> Annotations { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "telemetry", EmitDefaultValue = false)]
|
||||||
|
public IList<Telemetry> Telemetry { get; set; }
|
||||||
|
|
||||||
[DataMember(Name = "environmentUrl", EmitDefaultValue = false)]
|
[DataMember(Name = "environmentUrl", EmitDefaultValue = false)]
|
||||||
public string EnvironmentUrl { get; set; }
|
public string EnvironmentUrl { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace Sdk.RSWebApi.Contracts
|
|||||||
var columnNumber = GetAnnotationNumber(issue, RunIssueKeys.Col) ?? 0;
|
var columnNumber = GetAnnotationNumber(issue, RunIssueKeys.Col) ?? 0;
|
||||||
var endColumnNumber = GetAnnotationNumber(issue, RunIssueKeys.EndColumn) ?? columnNumber;
|
var endColumnNumber = GetAnnotationNumber(issue, RunIssueKeys.EndColumn) ?? columnNumber;
|
||||||
var logLineNumber = GetAnnotationNumber(issue, RunIssueKeys.LogLineNumber) ?? 0;
|
var logLineNumber = GetAnnotationNumber(issue, RunIssueKeys.LogLineNumber) ?? 0;
|
||||||
|
var stepNumber = GetAnnotationNumber(issue, RunIssueKeys.StepNumber) ?? 0;
|
||||||
|
|
||||||
if (path == null && lineNumber == 0 && logLineNumber != 0)
|
if (path == null && lineNumber == 0 && logLineNumber != 0)
|
||||||
{
|
{
|
||||||
@@ -38,6 +39,7 @@ namespace Sdk.RSWebApi.Contracts
|
|||||||
EndLine = endLineNumber,
|
EndLine = endLineNumber,
|
||||||
StartColumn = columnNumber,
|
StartColumn = columnNumber,
|
||||||
EndColumn = endColumnNumber,
|
EndColumn = endColumnNumber,
|
||||||
|
StepNumber = stepNumber,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,6 @@
|
|||||||
public const string EndLine = "endLine";
|
public const string EndLine = "endLine";
|
||||||
public const string EndColumn = "endColumn";
|
public const string EndColumn = "endColumn";
|
||||||
public const string LogLineNumber = "logFileLineNumber";
|
public const string LogLineNumber = "logFileLineNumber";
|
||||||
|
public const string StepNumber = "stepNumber";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
17
src/Sdk/RSWebApi/Contracts/RunServiceError.cs
Normal file
17
src/Sdk/RSWebApi/Contracts/RunServiceError.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -16,9 +16,20 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
[DataMember(Name = "number", EmitDefaultValue = false)]
|
[DataMember(Name = "number", EmitDefaultValue = false)]
|
||||||
public int? Number { get; set; }
|
public int? Number { get; set; }
|
||||||
|
|
||||||
|
// Example: "Run actions/checkout@v3"
|
||||||
[DataMember(Name = "name", EmitDefaultValue = false)]
|
[DataMember(Name = "name", EmitDefaultValue = false)]
|
||||||
public string Name { get; set; }
|
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")]
|
[DataMember(Name = "status")]
|
||||||
public TimelineRecordState? Status { get; set; }
|
public TimelineRecordState? Status { get; set; }
|
||||||
|
|
||||||
|
|||||||
20
src/Sdk/RSWebApi/Contracts/Telemetry.cs
Normal file
20
src/Sdk/RSWebApi/Contracts/Telemetry.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -86,6 +87,7 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri: requestUri,
|
requestUri: requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
|
readErrorBody: true,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
@@ -93,14 +95,26 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
return result.Value;
|
return result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (result.StatusCode)
|
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
|
||||||
{
|
{
|
||||||
case HttpStatusCode.NotFound:
|
switch ((HttpStatusCode)error.Code)
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job message not found: {messageId}");
|
{
|
||||||
case HttpStatusCode.Conflict:
|
case HttpStatusCode.NotFound:
|
||||||
throw new TaskOrchestrationJobAlreadyAcquiredException($"Job message already acquired: {messageId}");
|
throw new TaskOrchestrationJobNotFoundException($"Job message not found '{messageId}'. {error.Message}");
|
||||||
default:
|
case HttpStatusCode.Conflict:
|
||||||
throw new Exception($"Failed to get job message: {result.Error}");
|
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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,11 +122,12 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
Guid planId,
|
Guid planId,
|
||||||
Guid jobId,
|
Guid jobId,
|
||||||
TaskResult result,
|
TaskResult conclusion,
|
||||||
Dictionary<String, VariableValue> outputs,
|
Dictionary<String, VariableValue> outputs,
|
||||||
IList<StepResult> stepResults,
|
IList<StepResult> stepResults,
|
||||||
IList<Annotation> jobAnnotations,
|
IList<Annotation> jobAnnotations,
|
||||||
string environmentUrl,
|
string environmentUrl,
|
||||||
|
IList<Telemetry> telemetry,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
HttpMethod httpMethod = new HttpMethod("POST");
|
HttpMethod httpMethod = new HttpMethod("POST");
|
||||||
@@ -120,32 +135,43 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
{
|
{
|
||||||
PlanID = planId,
|
PlanID = planId,
|
||||||
JobID = jobId,
|
JobID = jobId,
|
||||||
Conclusion = result,
|
Conclusion = conclusion,
|
||||||
Outputs = outputs,
|
Outputs = outputs,
|
||||||
StepResults = stepResults,
|
StepResults = stepResults,
|
||||||
Annotations = jobAnnotations,
|
Annotations = jobAnnotations,
|
||||||
EnvironmentUrl = environmentUrl,
|
EnvironmentUrl = environmentUrl,
|
||||||
|
Telemetry = telemetry,
|
||||||
};
|
};
|
||||||
|
|
||||||
requestUri = new Uri(requestUri, "completejob");
|
requestUri = new Uri(requestUri, "completejob");
|
||||||
|
|
||||||
var requestContent = new ObjectContent<CompleteJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
|
var requestContent = new ObjectContent<CompleteJobRequest>(payload, new VssJsonMediaTypeFormatter(true));
|
||||||
var response = await SendAsync(
|
var result = await Send2Async(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri,
|
requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
if (response.IsSuccessStatusCode)
|
if (result.IsSuccess)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (response.StatusCode)
|
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
|
||||||
{
|
{
|
||||||
case HttpStatusCode.NotFound:
|
switch ((HttpStatusCode)error.Code)
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
|
{
|
||||||
default:
|
case HttpStatusCode.NotFound:
|
||||||
throw new Exception($"Failed to complete job: {response.ReasonPhrase}");
|
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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +195,7 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
httpMethod,
|
httpMethod,
|
||||||
requestUri,
|
requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
|
readErrorBody: true,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
@@ -176,12 +203,22 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
return result.Value;
|
return result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (result.StatusCode)
|
if (TryParseErrorBody(result.ErrorBody, out RunServiceError error))
|
||||||
{
|
{
|
||||||
case HttpStatusCode.NotFound:
|
switch ((HttpStatusCode)error.Code)
|
||||||
throw new TaskOrchestrationJobNotFoundException($"Job not found: {jobId}");
|
{
|
||||||
default:
|
case HttpStatusCode.NotFound:
|
||||||
throw new Exception($"Failed to renew job: {result.Error}");
|
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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,5 +227,36 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
var json = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||||
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
return JsonConvert.DeserializeObject<T>(json, s_serializerSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool TryParseErrorBody(string errorBody, out RunServiceError error)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(errorBody))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
error = JsonUtility.FromString<RunServiceError>(errorBody);
|
||||||
|
if (error?.Source == "actions-run-service")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
error = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Truncate(string errorBody)
|
||||||
|
{
|
||||||
|
if (errorBody.Length > 100)
|
||||||
|
{
|
||||||
|
return errorBody.Substring(0, 100) + "[truncated]";
|
||||||
|
}
|
||||||
|
|
||||||
|
return errorBody;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
|
<!-- <SelfContained>true</SelfContained> -->
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
<LangVersion>8.0</LangVersion>
|
<LangVersion>8.0</LangVersion>
|
||||||
@@ -13,18 +14,20 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Azure.Storage.Blobs" Version="12.19.1" />
|
<PackageReference Include="Azure.Storage.Blobs" Version="12.23.0" />
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="6.0.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.2.1" />
|
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.5.1" />
|
||||||
<PackageReference Include="System.Security.Cryptography.Cng" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.Cng" Version="5.0.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.Pkcs" Version="8.0.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="8.0.0" />
|
||||||
<PackageReference Include="Minimatch" Version="2.0.0" />
|
<PackageReference Include="Minimatch" Version="2.0.0" />
|
||||||
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
<PackageReference Include="YamlDotNet.Signed" Version="5.3.0" />
|
||||||
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
<PackageReference Include="System.Net.Http" Version="4.3.4" />
|
||||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
<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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
new HttpMethod("GET"),
|
new HttpMethod("GET"),
|
||||||
requestUri: requestUri,
|
requestUri: requestUri,
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
|
readErrorBody: true,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|
||||||
if (result.IsSuccess)
|
if (result.IsSuccess)
|
||||||
@@ -110,8 +111,23 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
return result.Value;
|
return result.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the only time we throw a `Forbidden` exception from Listener /messages is when the runner is
|
if (TryParseErrorBody(result.ErrorBody, out BrokerError brokerError))
|
||||||
// disable_update and is too old to poll
|
{
|
||||||
|
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
|
||||||
if (result.StatusCode == HttpStatusCode.Forbidden)
|
if (result.StatusCode == HttpStatusCode.Forbidden)
|
||||||
{
|
{
|
||||||
throw new AccessDeniedException($"{result.Error} Runner version v{runnerVersion} is deprecated and cannot receive messages.")
|
throw new AccessDeniedException($"{result.Error} Runner version v{runnerVersion} is deprecated and cannot receive messages.")
|
||||||
@@ -120,7 +136,7 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception($"Failed to get job message: {result.Error}");
|
throw new Exception($"Failed to get job message. Request to {requestUri} failed with status: {result.StatusCode}. Error message {result.Error}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TaskAgentSession> CreateSessionAsync(
|
public async Task<TaskAgentSession> CreateSessionAsync(
|
||||||
@@ -172,5 +188,26 @@ namespace GitHub.Actions.RunService.WebApi
|
|||||||
|
|
||||||
throw new Exception($"Failed to delete broker session: {result.Error}");
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
26
src/Sdk/WebApi/WebApi/Exceptions/RunnerNotFoundException.cs
Normal file
26
src/Sdk/WebApi/WebApi/Exceptions/RunnerNotFoundException.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -29,6 +29,9 @@ namespace GitHub.Services.Launch.Contracts
|
|||||||
{
|
{
|
||||||
[DataMember(EmitDefaultValue = false, Name = "authentication")]
|
[DataMember(EmitDefaultValue = false, Name = "authentication")]
|
||||||
public ActionDownloadAuthenticationResponse Authentication { get; set; }
|
public ActionDownloadAuthenticationResponse Authentication { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false, Name = "package_details")]
|
||||||
|
public ActionDownloadPackageDetailsResponse PackageDetails { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false, Name = "name")]
|
[DataMember(EmitDefaultValue = false, Name = "name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
@@ -59,6 +62,17 @@ namespace GitHub.Services.Launch.Contracts
|
|||||||
public string Token { get; set; }
|
public string Token { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public class ActionDownloadPackageDetailsResponse
|
||||||
|
{
|
||||||
|
[DataMember(EmitDefaultValue = false, Name = "version")]
|
||||||
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false, Name = "manifest_digest")]
|
||||||
|
public string ManifestDigest { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
public class ActionDownloadInfoResponseCollection
|
public class ActionDownloadInfoResponseCollection
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ namespace GitHub.Services.Launch.Client
|
|||||||
TarballUrl = actionDownloadInfoResponse.TarUrl,
|
TarballUrl = actionDownloadInfoResponse.TarUrl,
|
||||||
Ref = actionDownloadInfoResponse.Version,
|
Ref = actionDownloadInfoResponse.Version,
|
||||||
ZipballUrl = actionDownloadInfoResponse.ZipUrl,
|
ZipballUrl = actionDownloadInfoResponse.ZipUrl,
|
||||||
|
PackageDetails = ToServerData(actionDownloadInfoResponse.PackageDetails)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +109,21 @@ namespace GitHub.Services.Launch.Client
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static ActionDownloadPackageDetails? ToServerData(ActionDownloadPackageDetailsResponse? actionDownloadPackageDetails)
|
||||||
|
{
|
||||||
|
if (actionDownloadPackageDetails == null)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ActionDownloadPackageDetails
|
||||||
|
{
|
||||||
|
Version = actionDownloadPackageDetails.Version,
|
||||||
|
ManifestDigest = actionDownloadPackageDetails.ManifestDigest
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private MediaTypeFormatter m_formatter;
|
private MediaTypeFormatter m_formatter;
|
||||||
private Uri m_launchServiceUrl;
|
private Uri m_launchServiceUrl;
|
||||||
private string m_token;
|
private string m_token;
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ namespace GitHub.Services.OAuth
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
{
|
{
|
||||||
base.GetObjectData(info, context);
|
base.GetObjectData(info, context);
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace Sdk.WebApi.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Task<RawHttpClientResult<T>> SendAsync<T>(
|
protected async Task<RawHttpClientResult> Send2Async(
|
||||||
HttpMethod method,
|
HttpMethod method,
|
||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
HttpContent content = null,
|
HttpContent content = null,
|
||||||
@@ -109,7 +109,47 @@ namespace Sdk.WebApi.WebApi
|
|||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return SendAsync<T>(method, null, requestUri, content, queryParameters, userState, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
||||||
@@ -118,18 +158,20 @@ namespace Sdk.WebApi.WebApi
|
|||||||
Uri requestUri,
|
Uri requestUri,
|
||||||
HttpContent content = null,
|
HttpContent content = null,
|
||||||
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
||||||
|
Boolean readErrorBody = false,
|
||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||||
using (HttpRequestMessage requestMessage = CreateRequestMessage(method, additionalHeaders, requestUri, content, queryParameters))
|
using (HttpRequestMessage requestMessage = CreateRequestMessage(method, additionalHeaders, requestUri, content, queryParameters))
|
||||||
{
|
{
|
||||||
return await SendAsync<T>(requestMessage, userState, cancellationToken).ConfigureAwait(false);
|
return await SendAsync<T>(requestMessage, readErrorBody, userState, cancellationToken).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
protected async Task<RawHttpClientResult<T>> SendAsync<T>(
|
||||||
HttpRequestMessage message,
|
HttpRequestMessage message,
|
||||||
|
Boolean readErrorBody = false,
|
||||||
Object userState = null,
|
Object userState = null,
|
||||||
CancellationToken cancellationToken = default(CancellationToken))
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
@@ -145,8 +187,21 @@ namespace Sdk.WebApi.WebApi
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var errorBody = default(string);
|
||||||
|
if (readErrorBody)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
errorBody = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
errorBody = $"Error reading HTTP response body: {ex.Message}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string errorMessage = $"Error: {response.ReasonPhrase}";
|
string errorMessage = $"Error: {response.ReasonPhrase}";
|
||||||
return RawHttpClientResult<T>.Fail(errorMessage, response.StatusCode);
|
return RawHttpClientResult<T>.Fail(errorMessage, response.StatusCode, errorBody);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,15 +5,27 @@ namespace Sdk.WebApi.WebApi
|
|||||||
public class RawHttpClientResult
|
public class RawHttpClientResult
|
||||||
{
|
{
|
||||||
public bool IsSuccess { get; protected set; }
|
public bool IsSuccess { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A description of the HTTP status code, like "Error: Unprocessable Entity"
|
||||||
|
/// </summary>
|
||||||
public string Error { get; protected set; }
|
public string Error { get; protected set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The HTTP response body for unsuccessful HTTP status codes, or an error message when reading the response body fails.
|
||||||
|
/// </summary>
|
||||||
|
public string ErrorBody { get; protected set; }
|
||||||
|
|
||||||
public HttpStatusCode StatusCode { get; protected set; }
|
public HttpStatusCode StatusCode { get; protected set; }
|
||||||
|
|
||||||
public bool IsFailure => !IsSuccess;
|
public bool IsFailure => !IsSuccess;
|
||||||
|
|
||||||
protected RawHttpClientResult(bool isSuccess, string error, HttpStatusCode statusCode)
|
public RawHttpClientResult(bool isSuccess, string error, HttpStatusCode statusCode, string errorBody = null)
|
||||||
{
|
{
|
||||||
IsSuccess = isSuccess;
|
IsSuccess = isSuccess;
|
||||||
Error = error;
|
Error = error;
|
||||||
StatusCode = statusCode;
|
StatusCode = statusCode;
|
||||||
|
ErrorBody = errorBody;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,13 +33,13 @@ namespace Sdk.WebApi.WebApi
|
|||||||
{
|
{
|
||||||
public T Value { get; private set; }
|
public T Value { get; private set; }
|
||||||
|
|
||||||
protected internal RawHttpClientResult(T value, bool isSuccess, string error, HttpStatusCode statusCode)
|
protected internal RawHttpClientResult(T value, bool isSuccess, string error, HttpStatusCode statusCode, string errorBody)
|
||||||
: base(isSuccess, error, statusCode)
|
: base(isSuccess, error, statusCode, errorBody)
|
||||||
{
|
{
|
||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RawHttpClientResult<T> Fail(string message, HttpStatusCode statusCode) => new RawHttpClientResult<T>(default(T), false, message, statusCode);
|
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);
|
public static RawHttpClientResult<T> Ok(T value) => new RawHttpClientResult<T>(value, true, string.Empty, HttpStatusCode.OK, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace GitHub.Services.WebApi
|
|||||||
HttpStatusCode = (HttpStatusCode)info.GetInt32("HttpStatusCode");
|
HttpStatusCode = (HttpStatusCode)info.GetInt32("HttpStatusCode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Obsolete]
|
||||||
[SecurityCritical]
|
[SecurityCritical]
|
||||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
{
|
{
|
||||||
|
|||||||
213
src/Test/L0/Listener/ErrorThrottlerL0.cs
Normal file
213
src/Test/L0/Listener/ErrorThrottlerL0.cs
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Listener;
|
||||||
|
using GitHub.Runner.Listener.Configuration;
|
||||||
|
using GitHub.Runner.Common.Tests;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using Moq;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common.Tests.Listener
|
||||||
|
{
|
||||||
|
public sealed class ErrorThrottlerL0
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[InlineData(1)]
|
||||||
|
[InlineData(2)]
|
||||||
|
[InlineData(3)]
|
||||||
|
[InlineData(4)]
|
||||||
|
[InlineData(5)]
|
||||||
|
[InlineData(6)]
|
||||||
|
[InlineData(7)]
|
||||||
|
[InlineData(8)]
|
||||||
|
public async void TestIncrementAndWait(int totalAttempts)
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorThrottler = new ErrorThrottler();
|
||||||
|
errorThrottler.Initialize(hc);
|
||||||
|
var eventArgs = new List<DelayEventArgs>();
|
||||||
|
hc.Delaying += (sender, args) =>
|
||||||
|
{
|
||||||
|
eventArgs.Add(args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
for (int attempt = 1; attempt <= totalAttempts; attempt++)
|
||||||
|
{
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(totalAttempts - 1, eventArgs.Count);
|
||||||
|
for (int i = 0; i < eventArgs.Count; i++)
|
||||||
|
{
|
||||||
|
// Expected milliseconds
|
||||||
|
int expectedMin;
|
||||||
|
int expectedMax;
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
expectedMin = 1000; // Min backoff
|
||||||
|
expectedMax = 1000;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
expectedMin = 1800; // Min + 0.8 * Coefficient
|
||||||
|
expectedMax = 2200; // Min + 1.2 * Coefficient
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
expectedMin = 3400; // Min + 0.8 * Coefficient * 3
|
||||||
|
expectedMax = 4600; // Min + 1.2 * Coefficient * 3
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
expectedMin = 6600; // Min + 0.8 * Coefficient * 7
|
||||||
|
expectedMax = 9400; // Min + 1.2 * Coefficient * 7
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
expectedMin = 13000; // Min + 0.8 * Coefficient * 15
|
||||||
|
expectedMax = 19000; // Min + 1.2 * Coefficient * 15
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
expectedMin = 25800; // Min + 0.8 * Coefficient * 31
|
||||||
|
expectedMax = 38200; // Min + 1.2 * Coefficient * 31
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
expectedMin = 51400; // Min + 0.8 * Coefficient * 63
|
||||||
|
expectedMax = 60000; // Max backoff
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
expectedMin = 60000;
|
||||||
|
expectedMax = 60000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException("Unexpected eventArgs count");
|
||||||
|
}
|
||||||
|
|
||||||
|
var actualMilliseconds = eventArgs[i].Delay.TotalMilliseconds;
|
||||||
|
Assert.True(expectedMin <= actualMilliseconds, $"Unexpected min delay for eventArgs[{i}]. Expected min {expectedMin}, actual {actualMilliseconds}");
|
||||||
|
Assert.True(expectedMax >= actualMilliseconds, $"Unexpected max delay for eventArgs[{i}]. Expected max {expectedMax}, actual {actualMilliseconds}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void TestReset()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorThrottler = new ErrorThrottler();
|
||||||
|
errorThrottler.Initialize(hc);
|
||||||
|
var eventArgs = new List<DelayEventArgs>();
|
||||||
|
hc.Delaying += (sender, args) =>
|
||||||
|
{
|
||||||
|
eventArgs.Add(args);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
errorThrottler.Reset();
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(4, eventArgs.Count);
|
||||||
|
for (int i = 0; i < eventArgs.Count; i++)
|
||||||
|
{
|
||||||
|
// Expected milliseconds
|
||||||
|
int expectedMin;
|
||||||
|
int expectedMax;
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case 2:
|
||||||
|
expectedMin = 1000; // Min backoff
|
||||||
|
expectedMax = 1000;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 3:
|
||||||
|
expectedMin = 1800; // Min + 0.8 * Coefficient
|
||||||
|
expectedMax = 2200; // Min + 1.2 * Coefficient
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException("Unexpected eventArgs count");
|
||||||
|
}
|
||||||
|
|
||||||
|
var actualMilliseconds = eventArgs[i].Delay.TotalMilliseconds;
|
||||||
|
Assert.True(expectedMin <= actualMilliseconds, $"Unexpected min delay for eventArgs[{i}]. Expected min {expectedMin}, actual {actualMilliseconds}");
|
||||||
|
Assert.True(expectedMax >= actualMilliseconds, $"Unexpected max delay for eventArgs[{i}]. Expected max {expectedMax}, actual {actualMilliseconds}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void TestReceivesCancellationToken()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorThrottler = new ErrorThrottler();
|
||||||
|
errorThrottler.Initialize(hc);
|
||||||
|
var eventArgs = new List<DelayEventArgs>();
|
||||||
|
hc.Delaying += (sender, args) =>
|
||||||
|
{
|
||||||
|
eventArgs.Add(args);
|
||||||
|
};
|
||||||
|
var cancellationTokenSource1 = new CancellationTokenSource();
|
||||||
|
var cancellationTokenSource2 = new CancellationTokenSource();
|
||||||
|
var cancellationTokenSource3 = new CancellationTokenSource();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource1.Token);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource2.Token);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(cancellationTokenSource3.Token);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, eventArgs.Count);
|
||||||
|
Assert.Equal(cancellationTokenSource2.Token, eventArgs[0].Token);
|
||||||
|
Assert.Equal(cancellationTokenSource3.Token, eventArgs[1].Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async void TestReceivesSender()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var errorThrottler = new ErrorThrottler();
|
||||||
|
errorThrottler.Initialize(hc);
|
||||||
|
var senders = new List<object>();
|
||||||
|
hc.Delaying += (sender, args) =>
|
||||||
|
{
|
||||||
|
senders.Add(sender);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Act
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
await errorThrottler.IncrementAndWaitAsync(CancellationToken.None);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(2, senders.Count);
|
||||||
|
Assert.Equal(hc, senders[0]);
|
||||||
|
Assert.Equal(hc, senders[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
||||||
|
{
|
||||||
|
return new TestHostContext(this, testName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
private Mock<ITerminal> _term;
|
private Mock<ITerminal> _term;
|
||||||
private Mock<IConfigurationStore> _configStore;
|
private Mock<IConfigurationStore> _configStore;
|
||||||
private Mock<ISelfUpdater> _updater;
|
private Mock<ISelfUpdater> _updater;
|
||||||
|
private Mock<IErrorThrottler> _acquireJobThrottler;
|
||||||
|
|
||||||
public RunnerL0()
|
public RunnerL0()
|
||||||
{
|
{
|
||||||
@@ -35,6 +36,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_term = new Mock<ITerminal>();
|
_term = new Mock<ITerminal>();
|
||||||
_configStore = new Mock<IConfigurationStore>();
|
_configStore = new Mock<IConfigurationStore>();
|
||||||
_updater = new Mock<ISelfUpdater>();
|
_updater = new Mock<ISelfUpdater>();
|
||||||
|
_acquireJobThrottler = new Mock<IErrorThrottler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Pipelines.AgentJobRequestMessage CreateJobRequestMessage(string jobName)
|
private Pipelines.AgentJobRequestMessage CreateJobRequestMessage(string jobName)
|
||||||
@@ -67,6 +69,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
@@ -174,6 +177,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
|
|
||||||
var command = new CommandSettings(hc, args);
|
var command = new CommandSettings(hc, args);
|
||||||
|
|
||||||
@@ -205,6 +209,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
hc.SetSingleton<IMessageListener>(_messageListener.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
|
|
||||||
var command = new CommandSettings(hc, new[] { "run" });
|
var command = new CommandSettings(hc, new[] { "run" });
|
||||||
|
|
||||||
@@ -242,6 +247,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
@@ -338,6 +344,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
@@ -439,6 +446,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
hc.SetSingleton<IRunnerServer>(_runnerServer.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.SetSingleton<ISelfUpdater>(_updater.Object);
|
hc.SetSingleton<ISelfUpdater>(_updater.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
|
|
||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
@@ -522,6 +530,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
|
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
||||||
|
hc.EnqueueInstance<IErrorThrottler>(_acquireJobThrottler.Object);
|
||||||
|
|
||||||
var command = new CommandSettings(hc, new[] { "remove", "--local" });
|
var command = new CommandSettings(hc, new[] { "remove", "--local" });
|
||||||
|
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node20\bin\node");
|
||||||
#else
|
#else
|
||||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node20/bin/node");
|
||||||
hc.EnqueueInstance<IProcessInvoker>(new ProcessInvokerWrapper());
|
hc.EnqueueInstance<IProcessInvoker>(new ProcessInvokerWrapper());
|
||||||
#endif
|
#endif
|
||||||
var startInfo = new ProcessStartInfo(node, "-e \"setTimeout(function(){{}}, 15 * 1000);\"");
|
var startInfo = new ProcessStartInfo(node, "-e \"setTimeout(function(){{}}, 15 * 1000);\"");
|
||||||
|
|||||||
@@ -30,9 +30,11 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D"));
|
private string _tempDirectoryRoot = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("D"));
|
||||||
private StartupType _startupType;
|
private StartupType _startupType;
|
||||||
public event EventHandler Unloading;
|
public event EventHandler Unloading;
|
||||||
|
public event EventHandler<DelayEventArgs> Delaying;
|
||||||
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
public CancellationToken RunnerShutdownToken => _runnerShutdownTokenSource.Token;
|
||||||
public ShutdownReason RunnerShutdownReason { get; private set; }
|
public ShutdownReason RunnerShutdownReason { get; private set; }
|
||||||
public ISecretMasker SecretMasker => _secretMasker;
|
public ISecretMasker SecretMasker => _secretMasker;
|
||||||
|
|
||||||
public TestHostContext(object testClass, [CallerMemberName] string testName = "")
|
public TestHostContext(object testClass, [CallerMemberName] string testName = "")
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(testClass, nameof(testClass));
|
ArgUtil.NotNull(testClass, nameof(testClass));
|
||||||
@@ -92,6 +94,14 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
|
|
||||||
public async Task Delay(TimeSpan delay, CancellationToken token)
|
public async Task Delay(TimeSpan delay, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
// Event callback
|
||||||
|
EventHandler<DelayEventArgs> handler = Delaying;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, new DelayEventArgs(delay, token));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delay zero
|
||||||
await Task.Delay(TimeSpan.Zero);
|
await Task.Delay(TimeSpan.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -360,5 +370,25 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Unloading(this, null);
|
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; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -677,7 +677,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
ec.InitializeJob(jobRequest, CancellationToken.None);
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
ec.Start();
|
ec.Start();
|
||||||
|
|
||||||
ec.StepTelemetry.Type = "node16";
|
ec.StepTelemetry.Type = "node20";
|
||||||
ec.StepTelemetry.Action = "actions/checkout";
|
ec.StepTelemetry.Action = "actions/checkout";
|
||||||
ec.StepTelemetry.Ref = "v2";
|
ec.StepTelemetry.Ref = "v2";
|
||||||
ec.StepTelemetry.IsEmbedded = false;
|
ec.StepTelemetry.IsEmbedded = false;
|
||||||
@@ -695,7 +695,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(1, ec.Global.StepsTelemetry.Count);
|
Assert.Equal(1, ec.Global.StepsTelemetry.Count);
|
||||||
Assert.Equal("node16", ec.Global.StepsTelemetry.Single().Type);
|
Assert.Equal("node20", ec.Global.StepsTelemetry.Single().Type);
|
||||||
Assert.Equal("actions/checkout", ec.Global.StepsTelemetry.Single().Action);
|
Assert.Equal("actions/checkout", ec.Global.StepsTelemetry.Single().Action);
|
||||||
Assert.Equal("v2", ec.Global.StepsTelemetry.Single().Ref);
|
Assert.Equal("v2", ec.Global.StepsTelemetry.Single().Ref);
|
||||||
Assert.Equal(TaskResult.Succeeded, ec.Global.StepsTelemetry.Single().Result);
|
Assert.Equal(TaskResult.Succeeded, ec.Global.StepsTelemetry.Single().Result);
|
||||||
@@ -746,7 +746,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var embeddedStep = ec.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, ActionRunStage.Main, isEmbedded: true);
|
var embeddedStep = ec.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, ActionRunStage.Main, isEmbedded: true);
|
||||||
embeddedStep.Start();
|
embeddedStep.Start();
|
||||||
|
|
||||||
embeddedStep.StepTelemetry.Type = "node16";
|
embeddedStep.StepTelemetry.Type = "node20";
|
||||||
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
||||||
embeddedStep.StepTelemetry.Ref = "v2";
|
embeddedStep.StepTelemetry.Ref = "v2";
|
||||||
|
|
||||||
@@ -758,7 +758,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(1, ec.Global.StepsTelemetry.Count);
|
Assert.Equal(1, ec.Global.StepsTelemetry.Count);
|
||||||
Assert.Equal("node16", ec.Global.StepsTelemetry.Single().Type);
|
Assert.Equal("node20", ec.Global.StepsTelemetry.Single().Type);
|
||||||
Assert.Equal("actions/checkout", ec.Global.StepsTelemetry.Single().Action);
|
Assert.Equal("actions/checkout", ec.Global.StepsTelemetry.Single().Action);
|
||||||
Assert.Equal("v2", ec.Global.StepsTelemetry.Single().Ref);
|
Assert.Equal("v2", ec.Global.StepsTelemetry.Single().Ref);
|
||||||
Assert.Equal(ActionRunStage.Main.ToString(), ec.Global.StepsTelemetry.Single().Stage);
|
Assert.Equal(ActionRunStage.Main.ToString(), ec.Global.StepsTelemetry.Single().Stage);
|
||||||
@@ -773,6 +773,82 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
public void PublishStepResult_EmbeddedStep()
|
public void PublishStepResult_EmbeddedStep()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Job request
|
||||||
|
TaskOrchestrationPlanReference plan = new();
|
||||||
|
TimelineReference timeline = new();
|
||||||
|
Guid jobId = Guid.NewGuid();
|
||||||
|
string jobName = "some job name";
|
||||||
|
var variables = new Dictionary<string, VariableValue>()
|
||||||
|
{
|
||||||
|
["RunService.FixEmbeddedIssues"] = new VariableValue("true"),
|
||||||
|
};
|
||||||
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, variables, new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null, null);
|
||||||
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
|
{
|
||||||
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
Id = "github",
|
||||||
|
Version = "sha1"
|
||||||
|
});
|
||||||
|
jobRequest.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
|
|
||||||
|
// Mocks
|
||||||
|
var pagingLogger = new Mock<IPagingLogger>();
|
||||||
|
var pagingLogger2 = new Mock<IPagingLogger>();
|
||||||
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
|
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||||
|
hc.EnqueueInstance(pagingLogger.Object);
|
||||||
|
hc.EnqueueInstance(pagingLogger2.Object);
|
||||||
|
hc.SetSingleton(jobServerQueue.Object);
|
||||||
|
|
||||||
|
// Job context
|
||||||
|
var jobContext = new Runner.Worker.ExecutionContext();
|
||||||
|
jobContext.Initialize(hc);
|
||||||
|
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
jobContext.Start();
|
||||||
|
|
||||||
|
// Step 1 context
|
||||||
|
var step1 = jobContext.CreateChild(Guid.NewGuid(), "my_step", "my_step", null, null, ActionRunStage.Main);
|
||||||
|
step1.Start();
|
||||||
|
|
||||||
|
// Embedded step 1a context
|
||||||
|
var embeddedStep1a = step1.CreateEmbeddedChild(null, null, Guid.NewGuid(), ActionRunStage.Main);
|
||||||
|
embeddedStep1a.Start();
|
||||||
|
embeddedStep1a.StepTelemetry.Type = "node20";
|
||||||
|
embeddedStep1a.StepTelemetry.Action = "actions/checkout";
|
||||||
|
embeddedStep1a.StepTelemetry.Ref = "v2";
|
||||||
|
embeddedStep1a.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" }, ExecutionContextLogOptions.Default);
|
||||||
|
embeddedStep1a.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" }, ExecutionContextLogOptions.Default);
|
||||||
|
embeddedStep1a.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice" }, ExecutionContextLogOptions.Default);
|
||||||
|
embeddedStep1a.Complete();
|
||||||
|
|
||||||
|
// Embedded step 1b context
|
||||||
|
var embeddedStep1b = step1.CreateEmbeddedChild(null, null, Guid.NewGuid(), ActionRunStage.Main);
|
||||||
|
embeddedStep1b.Start();
|
||||||
|
embeddedStep1b.StepTelemetry.Type = "node20";
|
||||||
|
embeddedStep1b.StepTelemetry.Action = "actions/checkout";
|
||||||
|
embeddedStep1b.StepTelemetry.Ref = "v2";
|
||||||
|
embeddedStep1b.AddIssue(new Issue() { Type = IssueType.Error, Message = "error 2" }, ExecutionContextLogOptions.Default);
|
||||||
|
embeddedStep1b.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning 2" }, ExecutionContextLogOptions.Default);
|
||||||
|
embeddedStep1b.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice 2" }, ExecutionContextLogOptions.Default);
|
||||||
|
embeddedStep1b.Complete();
|
||||||
|
|
||||||
|
step1.Complete();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(3, jobContext.Global.StepsResult.Count);
|
||||||
|
Assert.Equal(0, jobContext.Global.StepsResult[0].Annotations.Count);
|
||||||
|
Assert.Equal(0, jobContext.Global.StepsResult[1].Annotations.Count);
|
||||||
|
Assert.Equal(6, jobContext.Global.StepsResult[2].Annotations.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void PublishStepResult_EmbeddedStep_Legacy()
|
||||||
{
|
{
|
||||||
using (TestHostContext hc = CreateTestContext())
|
using (TestHostContext hc = CreateTestContext())
|
||||||
{
|
{
|
||||||
@@ -807,10 +883,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
ec.InitializeJob(jobRequest, CancellationToken.None);
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
ec.Start();
|
ec.Start();
|
||||||
|
|
||||||
var embeddedStep = ec.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, ActionRunStage.Main, isEmbedded: true);
|
var embeddedStep = ec.CreateEmbeddedChild(null, null, Guid.NewGuid(), ActionRunStage.Main);
|
||||||
embeddedStep.Start();
|
embeddedStep.Start();
|
||||||
|
|
||||||
embeddedStep.StepTelemetry.Type = "node16";
|
embeddedStep.StepTelemetry.Type = "node20";
|
||||||
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
||||||
embeddedStep.StepTelemetry.Ref = "v2";
|
embeddedStep.StepTelemetry.Ref = "v2";
|
||||||
|
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
[Theory]
|
[Theory]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
[InlineData("node12", "node16")]
|
[InlineData("node12", "node20")]
|
||||||
[InlineData("node16", "node16")]
|
[InlineData("node16", "node20")]
|
||||||
[InlineData("node20", "node20")]
|
[InlineData("node20", "node20")]
|
||||||
public void IsNodeVersionUpgraded(string inputVersion, string expectedVersion)
|
public void IsNodeVersionUpgraded(string inputVersion, string expectedVersion)
|
||||||
{
|
{
|
||||||
@@ -70,7 +70,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal(expectedVersion, handler.Data.NodeVersion);
|
Assert.Equal(expectedVersion, handler.Data.NodeVersion);
|
||||||
Environment.SetEnvironmentVariable(Constants.Variables.Actions.AllowActionsUseUnsecureNodeVersion, null);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -505,7 +505,27 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
return EnsureSnapshotPostJobStepForToken(mappingToken, snapshot);
|
return EnsureSnapshotPostJobStepForToken(mappingToken, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task EnsureSnapshotPostJobStepForToken(TemplateToken snapshotToken, Pipelines.Snapshot expectedSnapshot)
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public Task EnsureSnapshotPostJobStepForMappingToken_WithIf_Is_False()
|
||||||
|
{
|
||||||
|
var snapshot = new Pipelines.Snapshot("TestImageNameFromMappingToken", condition: $"{PipelineTemplateConstants.Success}() && 1==0", version: "2.*");
|
||||||
|
var imageNameValueStringToken = new StringToken(null, null, null, snapshot.ImageName);
|
||||||
|
var condition = new StringToken(null, null, null, snapshot.Condition);
|
||||||
|
var version = new StringToken(null, null, null, snapshot.Version);
|
||||||
|
|
||||||
|
var mappingToken = new MappingToken(null, null, null)
|
||||||
|
{
|
||||||
|
{ new StringToken(null,null,null, PipelineTemplateConstants.ImageName), imageNameValueStringToken },
|
||||||
|
{ new StringToken(null,null,null, PipelineTemplateConstants.If), condition },
|
||||||
|
{ new StringToken(null,null,null, PipelineTemplateConstants.CustomImageVersion), version }
|
||||||
|
};
|
||||||
|
|
||||||
|
return EnsureSnapshotPostJobStepForToken(mappingToken, snapshot, skipSnapshotStep: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task EnsureSnapshotPostJobStepForToken(TemplateToken snapshotToken, Pipelines.Snapshot expectedSnapshot, bool skipSnapshotStep = false)
|
||||||
{
|
{
|
||||||
using (TestHostContext hc = CreateTestContext())
|
using (TestHostContext hc = CreateTestContext())
|
||||||
{
|
{
|
||||||
@@ -523,14 +543,28 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal(1, postJobSteps.Count);
|
Assert.Equal(1, postJobSteps.Count);
|
||||||
var snapshotStep = postJobSteps.First();
|
var snapshotStep = postJobSteps.First();
|
||||||
|
_jobEc.JobSteps.Enqueue(snapshotStep);
|
||||||
|
|
||||||
|
var _stepsRunner = new StepsRunner();
|
||||||
|
_stepsRunner.Initialize(hc);
|
||||||
|
await _stepsRunner.RunAsync(_jobEc);
|
||||||
|
|
||||||
Assert.Equal("Create custom image", snapshotStep.DisplayName);
|
Assert.Equal("Create custom image", snapshotStep.DisplayName);
|
||||||
Assert.Equal($"{PipelineTemplateConstants.Success}()", snapshotStep.Condition);
|
Assert.Equal(expectedSnapshot.Condition ?? $"{PipelineTemplateConstants.Success}()", snapshotStep.Condition);
|
||||||
|
|
||||||
// Run the mock snapshot step, so we can verify it was executed with the expected snapshot object.
|
// Run the mock snapshot step, so we can verify it was executed with the expected snapshot object.
|
||||||
await snapshotStep.RunAsync();
|
// await snapshotStep.RunAsync();
|
||||||
|
if (skipSnapshotStep)
|
||||||
Assert.NotNull(_requestedSnapshot);
|
{
|
||||||
Assert.Equal(expectedSnapshot.ImageName, _requestedSnapshot.ImageName);
|
Assert.Null(_requestedSnapshot);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.NotNull(_requestedSnapshot);
|
||||||
|
Assert.Equal(expectedSnapshot.ImageName, _requestedSnapshot.ImageName);
|
||||||
|
Assert.Equal(expectedSnapshot.Condition ?? $"{PipelineTemplateConstants.Success}()", _requestedSnapshot.Condition);
|
||||||
|
Assert.Equal(expectedSnapshot.Version ?? "1.*", _requestedSnapshot.Version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,10 +75,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
.ReturnsAsync(0);
|
.ReturnsAsync(0);
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
var nodeVersion = await sh.DetermineNodeRuntimeVersion(_ec.Object, "node16");
|
var nodeVersion = await sh.DetermineNodeRuntimeVersion(_ec.Object, "node20");
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal("node16_alpine", nodeVersion);
|
Assert.Equal("node20_alpine", nodeVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,10 +129,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
.ReturnsAsync(0);
|
.ReturnsAsync(0);
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
var nodeVersion = await sh.DetermineNodeRuntimeVersion(_ec.Object, "node16");
|
var nodeVersion = await sh.DetermineNodeRuntimeVersion(_ec.Object, "node20");
|
||||||
|
|
||||||
// Assert.
|
// Assert.
|
||||||
Assert.Equal("node16", nodeVersion);
|
Assert.Equal("node20", nodeVersion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603;NU1603;xUnit2013;</NoWarn>
|
<NoWarn>NU1701;NU1603;NU1603;xUnit2013;SYSLIB0050;SYSLIB0051</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -15,13 +15,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.2.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
|
||||||
<PackageReference Include="xunit" Version="2.7.1" />
|
<PackageReference Include="xunit" Version="2.7.1" />
|
||||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.8" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||||
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.4.0" />
|
<PackageReference Include="System.Reflection.TypeExtensions" Version="4.7.0" />
|
||||||
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
<PackageReference Include="System.Threading.ThreadPool" Version="4.3.0" />
|
||||||
<PackageReference Include="Moq" Version="4.11.0" />
|
<PackageReference Include="Moq" Version="4.20.72" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
|||||||
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
||||||
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
||||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||||
DOTNETSDK_VERSION="6.0.421"
|
DOTNETSDK_VERSION="8.0.405"
|
||||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||||
RUNNER_VERSION=$(cat runnerversion)
|
RUNNER_VERSION=$(cat runnerversion)
|
||||||
|
|
||||||
@@ -199,6 +199,7 @@ function package ()
|
|||||||
popd > /dev/null
|
popd > /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Install .NET SDK
|
||||||
if [[ (! -d "${DOTNETSDK_INSTALLDIR}") || (! -e "${DOTNETSDK_INSTALLDIR}/.${DOTNETSDK_VERSION}") || (! -e "${DOTNETSDK_INSTALLDIR}/dotnet") ]]; then
|
if [[ (! -d "${DOTNETSDK_INSTALLDIR}") || (! -e "${DOTNETSDK_INSTALLDIR}/.${DOTNETSDK_VERSION}") || (! -e "${DOTNETSDK_INSTALLDIR}/dotnet") ]]; then
|
||||||
|
|
||||||
# Download dotnet SDK to ../_dotnetsdk directory
|
# Download dotnet SDK to ../_dotnetsdk directory
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "6.0.421"
|
"version": "8.0.405"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.317.0
|
2.322.0
|
||||||
|
|||||||
Reference in New Issue
Block a user