mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
35 Commits
v2.289.3
...
thboop/con
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f71edd2af | ||
|
|
183b1f387c | ||
|
|
42ad85741e | ||
|
|
88ee16fb02 | ||
|
|
5cca207314 | ||
|
|
0b73794267 | ||
|
|
d7694774a4 | ||
|
|
0398f57125 | ||
|
|
fade0f46e7 | ||
|
|
02b52e8497 | ||
|
|
628f462ab7 | ||
|
|
7ba4f8587e | ||
|
|
88f7c56757 | ||
|
|
20b7e86e47 | ||
|
|
bd5f275830 | ||
|
|
a7aadf5615 | ||
|
|
1c582abc8b | ||
|
|
44d4d076fe | ||
|
|
b6195624ac | ||
|
|
ead3509d5a | ||
|
|
fee24199cb | ||
|
|
c8cb600ac7 | ||
|
|
f48f314a70 | ||
|
|
7b677e0618 | ||
|
|
d70f9f6174 | ||
|
|
0343e76789 | ||
|
|
909b05eb66 | ||
|
|
2e3976cf97 | ||
|
|
052ac521b0 | ||
|
|
408d6c579c | ||
|
|
46258428cd | ||
|
|
eb9a604b63 | ||
|
|
8792d8e5ee | ||
|
|
87e86e3d72 | ||
|
|
48b6cd9a42 |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64 ]
|
||||
include:
|
||||
- runtime: linux-x64
|
||||
os: ubuntu-latest
|
||||
@@ -36,13 +36,17 @@ jobs:
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: osx-arm64
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: win-x64
|
||||
os: windows-2019
|
||||
devScript: ./dev
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Build runner layout
|
||||
- name: Build & Layout Release
|
||||
@@ -78,7 +82,7 @@ jobs:
|
||||
run: |
|
||||
${{ matrix.devScript }} test
|
||||
working-directory: src
|
||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm' && matrix.runtime != 'osx-arm64'
|
||||
|
||||
# Create runner package tar.gz/zip
|
||||
- name: Package Release
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
78
.github/workflows/release.yml
vendored
78
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Make sure ./releaseVersion match ./src/runnerversion
|
||||
# Query GitHub release ensure version is not used
|
||||
@@ -51,24 +51,28 @@ jobs:
|
||||
linux-arm-sha: ${{ steps.sha.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha: ${{ steps.sha.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha: ${{ steps.sha.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha: ${{ steps.sha.outputs.osx-arm64-sha256 }}
|
||||
linux-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-x64-sha256 }}
|
||||
linux-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm64-sha256 }}
|
||||
linux-arm-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-arm64-sha256 }}
|
||||
linux-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-x64-sha256 }}
|
||||
linux-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm64-sha256 }}
|
||||
linux-arm-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-arm64-sha256 }}
|
||||
linux-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-x64-sha256 }}
|
||||
linux-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-arm64-sha256 }}
|
||||
linux-arm-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-arm64-sha256 }}
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64 ]
|
||||
include:
|
||||
- runtime: linux-x64
|
||||
os: ubuntu-latest
|
||||
@@ -86,13 +90,17 @@ jobs:
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: osx-arm64
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: win-x64
|
||||
os: windows-2019
|
||||
devScript: ./dev
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Build runner layout
|
||||
- name: Build & Layout Release
|
||||
@@ -100,13 +108,6 @@ jobs:
|
||||
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
||||
working-directory: src
|
||||
|
||||
# Run tests
|
||||
# - name: L0
|
||||
# run: |
|
||||
# ${{ matrix.devScript }} test
|
||||
# working-directory: src
|
||||
# if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
||||
|
||||
# Create runner package tar.gz/zip
|
||||
- name: Package Release
|
||||
if: github.event_name != 'pull_request'
|
||||
@@ -217,7 +218,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
# Download runner package tar.gz/zip produced by 'build' job
|
||||
- name: Download Artifact
|
||||
@@ -239,21 +240,25 @@ jobs:
|
||||
var releaseNote = fs.readFileSync('${{ github.workspace }}/releaseNote.md', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion)
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA>/g, '${{needs.build.outputs.win-x64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA>/g, '${{needs.build.outputs.osx-x64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA>/g, '${{needs.build.outputs.osx-arm64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA>/g, '${{needs.build.outputs.linux-x64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA>/g, '${{needs.build.outputs.linux-arm-sha}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA>/g, '${{needs.build.outputs.linux-arm64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.osx-x64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.osx-arm64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-x64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.win-x64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.osx-x64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA_NORUNTIME>/g, '${{needs.build.outputs.osx-arm64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-x64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-arm-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-arm64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.osx-x64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.osx-arm64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-x64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm64-sha-noruntime-noexternals}}')
|
||||
@@ -267,6 +272,7 @@ jobs:
|
||||
ls -l
|
||||
echo "${{needs.build.outputs.win-x64-sha}} actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.osx-x64-sha}} actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.osx-arm64-sha}} actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.linux-x64-sha}} actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.linux-arm-sha}} actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.linux-arm64-sha}} actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
@@ -314,6 +320,16 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -365,6 +381,16 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package_trims/trim_externals/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -416,6 +442,16 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-noruntime)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-noruntime)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -467,6 +503,16 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-noruntime-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime_externals/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-noruntime-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -518,6 +564,16 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-trimmedpackages.json)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/osx-arm64-trimmedpackages.json
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-trimmedpackages.json)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
|
||||
15
.vscode/launch.json
vendored
15
.vscode/launch.json
vendored
@@ -12,8 +12,7 @@
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src",
|
||||
"console": "integratedTerminal",
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Run",
|
||||
@@ -25,8 +24,7 @@
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src",
|
||||
"console": "integratedTerminal",
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Configure",
|
||||
@@ -39,24 +37,21 @@
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src",
|
||||
"console": "integratedTerminal",
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Debug Worker",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processName": "Runner.Worker",
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
"requireExactSource": false
|
||||
},
|
||||
{
|
||||
"name": "Attach Debugger",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}",
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
"requireExactSource": false
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
83
docs/adrs/1751-runner-job-hooks.md
Normal file
83
docs/adrs/1751-runner-job-hooks.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# ADR: Notification Hooks for Runners
|
||||
|
||||
## Context
|
||||
|
||||
This ADR details the design changes for supporting custom configurable hooks for on various runner events. This has been a long requested user feature [here](https://github.com/actions/runner/issues/1543), [here](https://github.com/actions/runner/issues/699) and [here](https://github.com/actions/runner/issues/1116) for users to have more information on runner observability, and for the ability to run cleanup and teardown jobs.
|
||||
|
||||
This feature is mainly intended for self hosted runner administrators.
|
||||
|
||||
**What we hope to solve with this feature**
|
||||
1. A runner admininstrator is able to add custom scripts to cleanup their runner environment at the start or end of a job
|
||||
2. A runner admininstrator is able to add custom scripts to help setup their runner environment at the beginning of a job, for reasons like [caching](https://github.com/actions/runner/issues/1543#issuecomment-1050346279)
|
||||
3. A runner administrator is able to grab custom telemetry of jobs running on their self hosted runner
|
||||
|
||||
**What we don't think this will solve**
|
||||
- Policy features that require certain steps run at the beginning or end of all jobs
|
||||
- This would be better solved to in a central place in settings, rather then decentralized on each runner.
|
||||
- The Proposed `Notification Hooks for Runners` is limited to self hosted runners, we don't beileve Policy features should be
|
||||
- Reuse scenarios between jobs are covered by [composite actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action) and [resuable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows)
|
||||
- Security applications, security should be handled on the policy side on the server, not decentralized on each runner
|
||||
|
||||
## Hooks
|
||||
- We will expose 2 variables that users can set to enable hooks
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_STARTED`
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_COMPLETED`
|
||||
|
||||
You can set these variables to the **absolute** path of a a `.sh` or `.ps1` file.
|
||||
|
||||
We will execute `pwsh` (fallback to `powershell`) or `bash` (fallback to `sh`) as appropriate.
|
||||
- `.sh` files will execute with the args `-e {pathtofile}`
|
||||
- `.ps1` files will execute with the args `-command \". '{pathtofile}'\"`
|
||||
|
||||
We will **not** set the [standard flags we typically set](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell) for `runs` commands. So, if you want to set `pipefail` on `bash` for example, you will need to do that in your script.
|
||||
|
||||
### UI
|
||||
We want to ensure the experience for users invoking workflows is good, if hooks take too long, you may feel your job is delayed or broken. So, much like `Set Up Job`, we will generate two new steps automatically in your job, one for each configured hook:
|
||||
- `Set up runner`
|
||||
- `Complete runner`
|
||||
|
||||
These steps will contain all of the output from invoking your hook, so you will have visibility into the runtime. We will also provide information on the path to the hook, and what shell we are invoking it as, much like we do for `run: ` steps.
|
||||
|
||||
### Contexts
|
||||
When running your hooks, some context on your job may be helpful.
|
||||
- The scripts will have access to the standard [default environment variables](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables)
|
||||
- Some of these variables are step specific like `GITHUB_ACTION`, in which case they will not be set
|
||||
- You can pull the full webhook event payload from `GITHUB_EVENT_PATH`
|
||||
|
||||
### Commands
|
||||
Should we expose [Commands](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions) and [Environment Files](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files)
|
||||
|
||||
**Yes**. Imagine a scenario where a runner administrator is deprecating a runner pool, and they need to [warn users](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message) to swap to a different pool, we should support them in doing this. However, there are some limitations:
|
||||
- [save-state](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions) will **not** be supported, these are not traditional steps with pre and post actions
|
||||
- [set-output](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions) will **not** be supported, there is no `id` as this is not a traditional step
|
||||
|
||||
|
||||
### Environment Files
|
||||
We will also enable [Environment Files](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files) to support setup scenarios for the runner environment.
|
||||
|
||||
While a self hosted runner admin can [set env variables](https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners#using-a-env-file-to-set-the-proxy-configuration), these apply to all jobs. By enabling the ability to `add a path` and `set an env` we give runner admins the ability to do this dynamically based on the [workflows environment variables](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables) to empower setup scenarios.
|
||||
|
||||
|
||||
### Exit codes
|
||||
These are **synchronous** hooks, so they will block job execution while they are being run. Exit code 0 will indicate a successful run of the hook and we will proceed with the job, any other exit code will fail the job with an appropriate annotation.
|
||||
- There will be no support for `continue-on-error`
|
||||
|
||||
## Key Decisions
|
||||
- We will expose 2 variables that users can set to enable hooks
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_STARTED`
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_COMPLETED`
|
||||
- Users can set these variables to the path of a `.sh` or `.ps1` file, which we will execute when Jobs are started or completed.
|
||||
- Output from these will be added to a new step at the start/end of a job named `Set up runner` or `Complete runner`.
|
||||
- These steps will only be generated on runs with these hooks
|
||||
- These hooks `always()` execute if the env variable is set
|
||||
- These files will execute as the Runner user, outside of any container specification on the job
|
||||
- These are **synchronous** hooks
|
||||
- Runner admins can execute a background process for async hooks if they want
|
||||
- We will fail the job and halt execution on any exit code that is not 0. The Runner admin is responsible for returning the correct exit code and ensuring resilency.
|
||||
- This includes that the runner user needs access to the file in the env and the file must exist
|
||||
- There will be no `continue-on-error` type option on launch
|
||||
- There will be no `timeout` option on launch
|
||||
|
||||
## Consequences
|
||||
- Runner admins have the ability to tie into the runner job execution to publish their own telemetry or perform their own cleanup or setup
|
||||
- New steps will be added to the UI showcasing the output of these hooks
|
||||
@@ -5,12 +5,6 @@
|
||||
## Supported Versions
|
||||
|
||||
- macOS High Sierra (10.13) and later versions
|
||||
|
||||
## Apple Silicon M1
|
||||
|
||||
The runner is currently not supported on devices with an Apple M1 chip.
|
||||
We are waiting for official .NET support. You can read more here about the [current state of support here](https://github.com/orgs/dotnet/projects/18#card-56812463).
|
||||
Current .NET project board about M1 support:
|
||||
https://github.com/orgs/dotnet/projects/18#card-56812463
|
||||
- x64 and arm64 (Apple Silicon)
|
||||
|
||||
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)
|
||||
|
||||
4
hooks/container/.eslintignore
Normal file
4
hooks/container/.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
**/__tests__/**
|
||||
56
hooks/container/.eslintrc.json
Normal file
56
hooks/container/.eslintrc.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": ["plugin:github/recommended"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-constant-condition": "off",
|
||||
"no-unused-vars": "off",
|
||||
"i18n-text/no-en": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error",
|
||||
"no-shadow": "off",
|
||||
"@typescript-eslint/no-shadow": ["error"]
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
}
|
||||
}
|
||||
3
hooks/container/.gitignore
vendored
Normal file
3
hooks/container/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
lib/
|
||||
dist/
|
||||
3
hooks/container/.prettierignore
Normal file
3
hooks/container/.prettierignore
Normal file
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
11
hooks/container/.prettierrc.json
Normal file
11
hooks/container/.prettierrc.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
}
|
||||
34
hooks/container/CONTRIBUTING.md
Normal file
34
hooks/container/CONTRIBUTING.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Basic setup
|
||||
You'll need a runner compatible with hooks, a repository with container workflows to which you can register the runner and the hooks from this repository.
|
||||
|
||||
|
||||
|
||||
## Getting Started
|
||||
- Run ` npm install && npm run bootstrap` to setup your environment and install all the needed packages
|
||||
- Run `npm run lint` and `npm run format` to ensure your charges will pass CI
|
||||
- Run `npm run build-all` to build and test end to end.
|
||||
|
||||
|
||||
## E2E
|
||||
- You'll need a runner compatible with hooks, a repository with container workflows to which you can register the runner and the hooks from this repository.
|
||||
- See [the runner contributing.md](../../github/CONTRIBUTING.MD) for how to get started with runner development.
|
||||
- Build your hook using `npm run build`
|
||||
- Enable the hooks by setting `ACTIONS_RUNNER_CONTAINER_HOOK=./src/{libraryname}/dist/index.js` file generated by [ncc](https://github.com/vercel/ncc)
|
||||
- Configure your self hosted runner against the a repository you have admin access
|
||||
- Run a workflow with a container job, for example
|
||||
```
|
||||
name: myjob
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
my_job:
|
||||
runs-on: self-hosted
|
||||
services:
|
||||
redis:
|
||||
image: redis
|
||||
container:
|
||||
image: alpine:3.15
|
||||
options: --cpus 1
|
||||
steps:
|
||||
- run: pwd
|
||||
```
|
||||
10
hooks/container/README.md
Normal file
10
hooks/container/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Container Hooks
|
||||
This repo contains example implementation of the container hook feature across various container providers. More information on how to implement your own hooks can be found in the [github docs]().
|
||||
|
||||
Three projects are included in the `src` folder
|
||||
- k8s: A kubernetes hook implementation that spins up pods dynamically to run a job
|
||||
- docker: A hook implementation of the runner's docker implementation
|
||||
- hooklib: a shared library which contains typescript definitions and utilities that the other projects consume
|
||||
|
||||
### Want to contribute
|
||||
We welcome contributions. See [how to contribute](CONTRIBUTING.md).
|
||||
3
hooks/container/hooklib/.eslintignore
Normal file
3
hooks/container/hooklib/.eslintignore
Normal file
@@ -0,0 +1,3 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
4350
hooks/container/hooklib/package-lock.json
generated
Normal file
4350
hooks/container/hooklib/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
28
hooks/container/hooklib/package.json
Normal file
28
hooks/container/hooklib/package.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "hooklib",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "tsc && ncc build",
|
||||
"format": "prettier --write '**/*.ts'",
|
||||
"format-check": "prettier --check '**/*.ts'",
|
||||
"lint": "eslint src/**/*.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.23",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"@zeit/ncc": "^0.22.3",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-github": "^4.3.6",
|
||||
"prettier": "^2.6.2",
|
||||
"typescript": "^4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.6.0"
|
||||
}
|
||||
}
|
||||
2
hooks/container/hooklib/src/index.ts
Normal file
2
hooks/container/hooklib/src/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from './interfaces'
|
||||
export * from './utils'
|
||||
87
hooks/container/hooklib/src/interfaces.ts
Normal file
87
hooks/container/hooklib/src/interfaces.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
export enum Command {
|
||||
PrepareJob = 'prepare_job',
|
||||
CleanupJob = 'cleanup_job',
|
||||
RunContainerStep = 'run_container_step',
|
||||
RunScriptStep = 'run_script_step'
|
||||
}
|
||||
|
||||
export interface HookData {
|
||||
command: Command
|
||||
responseFile: string
|
||||
args?: PrepareJobArgs | RunContainerStepArgs | RunScriptStepArgs
|
||||
state?: object
|
||||
}
|
||||
|
||||
export interface PrepareJobArgs {
|
||||
container?: JobContainerInfo
|
||||
services?: ServiceContainerInfo[]
|
||||
}
|
||||
|
||||
export type RunContainerStepArgs = StepContainerInfo
|
||||
|
||||
export interface RunScriptStepArgs {
|
||||
entrypoint: string
|
||||
entrypointArgs: string[]
|
||||
environmentVariables?: {[key: string]: string}
|
||||
prependPath?: string[]
|
||||
workingDirectory: string
|
||||
}
|
||||
|
||||
export interface ContainerInfo {
|
||||
entrypoint?: string
|
||||
entrypointArgs?: string[]
|
||||
createOptions?: string
|
||||
environmentVariables?: {[key: string]: string}
|
||||
userMountVolumes?: Mount[]
|
||||
registry?: Registry
|
||||
portMappings?: string[]
|
||||
}
|
||||
|
||||
export interface ServiceContainerInfo extends ContainerInfo {
|
||||
contextName: string
|
||||
image: string
|
||||
}
|
||||
|
||||
export interface JobContainerInfo extends ContainerInfo {
|
||||
image: string
|
||||
workingDirectory: string
|
||||
systemMountVolumes: Mount[]
|
||||
}
|
||||
|
||||
export interface StepContainerInfo extends ContainerInfo {
|
||||
prependPath?: string[]
|
||||
workingDirectory: string
|
||||
dockerfile?: string
|
||||
image?: string
|
||||
systemMountVolumes: Mount[]
|
||||
}
|
||||
|
||||
export interface Mount {
|
||||
sourceVolumePath: string
|
||||
targetVolumePath: string
|
||||
readOnly: boolean
|
||||
}
|
||||
|
||||
export interface Registry {
|
||||
username?: string
|
||||
password?: string
|
||||
serverUrl: string
|
||||
}
|
||||
|
||||
export enum Protocol {
|
||||
TCP = 'tcp',
|
||||
UDP = 'udp'
|
||||
}
|
||||
|
||||
export interface PrepareJobResponse {
|
||||
state?: object
|
||||
context?: ContainerContext
|
||||
services?: {[key: string]: ContainerContext}
|
||||
alpine: boolean
|
||||
}
|
||||
|
||||
export interface ContainerContext {
|
||||
id?: string
|
||||
network?: string
|
||||
ports?: {[key: string]: string}
|
||||
}
|
||||
44
hooks/container/hooklib/src/utils.ts
Normal file
44
hooks/container/hooklib/src/utils.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as events from 'events'
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
import * as readline from 'readline'
|
||||
import {HookData} from './interfaces'
|
||||
|
||||
export async function getInputFromStdin(): Promise<HookData> {
|
||||
let input = ''
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin
|
||||
})
|
||||
|
||||
rl.on('line', line => {
|
||||
core.debug(`Line from STDIN: ${line}`)
|
||||
input = line
|
||||
})
|
||||
await events.default.once(rl, 'close')
|
||||
const inputJson = JSON.parse(input)
|
||||
return inputJson as HookData
|
||||
}
|
||||
|
||||
export function writeToResponseFile(filePath: string, message: any): void {
|
||||
if (!filePath) {
|
||||
throw new Error(`Expected file path`)
|
||||
}
|
||||
if (!fs.existsSync(filePath)) {
|
||||
throw new Error(`Missing file at path: ${filePath}`)
|
||||
}
|
||||
|
||||
fs.appendFileSync(filePath, `${toCommandValue(message)}${os.EOL}`, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
}
|
||||
|
||||
function toCommandValue(input: any): string {
|
||||
if (input === null || input === undefined) {
|
||||
return ''
|
||||
} else if (typeof input === 'string' || input instanceof String) {
|
||||
return input as string
|
||||
}
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
11
hooks/container/hooklib/tsconfig.json
Normal file
11
hooks/container/hooklib/tsconfig.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
]
|
||||
}
|
||||
4368
hooks/container/package-lock.json
generated
Normal file
4368
hooks/container/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
37
hooks/container/package.json
Normal file
37
hooks/container/package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "hooks",
|
||||
"version": "1.0.0",
|
||||
"description": "Three projects are included - k8s: a kubernetes hook implementation that spins up pods dynamically to run a job - docker: A hook implementation of the runner's docker implementation - A hook lib, which contains shared typescript definitions and utilities that the other packages consume",
|
||||
"main": "",
|
||||
"directories": {
|
||||
"doc": "docs"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"bootstrap": "npm install --prefix src/hooklib && npm install --prefix src/k8s && npm install --prefix src/docker",
|
||||
"format": "prettier --write '**/*.ts'",
|
||||
"format-check": "prettier --check '**/*.ts'",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build-all": "npm run build --prefix src/hooklib && npm run build --prefix src/k8s && npm run build --prefix src/docker"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/runner.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/runner/issues"
|
||||
},
|
||||
"homepage": "https://github.com/actions/runner#readme",
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.23",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-github": "^4.3.6",
|
||||
"prettier": "^2.6.2",
|
||||
"typescript": "^4.6.3"
|
||||
}
|
||||
}
|
||||
70
hooks/container/tsconfig.json
Normal file
70
hooks/container/tsconfig.json
Normal file
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
## Features
|
||||
- Added a pre-release package for the `macOS-arm64` architecture
|
||||
- Note that this packages is pre-release status and may not work with all existing actions
|
||||
|
||||
## Bugs
|
||||
- Fixed an issue where websockets failed to successfully close when posting log lines (#1790)
|
||||
- Fixed an issue where live console logs would fail to close (#1903)
|
||||
|
||||
## Misc
|
||||
|
||||
## Windows x64
|
||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||
@@ -18,7 +21,7 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
|
||||
```
|
||||
|
||||
## OSX
|
||||
## OSX x64
|
||||
|
||||
``` bash
|
||||
# Create a folder
|
||||
@@ -29,6 +32,17 @@ curl -O -L https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>
|
||||
tar xzf ./actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz
|
||||
```
|
||||
|
||||
## [Pre-release] OSX arm64 (Apple silicon)
|
||||
|
||||
``` bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
curl -O -L https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz
|
||||
# Extract the installer
|
||||
tar xzf ./actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz
|
||||
```
|
||||
|
||||
## Linux x64
|
||||
|
||||
``` bash
|
||||
@@ -71,24 +85,28 @@ The SHA-256 checksums for the packages included in this build are shown below:
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>.zip <!-- BEGIN SHA win-x64 --><WIN_X64_SHA><!-- END SHA win-x64 -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA osx-x64 --><OSX_X64_SHA><!-- END SHA osx-x64 -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA osx-arm64 --><OSX_ARM64_SHA><!-- END SHA osx-arm64 -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-x64 --><LINUX_X64_SHA><!-- END SHA linux-x64 -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm64 --><LINUX_ARM64_SHA><!-- END SHA linux-arm64 -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm --><LINUX_ARM_SHA><!-- END SHA linux-arm -->
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>-noexternals.zip <!-- BEGIN SHA win-x64_noexternals --><WIN_X64_SHA_NOEXTERNALS><!-- END SHA win-x64_noexternals -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA osx-x64_noexternals --><OSX_X64_SHA_NOEXTERNALS><!-- END SHA osx-x64_noexternals -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA osx-arm64_noexternals --><OSX_ARM64_SHA_NOEXTERNALS><!-- END SHA osx-arm64_noexternals -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noexternals --><LINUX_X64_SHA_NOEXTERNALS><!-- END SHA linux-x64_noexternals -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-arm64_noexternals --><LINUX_ARM64_SHA_NOEXTERNALS><!-- END SHA linux-arm64_noexternals -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-arm_noexternals --><LINUX_ARM_SHA_NOEXTERNALS><!-- END SHA linux-arm_noexternals -->
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>-noruntime.zip <!-- BEGIN SHA win-x64_noruntime --><WIN_X64_SHA_NORUNTIME><!-- END SHA win-x64_noruntime -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA osx-x64_noruntime --><OSX_X64_SHA_NORUNTIME><!-- END SHA osx-x64_noruntime -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA osx-arm64_noruntime --><OSX_ARM64_SHA_NORUNTIME><!-- END SHA osx-arm64_noruntime -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-x64_noruntime --><LINUX_X64_SHA_NORUNTIME><!-- END SHA linux-x64_noruntime -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-arm64_noruntime --><LINUX_ARM64_SHA_NORUNTIME><!-- END SHA linux-arm64_noruntime -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-arm_noruntime --><LINUX_ARM_SHA_NORUNTIME><!-- END SHA linux-arm_noruntime -->
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>-noruntime-noexternals.zip <!-- BEGIN SHA win-x64_noruntime_noexternals --><WIN_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA win-x64_noruntime_noexternals -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA osx-x64_noruntime_noexternals --><OSX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA osx-x64_noruntime_noexternals -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA osx-arm64_noruntime_noexternals --><OSX_ARM64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA osx-arm64_noruntime_noexternals -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noruntime_noexternals --><LINUX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-x64_noruntime_noexternals -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-arm64_noruntime_noexternals --><LINUX_ARM64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-arm64_noruntime_noexternals -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-arm_noruntime_noexternals --><LINUX_ARM_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-arm_noruntime_noexternals -->
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.289.3
|
||||
<Update to ./src/runnerversion when creating release>
|
||||
|
||||
@@ -25,9 +25,12 @@
|
||||
<DefineConstants>$(DefineConstants);X86</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX'">
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX' AND '$(PackageRuntime)' == 'osx-x64'">
|
||||
<DefineConstants>$(DefineConstants);X64</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX' AND '$(PackageRuntime)' == 'osx-arm64'">
|
||||
<DefineConstants>$(DefineConstants);ARM64</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'Linux' AND ('$(PackageRuntime)' == 'linux-x64' OR '$(PackageRuntime)' == '')">
|
||||
<DefineConstants>$(DefineConstants);X64</DefineConstants>
|
||||
|
||||
@@ -1 +1 @@
|
||||
de62d296708908cfd1236e58869aebbc2bae8a8c3d629276968542626c508e37
|
||||
1d709d93e5d3c6c6c656a61aa6c1781050224788a05b0e6ecc4c3c0408bdf89c
|
||||
@@ -1 +1 @@
|
||||
44fcd0422dd98ed17d2c8e9057ff2260c50165f20674236a4ae7d2645a07df25
|
||||
b92a47cfeaad02255b1f7a377060651b73ae5e5db22a188dbbcb4183ab03a03d
|
||||
@@ -1 +1 @@
|
||||
e57652cf322ee16ce3af4f9e58f80858746b9e1e60279e991a3b3d9a6baf8d79
|
||||
68a9a8ef0843a8bb74241894f6f63fd76241a82295c5337d3cc7a940a314c78e
|
||||
1
src/Misc/contentHash/dotnetRuntime/osx-arm64
Normal file
1
src/Misc/contentHash/dotnetRuntime/osx-arm64
Normal file
@@ -0,0 +1 @@
|
||||
02c7126ff4d63ee2a0ae390c81434c125630522aadf35903bbeebb1a99d8af99
|
||||
@@ -1 +1 @@
|
||||
bdd247b2ff3f51095524412e2ac588e7a87af805e114d6caf2368366ee7be1ea
|
||||
c9d5a542f8d765168855a89e83ae0a8970d00869041c4f9a766651c04c72b212
|
||||
@@ -1 +1 @@
|
||||
d23a0cb9f20c0aa1cddb7a39567cd097020cdeb06a1e952940601d1a405c53b8
|
||||
d94f2fbaf210297162bc9f3add819d73682c3aa6899e321c3872412b924d5504
|
||||
1
src/Misc/contentHash/externals/osx-arm64
vendored
Normal file
1
src/Misc/contentHash/externals/osx-arm64
vendored
Normal file
@@ -0,0 +1 @@
|
||||
cc4708962a80325de0baa5ae8484e0cb9ae976ac6a4178c1c0d448b8c52bd7f7
|
||||
12
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
12
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
@@ -1823,9 +1823,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/ms": {
|
||||
@@ -3808,9 +3808,9 @@
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"version": "1.2.6",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
|
||||
"dev": true
|
||||
},
|
||||
"ms": {
|
||||
|
||||
@@ -140,6 +140,11 @@ if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-x64.tar.gz" node16 fix_nested_dir
|
||||
fi
|
||||
|
||||
if [[ "$PACKAGERUNTIME" == "osx-arm64" ]]; then
|
||||
# node.js v12 doesn't support macOS on arm64.
|
||||
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-arm64.tar.gz" node16 fix_nested_dir
|
||||
fi
|
||||
|
||||
# Download the external tools for Linux PACKAGERUNTIMEs.
|
||||
if [[ "$PACKAGERUNTIME" == "linux-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-x64.tar.gz" node12 fix_nested_dir
|
||||
|
||||
39
src/Misc/layoutroot/run-helper.cmd.template
Normal file
39
src/Misc/layoutroot/run-helper.cmd.template
Normal file
@@ -0,0 +1,39 @@
|
||||
@echo off
|
||||
|
||||
"%~dp0\bin\Runner.Listener.exe" run %*
|
||||
|
||||
rem using `if %ERRORLEVEL% EQU N` insterad of `if ERRORLEVEL N`
|
||||
rem `if ERRORLEVEL N` means: error level is N or MORE
|
||||
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo "Runner listener exit with 0 return code, stop the service, no retry needed."
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 1 (
|
||||
echo "Runner listener exit with terminated error, stop the service, no retry needed."
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 2 (
|
||||
echo "Runner listener exit with retryable error, re-launch runner in 5 seconds."
|
||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 3 (
|
||||
rem Sleep 5 seconds to wait for the runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch runner in 5 seconds"
|
||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if %ERRORLEVEL% EQU 4 (
|
||||
rem Sleep 5 seconds to wait for the ephemeral runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch ephemeral runner in 5 seconds"
|
||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo "Exiting after unknown error code: %ERRORLEVEL%"
|
||||
exit /b 0
|
||||
46
src/Misc/layoutroot/run-helper.sh.template
Executable file
46
src/Misc/layoutroot/run-helper.sh.template
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Validate not sudo
|
||||
user_id=`id -u`
|
||||
if [ $user_id -eq 0 -a -z "$RUNNER_ALLOW_RUNASROOT" ]; then
|
||||
echo "Must not run interactively with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Run
|
||||
shopt -s nocasematch
|
||||
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
SOURCE="$(readlink "$SOURCE")"
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
|
||||
returnCode=$?
|
||||
if [[ $returnCode == 0 ]]; then
|
||||
echo "Runner listener exit with 0 return code, stop the service, no retry needed."
|
||||
exit 0
|
||||
elif [[ $returnCode == 1 ]]; then
|
||||
echo "Runner listener exit with terminated error, stop the service, no retry needed."
|
||||
exit 0
|
||||
elif [[ $returnCode == 2 ]]; then
|
||||
echo "Runner listener exit with retryable error, re-launch runner in 5 seconds."
|
||||
"$DIR"/safe_sleep.sh 5
|
||||
exit 2
|
||||
elif [[ $returnCode == 3 ]]; then
|
||||
# Sleep 5 seconds to wait for the runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch runner in 5 seconds"
|
||||
"$DIR"/safe_sleep.sh 5
|
||||
exit 2
|
||||
elif [[ $returnCode == 4 ]]; then
|
||||
# Sleep 5 seconds to wait for the ephemeral runner update process finish
|
||||
echo "Runner listener exit because of updating, re-launch ephemeral runner in 5 seconds"
|
||||
"$DIR"/safe_sleep.sh 5
|
||||
exit 2
|
||||
else
|
||||
echo "Exiting with unknown error code: ${returnCode}"
|
||||
exit 0
|
||||
fi
|
||||
@@ -13,21 +13,19 @@ if defined VERBOSE_ARG (
|
||||
rem Unblock files in the root of the layout folder. E.g. .cmd files.
|
||||
powershell.exe -NoLogo -Sta -NoProfile -NonInteractive -ExecutionPolicy Unrestricted -Command "$VerbosePreference = %VERBOSE_ARG% ; Get-ChildItem -LiteralPath '%~dp0' | ForEach-Object { Write-Verbose ('Unblock: {0}' -f $_.FullName) ; $_ } | Unblock-File | Out-Null"
|
||||
|
||||
if /i "%~1" equ "localRun" (
|
||||
rem ********************************************************************************
|
||||
rem Local run.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" %*
|
||||
) else (
|
||||
|
||||
rem ********************************************************************************
|
||||
rem Run.
|
||||
rem ********************************************************************************
|
||||
"%~dp0bin\Runner.Listener.exe" run %*
|
||||
|
||||
rem Return code 4 means the run once runner received an update message.
|
||||
rem Sleep 5 seconds to wait for the update process finish and run the runner again.
|
||||
if ERRORLEVEL 4 (
|
||||
timeout /t 5 /nobreak > NUL
|
||||
"%~dp0bin\Runner.Listener.exe" run %*
|
||||
)
|
||||
:launch_helper
|
||||
copy "%~dp0run-helper.cmd.template" "%~dp0run-helper.cmd" /Y
|
||||
call "%~dp0run-helper.cmd" %*
|
||||
|
||||
if %ERRORLEVEL% EQU 1 (
|
||||
echo "Restarting runner..."
|
||||
goto :launch_helper
|
||||
) else (
|
||||
echo "Exiting runner..."
|
||||
exit /b 0
|
||||
)
|
||||
|
||||
@@ -1,12 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Validate not sudo
|
||||
user_id=`id -u`
|
||||
if [ $user_id -eq 0 -a -z "$RUNNER_ALLOW_RUNASROOT" ]; then
|
||||
echo "Must not run interactively with sudo"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Change directory to the script root directory
|
||||
# https://stackoverflow.com/questions/59895/getting-the-source-directory-of-a-bash-script-from-within
|
||||
SOURCE="${BASH_SOURCE[0]}"
|
||||
@@ -16,49 +9,16 @@ while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symli
|
||||
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
|
||||
done
|
||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||
|
||||
# Do not "cd $DIR". For localRun, the current directory is expected to be the repo location on disk.
|
||||
|
||||
# Run
|
||||
shopt -s nocasematch
|
||||
if [[ "$1" == "localRun" ]]; then
|
||||
"$DIR"/bin/Runner.Listener $*
|
||||
else
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
|
||||
# Return code 3 means the run once runner received an update message.
|
||||
# Sleep 5 seconds to wait for the update process finish
|
||||
cp -f "$DIR"/run-helper.sh.template "$DIR"/run-helper.sh
|
||||
# run the helper process which keep the listener alive
|
||||
while :;
|
||||
do
|
||||
"$DIR"/run-helper.sh $*
|
||||
returnCode=$?
|
||||
if [[ $returnCode == 3 ]]; then
|
||||
if [ ! -x "$(command -v sleep)" ]; then
|
||||
if [ ! -x "$(command -v ping)" ]; then
|
||||
COUNT="0"
|
||||
while [[ $COUNT != 5000 ]]; do
|
||||
echo "SLEEP" > /dev/null
|
||||
COUNT=$[$COUNT+1]
|
||||
if [[ $returnCode -eq 2 ]]; then
|
||||
echo "Restarting runner..."
|
||||
else
|
||||
echo "Exiting runner..."
|
||||
exit 0
|
||||
fi
|
||||
done
|
||||
else
|
||||
ping -c 5 127.0.0.1 > /dev/null
|
||||
fi
|
||||
else
|
||||
sleep 5
|
||||
fi
|
||||
elif [[ $returnCode == 4 ]]; then
|
||||
if [ ! -x "$(command -v sleep)" ]; then
|
||||
if [ ! -x "$(command -v ping)" ]; then
|
||||
COUNT="0"
|
||||
while [[ $COUNT != 5000 ]]; do
|
||||
echo "SLEEP" > /dev/null
|
||||
COUNT=$[$COUNT+1]
|
||||
done
|
||||
else
|
||||
ping -c 5 127.0.0.1 > /dev/null
|
||||
fi
|
||||
else
|
||||
sleep 5
|
||||
fi
|
||||
"$DIR"/bin/Runner.Listener run $*
|
||||
else
|
||||
exit $returnCode
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -3,6 +3,7 @@ api-ms-win-core-console-l1-2-0.dll
|
||||
api-ms-win-core-datetime-l1-1-0.dll
|
||||
api-ms-win-core-debug-l1-1-0.dll
|
||||
api-ms-win-core-errorhandling-l1-1-0.dll
|
||||
api-ms-win-core-fibers-l1-1-0.dll
|
||||
api-ms-win-core-file-l1-1-0.dll
|
||||
api-ms-win-core-file-l1-2-0.dll
|
||||
api-ms-win-core-file-l2-1-0.dll
|
||||
@@ -70,7 +71,7 @@ Microsoft.VisualBasic.dll
|
||||
Microsoft.Win32.Primitives.dll
|
||||
Microsoft.Win32.Registry.dll
|
||||
mscordaccore.dll
|
||||
mscordaccore_amd64_amd64_6.0.21.52210.dll
|
||||
mscordaccore_amd64_amd64_6.0.522.21309.dll
|
||||
mscordbi.dll
|
||||
mscorlib.dll
|
||||
mscorrc.debug.dll
|
||||
|
||||
@@ -86,7 +86,7 @@ namespace GitHub.Runner.Common
|
||||
public static class CommandLine
|
||||
{
|
||||
//if you are adding a new arg, please make sure you update the
|
||||
//validArgs array as well present in the CommandSettings.cs
|
||||
//validOptions dictionary as well present in the CommandSettings.cs
|
||||
public static class Args
|
||||
{
|
||||
public static readonly string Auth = "auth";
|
||||
@@ -121,7 +121,7 @@ namespace GitHub.Runner.Common
|
||||
}
|
||||
|
||||
//if you are adding a new flag, please make sure you update the
|
||||
//validFlags array as well present in the CommandSettings.cs
|
||||
//validOptions dictionary as well present in the CommandSettings.cs
|
||||
public static class Flags
|
||||
{
|
||||
public static readonly string Check = "check";
|
||||
@@ -149,6 +149,8 @@ namespace GitHub.Runner.Common
|
||||
public static class Features
|
||||
{
|
||||
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
||||
public static readonly string Node12Warning = "DistributedTask.AddWarningToNode12Action";
|
||||
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
||||
}
|
||||
|
||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||
@@ -158,6 +160,7 @@ namespace GitHub.Runner.Common
|
||||
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
||||
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 Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: {0}";
|
||||
}
|
||||
|
||||
public static class RunnerEvent
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.WebApi;
|
||||
using GitHub.Services.WebApi.Utilities.Internal;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace GitHub.Runner.Common
|
||||
@@ -171,6 +174,11 @@ namespace GitHub.Runner.Common
|
||||
Trace.Info($"Creating websocket client ..." + feedStreamUrl);
|
||||
this._websocketClient = new ClientWebSocket();
|
||||
this._websocketClient.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
|
||||
var userAgentValues = new List<ProductInfoHeaderValue>();
|
||||
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
|
||||
userAgentValues.AddRange(HostContext.UserAgents);
|
||||
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
|
||||
|
||||
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
||||
}
|
||||
else
|
||||
@@ -266,7 +274,7 @@ namespace GitHub.Runner.Common
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushedLinesViaWebsocket)
|
||||
if (!pushedLinesViaWebsocket && !cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
if (startLine.HasValue)
|
||||
{
|
||||
|
||||
@@ -299,7 +299,11 @@ namespace GitHub.Runner.Common
|
||||
{
|
||||
try
|
||||
{
|
||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, default(CancellationToken));
|
||||
// Give at most 60s for each request.
|
||||
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, timeoutTokenSource.Token);
|
||||
}
|
||||
|
||||
if (_firstConsoleOutputs)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -6,7 +6,13 @@ namespace GitHub.Runner.Common.Util
|
||||
public static class NodeUtil
|
||||
{
|
||||
private const string _defaultNodeVersion = "node16";
|
||||
|
||||
#if OS_OSX && ARM64
|
||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16" });
|
||||
#else
|
||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node12", "node16" });
|
||||
#endif
|
||||
|
||||
public static string GetInternalNodeVersion()
|
||||
{
|
||||
var forcedNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
||||
|
||||
@@ -17,43 +17,57 @@ namespace GitHub.Runner.Listener
|
||||
private readonly IPromptManager _promptManager;
|
||||
private readonly Tracing _trace;
|
||||
|
||||
private readonly string[] validCommands =
|
||||
// Valid flags for all commands
|
||||
private readonly string[] genericOptions =
|
||||
{
|
||||
Constants.Runner.CommandLine.Commands.Configure,
|
||||
Constants.Runner.CommandLine.Commands.Remove,
|
||||
Constants.Runner.CommandLine.Commands.Run,
|
||||
Constants.Runner.CommandLine.Commands.Warmup,
|
||||
Constants.Runner.CommandLine.Flags.Help,
|
||||
Constants.Runner.CommandLine.Flags.Version,
|
||||
Constants.Runner.CommandLine.Flags.Commit,
|
||||
Constants.Runner.CommandLine.Flags.Check
|
||||
};
|
||||
|
||||
private readonly string[] validFlags =
|
||||
// Valid flags and args for specific command - key: command, value: array of valid flags and args
|
||||
private readonly Dictionary<string, string[]> validOptions = new Dictionary<string, string[]>
|
||||
{
|
||||
// Valid configure flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Configure] =
|
||||
new string[]
|
||||
{
|
||||
Constants.Runner.CommandLine.Flags.Check,
|
||||
Constants.Runner.CommandLine.Flags.Commit,
|
||||
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
||||
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||
Constants.Runner.CommandLine.Flags.Help,
|
||||
Constants.Runner.CommandLine.Flags.Once,
|
||||
Constants.Runner.CommandLine.Flags.Replace,
|
||||
Constants.Runner.CommandLine.Flags.RunAsService,
|
||||
Constants.Runner.CommandLine.Flags.Unattended,
|
||||
Constants.Runner.CommandLine.Flags.Version
|
||||
};
|
||||
|
||||
private readonly string[] validArgs =
|
||||
{
|
||||
Constants.Runner.CommandLine.Args.Auth,
|
||||
Constants.Runner.CommandLine.Args.Labels,
|
||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||
Constants.Runner.CommandLine.Args.Name,
|
||||
Constants.Runner.CommandLine.Args.PAT,
|
||||
Constants.Runner.CommandLine.Args.RunnerGroup,
|
||||
Constants.Runner.CommandLine.Args.StartupType,
|
||||
Constants.Runner.CommandLine.Args.Token,
|
||||
Constants.Runner.CommandLine.Args.Url,
|
||||
Constants.Runner.CommandLine.Args.UserName,
|
||||
Constants.Runner.CommandLine.Args.WindowsLogonAccount,
|
||||
Constants.Runner.CommandLine.Args.WindowsLogonPassword,
|
||||
Constants.Runner.CommandLine.Args.Work
|
||||
},
|
||||
// Valid remove flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Remove] =
|
||||
new string[]
|
||||
{
|
||||
Constants.Runner.CommandLine.Args.Token,
|
||||
Constants.Runner.CommandLine.Args.PAT
|
||||
},
|
||||
// Valid run flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Run] =
|
||||
new string[]
|
||||
{
|
||||
Constants.Runner.CommandLine.Flags.Once,
|
||||
Constants.Runner.CommandLine.Args.StartupType
|
||||
},
|
||||
// valid warmup flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Warmup] =
|
||||
new string[] { }
|
||||
};
|
||||
|
||||
// Commands.
|
||||
@@ -126,17 +140,48 @@ namespace GitHub.Runner.Listener
|
||||
List<string> unknowns = new List<string>();
|
||||
|
||||
// detect unknown commands
|
||||
unknowns.AddRange(_parser.Commands.Where(x => !validCommands.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
unknowns.AddRange(_parser.Commands.Where(x => !validOptions.Keys.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
|
||||
// detect unknown flags
|
||||
unknowns.AddRange(_parser.Flags.Where(x => !validFlags.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
|
||||
// detect unknown args
|
||||
unknowns.AddRange(_parser.Args.Keys.Where(x => !validArgs.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
if (unknowns.Count == 0)
|
||||
{
|
||||
// detect unknown flags and args for valid commands
|
||||
foreach (var command in _parser.Commands)
|
||||
{
|
||||
if (validOptions.TryGetValue(command, out string[] options))
|
||||
{
|
||||
unknowns.AddRange(_parser.Flags.Where(x => !options.Contains(x, StringComparer.OrdinalIgnoreCase) && !genericOptions.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
unknowns.AddRange(_parser.Args.Keys.Where(x => !options.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return unknowns;
|
||||
}
|
||||
|
||||
public string GetCommandName()
|
||||
{
|
||||
string command = string.Empty;
|
||||
|
||||
if (Configure)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Configure;
|
||||
}
|
||||
else if (Remove)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Remove;
|
||||
}
|
||||
else if (Run)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Run;
|
||||
}
|
||||
else if (Warmup)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Warmup;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
//
|
||||
// Interactive flags.
|
||||
//
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
Trace.Info(nameof(LoadSettings));
|
||||
if (!IsConfigured())
|
||||
{
|
||||
throw new InvalidOperationException("Not configured. Run config.(sh/cmd) to configure the runner.");
|
||||
throw new NonRetryableException("Not configured. Run config.(sh/cmd) to configure the runner.");
|
||||
}
|
||||
|
||||
RunnerSettings settings = _store.GetSettings();
|
||||
@@ -624,9 +624,12 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
||||
|
||||
var responseStatus = System.Net.HttpStatusCode.OK;
|
||||
try
|
||||
{
|
||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
||||
responseStatus = response.StatusCode;
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@@ -634,11 +637,6 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
||||
}
|
||||
else if(response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
// It doesn't make sense to retry in this case, so just stop
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||
@@ -647,15 +645,15 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
catch(Exception ex) when (retryCount < 2)
|
||||
catch(Exception ex) when (retryCount < 2 && responseStatus != System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
retryCount++;
|
||||
Trace.Error($"Failed to get JIT runner token -- Atempt: {retryCount}");
|
||||
Trace.Error(ex);
|
||||
Trace.Info("Retrying in 5 seconds");
|
||||
}
|
||||
}
|
||||
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));
|
||||
Trace.Info($"Retrying in {backOff.Seconds} seconds");
|
||||
await Task.Delay(backOff);
|
||||
}
|
||||
return null;
|
||||
@@ -689,9 +687,11 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
{"runner_event", runnerEvent}
|
||||
};
|
||||
|
||||
var responseStatus = System.Net.HttpStatusCode.OK;
|
||||
try
|
||||
{
|
||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
||||
responseStatus = response.StatusCode;
|
||||
|
||||
if(response.IsSuccessStatusCode)
|
||||
{
|
||||
@@ -699,29 +699,23 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||
return StringUtil.ConvertFromJson<GitHubAuthResult>(jsonResponse);
|
||||
}
|
||||
else if(response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
// It doesn't make sense to retry in this case, so just stop
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||
_term.WriteError(errorResponse);
|
||||
// Something else bad happened, let's go to our retry logic
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
catch(Exception ex) when (retryCount < 2)
|
||||
catch(Exception ex) when (retryCount < 2 && responseStatus != System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
retryCount++;
|
||||
Trace.Error($"Failed to get tenant credentials -- Atempt: {retryCount}");
|
||||
Trace.Error(ex);
|
||||
Trace.Info("Retrying in 5 seconds");
|
||||
}
|
||||
}
|
||||
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));
|
||||
Trace.Info($"Retrying in {backOff.Seconds} seconds");
|
||||
await Task.Delay(backOff);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -95,7 +95,15 @@ namespace GitHub.Runner.Listener
|
||||
var unknownCommandlines = command.Validate();
|
||||
if (unknownCommandlines.Count > 0)
|
||||
{
|
||||
terminal.WriteError($"Unrecognized command-line input arguments: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||
string commandName = command.GetCommandName();
|
||||
if (string.IsNullOrEmpty(commandName))
|
||||
{
|
||||
terminal.WriteError($"This command does not recognize the command-line input arguments: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal.WriteError($"Unrecognized command-line input arguments for command {commandName}: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||
}
|
||||
}
|
||||
|
||||
// Defer to the Runner class to execute the command.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -430,7 +430,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
#endif
|
||||
var selfUpdater = HostContext.GetService<ISelfUpdater>();
|
||||
selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, !runOnce && HostContext.StartupType != StartupType.Service, HostContext.RunnerShutdownToken);
|
||||
selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, false, HostContext.RunnerShutdownToken);
|
||||
Trace.Info("Refresh message received, kick-off selfupdate background process.");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.ObjectTemplating;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
@@ -9,7 +10,6 @@ using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
@@ -171,8 +171,16 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
// Load the inputs.
|
||||
ExecutionContext.Debug("Loading inputs");
|
||||
Dictionary<string, string> inputs;
|
||||
if (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.UseContainerPathForTemplate) ?? false)
|
||||
{
|
||||
inputs = EvaluateStepInputs(stepHost);
|
||||
}
|
||||
else
|
||||
{
|
||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
||||
inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
||||
}
|
||||
|
||||
var userInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (KeyValuePair<string, string> input in inputs)
|
||||
@@ -299,6 +307,15 @@ namespace GitHub.Runner.Worker
|
||||
return didFullyEvaluate;
|
||||
}
|
||||
|
||||
private Dictionary<String, String> EvaluateStepInputs(IStepHost stepHost)
|
||||
{
|
||||
DictionaryContextData expressionValues = ExecutionContext.GetExpressionValues(stepHost);
|
||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, expressionValues, ExecutionContext.ExpressionFunctions);
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
private string GenerateDisplayName(ActionStep action, DictionaryContextData contextData, IExecutionContext context, out bool didFullyEvaluate)
|
||||
{
|
||||
ArgUtil.NotNull(context, nameof(context));
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace GitHub.Runner.Worker.Container
|
||||
{
|
||||
public class ContainerInfo
|
||||
{
|
||||
private IDictionary<string, string> _userMountVolumes;
|
||||
private List<MountVolume> _mountVolumes;
|
||||
private IDictionary<string, string> _userPortMappings;
|
||||
private List<PortMapping> _portMappings;
|
||||
@@ -68,8 +68,7 @@ namespace GitHub.Runner.Worker.Container
|
||||
{
|
||||
foreach (var volume in container.Volumes)
|
||||
{
|
||||
UserMountVolumes[volume] = volume;
|
||||
MountVolumes.Add(new MountVolume(volume));
|
||||
MountVolumes.Add(new MountVolume(volume, isUserProvided: true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,19 +103,20 @@ namespace GitHub.Runner.Worker.Container
|
||||
return _environmentVariables;
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary<string, string> UserMountVolumes
|
||||
public ReadOnlyCollection<MountVolume> UserMountVolumes
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_userMountVolumes == null)
|
||||
return MountVolumes.Where(v => !string.IsNullOrEmpty(v.UserProvidedValue)).ToList().AsReadOnly();
|
||||
}
|
||||
}
|
||||
public ReadOnlyCollection<MountVolume> SystemMountVolumes
|
||||
{
|
||||
_userMountVolumes = new Dictionary<string, string>();
|
||||
}
|
||||
return _userMountVolumes;
|
||||
get
|
||||
{
|
||||
return MountVolumes.Where(v => string.IsNullOrEmpty(v.UserProvidedValue)).ToList().AsReadOnly();
|
||||
}
|
||||
}
|
||||
|
||||
public List<MountVolume> MountVolumes
|
||||
{
|
||||
get
|
||||
@@ -260,18 +260,27 @@ namespace GitHub.Runner.Worker.Container
|
||||
|
||||
public class MountVolume
|
||||
{
|
||||
public string UserProvidedValue { get; set; }
|
||||
public MountVolume(string sourceVolumePath, string targetVolumePath, bool readOnly = false)
|
||||
{
|
||||
this.SourceVolumePath = sourceVolumePath;
|
||||
this.TargetVolumePath = targetVolumePath;
|
||||
this.ReadOnly = readOnly;
|
||||
}
|
||||
|
||||
public MountVolume(string fromString)
|
||||
{
|
||||
ParseVolumeString(fromString);
|
||||
}
|
||||
|
||||
public MountVolume(string fromString, bool isUserProvided)
|
||||
{
|
||||
ParseVolumeString(fromString);
|
||||
if (isUserProvided)
|
||||
{
|
||||
UserProvidedValue = fromString;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseVolumeString(string volume)
|
||||
{
|
||||
var volumeSplit = volume.Split(":");
|
||||
|
||||
@@ -192,13 +192,12 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
Trace.Info($"User provided port: {port.Value}");
|
||||
}
|
||||
foreach (var volume in container.UserMountVolumes)
|
||||
foreach (var mount in container.UserMountVolumes)
|
||||
{
|
||||
Trace.Info($"User provided volume: {volume.Value}");
|
||||
var mount = new MountVolume(volume.Value);
|
||||
Trace.Info($"User provided volume: {mount.UserProvidedValue}");
|
||||
if (string.Equals(mount.SourceVolumePath, "/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
executionContext.Warning($"Volume mount {volume.Value} is going to mount '/' into the container which may cause file ownership change in the entire file system and cause Actions Runner to lose permission to access the disk.");
|
||||
executionContext.Warning($"Volume mount {mount.UserProvidedValue} is going to mount '/' into the container which may cause file ownership change in the entire file system and cause Actions Runner to lose permission to access the disk.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using GitHub.DistributedTask.Expressions2;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
@@ -19,7 +15,7 @@ using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Services.WebApi;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using Newtonsoft.Json;
|
||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
@@ -109,6 +105,10 @@ namespace GitHub.Runner.Worker
|
||||
void ForceTaskComplete();
|
||||
void RegisterPostJobStep(IStep step);
|
||||
void PublishStepTelemetry();
|
||||
|
||||
void ApplyContinueOnError(TemplateToken continueOnError);
|
||||
void UpdateGlobalStepsContext();
|
||||
|
||||
void WriteWebhookPayload();
|
||||
}
|
||||
|
||||
@@ -439,14 +439,19 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
_logger.End();
|
||||
|
||||
UpdateGlobalStepsContext();
|
||||
|
||||
return Result.Value;
|
||||
}
|
||||
|
||||
public void UpdateGlobalStepsContext()
|
||||
{
|
||||
// Skip if generated context name. Generated context names start with "__". After 3.2 the server will never send an empty context name.
|
||||
if (!string.IsNullOrEmpty(ContextName) && !ContextName.StartsWith("__", StringComparison.Ordinal))
|
||||
{
|
||||
Global.StepsContext.SetOutcome(ScopeName, ContextName, (Outcome ?? Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
Global.StepsContext.SetConclusion(ScopeName, ContextName, (Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
}
|
||||
|
||||
return Result.Value;
|
||||
}
|
||||
|
||||
public void SetRunnerContext(string name, string value)
|
||||
@@ -1064,6 +1069,36 @@ namespace GitHub.Runner.Worker
|
||||
var newGuid = Guid.NewGuid();
|
||||
return CreateChild(newGuid, displayName, newGuid.ToString("N"), null, null, ActionRunStage.Post, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count, siblingScopeName: siblingScopeName);
|
||||
}
|
||||
|
||||
public void ApplyContinueOnError(TemplateToken continueOnErrorToken)
|
||||
{
|
||||
if (Result != TaskResult.Failed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var continueOnError = false;
|
||||
try
|
||||
{
|
||||
var templateEvaluator = this.ToPipelineTemplateEvaluator();
|
||||
continueOnError = templateEvaluator.EvaluateStepContinueOnError(continueOnErrorToken, ExpressionValues, ExpressionFunctions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.Info("The step failed and an error occurred when attempting to determine whether to continue on error.");
|
||||
Trace.Error(ex);
|
||||
this.Error("The step failed and an error occurred when attempting to determine whether to continue on error.");
|
||||
this.Error(ex);
|
||||
}
|
||||
|
||||
if (continueOnError)
|
||||
{
|
||||
Outcome = Result;
|
||||
Result = TaskResult.Succeeded;
|
||||
Trace.Info($"Updated step result (continue on error)");
|
||||
}
|
||||
|
||||
UpdateGlobalStepsContext();
|
||||
}
|
||||
}
|
||||
|
||||
// The Error/Warning/etc methods are created as extension methods to simplify unit testing.
|
||||
@@ -1085,7 +1120,6 @@ namespace GitHub.Runner.Worker
|
||||
context.Error(ex.Message);
|
||||
context.Debug(ex.ToString());
|
||||
}
|
||||
|
||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||
public static void Error(this IExecutionContext context, string message)
|
||||
{
|
||||
@@ -1159,6 +1193,66 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
return new TemplateTraceWriter(context);
|
||||
}
|
||||
|
||||
public static DictionaryContextData GetExpressionValues(this IExecutionContext context, IStepHost stepHost)
|
||||
{
|
||||
if (stepHost is ContainerStepHost)
|
||||
{
|
||||
|
||||
var expressionValues = context.ExpressionValues.Clone() as DictionaryContextData;
|
||||
context.UpdatePathsInExpressionValues("github", expressionValues, stepHost);
|
||||
context.UpdatePathsInExpressionValues("runner", expressionValues, stepHost);
|
||||
return expressionValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.ExpressionValues.Clone() as DictionaryContextData;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdatePathsInExpressionValues(this IExecutionContext context, string contextName, DictionaryContextData expressionValues, IStepHost stepHost)
|
||||
{
|
||||
var dict = expressionValues[contextName].AssertDictionary($"expected context {contextName} to be a dictionary");
|
||||
context.ResolvePathsInExpressionValuesDictionary(dict, stepHost);
|
||||
expressionValues[contextName] = dict;
|
||||
}
|
||||
|
||||
private static void ResolvePathsInExpressionValuesDictionary(this IExecutionContext context, DictionaryContextData dict, IStepHost stepHost)
|
||||
{
|
||||
foreach (var key in dict.Keys.ToList())
|
||||
{
|
||||
if (dict[key] is StringContextData)
|
||||
{
|
||||
var value = dict[key].ToString();
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
dict[key] = new StringContextData(stepHost.ResolvePathForStepHost(value));
|
||||
}
|
||||
}
|
||||
else if (dict[key] is DictionaryContextData)
|
||||
{
|
||||
var innerDict = dict[key].AssertDictionary("expected dictionary");
|
||||
context.ResolvePathsInExpressionValuesDictionary(innerDict, stepHost);
|
||||
var updatedDict = new DictionaryContextData();
|
||||
foreach (var k in innerDict.Keys.ToList())
|
||||
{
|
||||
updatedDict[k] = innerDict[k];
|
||||
}
|
||||
dict[key] = updatedDict;
|
||||
}
|
||||
else if (dict[key] is CaseSensitiveDictionaryContextData)
|
||||
{
|
||||
var innerDict = dict[key].AssertDictionary("expected dictionary");
|
||||
context.ResolvePathsInExpressionValuesDictionary(innerDict, stepHost);
|
||||
var updatedDict = new CaseSensitiveDictionaryContextData();
|
||||
foreach (var k in innerDict.Keys.ToList())
|
||||
{
|
||||
updatedDict[k] = innerDict[k];
|
||||
}
|
||||
dict[key] = updatedDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TemplateTraceWriter : ObjectTemplating.ITraceWriter
|
||||
|
||||
@@ -266,7 +266,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension
|
||||
{
|
||||
private const int _attachmentSizeLimit = 128 * 1024;
|
||||
public const int AttachmentSizeLimit = 1024 * 1024;
|
||||
|
||||
public string ContextName => "step_summary";
|
||||
public string FilePrefix => "step_summary_";
|
||||
@@ -296,9 +296,9 @@ namespace GitHub.Runner.Worker
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileSize > _attachmentSizeLimit)
|
||||
if (fileSize > AttachmentSizeLimit)
|
||||
{
|
||||
context.Error(String.Format(Constants.Runner.UnsupportedSummarySize, _attachmentSizeLimit / 1024, fileSize / 1024));
|
||||
context.Error(String.Format(Constants.Runner.UnsupportedSummarySize, AttachmentSizeLimit / 1024, fileSize / 1024));
|
||||
Trace.Info($"Step Summary file ({filePath}) is too large ({fileSize} bytes); skipping attachment upload");
|
||||
|
||||
return;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.Expressions2;
|
||||
@@ -13,7 +11,6 @@ using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Expressions;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
@@ -407,7 +404,7 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
}
|
||||
|
||||
// Update context
|
||||
SetStepsContext(step);
|
||||
step.ExecutionContext.UpdateGlobalStepsContext();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -452,6 +449,8 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
SetStepConclusion(step, Common.Util.TaskResultUtil.MergeTaskResults(step.ExecutionContext.Result, step.ExecutionContext.CommandResult.Value));
|
||||
}
|
||||
|
||||
step.ExecutionContext.ApplyContinueOnError(step.ContinueOnError);
|
||||
|
||||
Trace.Info($"Step result: {step.ExecutionContext.Result}");
|
||||
step.ExecutionContext.Debug($"Finished: {step.DisplayName}");
|
||||
step.ExecutionContext.PublishStepTelemetry();
|
||||
@@ -460,16 +459,7 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
private void SetStepConclusion(IStep step, TaskResult result)
|
||||
{
|
||||
step.ExecutionContext.Result = result;
|
||||
SetStepsContext(step);
|
||||
}
|
||||
private void SetStepsContext(IStep step)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(step.ExecutionContext.ContextName) && !step.ExecutionContext.ContextName.StartsWith("__", StringComparison.Ordinal))
|
||||
{
|
||||
// TODO: when we support continue on error, we may need to do logic here to change conclusion based on the continue on error result
|
||||
step.ExecutionContext.Global.StepsContext.SetOutcome(step.ExecutionContext.ScopeName, step.ExecutionContext.ContextName, (step.ExecutionContext.Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
step.ExecutionContext.Global.StepsContext.SetConclusion(step.ExecutionContext.ScopeName, step.ExecutionContext.ContextName, (step.ExecutionContext.Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
}
|
||||
step.ExecutionContext.UpdateGlobalStepsContext();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
@@ -92,6 +94,14 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
|
||||
}
|
||||
|
||||
#if OS_OSX
|
||||
if (string.Equals(Data.NodeVersion, "node12", StringComparison.OrdinalIgnoreCase) &&
|
||||
Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.Arm64))
|
||||
{
|
||||
ExecutionContext.Output($"The node12 is not supported on macOS ARM64 platform. Use node16 instead.");
|
||||
Data.NodeVersion = "node16";
|
||||
}
|
||||
#endif
|
||||
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
|
||||
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||
|
||||
@@ -112,6 +122,17 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
// Remove environment variable that may cause conflicts with the node within the runner.
|
||||
Environment.Remove("NODE_ICU_DATA"); // https://github.com/actions/runner/issues/795
|
||||
|
||||
if (Data.NodeVersion == "node12" && (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.Node12Warning) ?? false))
|
||||
{
|
||||
if (!ExecutionContext.JobContext.ContainsKey("Node12ActionsWarnings"))
|
||||
{
|
||||
ExecutionContext.JobContext["Node12ActionsWarnings"] = new ArrayContextData();
|
||||
}
|
||||
var repoAction = Action as RepositoryPathReference;
|
||||
var actionDisplayName = new StringContextData(repoAction.Name ?? repoAction.Path); // local actions don't have a 'Name'
|
||||
ExecutionContext.JobContext["Node12ActionsWarnings"].AssertArray("Node12ActionsWarnings").Add(actionDisplayName);
|
||||
}
|
||||
|
||||
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||
{
|
||||
|
||||
@@ -151,6 +151,11 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
if (line.Contains("fatal: unsafe repository", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_executionContext.StepTelemetry.ErrorMessages.Add(line);
|
||||
}
|
||||
|
||||
// Regular output
|
||||
_executionContext.Output(line);
|
||||
}
|
||||
|
||||
@@ -153,7 +153,8 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
string workingDirectory = null;
|
||||
if (!Inputs.TryGetValue("workingDirectory", out workingDirectory))
|
||||
{
|
||||
if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults))
|
||||
// Don't use job level working directories for hooks
|
||||
if (IsActionStep && string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults))
|
||||
{
|
||||
if (runDefaults.TryGetValue("working-directory", out workingDirectory))
|
||||
{
|
||||
|
||||
@@ -1,18 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Services.WebApi;
|
||||
using Newtonsoft.Json;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using System.Linq;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
|
||||
namespace GitHub.Runner.Worker.Handlers
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
@@ -257,6 +258,12 @@ namespace GitHub.Runner.Worker
|
||||
}
|
||||
}
|
||||
|
||||
if (jobContext.JobContext.ContainsKey("Node12ActionsWarnings"))
|
||||
{
|
||||
var actions = string.Join(", ", jobContext.JobContext["Node12ActionsWarnings"].AssertArray("Node12ActionsWarnings").Select(action => action.ToString()));
|
||||
jobContext.Warning(string.Format(Constants.Runner.Node12DetectedAfterEndOfLife, actions));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
await ShutdownQueue(throwOnFailure: true);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -133,8 +134,10 @@ namespace GitHub.Runner.Worker
|
||||
// Test the condition again. The job was cancelled after the condition was originally evaluated.
|
||||
jobCancelRegister = jobContext.CancellationToken.Register(() =>
|
||||
{
|
||||
// Mark job as cancelled
|
||||
jobContext.Result = TaskResult.Canceled;
|
||||
// Mark job as Cancelled or Failed depending on HostContext shutdown token's cancellation
|
||||
jobContext.Result = HostContext.RunnerShutdownToken.IsCancellationRequested
|
||||
? TaskResult.Failed
|
||||
: TaskResult.Canceled;
|
||||
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
||||
|
||||
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
||||
@@ -172,8 +175,10 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
if (jobContext.Result != TaskResult.Canceled)
|
||||
{
|
||||
// Mark job as cancelled
|
||||
jobContext.Result = TaskResult.Canceled;
|
||||
// Mark job as Cancelled or Failed depending on HostContext shutdown token's cancellation
|
||||
jobContext.Result = HostContext.RunnerShutdownToken.IsCancellationRequested
|
||||
? TaskResult.Failed
|
||||
: TaskResult.Canceled;
|
||||
jobContext.JobContext.Status = jobContext.Result?.ToActionResult();
|
||||
}
|
||||
}
|
||||
@@ -319,29 +324,8 @@ namespace GitHub.Runner.Worker
|
||||
step.ExecutionContext.Result = TaskResultUtil.MergeTaskResults(step.ExecutionContext.Result, step.ExecutionContext.CommandResult.Value);
|
||||
}
|
||||
|
||||
// Fixup the step result if ContinueOnError
|
||||
if (step.ExecutionContext.Result == TaskResult.Failed)
|
||||
{
|
||||
var continueOnError = false;
|
||||
try
|
||||
{
|
||||
continueOnError = templateEvaluator.EvaluateStepContinueOnError(step.ContinueOnError, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.Info("The step failed and an error occurred when attempting to determine whether to continue on error.");
|
||||
Trace.Error(ex);
|
||||
step.ExecutionContext.Error("The step failed and an error occurred when attempting to determine whether to continue on error.");
|
||||
step.ExecutionContext.Error(ex);
|
||||
}
|
||||
step.ExecutionContext.ApplyContinueOnError(step.ContinueOnError);
|
||||
|
||||
if (continueOnError)
|
||||
{
|
||||
step.ExecutionContext.Outcome = step.ExecutionContext.Result;
|
||||
step.ExecutionContext.Result = TaskResult.Succeeded;
|
||||
Trace.Info($"Updated step result (continue on error)");
|
||||
}
|
||||
}
|
||||
Trace.Info($"Step result: {step.ExecutionContext.Result}");
|
||||
|
||||
// Complete the step context
|
||||
|
||||
@@ -129,9 +129,10 @@
|
||||
"required": true
|
||||
},
|
||||
"env": "step-env",
|
||||
"continue-on-error": "boolean-steps-context",
|
||||
"working-directory": "string-steps-context",
|
||||
"shell": {
|
||||
"type": "non-empty-string",
|
||||
"type": "string-steps-context",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
@@ -147,6 +148,7 @@
|
||||
"type": "non-empty-string",
|
||||
"required": true
|
||||
},
|
||||
"continue-on-error": "boolean-steps-context",
|
||||
"with": "step-with",
|
||||
"env": "step-env"
|
||||
}
|
||||
@@ -201,6 +203,20 @@
|
||||
],
|
||||
"string": {}
|
||||
},
|
||||
"boolean-steps-context": {
|
||||
"context": [
|
||||
"github",
|
||||
"inputs",
|
||||
"strategy",
|
||||
"matrix",
|
||||
"steps",
|
||||
"job",
|
||||
"runner",
|
||||
"env",
|
||||
"hashFiles(1,255)"
|
||||
],
|
||||
"boolean": {}
|
||||
},
|
||||
"step-env": {
|
||||
"context": [
|
||||
"github",
|
||||
|
||||
@@ -23,7 +23,6 @@ namespace GitHub.Services.Common.ClientStorage
|
||||
private readonly string m_filePath;
|
||||
private readonly VssFileStorageReader m_reader;
|
||||
private readonly IVssClientStorageWriter m_writer;
|
||||
|
||||
private const char c_defaultPathSeparator = '\\';
|
||||
private const bool c_defaultIgnoreCaseInPaths = false;
|
||||
|
||||
@@ -192,7 +191,7 @@ namespace GitHub.Services.Common.ClientStorage
|
||||
// Windows Impersonation is being used.
|
||||
|
||||
// Check to see if we can find the user's local application data directory.
|
||||
string subDir = "GitHub\\ActionsService";
|
||||
string subDir = Path.Combine("GitHub", "ActionsService");
|
||||
string path = Environment.GetEnvironmentVariable("localappdata");
|
||||
SafeGetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
if (string.IsNullOrEmpty(path))
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -19,7 +19,8 @@ namespace GitHub.Runner.Common.Tests
|
||||
"linux-x64",
|
||||
"linux-arm",
|
||||
"linux-arm64",
|
||||
"osx-x64"
|
||||
"osx-x64",
|
||||
"osx-arm64"
|
||||
};
|
||||
|
||||
Assert.True(BuildConstants.Source.CommitHash.Length == 40, $"CommitHash should be SHA-1 hash {BuildConstants.Source.CommitHash}");
|
||||
|
||||
@@ -708,33 +708,85 @@ namespace GitHub.Runner.Common.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Theory]
|
||||
[InlineData("configure", "once")]
|
||||
[InlineData("remove", "disableupdate")]
|
||||
[InlineData("remove", "ephemeral")]
|
||||
[InlineData("remove", "once")]
|
||||
[InlineData("remove", "replace")]
|
||||
[InlineData("remove", "runasservice")]
|
||||
[InlineData("remove", "unattended")]
|
||||
[InlineData("run", "disableupdate")]
|
||||
[InlineData("run", "ephemeral")]
|
||||
[InlineData("run", "replace")]
|
||||
[InlineData("run", "runasservice")]
|
||||
[InlineData("run", "unattended")]
|
||||
[InlineData("warmup", "disableupdate")]
|
||||
[InlineData("warmup", "ephemeral")]
|
||||
[InlineData("warmup", "once")]
|
||||
[InlineData("warmup", "replace")]
|
||||
[InlineData("warmup", "runasservice")]
|
||||
[InlineData("warmup", "unattended")]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateFlags()
|
||||
public void ValidateInvalidFlagCommandCombination(string validCommand, string flag)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { "--badflag" });
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
||||
|
||||
// Assert.
|
||||
Assert.Contains("badflag", command.Validate());
|
||||
Assert.Contains(flag, command.Validate());
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Theory]
|
||||
[InlineData("remove", "auth", "bar arg value")]
|
||||
[InlineData("remove", "labels", "bar arg value")]
|
||||
[InlineData("remove", "monitorsocketaddress", "bar arg value")]
|
||||
[InlineData("remove", "name", "bar arg value")]
|
||||
[InlineData("remove", "runnergroup", "bar arg value")]
|
||||
[InlineData("remove", "url", "bar arg value")]
|
||||
[InlineData("remove", "username", "bar arg value")]
|
||||
[InlineData("remove", "windowslogonaccount", "bar arg value")]
|
||||
[InlineData("remove", "windowslogonpassword", "bar arg value")]
|
||||
[InlineData("remove", "work", "bar arg value")]
|
||||
[InlineData("run", "auth", "bad arg value")]
|
||||
[InlineData("run", "labels", "bad arg value")]
|
||||
[InlineData("run", "monitorsocketaddress", "bad arg value")]
|
||||
[InlineData("run", "name", "bad arg value")]
|
||||
[InlineData("run", "pat", "bad arg value")]
|
||||
[InlineData("run", "runnergroup", "bad arg value")]
|
||||
[InlineData("run", "token", "bad arg value")]
|
||||
[InlineData("run", "url", "bad arg value")]
|
||||
[InlineData("run", "username", "bad arg value")]
|
||||
[InlineData("run", "windowslogonaccount", "bad arg value")]
|
||||
[InlineData("run", "windowslogonpassword", "bad arg value")]
|
||||
[InlineData("run", "work", "bad arg value")]
|
||||
[InlineData("warmup", "auth", "bad arg value")]
|
||||
[InlineData("warmup", "labels", "bad arg value")]
|
||||
[InlineData("warmup", "monitorsocketaddress", "bad arg value")]
|
||||
[InlineData("warmup", "name", "bad arg value")]
|
||||
[InlineData("warmup", "pat", "bad arg value")]
|
||||
[InlineData("warmup", "runnergroup", "bad arg value")]
|
||||
[InlineData("warmup", "token", "bad arg value")]
|
||||
[InlineData("warmup", "url", "bad arg value")]
|
||||
[InlineData("warmup", "username", "bad arg value")]
|
||||
[InlineData("warmup", "windowslogonaccount", "bad arg value")]
|
||||
[InlineData("warmup", "windowslogonpassword", "bad arg value")]
|
||||
[InlineData("warmup", "work", "bad arg value")]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateArgs()
|
||||
public void ValidateInvalidArgCommandCombination(string validCommand, string arg, string argValue)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { "--badargname", "bad arg value" });
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
||||
|
||||
// Assert.
|
||||
Assert.Contains("badargname", command.Validate());
|
||||
Assert.Contains(arg, command.Validate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,6 +810,73 @@ namespace GitHub.Runner.Common.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("configure", "help")]
|
||||
[InlineData("configure", "version")]
|
||||
[InlineData("configure", "commit")]
|
||||
[InlineData("configure", "check")]
|
||||
[InlineData("configure", "disableupdate")]
|
||||
[InlineData("configure", "ephemeral")]
|
||||
[InlineData("configure", "replace")]
|
||||
[InlineData("configure", "runasservice")]
|
||||
[InlineData("configure", "unattended")]
|
||||
[InlineData("remove", "help")]
|
||||
[InlineData("remove", "version")]
|
||||
[InlineData("remove", "commit")]
|
||||
[InlineData("remove", "check")]
|
||||
[InlineData("run", "help")]
|
||||
[InlineData("run", "version")]
|
||||
[InlineData("run", "commit")]
|
||||
[InlineData("run", "check")]
|
||||
[InlineData("run", "once")]
|
||||
[InlineData("warmup", "help")]
|
||||
[InlineData("warmup", "version")]
|
||||
[InlineData("warmup", "commit")]
|
||||
[InlineData("warmup", "check")]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateGoodFlagCommandCombination(string validCommand, string flag)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
||||
|
||||
// Assert.
|
||||
Assert.True(command.Validate().Count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("configure", "auth", "good arg value")]
|
||||
[InlineData("configure", "labels", "good arg value")]
|
||||
[InlineData("configure", "monitorsocketaddress", "good arg value")]
|
||||
[InlineData("configure", "name", "good arg value")]
|
||||
[InlineData("configure", "pat", "good arg value")]
|
||||
[InlineData("configure", "runnergroup", "good arg value")]
|
||||
[InlineData("configure", "token", "good arg value")]
|
||||
[InlineData("configure", "url", "good arg value")]
|
||||
[InlineData("configure", "username", "good arg value")]
|
||||
[InlineData("configure", "windowslogonaccount", "good arg value")]
|
||||
[InlineData("configure", "windowslogonpassword", "good arg value")]
|
||||
[InlineData("configure", "work", "good arg value")]
|
||||
[InlineData("remove", "token", "good arg value")]
|
||||
[InlineData("remove", "pat", "good arg value")]
|
||||
[InlineData("run", "startuptype", "good arg value")]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateGoodArgCommandCombination(string validCommand, string arg, string argValue)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
||||
|
||||
// Assert.
|
||||
Assert.True(command.Validate().Count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
private TestHostContext CreateTestContext([CallerMemberName] string testName = "")
|
||||
{
|
||||
TestHostContext hc = new TestHostContext(this, testName);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#if !(OS_OSX && ARM64)
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -50,9 +51,9 @@ namespace GitHub.Runner.Common.Tests.Listener
|
||||
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://github.com/actions/runner/releases/latest"));
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.Redirect)
|
||||
{
|
||||
var redirect = await response.Content.ReadAsStringAsync();
|
||||
var redirectUrl = response.Headers.Location.ToString();
|
||||
Regex regex = new Regex(@"/runner/releases/tag/v(?<version>\d+\.\d+\.\d+)");
|
||||
var match = regex.Match(redirect);
|
||||
var match = regex.Match(redirectUrl);
|
||||
if (match.Success)
|
||||
{
|
||||
latestVersion = match.Groups["version"].Value;
|
||||
@@ -63,6 +64,10 @@ namespace GitHub.Runner.Common.Tests.Listener
|
||||
_packageUrl = $"https://github.com/actions/runner/releases/download/v{latestVersion}/actions-runner-{BuildConstants.RunnerPackage.PackageName}-{latestVersion}.zip";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("The latest runner version could not be determined so a download URL could not be generated for it. Please check the location header of the redirect response of 'https://github.com/actions/runner/releases/latest'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,3 +796,4 @@ namespace GitHub.Runner.Common.Tests.Listener
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -166,9 +166,9 @@ namespace GitHub.Runner.Common.Tests
|
||||
string binDir = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/bin");
|
||||
|
||||
#if OS_WINDOWS
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node12\bin\node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
||||
#else
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node12/bin/node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
||||
#endif
|
||||
string hashFilesScript = Path.Combine(binDir, "hashFiles");
|
||||
var hashResult = string.Empty;
|
||||
@@ -228,9 +228,9 @@ namespace GitHub.Runner.Common.Tests
|
||||
string binDir = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/bin");
|
||||
|
||||
#if OS_WINDOWS
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node12\bin\node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
||||
#else
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node12/bin/node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
||||
#endif
|
||||
string hashFilesScript = Path.Combine(binDir, "hashFiles");
|
||||
var hashResult = string.Empty;
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace GitHub.Runner.Common.Tests
|
||||
try
|
||||
{
|
||||
#if OS_WINDOWS
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node12\bin\node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
||||
#else
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node12/bin/node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
||||
hc.EnqueueInstance<IProcessInvoker>(new ProcessInvokerWrapper());
|
||||
#endif
|
||||
var startInfo = new ProcessStartInfo(node, "-e \"setTimeout(function(){{}}, 15 * 1000);\"");
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
using (var hostContext = Setup())
|
||||
{
|
||||
var stepSummaryFile = Path.Combine(_rootDirectory, "empty-file");
|
||||
File.WriteAllBytes(stepSummaryFile, new byte[128 * 1024 + 1]);
|
||||
File.WriteAllBytes(stepSummaryFile, new byte[CreateStepSummaryCommand.AttachmentSizeLimit + 1]);
|
||||
|
||||
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
||||
_jobExecutionContext.Complete();
|
||||
|
||||
@@ -6,8 +6,11 @@ using System.Threading;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Common.Tests.Worker
|
||||
@@ -90,6 +93,63 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void ApplyContinueOnError_CheckResultAndOutcome()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
|
||||
// Arrange: Create a job request message.
|
||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||
TimelineReference timeline = new TimelineReference();
|
||||
Guid jobId = Guid.NewGuid();
|
||||
string jobName = "some job name";
|
||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), 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();
|
||||
jobRequest.Variables["ACTIONS_STEP_DEBUG"] = "true";
|
||||
|
||||
// Arrange: Setup the paging logger.
|
||||
var pagingLogger = new Mock<IPagingLogger>();
|
||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<long>())).Callback((Guid id, string msg, long? lineNumber) => { hc.GetTrace().Info(msg); });
|
||||
|
||||
hc.EnqueueInstance(pagingLogger.Object);
|
||||
hc.SetSingleton(jobServerQueue.Object);
|
||||
|
||||
var ec = new Runner.Worker.ExecutionContext();
|
||||
ec.Initialize(hc);
|
||||
|
||||
// Act.
|
||||
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||
|
||||
foreach (var tc in new List<(TemplateToken token, TaskResult result, TaskResult? expectedResult, TaskResult? expectedOutcome)> {
|
||||
(token: new BooleanToken(null, null, null, true), result: TaskResult.Failed, expectedResult: TaskResult.Succeeded, expectedOutcome: TaskResult.Failed),
|
||||
(token: new BooleanToken(null, null, null, true), result: TaskResult.Succeeded, expectedResult: TaskResult.Succeeded, expectedOutcome: null),
|
||||
(token: new BooleanToken(null, null, null, true), result: TaskResult.Canceled, expectedResult: TaskResult.Canceled, expectedOutcome: null),
|
||||
(token: new BooleanToken(null, null, null, false), result: TaskResult.Failed, expectedResult: TaskResult.Failed, expectedOutcome: null),
|
||||
(token: new BooleanToken(null, null, null, false), result: TaskResult.Succeeded, expectedResult: TaskResult.Succeeded, expectedOutcome: null),
|
||||
(token: new BooleanToken(null, null, null, false), result: TaskResult.Canceled, expectedResult: TaskResult.Canceled, expectedOutcome: null),
|
||||
})
|
||||
{
|
||||
ec.Result = tc.result;
|
||||
ec.Outcome = null;
|
||||
ec.ApplyContinueOnError(tc.token);
|
||||
Assert.Equal(ec.Result, tc.expectedResult);
|
||||
Assert.Equal(ec.Outcome, tc.expectedOutcome);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
@@ -666,5 +726,149 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void GetExpressionValues_ContainerStepHost()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
const string source = "/home/username/Projects/work/runner/_layout";
|
||||
var containerInfo = new ContainerInfo();
|
||||
containerInfo.ContainerId = "test";
|
||||
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_work", "/__w");
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_temp", "/__t");
|
||||
containerInfo.AddPathTranslateMapping($"{source}/externals", "/__e");
|
||||
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_work/_temp/_github_home", "/github/home");
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_work/_temp/_github_workflow", "/github/workflow");
|
||||
|
||||
foreach (var v in new List<string>() {
|
||||
$"{source}/_work",
|
||||
$"{source}/externals",
|
||||
$"{source}/_work/_temp",
|
||||
$"{source}/_work/_actions",
|
||||
$"{source}/_work/_tool",
|
||||
})
|
||||
{
|
||||
containerInfo.MountVolumes.Add(new MountVolume(v, containerInfo.TranslateToContainerPath(v)));
|
||||
};
|
||||
|
||||
var stepHost = new ContainerStepHost();
|
||||
stepHost.Container = containerInfo;
|
||||
|
||||
var ec = new Runner.Worker.ExecutionContext();
|
||||
ec.Initialize(hc);
|
||||
|
||||
var inputGithubContext = new GitHubContext();
|
||||
var inputeRunnerContext = new RunnerContext();
|
||||
|
||||
// string context data
|
||||
inputGithubContext["action_path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_actions/owner/composite/main");
|
||||
inputGithubContext["action"] = new StringContextData("__owner_composite");
|
||||
inputGithubContext["api_url"] = new StringContextData("https://api.github.com/custom/path");
|
||||
inputGithubContext["env"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_runner_file_commands/set_env_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
inputGithubContext["path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_runner_file_commands/add_path_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
inputGithubContext["event_path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_github_workflow/event.json");
|
||||
inputGithubContext["repository"] = new StringContextData("owner/repo-name");
|
||||
inputGithubContext["run_id"] = new StringContextData("2033211332");
|
||||
inputGithubContext["workflow"] = new StringContextData("Name of Workflow");
|
||||
inputGithubContext["workspace"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/step-order/step-order");
|
||||
inputeRunnerContext["temp"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp");
|
||||
inputeRunnerContext["tool_cache"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_tool");
|
||||
|
||||
// dictionary context data
|
||||
var githubEvent = new DictionaryContextData();
|
||||
githubEvent["inputs"] = null;
|
||||
githubEvent["ref"] = new StringContextData("refs/heads/main");
|
||||
githubEvent["repository"] = new DictionaryContextData();
|
||||
githubEvent["sender"] = new DictionaryContextData();
|
||||
githubEvent["workflow"] = new StringContextData(".github/workflows/composite_step_host_translate.yaml");
|
||||
|
||||
inputGithubContext["event"] = githubEvent;
|
||||
|
||||
ec.ExpressionValues["github"] = inputGithubContext;
|
||||
ec.ExpressionValues["runner"] = inputeRunnerContext;
|
||||
|
||||
var ecExpect = new Runner.Worker.ExecutionContext();
|
||||
ecExpect.Initialize(hc);
|
||||
|
||||
var expectedGithubEvent = new DictionaryContextData();
|
||||
expectedGithubEvent["inputs"] = null;
|
||||
expectedGithubEvent["ref"] = new StringContextData("refs/heads/main");
|
||||
expectedGithubEvent["repository"] = new DictionaryContextData();
|
||||
expectedGithubEvent["sender"] = new DictionaryContextData();
|
||||
expectedGithubEvent["workflow"] = new StringContextData(".github/workflows/composite_step_host_translate.yaml");
|
||||
var expectedGithubContext = new GitHubContext();
|
||||
var expectedRunnerContext = new RunnerContext();
|
||||
expectedGithubContext["action_path"] = new StringContextData("/__w/_actions/owner/composite/main");
|
||||
expectedGithubContext["action"] = new StringContextData("__owner_composite");
|
||||
expectedGithubContext["api_url"] = new StringContextData("https://api.github.com/custom/path");
|
||||
expectedGithubContext["env"] = new StringContextData("/__w/_temp/_runner_file_commands/set_env_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
expectedGithubContext["path"] = new StringContextData("/__w/_temp/_runner_file_commands/add_path_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
expectedGithubContext["event_path"] = new StringContextData("/github/workflow/event.json");
|
||||
expectedGithubContext["repository"] = new StringContextData("owner/repo-name");
|
||||
expectedGithubContext["run_id"] = new StringContextData("2033211332");
|
||||
expectedGithubContext["workflow"] = new StringContextData("Name of Workflow");
|
||||
expectedGithubContext["workspace"] = new StringContextData("/__w/step-order/step-order");
|
||||
expectedGithubContext["event"] = expectedGithubEvent;
|
||||
expectedRunnerContext["temp"] = new StringContextData("/__w/_temp");
|
||||
expectedRunnerContext["tool_cache"] = new StringContextData("/__w/_tool");
|
||||
|
||||
ecExpect.ExpressionValues["github"] = expectedGithubContext;
|
||||
ecExpect.ExpressionValues["runner"] = expectedRunnerContext;
|
||||
|
||||
var translatedExpressionValues = ec.GetExpressionValues(stepHost);
|
||||
|
||||
foreach (var contextName in new string[] { "github", "runner" })
|
||||
{
|
||||
var dict = translatedExpressionValues[contextName].AssertDictionary($"expected context github to be a dictionary");
|
||||
var expectedExpressionValues = ecExpect.ExpressionValues[contextName].AssertDictionary("expect dict");
|
||||
foreach (var key in dict.Keys.ToList())
|
||||
{
|
||||
if (dict[key] is StringContextData)
|
||||
{
|
||||
var expect = dict[key].AssertString("expect string");
|
||||
var outcome = expectedExpressionValues[key].AssertString("expect string");
|
||||
Assert.Equal(expect.Value, outcome.Value);
|
||||
}
|
||||
else if (dict[key] is DictionaryContextData || dict[key] is CaseSensitiveDictionaryContextData)
|
||||
{
|
||||
var expectDict = dict[key].AssertDictionary("expect dict");
|
||||
var actualDict = expectedExpressionValues[key].AssertDictionary("expect dict");
|
||||
Assert.True(ExpressionValuesAssertEqual(expectDict, actualDict));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ExpressionValuesAssertEqual(DictionaryContextData expect, DictionaryContextData actual)
|
||||
{
|
||||
foreach (var key in expect.Keys.ToList())
|
||||
{
|
||||
if (expect[key] is StringContextData)
|
||||
{
|
||||
var expectValue = expect[key].AssertString("expect string");
|
||||
var actualValue = actual[key].AssertString("expect string");
|
||||
if (expectValue.Equals(actualValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (expect[key] is DictionaryContextData || expect[key] is CaseSensitiveDictionaryContextData)
|
||||
{
|
||||
var expectDict = expect[key].AssertDictionary("expect dict");
|
||||
var actualDict = actual[key].AssertDictionary("expect dict");
|
||||
if (!ExpressionValuesAssertEqual(expectDict, actualDict))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
@@ -937,6 +937,19 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void CaptureTelemetryForGitUnsafeRepository()
|
||||
{
|
||||
using (Setup())
|
||||
using (_outputManager)
|
||||
{
|
||||
Process("fatal: unsafe repository ('/github/workspace' is owned by someone else)");
|
||||
Assert.Contains("fatal: unsafe repository ('/github/workspace' is owned by someone else)", _executionContext.Object.StepTelemetry.ErrorMessages);
|
||||
}
|
||||
}
|
||||
|
||||
private TestHostContext Setup(
|
||||
[CallerMemberName] string name = "",
|
||||
IssueMatchersConfig matchers = null,
|
||||
@@ -962,6 +975,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Variables = _variables,
|
||||
WriteDebug = true,
|
||||
});
|
||||
_executionContext.Setup(x => x.StepTelemetry)
|
||||
.Returns(new DTWebApi.ActionsStepTelemetry());
|
||||
_executionContext.Setup(x => x.GetMatchers())
|
||||
.Returns(matchers?.Matchers ?? new List<IssueMatcherConfig>());
|
||||
_executionContext.Setup(x => x.Add(It.IsAny<OnMatcherChanged>()))
|
||||
|
||||
@@ -7,6 +7,9 @@ using Xunit;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using System.Linq;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Common.Tests.Worker
|
||||
{
|
||||
@@ -29,6 +32,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
return hc;
|
||||
}
|
||||
|
||||
#if OS_LINUX
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
@@ -105,5 +109,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Assert.Equal("node16", nodeVersion);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,6 +622,40 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
_stepContext.SetOutcome("", stepContext.Object.ContextName, (stepContext.Object.Outcome ?? stepContext.Object.Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
_stepContext.SetConclusion("", stepContext.Object.ContextName, (stepContext.Object.Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
});
|
||||
|
||||
stepContext.Setup(x => x.UpdateGlobalStepsContext()).Callback(() =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(stepContext.Object.ContextName) && !stepContext.Object.ContextName.StartsWith("__", StringComparison.Ordinal))
|
||||
{
|
||||
stepContext.Object.Global.StepsContext.SetOutcome(stepContext.Object.ScopeName, stepContext.Object.ContextName, (stepContext.Object.Outcome ?? stepContext.Object.Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
stepContext.Object.Global.StepsContext.SetConclusion(stepContext.Object.ScopeName, stepContext.Object.ContextName, (stepContext.Object.Result ?? TaskResult.Succeeded).ToActionResult());
|
||||
}
|
||||
});
|
||||
stepContext.Setup(x => x.ApplyContinueOnError(It.IsAny<TemplateToken>())).Callback((TemplateToken token) =>
|
||||
{
|
||||
if (stepContext.Object.Result != TaskResult.Failed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var continueOnError = false;
|
||||
try
|
||||
{
|
||||
var templateEvaluator = stepContext.Object.ToPipelineTemplateEvaluator();
|
||||
continueOnError = templateEvaluator.EvaluateStepContinueOnError(token, stepContext.Object.ExpressionValues, stepContext.Object.ExpressionFunctions);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
stepContext.Object.Error("The step failed and an error occurred when attempting to determine whether to continue on error.");
|
||||
stepContext.Object.Error(ex);
|
||||
}
|
||||
|
||||
if (continueOnError)
|
||||
{
|
||||
stepContext.Object.Outcome = stepContext.Object.Result;
|
||||
stepContext.Object.Result = TaskResult.Succeeded;
|
||||
}
|
||||
stepContext.Object.UpdateGlobalStepsContext();
|
||||
});
|
||||
var trace = hc.GetTrace();
|
||||
stepContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { trace.Info($"[{tag}]{message}"); });
|
||||
stepContext.Object.Result = result;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603;NU1603;xUnit2013;</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
12
src/dev.sh
12
src/dev.sh
@@ -22,7 +22,7 @@ DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
||||
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
||||
PACKAGE_TRIMS_DIR="$SCRIPT_DIR/../_package_trims"
|
||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||
DOTNETSDK_VERSION="6.0.100"
|
||||
DOTNETSDK_VERSION="6.0.300"
|
||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||
RUNNER_VERSION=$(cat runnerversion)
|
||||
|
||||
@@ -54,6 +54,12 @@ elif [[ "$CURRENT_PLATFORM" == 'linux' ]]; then
|
||||
fi
|
||||
elif [[ "$CURRENT_PLATFORM" == 'darwin' ]]; then
|
||||
RUNTIME_ID='osx-x64'
|
||||
if command -v uname > /dev/null; then
|
||||
CPU_NAME=$(uname -m)
|
||||
case $CPU_NAME in
|
||||
arm64) RUNTIME_ID="osx-arm64";;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$DEV_TARGET_RUNTIME" ]]; then
|
||||
@@ -63,7 +69,7 @@ fi
|
||||
# Make sure current platform support publish the dotnet runtime
|
||||
# Windows can publish win-x86/x64
|
||||
# Linux can publish linux-x64/arm/arm64
|
||||
# OSX can publish osx-x64
|
||||
# OSX can publish osx-x64/arm64
|
||||
if [[ "$CURRENT_PLATFORM" == 'windows' ]]; then
|
||||
if [[ ("$RUNTIME_ID" != 'win-x86') && ("$RUNTIME_ID" != 'win-x64') ]]; then
|
||||
echo "Failed: Can't build $RUNTIME_ID package $CURRENT_PLATFORM" >&2
|
||||
@@ -75,7 +81,7 @@ elif [[ "$CURRENT_PLATFORM" == 'linux' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$CURRENT_PLATFORM" == 'darwin' ]]; then
|
||||
if [[ ("$RUNTIME_ID" != 'osx-x64') ]]; then
|
||||
if [[ ("$RUNTIME_ID" != 'osx-x64') && ("$RUNTIME_ID" != 'osx-arm64') ]]; then
|
||||
echo "Failed: Can't build $RUNTIME_ID package $CURRENT_PLATFORM" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<Target Name="Test" DependsOnTargets="GenerateConstant">
|
||||
<Exec Command="dotnet build Test/Test.csproj -c $(BUILDCONFIG) /p:PackageRuntime=$(PackageRuntime)" ConsoleToMSBuild="true" />
|
||||
<Exec Command="dotnet test Test/Test.csproj --no-build --logger:trx" ConsoleToMSBuild="true" />
|
||||
<Exec Command="dotnet test Test/Test.csproj -c $(BUILDCONFIG) --no-build --logger:trx" ConsoleToMSBuild="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Layout" DependsOnTargets="Clean;Build">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.100"
|
||||
"version": "6.0.300"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.289.3
|
||||
2.292.0
|
||||
|
||||
Reference in New Issue
Block a user