mirror of
https://github.com/actions/runner.git
synced 2025-12-10 12:36:23 +00:00
Compare commits
62 Commits
thboop/con
...
v2.298.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f49f0247c8 | ||
|
|
123a02ce62 | ||
|
|
0232062da2 | ||
|
|
2f7a4649af | ||
|
|
c577be6e62 | ||
|
|
3dd27755cf | ||
|
|
3b8cfdae4e | ||
|
|
4935be5526 | ||
|
|
920fba93dc | ||
|
|
949269104d | ||
|
|
dca4f67143 | ||
|
|
01ff38f975 | ||
|
|
bc67f99bae | ||
|
|
ae2f4a6f27 | ||
|
|
15cbadb4af | ||
|
|
0678e8df09 | ||
|
|
3a1c89715c | ||
|
|
6cdd27263b | ||
|
|
32845a5448 | ||
|
|
6e6410d300 | ||
|
|
ed191b78ae | ||
|
|
75786756bb | ||
|
|
5e0c2ef816 | ||
|
|
95459dea5f | ||
|
|
59894790de | ||
|
|
cba19c4d7e | ||
|
|
01fd04464d | ||
|
|
1cb1779d6b | ||
|
|
42c86665a7 | ||
|
|
f9c2bf1dd7 | ||
|
|
84e7949457 | ||
|
|
694d73d43c | ||
|
|
352f201c62 | ||
|
|
503e50acb9 | ||
|
|
813af29886 | ||
|
|
72e2107b5e | ||
|
|
3567c042ea | ||
|
|
e646b6fec4 | ||
|
|
8d2be3d4fa | ||
|
|
407a347f83 | ||
|
|
7e74f8c9d5 | ||
|
|
efdda93aeb | ||
|
|
1d1998aabb | ||
|
|
d2c6a4e4bc | ||
|
|
d11bd3d8be | ||
|
|
761785620f | ||
|
|
416771d4b1 | ||
|
|
9499f477a2 | ||
|
|
6bc6d475f9 | ||
|
|
ca2b1bc6d5 | ||
|
|
591f8c3510 | ||
|
|
ac7b34a071 | ||
|
|
0d1e6fd57b | ||
|
|
9623a44c2f | ||
|
|
b2e2aa68c8 | ||
|
|
a9ce6b92c4 | ||
|
|
a1bf8401d7 | ||
|
|
a7152f1370 | ||
|
|
af285115e7 | ||
|
|
0431b6fd40 | ||
|
|
c3d5449146 | ||
|
|
9c5300b5b2 |
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@@ -10,7 +10,7 @@ on:
|
|||||||
- '**.md'
|
- '**.md'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- '**'
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64 ]
|
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, win-arm64, osx-x64, osx-arm64 ]
|
||||||
include:
|
include:
|
||||||
- runtime: linux-x64
|
- runtime: linux-x64
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
@@ -44,6 +44,10 @@ jobs:
|
|||||||
os: windows-2019
|
os: windows-2019
|
||||||
devScript: ./dev
|
devScript: ./dev
|
||||||
|
|
||||||
|
- runtime: win-arm64
|
||||||
|
os: windows-latest
|
||||||
|
devScript: ./dev
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -82,7 +86,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
${{ matrix.devScript }} test
|
${{ matrix.devScript }} test
|
||||||
working-directory: src
|
working-directory: src
|
||||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm' && matrix.runtime != 'osx-arm64'
|
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm' && matrix.runtime != 'osx-arm64' && matrix.runtime != 'win-arm64'
|
||||||
|
|
||||||
# Create runner package tar.gz/zip
|
# Create runner package tar.gz/zip
|
||||||
- name: Package Release
|
- name: Package Release
|
||||||
@@ -97,7 +101,7 @@ jobs:
|
|||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: runner-package-${{ matrix.runtime }}
|
name: runner-package-${{ matrix.runtime }}
|
||||||
path: |
|
path: |
|
||||||
_package
|
_package
|
||||||
_package_trims/trim_externals
|
_package_trims/trim_externals
|
||||||
_package_trims/trim_runtime
|
_package_trims/trim_runtime
|
||||||
|
|||||||
77
.github/workflows/release.yml
vendored
77
.github/workflows/release.yml
vendored
@@ -50,29 +50,33 @@ jobs:
|
|||||||
linux-arm64-sha: ${{ steps.sha.outputs.linux-arm64-sha256 }}
|
linux-arm64-sha: ${{ steps.sha.outputs.linux-arm64-sha256 }}
|
||||||
linux-arm-sha: ${{ steps.sha.outputs.linux-arm-sha256 }}
|
linux-arm-sha: ${{ steps.sha.outputs.linux-arm-sha256 }}
|
||||||
win-x64-sha: ${{ steps.sha.outputs.win-x64-sha256 }}
|
win-x64-sha: ${{ steps.sha.outputs.win-x64-sha256 }}
|
||||||
|
win-arm64-sha: ${{ steps.sha.outputs.win-arm64-sha256 }}
|
||||||
osx-x64-sha: ${{ steps.sha.outputs.osx-x64-sha256 }}
|
osx-x64-sha: ${{ steps.sha.outputs.osx-x64-sha256 }}
|
||||||
osx-arm64-sha: ${{ steps.sha.outputs.osx-arm64-sha256 }}
|
osx-arm64-sha: ${{ steps.sha.outputs.osx-arm64-sha256 }}
|
||||||
linux-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-x64-sha256 }}
|
linux-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-x64-sha256 }}
|
||||||
linux-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm64-sha256 }}
|
linux-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm64-sha256 }}
|
||||||
linux-arm-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm-sha256 }}
|
linux-arm-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm-sha256 }}
|
||||||
win-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.win-x64-sha256 }}
|
win-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.win-x64-sha256 }}
|
||||||
|
win-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.win-arm64-sha256 }}
|
||||||
osx-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-x64-sha256 }}
|
osx-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-x64-sha256 }}
|
||||||
osx-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-arm64-sha256 }}
|
osx-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-arm64-sha256 }}
|
||||||
linux-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-x64-sha256 }}
|
linux-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-x64-sha256 }}
|
||||||
linux-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm64-sha256 }}
|
linux-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm64-sha256 }}
|
||||||
linux-arm-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm-sha256 }}
|
linux-arm-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm-sha256 }}
|
||||||
win-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.win-x64-sha256 }}
|
win-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.win-x64-sha256 }}
|
||||||
|
win-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.win-arm64-sha256 }}
|
||||||
osx-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-x64-sha256 }}
|
osx-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-x64-sha256 }}
|
||||||
osx-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-arm64-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-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-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 }}
|
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 }}
|
win-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.win-x64-sha256 }}
|
||||||
|
win-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.win-arm64-sha256 }}
|
||||||
osx-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-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 }}
|
osx-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-arm64-sha256 }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64 ]
|
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64, win-arm64 ]
|
||||||
include:
|
include:
|
||||||
- runtime: linux-x64
|
- runtime: linux-x64
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
@@ -89,7 +93,7 @@ jobs:
|
|||||||
- runtime: osx-x64
|
- runtime: osx-x64
|
||||||
os: macOS-latest
|
os: macOS-latest
|
||||||
devScript: ./dev.sh
|
devScript: ./dev.sh
|
||||||
|
|
||||||
- runtime: osx-arm64
|
- runtime: osx-arm64
|
||||||
os: macOS-latest
|
os: macOS-latest
|
||||||
devScript: ./dev.sh
|
devScript: ./dev.sh
|
||||||
@@ -98,6 +102,10 @@ jobs:
|
|||||||
os: windows-2019
|
os: windows-2019
|
||||||
devScript: ./dev
|
devScript: ./dev
|
||||||
|
|
||||||
|
- runtime: win-arm64
|
||||||
|
os: windows-latest
|
||||||
|
devScript: ./dev
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -158,9 +166,9 @@ jobs:
|
|||||||
id: sha_noruntime_noexternals
|
id: sha_noruntime_noexternals
|
||||||
name: Compute SHA256
|
name: Compute SHA256
|
||||||
working-directory: _package_trims/trim_runtime_externals
|
working-directory: _package_trims/trim_runtime_externals
|
||||||
|
|
||||||
- name: Create trimmedpackages.json for ${{ matrix.runtime }}
|
- name: Create trimmedpackages.json for ${{ matrix.runtime }}
|
||||||
if: matrix.runtime == 'win-x64'
|
if: matrix.runtime == 'win-x64' || matrix.runtime == 'win-arm64'
|
||||||
uses: actions/github-script@0.3.0
|
uses: actions/github-script@0.3.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
@@ -180,7 +188,7 @@ jobs:
|
|||||||
fs.writeFileSync('${{ matrix.runtime }}-trimmedpackages.json', trimmedPackages)
|
fs.writeFileSync('${{ matrix.runtime }}-trimmedpackages.json', trimmedPackages)
|
||||||
|
|
||||||
- name: Create trimmedpackages.json for ${{ matrix.runtime }}
|
- name: Create trimmedpackages.json for ${{ matrix.runtime }}
|
||||||
if: matrix.runtime != 'win-x64'
|
if: matrix.runtime != 'win-x64' && matrix.runtime != 'win-arm64'
|
||||||
uses: actions/github-script@0.3.0
|
uses: actions/github-script@0.3.0
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
@@ -239,24 +247,28 @@ jobs:
|
|||||||
const runnerVersion = fs.readFileSync('${{ github.workspace }}/src/runnerversion', 'utf8').replace(/\n$/g, '')
|
const runnerVersion = fs.readFileSync('${{ github.workspace }}/src/runnerversion', 'utf8').replace(/\n$/g, '')
|
||||||
var releaseNote = fs.readFileSync('${{ github.workspace }}/releaseNote.md', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion)
|
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(/<WIN_X64_SHA>/g, '${{needs.build.outputs.win-x64-sha}}')
|
||||||
|
releaseNote = releaseNote.replace(/<WIN_ARM64_SHA>/g, '${{needs.build.outputs.win-arm64-sha}}')
|
||||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA>/g, '${{needs.build.outputs.osx-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(/<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_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_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(/<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(/<WIN_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<WIN_ARM64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.win-arm64-sha-noexternals}}')
|
||||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.osx-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(/<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_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_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(/<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(/<WIN_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.win-x64-sha-noruntime}}')
|
||||||
|
releaseNote = releaseNote.replace(/<WIN_ARM64_SHA_NORUNTIME>/g, '${{needs.build.outputs.win-arm64-sha-noruntime}}')
|
||||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.osx-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(/<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_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_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(/<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(/<WIN_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noruntime-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<WIN_ARM64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.win-arm64-sha-noruntime-noexternals}}')
|
||||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.osx-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(/<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_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-x64-sha-noruntime-noexternals}}')
|
||||||
@@ -271,6 +283,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
ls -l
|
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.win-x64-sha}} actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip" | shasum -a 256 -c
|
||||||
|
echo "${{needs.build.outputs.win-arm64-sha}} actions-runner-win-arm64-${{ 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-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.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-x64-sha}} actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||||
@@ -300,6 +313,16 @@ jobs:
|
|||||||
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip
|
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (win-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-win-arm64-${{ steps.releaseNote.outputs.version }}.zip
|
||||||
|
asset_name: actions-runner-win-arm64-${{ steps.releaseNote.outputs.version }}.zip
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
- name: Upload Release Asset (linux-x64)
|
- name: Upload Release Asset (linux-x64)
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
env:
|
env:
|
||||||
@@ -361,6 +384,17 @@ jobs:
|
|||||||
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-noexternals.zip
|
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-noexternals.zip
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trim externals)
|
||||||
|
- name: Upload Release Asset (win-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-win-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.zip
|
||||||
|
asset_name: actions-runner-win-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.zip
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
- name: Upload Release Asset (linux-x64-noexternals)
|
- name: Upload Release Asset (linux-x64-noexternals)
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
env:
|
env:
|
||||||
@@ -422,6 +456,17 @@ jobs:
|
|||||||
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-noruntime.zip
|
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-noruntime.zip
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trim runtime)
|
||||||
|
- name: Upload Release Asset (win-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-win-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.zip
|
||||||
|
asset_name: actions-runner-win-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.zip
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
- name: Upload Release Asset (linux-x64-noruntime)
|
- name: Upload Release Asset (linux-x64-noruntime)
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
env:
|
env:
|
||||||
@@ -483,6 +528,17 @@ jobs:
|
|||||||
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.zip
|
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.zip
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trim runtime and externals)
|
||||||
|
- name: Upload Release Asset (win-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-win-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.zip
|
||||||
|
asset_name: actions-runner-win-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.zip
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
- name: Upload Release Asset (linux-x64-noruntime-noexternals)
|
- name: Upload Release Asset (linux-x64-noruntime-noexternals)
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
env:
|
env:
|
||||||
@@ -544,6 +600,17 @@ jobs:
|
|||||||
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trimmedpackages.json)
|
||||||
|
- name: Upload Release Asset (win-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 }}/win-arm64-trimmedpackages.json
|
||||||
|
asset_name: actions-runner-win-arm64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
- name: Upload Release Asset (linux-x64-trimmedpackages.json)
|
- name: Upload Release Asset (linux-x64-trimmedpackages.json)
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
env:
|
env:
|
||||||
|
|||||||
596
docs/adrs/1891-container-hooks.md
Normal file
596
docs/adrs/1891-container-hooks.md
Normal file
@@ -0,0 +1,596 @@
|
|||||||
|
# ADR 0000: Container Hooks
|
||||||
|
|
||||||
|
**Date**: 2022-05-12
|
||||||
|
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
# Background
|
||||||
|
|
||||||
|
[Job Hooks](https://github.com/actions/runner/blob/main/docs/adrs/1751-runner-job-hooks.md) have given users the ability to customize how their self hosted runners run a job.
|
||||||
|
Users also want the ability to customize how they run containers during the scope of the job, rather then being locked into the docker implementation we have in the runner. They may want to use podman, kubernetes, or even change the docker commands we run.
|
||||||
|
We should give them that option, and publish examples how how they can create their own hooks.
|
||||||
|
|
||||||
|
# Guiding Principles
|
||||||
|
- **Extensibility** is the focus, we need to make sure we are flexible enough to cover current and future scenarios, even at the cost of making it harder to utilize these hooks
|
||||||
|
- Args should map **directly** to yaml values provided by the user.
|
||||||
|
- For example, the current runner overrides `HOME`, we can do that in the hook, but we shouldn't pass that hook as an ENV with the other env's the user has set, as that is not user input, it is how the runner invokes containers
|
||||||
|
|
||||||
|
## Interface
|
||||||
|
- You will set the variable `ACTIONS_RUNNER_CONTAINER_HOOKS=/Users/foo/runner/hooks.js` which is the entrypoint to your hook handler.
|
||||||
|
- There is no partial opt in, you must handle every hook
|
||||||
|
- We will pass a command and some args via `stdin`
|
||||||
|
- An exit code of 0 is a success, every other exit code is a failure
|
||||||
|
- We will support the same runner commands we support in [Job Hooks](https://github.com/actions/runner/blob/main/docs/adrs/1751-runner-job-hooks.md)
|
||||||
|
- On timeout, we will send a sigint to your process. If you fail to terminate within a reasonable amount of time, we will send a sigkill, and eventually kill the process tree.
|
||||||
|
|
||||||
|
An example input looks like
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "job_cleanup",
|
||||||
|
"responseFile": "/users/thboop/runner/_work/{guid}.json",
|
||||||
|
"args": {},
|
||||||
|
"state":
|
||||||
|
{
|
||||||
|
"id": "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`command` is the command we expect you to invoke
|
||||||
|
`responseFile` is the file you need to write your output to, if the command has output
|
||||||
|
`args` are the specific arguments the command needs
|
||||||
|
`state` is a json blog you can pass around to maintain your state, this is covered in more details below.
|
||||||
|
|
||||||
|
### Writing responses to a file
|
||||||
|
All text written to stdout or stderr should appear in the job or step logs. With that in mind, we support a few ways to actually return data:
|
||||||
|
1. Wrapping the json in some unique tag and processing it like we do commands
|
||||||
|
2. Writing to a file
|
||||||
|
|
||||||
|
For 1, users typically view logging information as a safe action, so we worry someone accidentialy logging unsantized information and causing unexpected or un-secure behavior. We eventually plan to move off of stdout/stderr style commands in favor of a runner cli.
|
||||||
|
Investing in this area doesn't make a lot of sense at this time.
|
||||||
|
|
||||||
|
While writing to a file to communicate isn't the most ideal pattern, its an existing pattern in the runner and serves us well, so lets reuse it.
|
||||||
|
|
||||||
|
### Output
|
||||||
|
Your output must be correctly formatted json. An example output looks like:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"state": {},
|
||||||
|
"context"
|
||||||
|
{
|
||||||
|
"container" :
|
||||||
|
{
|
||||||
|
"id": "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480"
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c"
|
||||||
|
}
|
||||||
|
"services": {
|
||||||
|
"redis": {
|
||||||
|
"id": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105",
|
||||||
|
"ports": {
|
||||||
|
"8080": "8080"
|
||||||
|
},
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"alpine: true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`state` is a unique field any command can return. If it is not empty, we will store the state for you and pass it into all future commands. You can overwrite it by having the next hook invoked return a unique state.
|
||||||
|
|
||||||
|
Other fields are dependent upon the command being run.
|
||||||
|
|
||||||
|
### Versioning
|
||||||
|
We will not version these hooks at launch. If needed, we can always major version split these hooks in the future. We will ship in Beta to allow for breaking changes for a few months.
|
||||||
|
|
||||||
|
### The Job Context
|
||||||
|
The [job context](https://docs.github.com/en/actions/learn-github-actions/contexts#example-contents-of-the-job-context) currently has a variety of fields that correspond to containers. We should consider allowing hooks to populate new fields in the job context. That is out of scope for this original release however.
|
||||||
|
|
||||||
|
## Hooks
|
||||||
|
Hooks are to be implemented at a very high level, and map to actions the runner does, rather then specific docker actions like `docker build` or `docker create`. By mapping to runner actions, we create a very extensible framework that is flexible enough to solve any user concerns in the future. By providing first party implementations, we give users easy starting points to customize specific hooks (like `docker build`) without having to write full blown solutions.
|
||||||
|
|
||||||
|
The other would be to provide hooks that mirror every docker call we make, and expose more hooks to help support k8s users, with the expectation that users may have to no-op on multiple hooks if they don't correspond to our use case.
|
||||||
|
|
||||||
|
Why we don't want to go that way
|
||||||
|
- It feels clunky, users need to understand which hooks they need to implement and which they can ignore, which isn't a great UX
|
||||||
|
- It doesn't scale well, I don't want to build a solution where we may need to add more hooks, by mapping to runner actions, updating hooks is a painful experience for users
|
||||||
|
- Its overwhelming, its easier to tell users to build 4 hooks and track data themselves, rather then 16 hooks where the runner needs certain information and then needs to provide that information back into each hook. If we expose `Container Create`, you need to return the container you created, then we do `container run` which uses that container. If we just give you an image and say create and run this container, you don't need to store the container id in the runner, and it maps better to k8s scenarios where we don't really have container ids.
|
||||||
|
|
||||||
|
### Prepare_job hook
|
||||||
|
The `prepare_job` hook is called when a job is started. We pass in any job or service containers the job has. We expect that you:
|
||||||
|
- Prune anything from previous jobs if needed
|
||||||
|
- Create a network if needed
|
||||||
|
- Pull the job and service containers
|
||||||
|
- Start the job container
|
||||||
|
- Start the service containers
|
||||||
|
- Write to the response file some information we need
|
||||||
|
- Required: if the container is alpine, otherwise x64
|
||||||
|
- Optional: any context fields you want to set on the job context, otherwise they will be unavailable for users to use
|
||||||
|
- Return 0 when the health checks have succeeded and the job/service containers are started
|
||||||
|
|
||||||
|
This hook will **always** be called if you have container hooks enabled, even if no service or job containers exist in the job. This allows you to fail the job or implement a default job container if you want to and no job container has been provided.
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example Input</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"command": "prepare_job",
|
||||||
|
"responseFile": "/users/thboop/runner/_work/{guid}.json",
|
||||||
|
"state": {},
|
||||||
|
"args":
|
||||||
|
{
|
||||||
|
"jobContainer": {
|
||||||
|
"image": "node:14.16",
|
||||||
|
"workingDirectory": "/__w/thboop-test2/thboop-test2",
|
||||||
|
"createOptions": "--cpus 1",
|
||||||
|
"environmentVariables": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"userMountVolumes:[
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "my_docker_volume",
|
||||||
|
"targetVolumePath": "/volume_mount",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"mountVolumes": [
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work",
|
||||||
|
"targetVolumePath": "/__w",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/externals",
|
||||||
|
"targetVolumePath": "/__e",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp",
|
||||||
|
"targetVolumePath": "/__w/_temp",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_actions",
|
||||||
|
"targetVolumePath": "/__w/_actions",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_tool",
|
||||||
|
"targetVolumePath": "/__w/_tool",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp/_github_home",
|
||||||
|
"targetVolumePath": "/github/home",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp/_github_workflow",
|
||||||
|
"targetVolumePath": "/github/workflow",
|
||||||
|
"readOnly": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registry": {
|
||||||
|
"username": "foo",
|
||||||
|
"password": "bar",
|
||||||
|
"serverUrl": "https://index.docker.io/v1"
|
||||||
|
},
|
||||||
|
"portMappings": [ "8080:80/tcp", "8080:80/udp" ]
|
||||||
|
},
|
||||||
|
"services": [
|
||||||
|
{
|
||||||
|
"contextName": "redis",
|
||||||
|
"image": "redis",
|
||||||
|
"createOptions": "--cpus 1",
|
||||||
|
"environmentVariables": {},
|
||||||
|
"mountVolumes": [],
|
||||||
|
"portMappings": [ "8080:80/tcp", "8080:80/udp" ]
|
||||||
|
"registry": {
|
||||||
|
"username": "foo",
|
||||||
|
"password": "bar",
|
||||||
|
"serverUrl": "https://index.docker.io/v1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Field Descriptions</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
Arg Fields:
|
||||||
|
|
||||||
|
jobContainer: **Optional** An Object containing information about the specified job container
|
||||||
|
"image": **Required** A string containing the docker image
|
||||||
|
"workingDirectory": **Required** A string containing the absolute path of the working directory
|
||||||
|
"createOptions": **Optional** The optional create options specified in the [YAML](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container#example-running-a-job-within-a-container)
|
||||||
|
"environmentVariables": **Optional** A map of key value env's to set
|
||||||
|
"userMountVolumes: ** Optional** an array of user mount volumes set in the [YAML](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container#example-running-a-job-within-a-container)
|
||||||
|
"sourceVolumePath": **Required** The source path to the volume to be mounted into the docker container
|
||||||
|
"targetVolumePath": **Required** The target path to the volume to be mounted into the docker container
|
||||||
|
"readOnly": false **Required** whether or not the mount should be read only
|
||||||
|
"mountVolumes": **Required** an array of mounts to mount into the container, same fields as above
|
||||||
|
"sourceVolumePath": **Required** The source path to the volume to be mounted into the docker container
|
||||||
|
"targetVolumePath": **Required** The target path to the volume to be mounted into the docker container
|
||||||
|
"readOnly": false **Required** whether or not the mount should be read only
|
||||||
|
"registry" **Optional** docker registry credentials to use when using a private container registry
|
||||||
|
"username": **Optional** the username
|
||||||
|
"password": **Optional** the password
|
||||||
|
"serverUrl": **Optional** the registry url
|
||||||
|
"portMappings": **Optional** an array of source:target ports to map into the container
|
||||||
|
|
||||||
|
"services": an array of service containers to spin up
|
||||||
|
"contextName": **Required** the name of the service in the Job context
|
||||||
|
"image": **Required** A string containing the docker image
|
||||||
|
"createOptions": **Optional** The optional create options specified in the [YAML](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container#example-running-a-job-within-a-container)
|
||||||
|
"environmentVariables": **Optional** A map of key value env's to set
|
||||||
|
"mountVolumes": **Required** an array of mounts to mount into the container, same fields as above
|
||||||
|
"sourceVolumePath": **Required** The source path to the volume to be mounted into the docker container
|
||||||
|
"targetVolumePath": **Required** The target path to the volume to be mounted into the docker container
|
||||||
|
"readOnly": false **Required** whether or not the mount should be read only
|
||||||
|
"registry" **Optional** docker registry credentials to use when using a private container registry
|
||||||
|
"username": **Optional** the username
|
||||||
|
"password": **Optional** the password
|
||||||
|
"serverUrl": **Optional** the registry url
|
||||||
|
"portMappings": **Optional** an array of source:target ports to map into the container
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example Output</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"state":
|
||||||
|
{
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c",
|
||||||
|
"jobContainer" : "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480",
|
||||||
|
"serviceContainers":
|
||||||
|
{
|
||||||
|
"redis": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"context"
|
||||||
|
{
|
||||||
|
"container" :
|
||||||
|
{
|
||||||
|
"id": "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480"
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c"
|
||||||
|
}
|
||||||
|
"services": {
|
||||||
|
"redis": {
|
||||||
|
"id": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105",
|
||||||
|
"ports": {
|
||||||
|
"8080": "8080"
|
||||||
|
},
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"alpine: true,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
### Cleanup Job
|
||||||
|
The `cleanup_job` hook is called at the end of a job and expects you to:
|
||||||
|
- Stop any running service or job containers (or the equiavalent pod)
|
||||||
|
- Stop the network (if one exists)
|
||||||
|
- Delete any job or service containers (or the equiavalent pod)
|
||||||
|
- Delete the network (if one exists)
|
||||||
|
- Cleanup anything else that was created for the run
|
||||||
|
|
||||||
|
Its input looks like
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example Input</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
"command": "cleanup_job",
|
||||||
|
"responseFile": null,
|
||||||
|
"state":
|
||||||
|
{
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c",
|
||||||
|
"jobContainer" : "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480",
|
||||||
|
"serviceContainers":
|
||||||
|
{
|
||||||
|
"redis": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"args": {}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
No args are provided.
|
||||||
|
|
||||||
|
No output is expected.
|
||||||
|
|
||||||
|
|
||||||
|
### Run Container Step
|
||||||
|
The `run_container_step` is called once per container action in your job and expects you to:
|
||||||
|
- Pull or build the required container (or fail if you cannot)
|
||||||
|
- Run the container action and return the exit code of the container
|
||||||
|
- Stream any step logs output to stdout and stderr
|
||||||
|
- Cleanup the container after it executes
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example Input for Image</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
"command": "run_container_step",
|
||||||
|
"responseFile": null,
|
||||||
|
"state":
|
||||||
|
{
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c",
|
||||||
|
"jobContainer" : "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480",
|
||||||
|
"serviceContainers":
|
||||||
|
{
|
||||||
|
"redis": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"args":
|
||||||
|
{
|
||||||
|
"image": "node:14.16",
|
||||||
|
"dockerfile": null,
|
||||||
|
"entryPointArgs": ["-f", "/dev/null"],
|
||||||
|
"entryPoint": "tail",
|
||||||
|
"workingDirectory": "/__w/thboop-test2/thboop-test2",
|
||||||
|
"createOptions": "--cpus 1",
|
||||||
|
"environmentVariables": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"prependPath":["/foo/bar", "bar/foo"]
|
||||||
|
"userMountVolumes:[
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "my_docker_volume",
|
||||||
|
"targetVolumePath": "/volume_mount",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"mountVolumes": [
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work",
|
||||||
|
"targetVolumePath": "/__w",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/externals",
|
||||||
|
"targetVolumePath": "/__e",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp",
|
||||||
|
"targetVolumePath": "/__w/_temp",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_actions",
|
||||||
|
"targetVolumePath": "/__w/_actions",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_tool",
|
||||||
|
"targetVolumePath": "/__w/_tool",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp/_github_home",
|
||||||
|
"targetVolumePath": "/github/home",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp/_github_workflow",
|
||||||
|
"targetVolumePath": "/github/workflow",
|
||||||
|
"readOnly": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registry": null,
|
||||||
|
"portMappings": { "80": "801" }
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example Input for dockerfile</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
"command": "run_container_step",
|
||||||
|
"responseFile": null,
|
||||||
|
"state":
|
||||||
|
{
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c",
|
||||||
|
"jobContainer" : "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480",
|
||||||
|
"services":
|
||||||
|
{
|
||||||
|
"redis": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"args":
|
||||||
|
{
|
||||||
|
"image": null,
|
||||||
|
"dockerfile": /__w/_actions/foo/dockerfile,
|
||||||
|
"entryPointArgs": ["hello world"],
|
||||||
|
"entryPoint": "echo",
|
||||||
|
"workingDirectory": "/__w/thboop-test2/thboop-test2",
|
||||||
|
"createOptions": "--cpus 1",
|
||||||
|
"environmentVariables": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"prependPath":["/foo/bar", "bar/foo"]
|
||||||
|
"userMountVolumes:[
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "my_docker_volume",
|
||||||
|
"targetVolumePath": "/volume_mount",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"mountVolumes": [
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "my_docker_volume",
|
||||||
|
"targetVolumePath": "/volume_mount",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work",
|
||||||
|
"targetVolumePath": "/__w",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/externals",
|
||||||
|
"targetVolumePath": "/__e",
|
||||||
|
"readOnly": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp",
|
||||||
|
"targetVolumePath": "/__w/_temp",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_actions",
|
||||||
|
"targetVolumePath": "/__w/_actions",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_tool",
|
||||||
|
"targetVolumePath": "/__w/_tool",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp/_github_home",
|
||||||
|
"targetVolumePath": "/github/home",
|
||||||
|
"readOnly": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"sourceVolumePath": "/home/thomas/git/runner/_layout/_work/_temp/_github_workflow",
|
||||||
|
"targetVolumePath": "/github/workflow",
|
||||||
|
"readOnly": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"registry": null,
|
||||||
|
"portMappings": [ "8080:80/tcp", "8080:80/udp" ]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Field Descriptions</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
Arg Fields:
|
||||||
|
|
||||||
|
|
||||||
|
"image": **Optional** A string containing the docker image. Otherwise a dockerfile must be provided
|
||||||
|
"dockerfile": **Optional** A string containing the path to the dockerfile, otherwise an image must be provided
|
||||||
|
"entryPointArgs": **Optional** A list containing the entry point args
|
||||||
|
"entryPoint": **Optional** The container entry point to use if the default image entrypoint should be overwritten
|
||||||
|
"workingDirectory": **Required** A string containing the absolute path of the working directory
|
||||||
|
"createOptions": **Optional** The optional create options specified in the [YAML](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container#example-running-a-job-within-a-container)
|
||||||
|
"environmentVariables": **Optional** A map of key value env's to set
|
||||||
|
"prependPath": **Optional** an array of additional paths to prepend to the $PATH variable
|
||||||
|
"userMountVolumes: ** Optional** an array of user mount volumes set in the [YAML](https://docs.github.com/en/actions/using-jobs/running-jobs-in-a-container#example-running-a-job-within-a-container)
|
||||||
|
"sourceVolumePath": **Required** The source path to the volume to be mounted into the docker container
|
||||||
|
"targetVolumePath": **Required** The target path to the volume to be mounted into the docker container
|
||||||
|
"readOnly": false **Required** whether or not the mount should be read only
|
||||||
|
"mountVolumes": **Required** an array of mounts to mount into the container, same fields as above
|
||||||
|
"sourceVolumePath": **Required** The source path to the volume to be mounted into the docker container
|
||||||
|
"targetVolumePath": **Required** The target path to the volume to be mounted into the docker container
|
||||||
|
"readOnly": false **Required** whether or not the mount should be read only
|
||||||
|
"registry" **Optional** docker registry credentials to use when using a private container registry
|
||||||
|
"username": **Optional** the username
|
||||||
|
"password": **Optional** the password
|
||||||
|
"serverUrl": **Optional** the registry url
|
||||||
|
"portMappings": **Optional** an array of source:target ports to map into the container
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
No output is expected
|
||||||
|
|
||||||
|
Currently we build all container actions at the start of the job. By doing it during the hook, we move this to just in time building for hooks. We could expose a hook to build/pull a container action, and have those called at the start of a job, but doing so would require hook authors to track the build containers in the state, which could be painful.
|
||||||
|
|
||||||
|
### Run Script Step
|
||||||
|
The `run_script_step` expects you to:
|
||||||
|
- Invoke the provided script inside the job container and return the exit code
|
||||||
|
- Stream any step log output to stdout and stderr
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Example Input</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
"command": "run_script_step",
|
||||||
|
"responseFile": null,
|
||||||
|
"state":
|
||||||
|
{
|
||||||
|
"network": "github_network_53269bd575974817b43f4733536b200c",
|
||||||
|
"jobContainer" : "82e8219701fe096a35941d869cf8d71af1d943b5d3bdd718850fb87ac3042480",
|
||||||
|
"serviceContainers":
|
||||||
|
{
|
||||||
|
"redis": "60972d9aa486605e66b0dad4abb638dc3d9116f566579e418166eedb8abb9105"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"args":
|
||||||
|
{
|
||||||
|
"entryPointArgs": ["-e", "/runner/temp/abc123.sh"],
|
||||||
|
"entryPoint": "bash",
|
||||||
|
"environmentVariables": {
|
||||||
|
"NODE_ENV": "development"
|
||||||
|
},
|
||||||
|
"prependPath": ["/foo/bar", "bar/foo"],
|
||||||
|
"workingDirectory": "/__w/thboop-test2/thboop-test2"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>Field Descriptions</summary>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
```
|
||||||
|
Arg Fields:
|
||||||
|
|
||||||
|
|
||||||
|
"entryPointArgs": **Optional** A list containing the entry point args
|
||||||
|
"entryPoint": **Optional** The container entry point to use if the default image entrypoint should be overwritten
|
||||||
|
"prependPath": **Optional** an array of additional paths to prepend to the $PATH variable
|
||||||
|
"workingDirectory": **Required** A string containing the absolute path of the working directory
|
||||||
|
"environmentVariables": **Optional** A map of key value env's to set
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
No output is expected
|
||||||
|
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
- We will only support linux on launch
|
||||||
|
- Hooks are set by the runner admin, and thus are only supported on self hosted runners
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
- We support non docker scenarios for self hosted runners and allow customers to customize their docker invocations
|
||||||
|
- We ship/maintain docs on docker hooks and an open source repo with examples
|
||||||
|
- We support these hooks and add enough telemetry to be able to troubleshoot support issues as they come in.
|
||||||
@@ -15,7 +15,7 @@ Make sure the runner has access to actions service for GitHub.com or GitHub Ente
|
|||||||
```
|
```
|
||||||
curl -v https://api.github.com/api/v3/zen
|
curl -v https://api.github.com/api/v3/zen
|
||||||
curl -v https://vstoken.actions.githubusercontent.com/_apis/health
|
curl -v https://vstoken.actions.githubusercontent.com/_apis/health
|
||||||
curl -v https://pipelines.actions.githubusercontent/_apis/health
|
curl -v https://pipelines.actions.githubusercontent.com/_apis/health
|
||||||
```
|
```
|
||||||
|
|
||||||
- For GitHub Enterprise Server
|
- For GitHub Enterprise Server
|
||||||
|
|||||||
@@ -20,11 +20,30 @@ The test also set environment variable `GIT_TRACE=1` and `GIT_CURL_VERBOSE=1` be
|
|||||||
|
|
||||||
## How to fix the issue?
|
## How to fix the issue?
|
||||||
|
|
||||||
### 1. Check the common network issue
|
### 1. Check global and system git config
|
||||||
|
|
||||||
|
If you are having issues connecting to the server, check your global and system git config for any unexpected authentication headers. You might be seeing an error like:
|
||||||
|
|
||||||
|
```
|
||||||
|
fatal: unable to access 'https://github.com/actions/checkout/': The requested URL returned error: 400
|
||||||
|
```
|
||||||
|
|
||||||
|
The following commands can be used to check for unexpected authentication headers:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git config --global --list | grep extraheader
|
||||||
|
http.extraheader=AUTHORIZATION: unexpected_auth_header
|
||||||
|
|
||||||
|
$ git config --system --list | grep extraheader
|
||||||
|
```
|
||||||
|
|
||||||
|
The following command can be used to remove the above value: `git config --global --unset http.extraheader`
|
||||||
|
|
||||||
|
### 2. Check the common network issue
|
||||||
|
|
||||||
> Please check the [network doc](./network.md)
|
> Please check the [network doc](./network.md)
|
||||||
|
|
||||||
### 2. SSL certificate related issue
|
### 3. SSL certificate related issue
|
||||||
|
|
||||||
If you are seeing `SSL Certificate problem:` in the log, it means the `git` can't connect to the GitHub server due to SSL handshake failure.
|
If you are seeing `SSL Certificate problem:` in the log, it means the `git` can't connect to the GitHub server due to SSL handshake failure.
|
||||||
> Please check the [SSL cert doc](./sslcert.md)
|
> Please check the [SSL cert doc](./sslcert.md)
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ An ADR is an Architectural Decision Record. This allows consensus on the direct
|
|||||||
|
|
||||||
 Visual Studio 2017 or newer [Install here](https://visualstudio.microsoft.com) (needed for dev sh script)
|
 Visual Studio 2017 or newer [Install here](https://visualstudio.microsoft.com) (needed for dev sh script)
|
||||||
|
|
||||||
|
 Visual Studio 2022 17.3 Preview or later. [Install here](https://docs.microsoft.com/en-us/visualstudio/releases/2022/release-notes-preview)
|
||||||
|
|
||||||
## Quickstart: Run a job from a real repository
|
## Quickstart: Run a job from a real repository
|
||||||
|
|
||||||
If you just want to get from building the sourcecode to using it to execute an action, you will need:
|
If you just want to get from building the sourcecode to using it to execute an action, you will need:
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ The `installdependencies.sh` script should install all required dependencies on
|
|||||||
|
|
||||||
Debian based OS (Debian, Ubuntu, Linux Mint)
|
Debian based OS (Debian, Ubuntu, Linux Mint)
|
||||||
|
|
||||||
- liblttng-ust0
|
- liblttng-ust1 or liblttng-ust0
|
||||||
- libkrb5-3
|
- libkrb5-3
|
||||||
- zlib1g
|
- zlib1g
|
||||||
- libssl1.1, libssl1.0.2 or libssl1.0.0
|
- libssl1.1, libssl1.0.2 or libssl1.0.0
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
## Features
|
## Features
|
||||||
- Added a pre-release package for the `macOS-arm64` architecture
|
- [REVERTED] Service containers startup error logs are now included in workflow's logs (#2110)
|
||||||
- Note that this packages is pre-release status and may not work with all existing actions
|
- Reverted due to https://github.com/actions/runner/issues/2173
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Fixed an issue where live console logs would fail to close (#1903)
|
- Fixed missing SHA for Windows arm64 release archive (#2171)
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
|
- Added a feature flag to start warning on `save-state` and `set-output` deprecation (#2164)
|
||||||
|
- Prepare supporting `vars` in workflow templates (#2096)
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
@@ -21,6 +23,22 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
|||||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
|
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## [Pre-release] Windows arm64
|
||||||
|
**Warning:** Windows arm64 runners are currently in preview status and use [unofficial versions of nodejs](https://unofficial-builds.nodejs.org/). They are not intended for production workflows.
|
||||||
|
|
||||||
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|
||||||
|
The following snipped needs to be run on `powershell`:
|
||||||
|
``` powershell
|
||||||
|
# Create a folder under the drive root
|
||||||
|
mkdir \actions-runner ; cd \actions-runner
|
||||||
|
# Download the latest runner package
|
||||||
|
Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-win-arm64-<RUNNER_VERSION>.zip -OutFile actions-runner-win-arm64-<RUNNER_VERSION>.zip
|
||||||
|
# Extract the installer
|
||||||
|
Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
||||||
|
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-arm64-<RUNNER_VERSION>.zip", "$PWD")
|
||||||
|
```
|
||||||
|
|
||||||
## OSX x64
|
## OSX x64
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
@@ -32,7 +50,7 @@ curl -O -L https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>
|
|||||||
tar xzf ./actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz
|
tar xzf ./actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
## [Pre-release] OSX arm64 (Apple silicon)
|
## OSX arm64 (Apple silicon)
|
||||||
|
|
||||||
``` bash
|
``` bash
|
||||||
# Create a folder
|
# Create a folder
|
||||||
@@ -84,6 +102,7 @@ For additional details about configuring, running, or shutting down the runner p
|
|||||||
The SHA-256 checksums for the packages included in this build are shown below:
|
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-win-x64-<RUNNER_VERSION>.zip <!-- BEGIN SHA win-x64 --><WIN_X64_SHA><!-- END SHA win-x64 -->
|
||||||
|
- actions-runner-win-arm64-<RUNNER_VERSION>.zip <!-- BEGIN SHA win-arm64 --><WIN_ARM64_SHA><!-- END SHA win-arm64 -->
|
||||||
- actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA osx-x64 --><OSX_X64_SHA><!-- END SHA osx-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-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-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-x64 --><LINUX_X64_SHA><!-- END SHA linux-x64 -->
|
||||||
@@ -91,6 +110,7 @@ The SHA-256 checksums for the packages included in this build are shown below:
|
|||||||
- actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm --><LINUX_ARM_SHA><!-- END SHA linux-arm -->
|
- 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-win-x64-<RUNNER_VERSION>-noexternals.zip <!-- BEGIN SHA win-x64_noexternals --><WIN_X64_SHA_NOEXTERNALS><!-- END SHA win-x64_noexternals -->
|
||||||
|
- actions-runner-win-arm64-<RUNNER_VERSION>-noexternals.zip <!-- BEGIN SHA win-arm64_noexternals --><WIN_ARM64_SHA_NOEXTERNALS><!-- END SHA win-arm64_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-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-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-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noexternals --><LINUX_X64_SHA_NOEXTERNALS><!-- END SHA linux-x64_noexternals -->
|
||||||
@@ -98,6 +118,7 @@ The SHA-256 checksums for the packages included in this build are shown below:
|
|||||||
- 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-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-win-x64-<RUNNER_VERSION>-noruntime.zip <!-- BEGIN SHA win-x64_noruntime --><WIN_X64_SHA_NORUNTIME><!-- END SHA win-x64_noruntime -->
|
||||||
|
- actions-runner-win-arm64-<RUNNER_VERSION>-noruntime.zip <!-- BEGIN SHA win-arm64_noruntime --><WIN_ARM64_SHA_NORUNTIME><!-- END SHA win-arm64_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-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-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-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-x64_noruntime --><LINUX_X64_SHA_NORUNTIME><!-- END SHA linux-x64_noruntime -->
|
||||||
@@ -105,6 +126,7 @@ The SHA-256 checksums for the packages included in this build are shown below:
|
|||||||
- 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-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-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-win-arm64-<RUNNER_VERSION>-noruntime-noexternals.zip <!-- BEGIN SHA win-arm64_noruntime_noexternals --><WIN_ARM64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA win-arm64_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-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-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-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noruntime_noexternals --><LINUX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-x64_noruntime_noexternals -->
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<Update to ./src/runnerversion when creating release>
|
2.298.2
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'Windows' AND '$(PackageRuntime)' == 'win-x86'">
|
<PropertyGroup Condition="'$(BUILD_OS)' == 'Windows' AND '$(PackageRuntime)' == 'win-x86'">
|
||||||
<DefineConstants>$(DefineConstants);X86</DefineConstants>
|
<DefineConstants>$(DefineConstants);X86</DefineConstants>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(BUILD_OS)' == 'Windows' AND '$(PackageRuntime)' == 'win-arm64'">
|
||||||
|
<DefineConstants>$(DefineConstants);ARM64</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX' AND '$(PackageRuntime)' == 'osx-x64'">
|
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX' AND '$(PackageRuntime)' == 'osx-x64'">
|
||||||
<DefineConstants>$(DefineConstants);X64</DefineConstants>
|
<DefineConstants>$(DefineConstants);X64</DefineConstants>
|
||||||
|
|||||||
1
src/Misc/contentHash/dotnetRuntime/win-arm64
Normal file
1
src/Misc/contentHash/dotnetRuntime/win-arm64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
39d0683f0f115a211cb10c473e9574c16549a19d4e9a6c637ded3d7022bf809f
|
||||||
1
src/Misc/contentHash/externals/win-arm64
vendored
Normal file
1
src/Misc/contentHash/externals/win-arm64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
e5dace2d41cc0682d096dcce4970079ad48ec7107e46195970eecfdb3df2acef
|
||||||
@@ -1 +1,4 @@
|
|||||||
To update hashFiles under `Misc/layoutbin` run `npm install && npm run all`
|
To compile this package (output will be stored in `Misc/layoutbin`) run `npm install && npm run all`.
|
||||||
|
|
||||||
|
> Note: this package also needs to be recompiled for dependabot PRs updating one of
|
||||||
|
> its dependencies.
|
||||||
|
|||||||
62
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
62
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
@@ -22,9 +22,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/core": {
|
"node_modules/@actions/core": {
|
||||||
"version": "1.2.6",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
|
||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/http-client": "^2.0.1",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@actions/glob": {
|
"node_modules/@actions/glob": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -35,6 +39,14 @@
|
|||||||
"minimatch": "^3.0.4"
|
"minimatch": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@actions/http-client": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||||
|
"dependencies": {
|
||||||
|
"tunnel": "^0.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@eslint/eslintrc": {
|
"node_modules/@eslint/eslintrc": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz",
|
||||||
@@ -2381,6 +2393,14 @@
|
|||||||
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
|
"typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tunnel": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.6.11 <=0.7.0 || >=0.7.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/type-check": {
|
"node_modules/type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
@@ -2442,6 +2462,14 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/uuid": {
|
||||||
|
"version": "8.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/v8-compile-cache": {
|
"node_modules/v8-compile-cache": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
|
||||||
@@ -2503,9 +2531,13 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.2.6",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
|
||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
|
||||||
|
"requires": {
|
||||||
|
"@actions/http-client": "^2.0.1",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"@actions/glob": {
|
"@actions/glob": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
@@ -2516,6 +2548,14 @@
|
|||||||
"minimatch": "^3.0.4"
|
"minimatch": "^3.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@actions/http-client": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
|
||||||
|
"requires": {
|
||||||
|
"tunnel": "^0.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@eslint/eslintrc": {
|
"@eslint/eslintrc": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz",
|
||||||
@@ -4189,6 +4229,11 @@
|
|||||||
"tslib": "^1.8.1"
|
"tslib": "^1.8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tunnel": {
|
||||||
|
"version": "0.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
|
||||||
|
"integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
|
||||||
|
},
|
||||||
"type-check": {
|
"type-check": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
|
||||||
@@ -4231,6 +4276,11 @@
|
|||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "8.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||||
|
},
|
||||||
"v8-compile-cache": {
|
"v8-compile-cache": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ PACKAGERUNTIME=$1
|
|||||||
PRECACHE=$2
|
PRECACHE=$2
|
||||||
|
|
||||||
NODE_URL=https://nodejs.org/dist
|
NODE_URL=https://nodejs.org/dist
|
||||||
|
UNOFFICIAL_NODE_URL=https://unofficial-builds.nodejs.org/download/release
|
||||||
NODE12_VERSION="12.22.7"
|
NODE12_VERSION="12.22.7"
|
||||||
NODE16_VERSION="16.13.0"
|
NODE16_VERSION="16.13.0"
|
||||||
|
|
||||||
@@ -134,6 +135,16 @@ if [[ "$PACKAGERUNTIME" == "win-x64" || "$PACKAGERUNTIME" == "win-x86" ]]; then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Download the external tools only for Windows.
|
||||||
|
if [[ "$PACKAGERUNTIME" == "win-arm64" ]]; then
|
||||||
|
# todo: replace these with official release when available
|
||||||
|
acquireExternalTool "$UNOFFICIAL_NODE_URL/v${NODE16_VERSION}/$PACKAGERUNTIME/node.exe" node16/bin
|
||||||
|
acquireExternalTool "$UNOFFICIAL_NODE_URL/v${NODE16_VERSION}/$PACKAGERUNTIME/node.lib" node16/bin
|
||||||
|
if [[ "$PRECACHE" != "" ]]; then
|
||||||
|
acquireExternalTool "https://github.com/microsoft/vswhere/releases/download/2.6.7/vswhere.exe" vswhere
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Download the external tools only for OSX.
|
# Download the external tools only for OSX.
|
||||||
if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
|
if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
|
||||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-darwin-x64.tar.gz" node12 fix_nested_dir
|
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-darwin-x64.tar.gz" node12 fix_nested_dir
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -66,7 +66,7 @@ then
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$apt_get update && $apt_get install -y liblttng-ust0 libkrb5-3 zlib1g
|
$apt_get update && $apt_get install -y libkrb5-3 zlib1g
|
||||||
if [ $? -ne 0 ]
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
echo "'$apt_get' failed with exit code '$?'"
|
||||||
@@ -94,6 +94,14 @@ then
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apt_get_with_fallbacks liblttng-ust1 liblttng-ust0
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "'$apt_get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
apt_get_with_fallbacks libssl1.1$ libssl1.0.2$ libssl1.0.0$
|
apt_get_with_fallbacks libssl1.1$ libssl1.0.2$ libssl1.0.0$
|
||||||
if [ $? -ne 0 ]
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
|
|||||||
@@ -120,6 +120,9 @@ if ERRORLEVEL 1 (
|
|||||||
|
|
||||||
echo [%date% %time%] Update succeed >> "%logfile%" 2>&1
|
echo [%date% %time%] Update succeed >> "%logfile%" 2>&1
|
||||||
|
|
||||||
|
type nul > update.finished
|
||||||
|
echo [%date% %time%] update.finished file creation succeed >> "%logfile%" 2>&1
|
||||||
|
|
||||||
rem rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
rem rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
||||||
rem runner service host can base on the log file name determin the result of the runner update
|
rem runner service host can base on the log file name determin the result of the runner update
|
||||||
echo [%date% %time%] Rename "%logfile%" to be "%logfile%.succeed" >> "%logfile%" 2>&1
|
echo [%date% %time%] Rename "%logfile%" to be "%logfile%.succeed" >> "%logfile%" 2>&1
|
||||||
|
|||||||
@@ -180,6 +180,9 @@ fi
|
|||||||
|
|
||||||
date "+[%F %T-%4N] Update succeed" >> "$logfile"
|
date "+[%F %T-%4N] Update succeed" >> "$logfile"
|
||||||
|
|
||||||
|
touch update.finished
|
||||||
|
date "+[%F %T-%4N] update.finished file creation succeed" >> "$logfile"
|
||||||
|
|
||||||
# rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
# rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
||||||
# runner service host can base on the log file name determin the result of the runner update
|
# runner service host can base on the log file name determin the result of the runner update
|
||||||
date "+[%F %T-%4N] Rename $logfile to be $logfile.succeed" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Rename $logfile to be $logfile.succeed" >> "$logfile" 2>&1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
SET UPDATEFILE=update.finished
|
||||||
"%~dp0\bin\Runner.Listener.exe" run %*
|
"%~dp0\bin\Runner.Listener.exe" run %*
|
||||||
|
|
||||||
rem using `if %ERRORLEVEL% EQU N` insterad of `if ERRORLEVEL N`
|
rem using `if %ERRORLEVEL% EQU N` insterad of `if ERRORLEVEL N`
|
||||||
@@ -22,16 +22,30 @@ if %ERRORLEVEL% EQU 2 (
|
|||||||
)
|
)
|
||||||
|
|
||||||
if %ERRORLEVEL% EQU 3 (
|
if %ERRORLEVEL% EQU 3 (
|
||||||
rem Sleep 5 seconds to wait for the runner update process finish
|
rem Wait for 30 seconds or for flag file to exists for the ephemeral runner update process finish
|
||||||
echo "Runner listener exit because of updating, re-launch runner in 5 seconds"
|
echo "Runner listener exit because of updating, re-launch runner after successful update"
|
||||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
FOR /L %%G IN (1,1,30) DO (
|
||||||
|
IF EXIST %UPDATEFILE% (
|
||||||
|
echo "Update finished successfully."
|
||||||
|
del %FILE%
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
ping 127.0.0.1 -n 2 -w 1000 >NUL
|
||||||
|
)
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
if %ERRORLEVEL% EQU 4 (
|
if %ERRORLEVEL% EQU 4 (
|
||||||
rem Sleep 5 seconds to wait for the ephemeral runner update process finish
|
rem Wait for 30 seconds or for flag file to exists for the runner update process finish
|
||||||
echo "Runner listener exit because of updating, re-launch ephemeral runner in 5 seconds"
|
echo "Runner listener exit because of updating, re-launch runner after successful update"
|
||||||
ping 127.0.0.1 -n 6 -w 1000 >NUL
|
FOR /L %%G IN (1,1,30) DO (
|
||||||
|
IF EXIST %UPDATEFILE% (
|
||||||
|
echo "Update finished successfully."
|
||||||
|
del %FILE%
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
ping 127.0.0.1 -n 2 -w 1000 >NUL
|
||||||
|
)
|
||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ 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
|
[[ $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
|
done
|
||||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||||
|
|
||||||
|
updateFile="update.finished"
|
||||||
"$DIR"/bin/Runner.Listener run $*
|
"$DIR"/bin/Runner.Listener run $*
|
||||||
|
|
||||||
returnCode=$?
|
returnCode=$?
|
||||||
@@ -31,14 +33,28 @@ elif [[ $returnCode == 2 ]]; then
|
|||||||
"$DIR"/safe_sleep.sh 5
|
"$DIR"/safe_sleep.sh 5
|
||||||
exit 2
|
exit 2
|
||||||
elif [[ $returnCode == 3 ]]; then
|
elif [[ $returnCode == 3 ]]; then
|
||||||
# Sleep 5 seconds to wait for the runner update process finish
|
# Wait for 30 seconds or for flag file to exists for the runner update process finish
|
||||||
echo "Runner listener exit because of updating, re-launch runner in 5 seconds"
|
echo "Runner listener exit because of updating, re-launch runner after successful update"
|
||||||
"$DIR"/safe_sleep.sh 5
|
for i in {0..30}; do
|
||||||
|
if test -f "$updateFile"; then
|
||||||
|
echo "Update finished successfully."
|
||||||
|
rm "$updateFile"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
"$DIR"/safe_sleep.sh 1
|
||||||
|
done
|
||||||
exit 2
|
exit 2
|
||||||
elif [[ $returnCode == 4 ]]; then
|
elif [[ $returnCode == 4 ]]; then
|
||||||
# Sleep 5 seconds to wait for the ephemeral runner update process finish
|
# Wait for 30 seconds or for flag file to exists for the ephemeral runner update process finish
|
||||||
echo "Runner listener exit because of updating, re-launch ephemeral runner in 5 seconds"
|
echo "Runner listener exit because of updating, re-launch runner after successful update"
|
||||||
"$DIR"/safe_sleep.sh 5
|
for i in {0..30}; do
|
||||||
|
if test -f "$updateFile"; then
|
||||||
|
echo "Update finished successfully."
|
||||||
|
rm "$updateFile"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
"$DIR"/safe_sleep.sh 1
|
||||||
|
done
|
||||||
exit 2
|
exit 2
|
||||||
else
|
else
|
||||||
echo "Exiting with unknown error code: ${returnCode}"
|
echo "Exiting with unknown error code: ${returnCode}"
|
||||||
|
|||||||
@@ -9,10 +9,10 @@ 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
|
[[ $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
|
done
|
||||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||||
cp -f "$DIR"/run-helper.sh.template "$DIR"/run-helper.sh
|
|
||||||
# run the helper process which keep the listener alive
|
# run the helper process which keep the listener alive
|
||||||
while :;
|
while :;
|
||||||
do
|
do
|
||||||
|
cp -f "$DIR"/run-helper.sh.template "$DIR"/run-helper.sh
|
||||||
"$DIR"/run-helper.sh $*
|
"$DIR"/run-helper.sh $*
|
||||||
returnCode=$?
|
returnCode=$?
|
||||||
if [[ $returnCode -eq 2 ]]; then
|
if [[ $returnCode -eq 2 ]]; then
|
||||||
|
|||||||
@@ -66,12 +66,14 @@ libmscordbi.dylib
|
|||||||
libmscordbi.so
|
libmscordbi.so
|
||||||
Microsoft.CSharp.dll
|
Microsoft.CSharp.dll
|
||||||
Microsoft.DiaSymReader.Native.amd64.dll
|
Microsoft.DiaSymReader.Native.amd64.dll
|
||||||
|
Microsoft.DiaSymReader.Native.arm64.dll
|
||||||
Microsoft.VisualBasic.Core.dll
|
Microsoft.VisualBasic.Core.dll
|
||||||
Microsoft.VisualBasic.dll
|
Microsoft.VisualBasic.dll
|
||||||
Microsoft.Win32.Primitives.dll
|
Microsoft.Win32.Primitives.dll
|
||||||
Microsoft.Win32.Registry.dll
|
Microsoft.Win32.Registry.dll
|
||||||
mscordaccore.dll
|
mscordaccore.dll
|
||||||
mscordaccore_amd64_amd64_6.0.522.21309.dll
|
mscordaccore_amd64_amd64_6.0.522.21309.dll
|
||||||
|
mscordaccore_arm64_arm64_6.0.522.21309.dll
|
||||||
mscordbi.dll
|
mscordbi.dll
|
||||||
mscorlib.dll
|
mscorlib.dll
|
||||||
mscorrc.debug.dll
|
mscorrc.debug.dll
|
||||||
@@ -261,4 +263,4 @@ System.Xml.XmlSerializer.dll
|
|||||||
System.Xml.XPath.dll
|
System.Xml.XPath.dll
|
||||||
System.Xml.XPath.XDocument.dll
|
System.Xml.XPath.XDocument.dll
|
||||||
ucrtbase.dll
|
ucrtbase.dll
|
||||||
WindowsBase.dll
|
WindowsBase.dll
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
public enum ActionResult
|
public enum ActionResult
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using GitHub.DistributedTask.Logging;
|
using GitHub.DistributedTask.Logging;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly Architecture PlatformArchitecture = Architecture.X64;
|
public static readonly Architecture PlatformArchitecture = Architecture.X64;
|
||||||
#elif ARM
|
#elif ARM
|
||||||
public static readonly Architecture PlatformArchitecture = Architecture.Arm;
|
public static readonly Architecture PlatformArchitecture = Architecture.Arm;
|
||||||
#elif ARM64
|
#elif ARM64
|
||||||
public static readonly Architecture PlatformArchitecture = Architecture.Arm64;
|
public static readonly Architecture PlatformArchitecture = Architecture.Arm64;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -90,6 +90,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static class Args
|
public static class Args
|
||||||
{
|
{
|
||||||
public static readonly string Auth = "auth";
|
public static readonly string Auth = "auth";
|
||||||
|
public static readonly string JitConfig = "jitconfig";
|
||||||
public static readonly string Labels = "labels";
|
public static readonly string Labels = "labels";
|
||||||
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
||||||
public static readonly string Name = "name";
|
public static readonly string Name = "name";
|
||||||
@@ -151,16 +152,18 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
||||||
public static readonly string Node12Warning = "DistributedTask.AddWarningToNode12Action";
|
public static readonly string Node12Warning = "DistributedTask.AddWarningToNode12Action";
|
||||||
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
||||||
|
public static readonly string AllowRunnerContainerHooks = "DistributedTask.AllowRunnerContainerHooks";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||||
public static readonly string WorkerCrash = "WORKER_CRASH";
|
public static readonly string WorkerCrash = "WORKER_CRASH";
|
||||||
public static readonly string LowDiskSpace = "LOW_DISK_SPACE";
|
public static readonly string LowDiskSpace = "LOW_DISK_SPACE";
|
||||||
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
||||||
|
public static readonly string UnsupportedCommandMessage = "The `{0}` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/";
|
||||||
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 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 UnsupportedStopCommandTokenDisabled = "You cannot use a endToken that is an empty string, the string 'pause-logging', or another workflow command. For more information see: https://docs.github.com/actions/learn-github-actions/workflow-commands-for-github-actions#example-stopping-and-starting-workflow-commands or opt into insecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS` environment variable to `true`.";
|
||||||
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
||||||
public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: {0}";
|
public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/. Please update the following actions to use Node.js 16: {0}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RunnerEvent
|
public static class RunnerEvent
|
||||||
@@ -196,6 +199,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
public static readonly string JobStartedStepName = "Set up runner";
|
public static readonly string JobStartedStepName = "Set up runner";
|
||||||
public static readonly string JobCompletedStepName = "Complete runner";
|
public static readonly string JobCompletedStepName = "Complete runner";
|
||||||
|
public static readonly string ContainerHooksPath = "ACTIONS_RUNNER_CONTAINER_HOOKS";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Path
|
public static class Path
|
||||||
@@ -227,6 +231,7 @@ namespace GitHub.Runner.Common
|
|||||||
//
|
//
|
||||||
public static readonly string AllowUnsupportedCommands = "ACTIONS_ALLOW_UNSECURE_COMMANDS";
|
public static readonly string AllowUnsupportedCommands = "ACTIONS_ALLOW_UNSECURE_COMMANDS";
|
||||||
public static readonly string AllowUnsupportedStopCommandTokens = "ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS";
|
public static readonly string AllowUnsupportedStopCommandTokens = "ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS";
|
||||||
|
public static readonly string RequireJobContainer = "ACTIONS_RUNNER_REQUIRE_JOB_CONTAINER";
|
||||||
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
||||||
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
||||||
public static readonly string AllowActionsUseUnsecureNodeVersion = "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION";
|
public static readonly string AllowActionsUseUnsecureNodeVersion = "ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION";
|
||||||
@@ -237,7 +242,8 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
||||||
|
|
||||||
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
||||||
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
||||||
|
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class System
|
public static class System
|
||||||
@@ -250,5 +256,12 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string PhaseDisplayName = "system.phaseDisplayName";
|
public static readonly string PhaseDisplayName = "system.phaseDisplayName";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class OperatingSystem
|
||||||
|
{
|
||||||
|
public static readonly int Windows11BuildVersion = 22000;
|
||||||
|
// Both windows 10 and windows 11 share the same Major Version 10, need to use the build version to differentiate
|
||||||
|
public static readonly int Windows11MajorVersion = 10;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
@@ -61,6 +60,8 @@ namespace GitHub.Runner.Common
|
|||||||
Add<T>(extensions, "GitHub.Runner.Worker.AddPathFileCommand, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.AddPathFileCommand, Runner.Worker");
|
||||||
Add<T>(extensions, "GitHub.Runner.Worker.SetEnvFileCommand, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.SetEnvFileCommand, Runner.Worker");
|
||||||
Add<T>(extensions, "GitHub.Runner.Worker.CreateStepSummaryCommand, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.CreateStepSummaryCommand, Runner.Worker");
|
||||||
|
Add<T>(extensions, "GitHub.Runner.Worker.SaveStateFileCommand, Runner.Worker");
|
||||||
|
Add<T>(extensions, "GitHub.Runner.Worker.SetOutputFileCommand, Runner.Worker");
|
||||||
break;
|
break;
|
||||||
case "GitHub.Runner.Listener.Check.ICheckExtension":
|
case "GitHub.Runner.Listener.Check.ICheckExtension":
|
||||||
Add<T>(extensions, "GitHub.Runner.Listener.Check.InternetCheck, Runner.Listener");
|
Add<T>(extensions, "GitHub.Runner.Listener.Check.InternetCheck, Runner.Listener");
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using System.Runtime.Loader;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.Logging;
|
using GitHub.DistributedTask.Logging;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
@@ -641,6 +642,31 @@ namespace GitHub.Runner.Common
|
|||||||
var handlerFactory = context.GetService<IHttpClientHandlerFactory>();
|
var handlerFactory = context.GetService<IHttpClientHandlerFactory>();
|
||||||
return handlerFactory.CreateClientHandler(context.WebProxy);
|
return handlerFactory.CreateClientHandler(context.WebProxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetDefaultShellForScript(this IHostContext hostContext, string path, string prependPath)
|
||||||
|
{
|
||||||
|
var trace = hostContext.GetTrace(nameof(GetDefaultShellForScript));
|
||||||
|
switch (Path.GetExtension(path))
|
||||||
|
{
|
||||||
|
case ".sh":
|
||||||
|
// use 'sh' args but prefer bash
|
||||||
|
if (WhichUtil.Which("bash", false, trace, prependPath) != null)
|
||||||
|
{
|
||||||
|
return "bash";
|
||||||
|
}
|
||||||
|
return "sh";
|
||||||
|
case ".ps1":
|
||||||
|
if (WhichUtil.Which("pwsh", false, trace, prependPath) != null)
|
||||||
|
{
|
||||||
|
return "pwsh";
|
||||||
|
}
|
||||||
|
return "powershell";
|
||||||
|
case ".js":
|
||||||
|
return Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Externals), NodeUtil.GetInternalNodeVersion(), "bin", $"node{IOUtil.ExeExtension}") + " {0}";
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"{path} is not a valid path to a script. Make sure it ends in '.sh', '.ps1' or '.js'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ShutdownReason
|
public enum ShutdownReason
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using System.IO.Pipes;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -13,7 +13,6 @@ using GitHub.Runner.Sdk;
|
|||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using GitHub.Services.WebApi.Utilities.Internal;
|
using GitHub.Services.WebApi.Utilities.Internal;
|
||||||
using Newtonsoft.Json;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
|
|||||||
14
src/Runner.Common/JobStatusEventArgs.cs
Normal file
14
src/Runner.Common/JobStatusEventArgs.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common
|
||||||
|
{
|
||||||
|
public class JobStatusEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
public JobStatusEventArgs(TaskAgentStatus status)
|
||||||
|
{
|
||||||
|
this.Status = status;
|
||||||
|
}
|
||||||
|
public TaskAgentStatus Status { get; private set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
103
src/Runner.Common/RunServer.cs
Normal file
103
src/Runner.Common/RunServer.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.Pipelines;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common
|
||||||
|
{
|
||||||
|
[ServiceLocator(Default = typeof(RunServer))]
|
||||||
|
public interface IRunServer : IRunnerService
|
||||||
|
{
|
||||||
|
Task ConnectAsync(Uri serverUrl, VssCredentials credentials);
|
||||||
|
|
||||||
|
Task<AgentJobRequestMessage> GetJobMessageAsync(string id, CancellationToken token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class RunServer : RunnerService, IRunServer
|
||||||
|
{
|
||||||
|
private bool _hasConnection;
|
||||||
|
private VssConnection _connection;
|
||||||
|
private TaskAgentHttpClient _taskAgentClient;
|
||||||
|
|
||||||
|
public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials)
|
||||||
|
{
|
||||||
|
_connection = await EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||||
|
_taskAgentClient = _connection.GetClient<TaskAgentHttpClient>();
|
||||||
|
_hasConnection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<VssConnection> EstablishVssConnection(Uri serverUrl, VssCredentials credentials, TimeSpan timeout)
|
||||||
|
{
|
||||||
|
Trace.Info($"EstablishVssConnection");
|
||||||
|
Trace.Info($"Establish connection with {timeout.TotalSeconds} seconds timeout.");
|
||||||
|
int attemptCount = 5;
|
||||||
|
while (attemptCount-- > 0)
|
||||||
|
{
|
||||||
|
var connection = VssUtil.CreateConnection(serverUrl, credentials, timeout: timeout);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await connection.ConnectAsync();
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (attemptCount > 0)
|
||||||
|
{
|
||||||
|
Trace.Info($"Catch exception during connect. {attemptCount} attempt left.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
|
||||||
|
await HostContext.Delay(TimeSpan.FromMilliseconds(100), CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// should never reach here.
|
||||||
|
throw new InvalidOperationException(nameof(EstablishVssConnection));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckConnection()
|
||||||
|
{
|
||||||
|
if (!_hasConnection)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"SetConnection");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<AgentJobRequestMessage> GetJobMessageAsync(string id, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
CheckConnection();
|
||||||
|
var jobMessage = RetryRequest<AgentJobRequestMessage>(async () =>
|
||||||
|
{
|
||||||
|
return await _taskAgentClient.GetJobMessageAsync(id, cancellationToken);
|
||||||
|
}, cancellationToken);
|
||||||
|
return jobMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<T> RetryRequest<T>(Func<Task<T>> func,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
int maxRetryAttemptsCount = 5
|
||||||
|
)
|
||||||
|
{
|
||||||
|
var retryCount = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
retryCount++;
|
||||||
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return await func();
|
||||||
|
}
|
||||||
|
// TODO: Add handling of non-retriable exceptions: https://github.com/github/actions-broker/issues/122
|
||||||
|
catch (Exception ex) when (retryCount < maxRetryAttemptsCount)
|
||||||
|
{
|
||||||
|
Trace.Error("Catch exception during get full job message");
|
||||||
|
Trace.Error(ex);
|
||||||
|
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(15));
|
||||||
|
Trace.Warning($"Back off {backOff.TotalSeconds} seconds before next retry. {maxRetryAttemptsCount - retryCount} attempt left.");
|
||||||
|
await Task.Delay(backOff, cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
||||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.4.0" />
|
||||||
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
|
<PackageReference Include="System.Threading.Channels" Version="4.4.0" />
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
@@ -39,7 +38,7 @@ namespace GitHub.Runner.Common
|
|||||||
Task<TaskAgentSession> CreateAgentSessionAsync(Int32 poolId, TaskAgentSession session, CancellationToken cancellationToken);
|
Task<TaskAgentSession> CreateAgentSessionAsync(Int32 poolId, TaskAgentSession session, CancellationToken cancellationToken);
|
||||||
Task DeleteAgentMessageAsync(Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken);
|
Task DeleteAgentMessageAsync(Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken);
|
||||||
Task DeleteAgentSessionAsync(Int32 poolId, Guid sessionId, CancellationToken cancellationToken);
|
Task DeleteAgentSessionAsync(Int32 poolId, Guid sessionId, CancellationToken cancellationToken);
|
||||||
Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken);
|
Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, CancellationToken cancellationToken);
|
||||||
|
|
||||||
// job request
|
// job request
|
||||||
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
||||||
@@ -298,10 +297,10 @@ namespace GitHub.Runner.Common
|
|||||||
return _messageTaskAgentClient.DeleteAgentSessionAsync(poolId, sessionId, cancellationToken: cancellationToken);
|
return _messageTaskAgentClient.DeleteAgentSessionAsync(poolId, sessionId, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken)
|
public Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
CheckConnection(RunnerConnectionType.MessageQueue);
|
||||||
return _messageTaskAgentClient.GetMessageAsync(poolId, sessionId, lastMessageId, cancellationToken: cancellationToken);
|
return _messageTaskAgentClient.GetMessageAsync(poolId, sessionId, lastMessageId, status, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common.Internal;
|
using GitHub.Services.Common.Internal;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace GitHub.Runner.Common.Util
|
|||||||
{
|
{
|
||||||
private const string _defaultNodeVersion = "node16";
|
private const string _defaultNodeVersion = "node16";
|
||||||
|
|
||||||
#if OS_OSX && ARM64
|
#if (OS_OSX || OS_WINDOWS) && ARM64
|
||||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16" });
|
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16" });
|
||||||
#else
|
#else
|
||||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node12", "node16" });
|
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node12", "node16" });
|
||||||
@@ -15,8 +15,14 @@ namespace GitHub.Runner.Common.Util
|
|||||||
|
|
||||||
public static string GetInternalNodeVersion()
|
public static string GetInternalNodeVersion()
|
||||||
{
|
{
|
||||||
var forcedNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
var forcedInternalNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
||||||
return !string.IsNullOrEmpty(forcedNodeVersion) && BuiltInNodeVersions.Contains(forcedNodeVersion) ? forcedNodeVersion : _defaultNodeVersion;
|
var isForcedInternalNodeVersion = !string.IsNullOrEmpty(forcedInternalNodeVersion) && BuiltInNodeVersions.Contains(forcedInternalNodeVersion);
|
||||||
|
|
||||||
|
if (isForcedInternalNodeVersion)
|
||||||
|
{
|
||||||
|
return forcedInternalNodeVersion;
|
||||||
|
}
|
||||||
|
return _defaultNodeVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Util
|
namespace GitHub.Runner.Common.Util
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
@@ -168,4 +167,4 @@ namespace GitHub.Runner.Listener.Check
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
@@ -179,4 +178,4 @@ namespace GitHub.Runner.Listener.Check
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System;
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.Logging;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|
||||||
@@ -63,6 +62,7 @@ namespace GitHub.Runner.Listener
|
|||||||
new string[]
|
new string[]
|
||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Flags.Once,
|
Constants.Runner.CommandLine.Flags.Once,
|
||||||
|
Constants.Runner.CommandLine.Args.JitConfig,
|
||||||
Constants.Runner.CommandLine.Args.StartupType
|
Constants.Runner.CommandLine.Args.StartupType
|
||||||
},
|
},
|
||||||
// valid warmup flags and args
|
// valid warmup flags and args
|
||||||
@@ -213,6 +213,12 @@ namespace GitHub.Runner.Listener
|
|||||||
validator: Validators.AuthSchemeValidator);
|
validator: Validators.AuthSchemeValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetJitConfig()
|
||||||
|
{
|
||||||
|
return GetArg(
|
||||||
|
name: Constants.Runner.CommandLine.Args.JitConfig);
|
||||||
|
}
|
||||||
|
|
||||||
public string GetRunnerName()
|
public string GetRunnerName()
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using GitHub.Runner.Common;
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Services.Common.Internal;
|
||||||
using GitHub.Services.OAuth;
|
using GitHub.Services.OAuth;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -128,7 +129,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// Example githubServerUrl is https://my-ghes
|
// Example githubServerUrl is https://my-ghes
|
||||||
var actionsServerUrl = new Uri(runnerSettings.ServerUrl);
|
var actionsServerUrl = new Uri(runnerSettings.ServerUrl);
|
||||||
var githubServerUrl = new Uri(runnerSettings.GitHubUrl);
|
var githubServerUrl = new Uri(runnerSettings.GitHubUrl);
|
||||||
if (!string.Equals(actionsServerUrl.Authority, githubServerUrl.Authority, StringComparison.OrdinalIgnoreCase))
|
if (!UriUtility.IsSubdomainOf(actionsServerUrl.Authority, githubServerUrl.Authority))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"GitHub Actions is not properly configured in GHES. GHES url: {runnerSettings.GitHubUrl}, Actions url: {runnerSettings.ServerUrl}.");
|
throw new InvalidOperationException($"GitHub Actions is not properly configured in GHES. GHES url: {runnerSettings.GitHubUrl}, Actions url: {runnerSettings.ServerUrl}.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
@@ -72,7 +71,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
else if (isOptional)
|
else if (isOptional)
|
||||||
{
|
{
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
@@ -87,11 +86,12 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// Write the message prompt.
|
// Write the message prompt.
|
||||||
_terminal.Write($"{description} ");
|
_terminal.Write($"{description} ");
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(defaultValue))
|
if (!string.IsNullOrEmpty(defaultValue))
|
||||||
{
|
{
|
||||||
_terminal.Write($"[press Enter for {defaultValue}] ");
|
_terminal.Write($"[press Enter for {defaultValue}] ");
|
||||||
}
|
}
|
||||||
else if (isOptional){
|
else if (isOptional)
|
||||||
|
{
|
||||||
_terminal.Write($"[press Enter to skip] ");
|
_terminal.Write($"[press Enter to skip] ");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the value if it is not empty and it is valid.
|
// Return the value if it is not empty and it is valid.
|
||||||
// Otherwise try the loop again.
|
// Otherwise try the loop again.
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrEmpty(value))
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if OS_LINUX
|
#if OS_LINUX
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
@@ -6,7 +6,6 @@ using System.Linq;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Configuration
|
namespace GitHub.Runner.Listener.Configuration
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace GitHub.Runner.Listener
|
|||||||
bool Cancel(JobCancelMessage message);
|
bool Cancel(JobCancelMessage message);
|
||||||
Task WaitAsync(CancellationToken token);
|
Task WaitAsync(CancellationToken token);
|
||||||
Task ShutdownAsync();
|
Task ShutdownAsync();
|
||||||
|
event EventHandler<JobStatusEventArgs> JobStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This implementation of IJobDispatcher is not thread safe.
|
// This implementation of IJobDispatcher is not thread safe.
|
||||||
@@ -55,6 +56,8 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
private TaskCompletionSource<bool> _runOnceJobCompleted = new TaskCompletionSource<bool>();
|
private TaskCompletionSource<bool> _runOnceJobCompleted = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
public event EventHandler<JobStatusEventArgs> JobStatus;
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
@@ -335,6 +338,11 @@ namespace GitHub.Runner.Listener
|
|||||||
Busy = true;
|
Busy = true;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (JobStatus != null)
|
||||||
|
{
|
||||||
|
JobStatus(this, new JobStatusEventArgs(TaskAgentStatus.Busy));
|
||||||
|
}
|
||||||
|
|
||||||
if (previousJobDispatch != null)
|
if (previousJobDispatch != null)
|
||||||
{
|
{
|
||||||
Trace.Verbose($"Make sure the previous job request {previousJobDispatch.JobId} has successfully finished on worker.");
|
Trace.Verbose($"Make sure the previous job request {previousJobDispatch.JobId} has successfully finished on worker.");
|
||||||
@@ -650,6 +658,11 @@ namespace GitHub.Runner.Listener
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Busy = false;
|
Busy = false;
|
||||||
|
|
||||||
|
if (JobStatus != null)
|
||||||
|
{
|
||||||
|
JobStatus(this, new JobStatusEventArgs(TaskAgentStatus.Online));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ namespace GitHub.Runner.Listener
|
|||||||
Task DeleteSessionAsync();
|
Task DeleteSessionAsync();
|
||||||
Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token);
|
Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token);
|
||||||
Task DeleteMessageAsync(TaskAgentMessage message);
|
Task DeleteMessageAsync(TaskAgentMessage message);
|
||||||
|
void OnJobStatus(object sender, JobStatusEventArgs e);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class MessageListener : RunnerService, IMessageListener
|
public sealed class MessageListener : RunnerService, IMessageListener
|
||||||
@@ -38,6 +39,8 @@ namespace GitHub.Runner.Listener
|
|||||||
private readonly TimeSpan _sessionConflictRetryLimit = TimeSpan.FromMinutes(4);
|
private readonly TimeSpan _sessionConflictRetryLimit = TimeSpan.FromMinutes(4);
|
||||||
private readonly TimeSpan _clockSkewRetryLimit = TimeSpan.FromMinutes(30);
|
private readonly TimeSpan _clockSkewRetryLimit = TimeSpan.FromMinutes(30);
|
||||||
private readonly Dictionary<string, int> _sessionCreationExceptionTracker = new Dictionary<string, int>();
|
private readonly Dictionary<string, int> _sessionCreationExceptionTracker = new Dictionary<string, int>();
|
||||||
|
private TaskAgentStatus runnerStatus = TaskAgentStatus.Online;
|
||||||
|
private CancellationTokenSource _getMessagesTokenSource;
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
@@ -170,6 +173,23 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnJobStatus(object sender, JobStatusEventArgs e)
|
||||||
|
{
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("USE_BROKER_FLOW")))
|
||||||
|
{
|
||||||
|
Trace.Info("Received job status event. JobState: {0}", e.Status);
|
||||||
|
runnerStatus = e.Status;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_getMessagesTokenSource?.Cancel();
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
Trace.Info("_getMessagesTokenSource is already disposed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
@@ -184,12 +204,14 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
token.ThrowIfCancellationRequested();
|
token.ThrowIfCancellationRequested();
|
||||||
TaskAgentMessage message = null;
|
TaskAgentMessage message = null;
|
||||||
|
_getMessagesTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
message = await _runnerServer.GetAgentMessageAsync(_settings.PoolId,
|
message = await _runnerServer.GetAgentMessageAsync(_settings.PoolId,
|
||||||
_session.SessionId,
|
_session.SessionId,
|
||||||
_lastMessageId,
|
_lastMessageId,
|
||||||
token);
|
runnerStatus,
|
||||||
|
_getMessagesTokenSource.Token);
|
||||||
|
|
||||||
// Decrypt the message body if the session is using encryption
|
// Decrypt the message body if the session is using encryption
|
||||||
message = DecryptMessage(message);
|
message = DecryptMessage(message);
|
||||||
@@ -206,6 +228,11 @@ namespace GitHub.Runner.Listener
|
|||||||
continuousError = 0;
|
continuousError = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (OperationCanceledException) when (_getMessagesTokenSource.Token.IsCancellationRequested && !token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Trace.Info("Get messages has been cancelled using local token source. Continue to get messages with new status.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Trace.Info("Get next message has been cancelled.");
|
Trace.Info("Get next message has been cancelled.");
|
||||||
@@ -261,6 +288,10 @@ namespace GitHub.Runner.Listener
|
|||||||
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_getMessagesTokenSource.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
if (message == null)
|
if (message == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
@@ -60,6 +58,18 @@ namespace GitHub.Runner.Listener
|
|||||||
terminal.WriteLine("This runner version is built for Windows. Please install a correct build for your OS.");
|
terminal.WriteLine("This runner version is built for Windows. Please install a correct build for your OS.");
|
||||||
return Constants.Runner.ReturnCode.TerminatedError;
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
}
|
}
|
||||||
|
#if ARM64
|
||||||
|
// A little hacky, but windows gives no way to differentiate between windows 10 and 11.
|
||||||
|
// By default only 11 supports native x64 app emulation on arm, so we only want to support windows 11
|
||||||
|
// https://docs.microsoft.com/en-us/windows/arm/overview#build-windows-apps-that-run-on-arm
|
||||||
|
// Windows 10 and 11 share a MajorVersion, so we also check the build version. Minor for both is 0, so doing < 0 doesn't really make a lot of sense.
|
||||||
|
if (Environment.OSVersion.Version.Major < Constants.OperatingSystem.Windows11MajorVersion ||
|
||||||
|
Environment.OSVersion.Version.Build < Constants.OperatingSystem.Windows11BuildVersion)
|
||||||
|
{
|
||||||
|
terminal.WriteLine("Win-arm64 runners require windows 11 or later. Please upgrade your operating system.");
|
||||||
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
terminal.WriteLine($"Running the runner on this platform is not supported. The current platform is {RuntimeInformation.OSDescription} and it was built for {Constants.Runner.Platform.ToString()}.");
|
terminal.WriteLine($"Running the runner on this platform is not supported. The current platform is {RuntimeInformation.OSDescription} and it was built for {Constants.Runner.Platform.ToString()}.");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
<PackageReference Include="Microsoft.Win32.Registry" Version="4.4.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.4.0" />
|
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="4.4.0" />
|
||||||
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.4.0" />
|
||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Listener.Configuration;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using System.Linq;
|
|
||||||
using GitHub.Runner.Listener.Check;
|
using GitHub.Runner.Listener.Check;
|
||||||
using System.Collections.Generic;
|
using GitHub.Runner.Listener.Configuration;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -192,6 +193,30 @@ namespace GitHub.Runner.Listener
|
|||||||
return Constants.Runner.ReturnCode.Success;
|
return Constants.Runner.ReturnCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var base64JitConfig = command.GetJitConfig();
|
||||||
|
if (!string.IsNullOrEmpty(base64JitConfig))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var decodedJitConfig = Encoding.UTF8.GetString(Convert.FromBase64String(base64JitConfig));
|
||||||
|
var jitConfig = StringUtil.ConvertFromJson<Dictionary<string, string>>(decodedJitConfig);
|
||||||
|
foreach (var config in jitConfig)
|
||||||
|
{
|
||||||
|
var configFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), config.Key);
|
||||||
|
var configContent = Encoding.UTF8.GetString(Convert.FromBase64String(config.Value));
|
||||||
|
File.WriteAllText(configFile, configContent, Encoding.UTF8);
|
||||||
|
File.SetAttributes(configFile, File.GetAttributes(configFile) | FileAttributes.Hidden);
|
||||||
|
Trace.Info($"Save {configContent.Length} chars to '{configFile}'.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error(ex);
|
||||||
|
_term.WriteError(ex.Message);
|
||||||
|
return Constants.Runner.ReturnCode.TerminatedError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RunnerSettings settings = configManager.LoadSettings();
|
RunnerSettings settings = configManager.LoadSettings();
|
||||||
|
|
||||||
var store = HostContext.GetService<IConfigurationStore>();
|
var store = HostContext.GetService<IConfigurationStore>();
|
||||||
@@ -322,6 +347,7 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
// Should we try to cleanup ephemeral runners
|
// Should we try to cleanup ephemeral runners
|
||||||
bool runOnceJobCompleted = false;
|
bool runOnceJobCompleted = false;
|
||||||
|
bool skipSessionDeletion = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var notification = HostContext.GetService<IJobNotification>();
|
var notification = HostContext.GetService<IJobNotification>();
|
||||||
@@ -333,6 +359,8 @@ namespace GitHub.Runner.Listener
|
|||||||
bool runOnceJobReceived = false;
|
bool runOnceJobReceived = false;
|
||||||
jobDispatcher = HostContext.CreateService<IJobDispatcher>();
|
jobDispatcher = HostContext.CreateService<IJobDispatcher>();
|
||||||
|
|
||||||
|
jobDispatcher.JobStatus += _listener.OnJobStatus;
|
||||||
|
|
||||||
while (!HostContext.RunnerShutdownToken.IsCancellationRequested)
|
while (!HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
TaskAgentMessage message = null;
|
TaskAgentMessage message = null;
|
||||||
@@ -457,6 +485,34 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Broker flow
|
||||||
|
else if (string.Equals(message.MessageType, JobRequestMessageTypes.RunnerJobRequest, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (autoUpdateInProgress || runOnceJobReceived)
|
||||||
|
{
|
||||||
|
skipMessageDeletion = true;
|
||||||
|
Trace.Info($"Skip message deletion for job request message '{message.MessageId}'.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var messageRef = StringUtil.ConvertFromJson<RunnerJobRequestRef>(message.Body);
|
||||||
|
|
||||||
|
// Create connection
|
||||||
|
var credMgr = HostContext.GetService<ICredentialManager>();
|
||||||
|
var creds = credMgr.LoadCredentials();
|
||||||
|
|
||||||
|
var runServer = HostContext.CreateService<IRunServer>();
|
||||||
|
await runServer.ConnectAsync(new Uri(settings.ServerUrl), creds);
|
||||||
|
var jobMessage = await runServer.GetJobMessageAsync(messageRef.RunnerRequestId, messageQueueLoopTokenSource.Token);
|
||||||
|
|
||||||
|
jobDispatcher.Run(jobMessage, runOnce);
|
||||||
|
if (runOnce)
|
||||||
|
{
|
||||||
|
Trace.Info("One time used runner received job message.");
|
||||||
|
runOnceJobReceived = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (string.Equals(message.MessageType, JobCancelMessage.MessageType, StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(message.MessageType, JobCancelMessage.MessageType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var cancelJobMessage = JsonUtility.FromString<JobCancelMessage>(message.Body);
|
var cancelJobMessage = JsonUtility.FromString<JobCancelMessage>(message.Body);
|
||||||
@@ -468,6 +524,14 @@ namespace GitHub.Runner.Listener
|
|||||||
Trace.Info($"Skip message deletion for cancellation message '{message.MessageId}'.");
|
Trace.Info($"Skip message deletion for cancellation message '{message.MessageId}'.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (string.Equals(message.MessageType, Pipelines.HostedRunnerShutdownMessage.MessageType, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var HostedRunnerShutdownMessage = JsonUtility.FromString<Pipelines.HostedRunnerShutdownMessage>(message.Body);
|
||||||
|
skipMessageDeletion = true;
|
||||||
|
skipSessionDeletion = true;
|
||||||
|
Trace.Info($"Service requests the hosted runner to shutdown. Reason: '{HostedRunnerShutdownMessage.Reason}'.");
|
||||||
|
return Constants.Runner.ReturnCode.Success;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.Error($"Received message {message.MessageId} with unsupported message type {message.MessageType}.");
|
Trace.Error($"Received message {message.MessageId} with unsupported message type {message.MessageType}.");
|
||||||
@@ -498,18 +562,22 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
if (jobDispatcher != null)
|
if (jobDispatcher != null)
|
||||||
{
|
{
|
||||||
|
jobDispatcher.JobStatus -= _listener.OnJobStatus;
|
||||||
await jobDispatcher.ShutdownAsync();
|
await jobDispatcher.ShutdownAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
if (!skipSessionDeletion)
|
||||||
{
|
{
|
||||||
await _listener.DeleteSessionAsync();
|
try
|
||||||
}
|
{
|
||||||
catch (Exception ex) when (runOnce)
|
await _listener.DeleteSessionAsync();
|
||||||
{
|
}
|
||||||
// ignore exception during delete session for ephemeral runner since the runner might already be deleted from the server side
|
catch (Exception ex) when (runOnce)
|
||||||
// and the delete session call will ends up with 401.
|
{
|
||||||
Trace.Info($"Ignore any exception during DeleteSession for an ephemeral runner. {ex}");
|
// ignore exception during delete session for ephemeral runner since the runner might already be deleted from the server side
|
||||||
|
// and the delete session call will ends up with 401.
|
||||||
|
Trace.Info($"Ignore any exception during DeleteSession for an ephemeral runner. {ex}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
messageQueueLoopTokenSource.Dispose();
|
messageQueueLoopTokenSource.Dispose();
|
||||||
@@ -561,7 +629,7 @@ Config Options:
|
|||||||
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
||||||
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
||||||
--replace Replace any existing runner with the same name (default false)
|
--replace Replace any existing runner with the same name (default false)
|
||||||
--pat GitHub personal access token used for checking network connectivity when executing `.{separator}run.{ext} --check`
|
--pat GitHub personal access token with repo scope. Used for checking network connectivity when executing `.{separator}run.{ext} --check`
|
||||||
--disableupdate Disable self-hosted runner automatic update to the latest released version`
|
--disableupdate Disable self-hosted runner automatic update to the latest released version`
|
||||||
--ephemeral Configure the runner to only take one job and then let the service un-configure the runner after the job finishes (default false)");
|
--ephemeral Configure the runner to only take one job and then let the service un-configure the runner after the job finishes (default false)");
|
||||||
|
|
||||||
|
|||||||
13
src/Runner.Listener/RunnerJobRequestRef.cs
Normal file
13
src/Runner.Listener/RunnerJobRequestRef.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Listener
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public sealed class RunnerJobRequestRef
|
||||||
|
{
|
||||||
|
[DataMember(Name = "id")]
|
||||||
|
public string Id { get; set; }
|
||||||
|
[DataMember(Name = "runner_request_id")]
|
||||||
|
public string RunnerRequestId { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -131,6 +131,8 @@ namespace GitHub.Runner.Listener
|
|||||||
// For L0, we will skip execute update script.
|
// For L0, we will skip execute update script.
|
||||||
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_GITHUB_ACTION_EXECUTE_UPDATE_SCRIPT")))
|
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_GITHUB_ACTION_EXECUTE_UPDATE_SCRIPT")))
|
||||||
{
|
{
|
||||||
|
string flagFile = "update.finished";
|
||||||
|
IOUtil.DeleteFile(flagFile);
|
||||||
// kick off update script
|
// kick off update script
|
||||||
Process invokeScript = new Process();
|
Process invokeScript = new Process();
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
@@ -294,12 +296,12 @@ namespace GitHub.Runner.Listener
|
|||||||
archiveFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), $"runner{targetVersion}.tar.gz");
|
archiveFile = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), $"runner{targetVersion}.tar.gz");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (File.Exists(archiveFile))
|
if (File.Exists(archiveFile))
|
||||||
{
|
{
|
||||||
_updateTrace.Enqueue($"Mocking update with file: '{archiveFile}' and targetVersion: '{targetVersion}', nothing is downloaded");
|
_updateTrace.Enqueue($"Mocking update with file: '{archiveFile}' and targetVersion: '{targetVersion}', nothing is downloaded");
|
||||||
_terminal.WriteLine($"Mocking update with file: '{archiveFile}' and targetVersion: '{targetVersion}', nothing is downloaded");
|
_terminal.WriteLine($"Mocking update with file: '{archiveFile}' and targetVersion: '{targetVersion}', nothing is downloaded");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
archiveFile = null;
|
archiveFile = null;
|
||||||
_terminal.WriteLine($"Mock runner archive not found at {archiveFile} for target version {targetVersion}, proceeding with download instead");
|
_terminal.WriteLine($"Mock runner archive not found at {archiveFile} for target version {targetVersion}, proceeding with download instead");
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.Loader;
|
using System.Runtime.Loader;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Actions.Pipelines.WebApi;
|
using GitHub.Actions.Pipelines.WebApi;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -9,7 +8,6 @@ using System.Threading.Tasks;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Plugins.Repository
|
namespace GitHub.Runner.Plugins.Repository
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -6,11 +6,9 @@ using System.Threading.Tasks;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Plugins.Repository.v1_0
|
namespace GitHub.Runner.Plugins.Repository.v1_0
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,12 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using GitHub.DistributedTask.Pipelines.Expressions;
|
using GitHub.DistributedTask.Pipelines.Expressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ using System.Collections.Generic;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using GitHub.DistributedTask.Pipelines.Expressions;
|
using GitHub.DistributedTask.Pipelines.Expressions;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -11,7 +10,6 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Sdk
|
namespace GitHub.Runner.Sdk
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,12 +3,12 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64;win-arm64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Sdk\Sdk.csproj" />
|
<ProjectReference Include="..\Sdk\Sdk.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using System.Collections.Concurrent;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -424,6 +423,12 @@ namespace GitHub.Runner.Sdk
|
|||||||
throw new NotSupportedException($"Unable to validate execute permissions for directory '{directory}'. Exceeded maximum iterations.");
|
throw new NotSupportedException($"Unable to validate execute permissions for directory '{directory}'. Exceeded maximum iterations.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void CreateEmptyFile(string path)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||||
|
File.WriteAllText(path, null);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Recursively enumerates a directory without following directory reparse points.
|
/// Recursively enumerates a directory without following directory reparse points.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
namespace GitHub.Runner.Sdk
|
namespace GitHub.Runner.Sdk
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace GitHub.Runner.Sdk
|
namespace GitHub.Runner.Sdk
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ namespace GitHub.Runner.Sdk
|
|||||||
settings.SendTimeout = TimeSpan.FromSeconds(Math.Min(Math.Max(httpRequestTimeoutSeconds, 100), 1200));
|
settings.SendTimeout = TimeSpan.FromSeconds(Math.Min(Math.Max(httpRequestTimeoutSeconds, 100), 1200));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("USE_BROKER_FLOW")))
|
||||||
|
{
|
||||||
|
settings.AllowAutoRedirect = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove Invariant from the list of accepted languages.
|
// Remove Invariant from the list of accepted languages.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Sdk
|
namespace GitHub.Runner.Sdk
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8" ?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<startup>
|
<startup>
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
|
||||||
</startup>
|
</startup>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
6
src/Runner.Service/Windows/AppARM.config
Normal file
6
src/Runner.Service/Windows/AppARM.config
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
||||||
@@ -11,10 +11,15 @@
|
|||||||
<AssemblyName>RunnerService</AssemblyName>
|
<AssemblyName>RunnerService</AssemblyName>
|
||||||
<SignAssembly>false</SignAssembly>
|
<SignAssembly>false</SignAssembly>
|
||||||
<DelaySign>false</DelaySign>
|
<DelaySign>false</DelaySign>
|
||||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
<FileAlignment>512</FileAlignment>
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(PackageRuntime)' == 'win-arm64' ">
|
||||||
|
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(PackageRuntime)' != 'win-arm64' ">
|
||||||
|
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
<DebugSymbols>true</DebugSymbols>
|
<DebugSymbols>true</DebugSymbols>
|
||||||
@@ -61,7 +66,10 @@
|
|||||||
<DependentUpon>Resource.resx</DependentUpon>
|
<DependentUpon>Resource.resx</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup Condition=" '$(Platform)' == 'ARM' ">
|
||||||
|
<None Include="AppARM.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup Condition=" '$(Platform)' != 'ARM' ">
|
||||||
<None Include="App.config" />
|
<None Include="App.config" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -71,7 +79,7 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
<Target Name="BeforeBuild">
|
<Target Name="BeforeBuild">
|
||||||
</Target>
|
</Target>
|
||||||
|
|||||||
@@ -307,6 +307,17 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
|
if (context.Global.Variables.GetBoolean("DistributedTask.DeprecateStepOutputCommands") ?? false)
|
||||||
|
{
|
||||||
|
var issue = new Issue()
|
||||||
|
{
|
||||||
|
Type = IssueType.Warning,
|
||||||
|
Message = String.Format(Constants.Runner.UnsupportedCommandMessage, this.Command)
|
||||||
|
};
|
||||||
|
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.UnsupportedCommand;
|
||||||
|
context.AddIssue(issue);
|
||||||
|
}
|
||||||
|
|
||||||
if (!command.Properties.TryGetValue(SetOutputCommandProperties.Name, out string outputName) || string.IsNullOrEmpty(outputName))
|
if (!command.Properties.TryGetValue(SetOutputCommandProperties.Name, out string outputName) || string.IsNullOrEmpty(outputName))
|
||||||
{
|
{
|
||||||
throw new Exception("Required field 'name' is missing in ##[set-output] command.");
|
throw new Exception("Required field 'name' is missing in ##[set-output] command.");
|
||||||
@@ -331,6 +342,17 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
|
if (context.Global.Variables.GetBoolean("DistributedTask.DeprecateStepOutputCommands") ?? false)
|
||||||
|
{
|
||||||
|
var issue = new Issue()
|
||||||
|
{
|
||||||
|
Type = IssueType.Warning,
|
||||||
|
Message = String.Format(Constants.Runner.UnsupportedCommandMessage, this.Command)
|
||||||
|
};
|
||||||
|
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.UnsupportedCommand;
|
||||||
|
context.AddIssue(issue);
|
||||||
|
}
|
||||||
|
|
||||||
if (!command.Properties.TryGetValue(SaveStateCommandProperties.Name, out string stateName) || string.IsNullOrEmpty(stateName))
|
if (!command.Properties.TryGetValue(SaveStateCommandProperties.Name, out string stateName) || string.IsNullOrEmpty(stateName))
|
||||||
{
|
{
|
||||||
throw new Exception("Required field 'name' is missing in ##[save-state] command.");
|
throw new Exception("Required field 'name' is missing in ##[save-state] command.");
|
||||||
@@ -585,6 +607,8 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string inputLine, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
|
ValidateLinesAndColumns(command, context);
|
||||||
|
|
||||||
command.Properties.TryGetValue(IssueCommandProperties.File, out string file);
|
command.Properties.TryGetValue(IssueCommandProperties.File, out string file);
|
||||||
command.Properties.TryGetValue(IssueCommandProperties.Line, out string line);
|
command.Properties.TryGetValue(IssueCommandProperties.Line, out string line);
|
||||||
command.Properties.TryGetValue(IssueCommandProperties.Column, out string column);
|
command.Properties.TryGetValue(IssueCommandProperties.Column, out string column);
|
||||||
|
|||||||
@@ -101,38 +101,41 @@ namespace GitHub.Runner.Worker
|
|||||||
IEnumerable<Pipelines.ActionStep> actions = steps.OfType<Pipelines.ActionStep>();
|
IEnumerable<Pipelines.ActionStep> actions = steps.OfType<Pipelines.ActionStep>();
|
||||||
executionContext.Output("Prepare all required actions");
|
executionContext.Output("Prepare all required actions");
|
||||||
var result = await PrepareActionsRecursiveAsync(executionContext, state, actions, depth, rootStepId);
|
var result = await PrepareActionsRecursiveAsync(executionContext, state, actions, depth, rootStepId);
|
||||||
if (state.ImagesToPull.Count > 0)
|
if (!FeatureManager.IsContainerHooksEnabled(executionContext.Global.Variables))
|
||||||
{
|
{
|
||||||
foreach (var imageToPull in result.ImagesToPull)
|
if (state.ImagesToPull.Count > 0)
|
||||||
{
|
{
|
||||||
Trace.Info($"{imageToPull.Value.Count} steps need to pull image '{imageToPull.Key}'");
|
foreach (var imageToPull in result.ImagesToPull)
|
||||||
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.PullActionContainerAsync,
|
{
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
Trace.Info($"{imageToPull.Value.Count} steps need to pull image '{imageToPull.Key}'");
|
||||||
displayName: $"Pull {imageToPull.Key}",
|
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.PullActionContainerAsync,
|
||||||
data: new ContainerSetupInfo(imageToPull.Value, imageToPull.Key)));
|
condition: $"{PipelineTemplateConstants.Success}()",
|
||||||
|
displayName: $"Pull {imageToPull.Key}",
|
||||||
|
data: new ContainerSetupInfo(imageToPull.Value, imageToPull.Key)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (result.ImagesToBuild.Count > 0)
|
if (result.ImagesToBuild.Count > 0)
|
||||||
{
|
|
||||||
foreach (var imageToBuild in result.ImagesToBuild)
|
|
||||||
{
|
{
|
||||||
var setupInfo = result.ImagesToBuildInfo[imageToBuild.Key];
|
foreach (var imageToBuild in result.ImagesToBuild)
|
||||||
Trace.Info($"{imageToBuild.Value.Count} steps need to build image from '{setupInfo.Dockerfile}'");
|
{
|
||||||
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.BuildActionContainerAsync,
|
var setupInfo = result.ImagesToBuildInfo[imageToBuild.Key];
|
||||||
condition: $"{PipelineTemplateConstants.Success}()",
|
Trace.Info($"{imageToBuild.Value.Count} steps need to build image from '{setupInfo.Dockerfile}'");
|
||||||
displayName: $"Build {setupInfo.ActionRepository}",
|
containerSetupSteps.Add(new JobExtensionRunner(runAsync: this.BuildActionContainerAsync,
|
||||||
data: new ContainerSetupInfo(imageToBuild.Value, setupInfo.Dockerfile, setupInfo.WorkingDirectory)));
|
condition: $"{PipelineTemplateConstants.Success}()",
|
||||||
|
displayName: $"Build {setupInfo.ActionRepository}",
|
||||||
|
data: new ContainerSetupInfo(imageToBuild.Value, setupInfo.Dockerfile, setupInfo.WorkingDirectory)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if !OS_LINUX
|
#if !OS_LINUX
|
||||||
if (containerSetupSteps.Count > 0)
|
if (containerSetupSteps.Count > 0)
|
||||||
{
|
{
|
||||||
executionContext.Output("Container action is only supported on Linux, skip pull and build docker images.");
|
executionContext.Output("Container action is only supported on Linux, skip pull and build docker images.");
|
||||||
containerSetupSteps.Clear();
|
containerSetupSteps.Clear();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
return new PrepareResult(containerSetupSteps, result.PreStepTracker);
|
return new PrepareResult(containerSetupSteps, result.PreStepTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -10,9 +10,6 @@ using GitHub.DistributedTask.ObjectTemplating.Schema;
|
|||||||
using GitHub.DistributedTask.ObjectTemplating;
|
using GitHub.DistributedTask.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using YamlDotNet.Core;
|
|
||||||
using YamlDotNet.Core.Events;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
@@ -503,7 +500,7 @@ namespace GitHub.Runner.Worker
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotSupportedException(nameof(ConvertRuns));
|
throw new NotSupportedException("Missing 'using' value. 'using' requires 'composite', 'docker', 'node12' or 'node16'.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConvertInputs(
|
private void ConvertInputs(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.ObjectTemplating;
|
using GitHub.DistributedTask.ObjectTemplating;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||||
@@ -158,8 +157,12 @@ namespace GitHub.Runner.Worker
|
|||||||
// Setup container stephost for running inside the container.
|
// Setup container stephost for running inside the container.
|
||||||
if (ExecutionContext.Global.Container != null)
|
if (ExecutionContext.Global.Container != null)
|
||||||
{
|
{
|
||||||
// Make sure required container is already created.
|
// Make sure the required container is already created
|
||||||
ArgUtil.NotNullOrEmpty(ExecutionContext.Global.Container.ContainerId, nameof(ExecutionContext.Global.Container.ContainerId));
|
// Container hooks do not necessarily set 'ContainerId'
|
||||||
|
if (!FeatureManager.IsContainerHooksEnabled(ExecutionContext.Global.Variables))
|
||||||
|
{
|
||||||
|
ArgUtil.NotNullOrEmpty(ExecutionContext.Global.Container.ContainerId, nameof(ExecutionContext.Global.Container.ContainerId));
|
||||||
|
}
|
||||||
var containerStepHost = HostContext.CreateService<IContainerStepHost>();
|
var containerStepHost = HostContext.CreateService<IContainerStepHost>();
|
||||||
containerStepHost.Container = ExecutionContext.Global.Container;
|
containerStepHost.Container = ExecutionContext.Global.Container;
|
||||||
stepHost = containerStepHost;
|
stepHost = containerStepHost;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Worker.Handlers;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Worker.Container.ContainerHooks
|
||||||
|
{
|
||||||
|
[ServiceLocator(Default = typeof(ContainerHookManager))]
|
||||||
|
public interface IContainerHookManager : IRunnerService
|
||||||
|
{
|
||||||
|
Task PrepareJobAsync(IExecutionContext context, List<ContainerInfo> containers);
|
||||||
|
Task RunContainerStepAsync(IExecutionContext context, ContainerInfo container, string dockerFile);
|
||||||
|
Task RunScriptStepAsync(IExecutionContext context, ContainerInfo container, string workingDirectory, string fileName, string arguments, IDictionary<string, string> environment, string prependPath);
|
||||||
|
Task CleanupJobAsync(IExecutionContext context, List<ContainerInfo> containers);
|
||||||
|
string GetContainerHookData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContainerHookManager : RunnerService, IContainerHookManager
|
||||||
|
{
|
||||||
|
private const string ResponseFolderName = "_runner_hook_responses";
|
||||||
|
private string HookScriptPath;
|
||||||
|
|
||||||
|
public override void Initialize(IHostContext hostContext)
|
||||||
|
{
|
||||||
|
base.Initialize(hostContext);
|
||||||
|
HookScriptPath = $"{Environment.GetEnvironmentVariable(Constants.Hooks.ContainerHooksPath)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task PrepareJobAsync(IExecutionContext context, List<ContainerInfo> containers)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
var jobContainer = containers.Where(c => c.IsJobContainer).SingleOrDefault();
|
||||||
|
var serviceContainers = containers.Where(c => !c.IsJobContainer).ToList();
|
||||||
|
|
||||||
|
var input = new HookInput
|
||||||
|
{
|
||||||
|
Command = HookCommand.PrepareJob,
|
||||||
|
ResponseFile = GenerateResponsePath(),
|
||||||
|
Args = new PrepareJobArgs
|
||||||
|
{
|
||||||
|
Container = jobContainer?.GetHookContainer(),
|
||||||
|
Services = serviceContainers.Select(c => c.GetHookContainer()).ToList(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var prependPath = GetPrependPath(context);
|
||||||
|
var response = await ExecuteHookScript<PrepareJobResponse>(context, input, ActionRunStage.Pre, prependPath);
|
||||||
|
if (jobContainer != null)
|
||||||
|
{
|
||||||
|
jobContainer.IsAlpine = response.IsAlpine.Value;
|
||||||
|
}
|
||||||
|
SaveHookState(context, response.State, input);
|
||||||
|
UpdateJobContext(context, jobContainer, serviceContainers, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunContainerStepAsync(IExecutionContext context, ContainerInfo container, string dockerFile)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
var hookState = context.Global.ContainerHookState;
|
||||||
|
var containerStepArgs = new ContainerStepArgs(container);
|
||||||
|
if (!string.IsNullOrEmpty(dockerFile))
|
||||||
|
{
|
||||||
|
containerStepArgs.Dockerfile = dockerFile;
|
||||||
|
containerStepArgs.Image = null;
|
||||||
|
}
|
||||||
|
var input = new HookInput
|
||||||
|
{
|
||||||
|
Args = containerStepArgs,
|
||||||
|
Command = HookCommand.RunContainerStep,
|
||||||
|
ResponseFile = GenerateResponsePath(),
|
||||||
|
State = hookState
|
||||||
|
};
|
||||||
|
|
||||||
|
var prependPath = GetPrependPath(context);
|
||||||
|
var response = await ExecuteHookScript<HookResponse>(context, input, ActionRunStage.Pre, prependPath);
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SaveHookState(context, response.State, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunScriptStepAsync(IExecutionContext context, ContainerInfo container, string workingDirectory, string entryPoint, string entryPointArgs, IDictionary<string, string> environmentVariables, string prependPath)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
var input = new HookInput
|
||||||
|
{
|
||||||
|
Command = HookCommand.RunScriptStep,
|
||||||
|
ResponseFile = GenerateResponsePath(),
|
||||||
|
Args = new ScriptStepArgs
|
||||||
|
{
|
||||||
|
EntryPointArgs = entryPointArgs.Split(' ').Select(arg => arg.Trim()),
|
||||||
|
EntryPoint = entryPoint,
|
||||||
|
EnvironmentVariables = environmentVariables,
|
||||||
|
PrependPath = context.Global.PrependPath.Reverse<string>(),
|
||||||
|
WorkingDirectory = workingDirectory,
|
||||||
|
},
|
||||||
|
State = context.Global.ContainerHookState
|
||||||
|
};
|
||||||
|
|
||||||
|
var response = await ExecuteHookScript<HookResponse>(context, input, ActionRunStage.Pre, prependPath);
|
||||||
|
|
||||||
|
if (response == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SaveHookState(context, response.State, input);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CleanupJobAsync(IExecutionContext context, List<ContainerInfo> containers)
|
||||||
|
{
|
||||||
|
Trace.Entering();
|
||||||
|
var input = new HookInput
|
||||||
|
{
|
||||||
|
Command = HookCommand.CleanupJob,
|
||||||
|
ResponseFile = GenerateResponsePath(),
|
||||||
|
Args = new CleanupJobArgs(),
|
||||||
|
State = context.Global.ContainerHookState
|
||||||
|
};
|
||||||
|
var prependPath = GetPrependPath(context);
|
||||||
|
await ExecuteHookScript<HookResponse>(context, input, ActionRunStage.Pre, prependPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetContainerHookData()
|
||||||
|
{
|
||||||
|
return JsonUtility.ToString(new { HookScriptPath });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<T> ExecuteHookScript<T>(IExecutionContext context, HookInput input, ActionRunStage stage, string prependPath) where T : HookResponse
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ValidateHookExecutable();
|
||||||
|
context.StepTelemetry.ContainerHookData = GetContainerHookData();
|
||||||
|
var scriptDirectory = Path.GetDirectoryName(HookScriptPath);
|
||||||
|
var stepHost = HostContext.CreateService<IDefaultStepHost>();
|
||||||
|
|
||||||
|
Dictionary<string, string> inputs = new()
|
||||||
|
{
|
||||||
|
["standardInInput"] = JsonUtility.ToString(input),
|
||||||
|
["path"] = HookScriptPath,
|
||||||
|
["shell"] = HostContext.GetDefaultShellForScript(HookScriptPath, prependPath)
|
||||||
|
};
|
||||||
|
var handlerFactory = HostContext.GetService<IHandlerFactory>();
|
||||||
|
var handler = handlerFactory.Create(
|
||||||
|
context,
|
||||||
|
null,
|
||||||
|
stepHost,
|
||||||
|
new ScriptActionExecutionData(),
|
||||||
|
inputs,
|
||||||
|
environment: new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
||||||
|
context.Global.Variables,
|
||||||
|
actionDirectory: scriptDirectory,
|
||||||
|
localActionContainerSetupSteps: null) as ScriptHandler;
|
||||||
|
handler.PrepareExecution(stage);
|
||||||
|
|
||||||
|
IOUtil.CreateEmptyFile(input.ResponseFile);
|
||||||
|
await handler.RunAsync(stage);
|
||||||
|
if (handler.ExecutionContext.Result == TaskResult.Failed)
|
||||||
|
{
|
||||||
|
throw new Exception($"The hook script at '{HookScriptPath}' running command '{input.Command}' did not execute successfully");
|
||||||
|
}
|
||||||
|
var response = GetResponse<T>(input);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"Executing the custom container implementation failed. Please contact your self hosted runner administrator.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateResponsePath() => Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), ResponseFolderName, $"{Guid.NewGuid()}.json");
|
||||||
|
|
||||||
|
private static string GetPrependPath(IExecutionContext context) => string.Join(Path.PathSeparator.ToString(), context.Global.PrependPath.Reverse<string>());
|
||||||
|
|
||||||
|
private void ValidateHookExecutable()
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(HookScriptPath) && !File.Exists(HookScriptPath))
|
||||||
|
{
|
||||||
|
throw new FileNotFoundException($"File not found at '{HookScriptPath}'. Set {Constants.Hooks.ContainerHooksPath} to the path of an existing file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var supportedHookExtensions = new string[] { ".js", ".sh", ".ps1" };
|
||||||
|
if (!supportedHookExtensions.Any(extension => HookScriptPath.EndsWith(extension)))
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException($"Invalid file extension at '{HookScriptPath}'. {Constants.Hooks.ContainerHooksPath} must be a path to a file with one of the following extensions: {string.Join(", ", supportedHookExtensions)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private T GetResponse<T>(HookInput input) where T : HookResponse
|
||||||
|
{
|
||||||
|
if (!File.Exists(input.ResponseFile))
|
||||||
|
{
|
||||||
|
Trace.Info($"Response file for the hook script at '{HookScriptPath}' running command '{input.Command}' not found.");
|
||||||
|
if (input.Args.IsRequireAlpineInResponse())
|
||||||
|
{
|
||||||
|
throw new Exception($"Response file is required but not found for the hook script at '{HookScriptPath}' running command '{input.Command}'");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
T response = IOUtil.LoadObject<T>(input.ResponseFile);
|
||||||
|
Trace.Info($"Response file for the hook script at '{HookScriptPath}' running command '{input.Command}' was processed successfully");
|
||||||
|
IOUtil.DeleteFile(input.ResponseFile);
|
||||||
|
Trace.Info($"Response file for the hook script at '{HookScriptPath}' running command '{input.Command}' was deleted successfully");
|
||||||
|
if (response == null && input.Args.IsRequireAlpineInResponse())
|
||||||
|
{
|
||||||
|
throw new Exception($"Response file could not be read at '{HookScriptPath}' running command '{input.Command}'");
|
||||||
|
}
|
||||||
|
response?.Validate(input);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SaveHookState(IExecutionContext context, JObject hookState, HookInput input)
|
||||||
|
{
|
||||||
|
if (hookState == null)
|
||||||
|
{
|
||||||
|
Trace.Info($"No 'state' property found in response file for '{input.Command}'. Global variable for 'ContainerHookState' will not be updated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.Global.ContainerHookState = hookState;
|
||||||
|
Trace.Info($"Global variable 'ContainerHookState' updated successfully for '{input.Command}' with data found in 'state' property of the response file.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateJobContext(IExecutionContext context, ContainerInfo jobContainer, List<ContainerInfo> serviceContainers, PrepareJobResponse response)
|
||||||
|
{
|
||||||
|
if (response.Context == null)
|
||||||
|
{
|
||||||
|
Trace.Info($"The response file does not contain a context. The fields 'jobContext.Container' and 'jobContext.Services' will not be set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var containerId = response.Context.Container?.Id;
|
||||||
|
if (containerId != null)
|
||||||
|
{
|
||||||
|
context.JobContext.Container["id"] = new StringContextData(containerId);
|
||||||
|
jobContainer.ContainerId = containerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
var containerNetwork = response.Context.Container?.Network;
|
||||||
|
if (containerNetwork != null)
|
||||||
|
{
|
||||||
|
context.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
||||||
|
jobContainer.ContainerNetwork = containerNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i = 0; i < response.Context.Services.Count; i++)
|
||||||
|
{
|
||||||
|
var responseContainerInfo = response.Context.Services[i];
|
||||||
|
var globalContainerInfo = serviceContainers[i];
|
||||||
|
globalContainerInfo.ContainerId = responseContainerInfo.Id;
|
||||||
|
globalContainerInfo.ContainerNetwork = responseContainerInfo.Network;
|
||||||
|
|
||||||
|
var service = new DictionaryContextData()
|
||||||
|
{
|
||||||
|
["id"] = new StringContextData(responseContainerInfo.Id),
|
||||||
|
["ports"] = new DictionaryContextData(),
|
||||||
|
["network"] = new StringContextData(responseContainerInfo.Network)
|
||||||
|
};
|
||||||
|
|
||||||
|
globalContainerInfo.AddPortMappings(responseContainerInfo.Ports);
|
||||||
|
foreach (var portMapping in responseContainerInfo.Ports)
|
||||||
|
{
|
||||||
|
(service["ports"] as DictionaryContextData)[portMapping.Key] = new StringContextData(portMapping.Value);
|
||||||
|
}
|
||||||
|
context.JobContext.Services[globalContainerInfo.ContainerNetworkAlias] = service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
113
src/Runner.Worker/Container/ContainerHooks/HookInput.cs
Normal file
113
src/Runner.Worker/Container/ContainerHooks/HookInput.cs
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Converters;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Worker.Container.ContainerHooks
|
||||||
|
{
|
||||||
|
public class HookInput
|
||||||
|
{
|
||||||
|
public HookCommand Command { get; set; }
|
||||||
|
public string ResponseFile { get; set; }
|
||||||
|
public IHookArgs Args { get; set; }
|
||||||
|
public JObject State { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonConverter(typeof(StringEnumConverter))]
|
||||||
|
public enum HookCommand
|
||||||
|
{
|
||||||
|
[EnumMember(Value = "prepare_job")]
|
||||||
|
PrepareJob,
|
||||||
|
[EnumMember(Value = "cleanup_job")]
|
||||||
|
CleanupJob,
|
||||||
|
[EnumMember(Value = "run_script_step")]
|
||||||
|
RunScriptStep,
|
||||||
|
[EnumMember(Value = "run_container_step")]
|
||||||
|
RunContainerStep,
|
||||||
|
}
|
||||||
|
public interface IHookArgs
|
||||||
|
{
|
||||||
|
bool IsRequireAlpineInResponse();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PrepareJobArgs : IHookArgs
|
||||||
|
{
|
||||||
|
public HookContainer Container { get; set; }
|
||||||
|
public IList<HookContainer> Services { get; set; }
|
||||||
|
public bool IsRequireAlpineInResponse() => Container != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ScriptStepArgs : IHookArgs
|
||||||
|
{
|
||||||
|
public IEnumerable<string> EntryPointArgs { get; set; }
|
||||||
|
public string EntryPoint { get; set; }
|
||||||
|
public IDictionary<string, string> EnvironmentVariables { get; set; }
|
||||||
|
public IEnumerable<string> PrependPath { get; set; }
|
||||||
|
public string WorkingDirectory { get; set; }
|
||||||
|
public bool IsRequireAlpineInResponse() => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContainerStepArgs : HookContainer, IHookArgs
|
||||||
|
{
|
||||||
|
public bool IsRequireAlpineInResponse() => false;
|
||||||
|
public ContainerStepArgs(ContainerInfo container) : base(container) { }
|
||||||
|
}
|
||||||
|
public class CleanupJobArgs : IHookArgs
|
||||||
|
{
|
||||||
|
public bool IsRequireAlpineInResponse() => false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ContainerRegistry
|
||||||
|
{
|
||||||
|
public string Username { get; set; }
|
||||||
|
public string Password { get; set; }
|
||||||
|
public string ServerUrl { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HookContainer
|
||||||
|
{
|
||||||
|
public string Image { get; set; }
|
||||||
|
public string Dockerfile { get; set; }
|
||||||
|
public IEnumerable<string> EntryPointArgs { get; set; } = new List<string>();
|
||||||
|
public string EntryPoint { get; set; }
|
||||||
|
public string WorkingDirectory { get; set; }
|
||||||
|
public string CreateOptions { get; private set; }
|
||||||
|
public ContainerRegistry Registry { get; set; }
|
||||||
|
public IDictionary<string, string> EnvironmentVariables { get; set; } = new Dictionary<string, string>();
|
||||||
|
public IEnumerable<string> PortMappings { get; set; } = new List<string>();
|
||||||
|
public IEnumerable<MountVolume> SystemMountVolumes { get; set; } = new List<MountVolume>();
|
||||||
|
public IEnumerable<MountVolume> UserMountVolumes { get; set; } = new List<MountVolume>();
|
||||||
|
public HookContainer() { } // For Json deserializer
|
||||||
|
public HookContainer(ContainerInfo container)
|
||||||
|
{
|
||||||
|
Image = container.ContainerImage;
|
||||||
|
EntryPointArgs = container.ContainerEntryPointArgs?.Split(' ').Select(arg => arg.Trim()) ?? new List<string>();
|
||||||
|
EntryPoint = container.ContainerEntryPoint;
|
||||||
|
WorkingDirectory = container.ContainerWorkDirectory;
|
||||||
|
CreateOptions = container.ContainerCreateOptions;
|
||||||
|
if (!string.IsNullOrEmpty(container.RegistryAuthUsername))
|
||||||
|
{
|
||||||
|
Registry = new ContainerRegistry
|
||||||
|
{
|
||||||
|
Username = container.RegistryAuthUsername,
|
||||||
|
Password = container.RegistryAuthPassword,
|
||||||
|
ServerUrl = container.RegistryServer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
EnvironmentVariables = container.ContainerEnvironmentVariables;
|
||||||
|
PortMappings = container.UserPortMappings.Select(p => p.Value).ToList();
|
||||||
|
SystemMountVolumes = container.SystemMountVolumes;
|
||||||
|
UserMountVolumes = container.UserMountVolumes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ContainerInfoExtensions
|
||||||
|
{
|
||||||
|
public static HookContainer GetHookContainer(this ContainerInfo containerInfo)
|
||||||
|
{
|
||||||
|
return new HookContainer(containerInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
src/Runner.Worker/Container/ContainerHooks/HookResponse.cs
Normal file
37
src/Runner.Worker/Container/ContainerHooks/HookResponse.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Worker.Container.ContainerHooks
|
||||||
|
{
|
||||||
|
public class HookResponse
|
||||||
|
{
|
||||||
|
public JObject State { get; set; }
|
||||||
|
public virtual void Validate(HookInput input) { }
|
||||||
|
}
|
||||||
|
public class PrepareJobResponse : HookResponse
|
||||||
|
{
|
||||||
|
public ResponseContext Context { get; set; }
|
||||||
|
public bool? IsAlpine { get; set; }
|
||||||
|
|
||||||
|
public override void Validate(HookInput input)
|
||||||
|
{
|
||||||
|
bool hasJobContainer = ((PrepareJobArgs)input.Args).Container != null;
|
||||||
|
if (hasJobContainer && IsAlpine == null)
|
||||||
|
{
|
||||||
|
throw new Exception("The property 'isAlpine' is required but was not found in the response file.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class ResponseContext
|
||||||
|
{
|
||||||
|
public ResponseContainer Container { get; set; }
|
||||||
|
public IList<ResponseContainer> Services { get; set; } = new List<ResponseContainer>();
|
||||||
|
}
|
||||||
|
public class ResponseContainer
|
||||||
|
{
|
||||||
|
public string Id { get; set; }
|
||||||
|
public string Network { get; set; }
|
||||||
|
public IDictionary<string, string> Ports { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -90,6 +90,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
public string RegistryAuthUsername { get; set; }
|
public string RegistryAuthUsername { get; set; }
|
||||||
public string RegistryAuthPassword { get; set; }
|
public string RegistryAuthPassword { get; set; }
|
||||||
public bool IsJobContainer { get; set; }
|
public bool IsJobContainer { get; set; }
|
||||||
|
public bool IsAlpine { get; set; }
|
||||||
|
|
||||||
public IDictionary<string, string> ContainerEnvironmentVariables
|
public IDictionary<string, string> ContainerEnvironmentVariables
|
||||||
{
|
{
|
||||||
@@ -232,6 +233,14 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddPortMappings(IDictionary<string, string> portMappings)
|
||||||
|
{
|
||||||
|
foreach (var pair in portMappings)
|
||||||
|
{
|
||||||
|
PortMappings.Add(new PortMapping(pair.Key, pair.Value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void AddPathTranslateMapping(string hostCommonPath, string containerCommonPath)
|
public void AddPathTranslateMapping(string hostCommonPath, string containerCommonPath)
|
||||||
{
|
{
|
||||||
_pathMappings.Insert(0, new PathMapping(hostCommonPath, containerCommonPath));
|
_pathMappings.Insert(0, new PathMapping(hostCommonPath, containerCommonPath));
|
||||||
@@ -322,6 +331,12 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
|
|
||||||
public class PortMapping
|
public class PortMapping
|
||||||
{
|
{
|
||||||
|
public PortMapping(string hostPort, string containerPort)
|
||||||
|
{
|
||||||
|
this.HostPort = hostPort;
|
||||||
|
this.ContainerPort = containerPort;
|
||||||
|
}
|
||||||
|
|
||||||
public PortMapping(string hostPort, string containerPort, string protocol)
|
public PortMapping(string hostPort, string containerPort, string protocol)
|
||||||
{
|
{
|
||||||
this.HostPort = hostPort;
|
this.HostPort = hostPort;
|
||||||
|
|||||||
@@ -131,11 +131,11 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
{
|
{
|
||||||
if (String.IsNullOrEmpty(env.Value))
|
if (String.IsNullOrEmpty(env.Value))
|
||||||
{
|
{
|
||||||
dockerOptions.Add($"-e \"{env.Key}\"");
|
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dockerOptions.Add($"-e \"{env.Key}={env.Value.Replace("\"", "\\\"")}\"");
|
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key, env.Value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
{
|
{
|
||||||
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
||||||
// the value directly in the command
|
// the value directly in the command
|
||||||
dockerOptions.Add($"-e {env.Key}");
|
dockerOptions.Add(DockerUtil.CreateEscapedOption("-e", env.Key));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watermark for GitHub Action environment
|
// Watermark for GitHub Action environment
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
{
|
{
|
||||||
public class DockerUtil
|
public class DockerUtil
|
||||||
{
|
{
|
||||||
|
private static readonly Regex QuoteEscape = new Regex(@"(\\*)" + "\"", RegexOptions.Compiled);
|
||||||
|
private static readonly Regex EndOfStringEscape = new Regex(@"(\\+)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
public static List<PortMapping> ParseDockerPort(IList<string> portMappingLines)
|
public static List<PortMapping> ParseDockerPort(IList<string> portMappingLines)
|
||||||
{
|
{
|
||||||
const string targetPort = "targetPort";
|
const string targetPort = "targetPort";
|
||||||
@@ -17,7 +20,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
string pattern = $"^(?<{targetPort}>\\d+)/(?<{proto}>\\w+) -> (?<{host}>.+):(?<{hostPort}>\\d+)$";
|
string pattern = $"^(?<{targetPort}>\\d+)/(?<{proto}>\\w+) -> (?<{host}>.+):(?<{hostPort}>\\d+)$";
|
||||||
|
|
||||||
List<PortMapping> portMappings = new List<PortMapping>();
|
List<PortMapping> portMappings = new List<PortMapping>();
|
||||||
foreach(var line in portMappingLines)
|
foreach (var line in portMappingLines)
|
||||||
{
|
{
|
||||||
Match m = Regex.Match(line, pattern, RegexOptions.None, TimeSpan.FromSeconds(1));
|
Match m = Regex.Match(line, pattern, RegexOptions.None, TimeSpan.FromSeconds(1));
|
||||||
if (m.Success)
|
if (m.Success)
|
||||||
@@ -61,5 +64,44 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string CreateEscapedOption(string flag, string key)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return $"{flag} {EscapeString(key)}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CreateEscapedOption(string flag, string key, string value)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(key))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
var escapedString = EscapeString($"{key}={value}");
|
||||||
|
return $"{flag} {escapedString}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string EscapeString(string value)
|
||||||
|
{
|
||||||
|
if (String.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
// Dotnet escaping rules are weird here, we can only escape \ if it precedes a "
|
||||||
|
// If a double quotation mark follows two or an even number of backslashes, each proceeding backslash pair is replaced with one backslash and the double quotation mark is removed.
|
||||||
|
// If a double quotation mark follows an odd number of backslashes, including just one, each preceding pair is replaced with one backslash and the remaining backslash is removed; however, in this case the double quotation mark is not removed.
|
||||||
|
// https://docs.microsoft.com/en-us/dotnet/api/system.environment.getcommandlineargs?redirectedfrom=MSDN&view=net-6.0#remarks
|
||||||
|
|
||||||
|
// First, find any \ followed by a " and double the number of \ + 1.
|
||||||
|
value = QuoteEscape.Replace(value, @"$1$1\" + "\"");
|
||||||
|
// Next, what if it ends in `\`, it would escape the end quote. So, we need to detect that at the end of the string and perform the same escape
|
||||||
|
// Luckily, we can just use the $ character with detects the end of string in regex
|
||||||
|
value = EndOfStringEscape.Replace(value, @"$1$1");
|
||||||
|
// Finally, wrap it in quotes
|
||||||
|
return $"\"{value}\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.ServiceProcess;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -10,8 +9,12 @@ using GitHub.Services.Common;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using Microsoft.Win32;
|
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
|
#if OS_WINDOWS // keep win specific imports around even through we don't support containers on win at the moment
|
||||||
|
using System.ServiceProcess;
|
||||||
|
using Microsoft.Win32;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -25,11 +28,13 @@ namespace GitHub.Runner.Worker
|
|||||||
public class ContainerOperationProvider : RunnerService, IContainerOperationProvider
|
public class ContainerOperationProvider : RunnerService, IContainerOperationProvider
|
||||||
{
|
{
|
||||||
private IDockerCommandManager _dockerManager;
|
private IDockerCommandManager _dockerManager;
|
||||||
|
private IContainerHookManager _containerHookManager;
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
_dockerManager = HostContext.GetService<IDockerCommandManager>();
|
_dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
|
_containerHookManager = HostContext.GetService<IContainerHookManager>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
||||||
@@ -50,72 +55,15 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
||||||
executionContext.RegisterPostJobStep(postJobStep);
|
executionContext.RegisterPostJobStep(postJobStep);
|
||||||
|
if (FeatureManager.IsContainerHooksEnabled(executionContext.Global.Variables))
|
||||||
// Check whether we are inside a container.
|
|
||||||
// Our container feature requires to map working directory from host to the container.
|
|
||||||
// If we are already inside a container, we will not able to find out the real working direcotry path on the host.
|
|
||||||
#if OS_WINDOWS
|
|
||||||
#pragma warning disable CA1416
|
|
||||||
// service CExecSvc is Container Execution Agent.
|
|
||||||
ServiceController[] scServices = ServiceController.GetServices();
|
|
||||||
if (scServices.Any(x => String.Equals(x.ServiceName, "cexecsvc", StringComparison.OrdinalIgnoreCase) && x.Status == ServiceControllerStatus.Running))
|
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
// Initialize the containers
|
||||||
}
|
containers.ForEach(container => UpdateRegistryAuthForGitHubToken(executionContext, container));
|
||||||
#pragma warning restore CA1416
|
containers.Where(container => container.IsJobContainer).ForEach(container => MountWellKnownDirectories(executionContext, container));
|
||||||
#else
|
await _containerHookManager.PrepareJobAsync(executionContext, containers);
|
||||||
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
return;
|
||||||
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
#pragma warning disable CA1416
|
|
||||||
// Check OS version (Windows server 1803 is required)
|
|
||||||
object windowsInstallationType = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "InstallationType", defaultValue: null);
|
|
||||||
ArgUtil.NotNull(windowsInstallationType, nameof(windowsInstallationType));
|
|
||||||
object windowsReleaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", defaultValue: null);
|
|
||||||
ArgUtil.NotNull(windowsReleaseId, nameof(windowsReleaseId));
|
|
||||||
executionContext.Debug($"Current Windows version: '{windowsReleaseId} ({windowsInstallationType})'");
|
|
||||||
|
|
||||||
if (int.TryParse(windowsReleaseId.ToString(), out int releaseId))
|
|
||||||
{
|
|
||||||
if (!windowsInstallationType.ToString().StartsWith("Server", StringComparison.OrdinalIgnoreCase) || releaseId < 1803)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("Container feature requires Windows Server 1803 or higher.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new ArgumentOutOfRangeException(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseId");
|
|
||||||
}
|
|
||||||
#pragma warning restore CA1416
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Check docker client/server version
|
|
||||||
executionContext.Output("##[group]Checking docker version");
|
|
||||||
DockerVersion dockerVersion = await _dockerManager.DockerVersion(executionContext);
|
|
||||||
executionContext.Output("##[endgroup]");
|
|
||||||
|
|
||||||
ArgUtil.NotNull(dockerVersion.ServerVersion, nameof(dockerVersion.ServerVersion));
|
|
||||||
ArgUtil.NotNull(dockerVersion.ClientVersion, nameof(dockerVersion.ClientVersion));
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
Version requiredDockerEngineAPIVersion = new Version(1, 30); // Docker-EE version 17.6
|
|
||||||
#else
|
|
||||||
Version requiredDockerEngineAPIVersion = new Version(1, 35); // Docker-CE version 17.12
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (dockerVersion.ServerVersion < requiredDockerEngineAPIVersion)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException($"Min required docker engine API server version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') server version is '{dockerVersion.ServerVersion}'");
|
|
||||||
}
|
|
||||||
if (dockerVersion.ClientVersion < requiredDockerEngineAPIVersion)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException($"Min required docker engine API client version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') client version is '{dockerVersion.ClientVersion}'");
|
|
||||||
}
|
}
|
||||||
|
await AssertCompatibleOS(executionContext);
|
||||||
|
|
||||||
// Clean up containers left by previous runs
|
// Clean up containers left by previous runs
|
||||||
executionContext.Output("##[group]Clean up resources from previous jobs");
|
executionContext.Output("##[group]Clean up resources from previous jobs");
|
||||||
@@ -166,6 +114,12 @@ namespace GitHub.Runner.Worker
|
|||||||
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
||||||
ArgUtil.NotNull(containers, nameof(containers));
|
ArgUtil.NotNull(containers, nameof(containers));
|
||||||
|
|
||||||
|
if (FeatureManager.IsContainerHooksEnabled(executionContext.Global.Variables))
|
||||||
|
{
|
||||||
|
await _containerHookManager.CleanupJobAsync(executionContext, containers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var container in containers)
|
foreach (var container in containers)
|
||||||
{
|
{
|
||||||
await StopContainerAsync(executionContext, container);
|
await StopContainerAsync(executionContext, container);
|
||||||
@@ -238,35 +192,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (container.IsJobContainer)
|
if (container.IsJobContainer)
|
||||||
{
|
{
|
||||||
// Configure job container - Mount workspace and tools, set up environment, and start long running process
|
MountWellKnownDirectories(executionContext, container);
|
||||||
var githubContext = executionContext.ExpressionValues["github"] as GitHubContext;
|
|
||||||
ArgUtil.NotNull(githubContext, nameof(githubContext));
|
|
||||||
var workingDirectory = githubContext["workspace"] as StringContextData;
|
|
||||||
ArgUtil.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Work), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Work))));
|
|
||||||
#if OS_WINDOWS
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals))));
|
|
||||||
#else
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
|
||||||
#endif
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Temp), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Temp))));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Actions), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Actions))));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Tools), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Tools))));
|
|
||||||
|
|
||||||
var tempHomeDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_home");
|
|
||||||
Directory.CreateDirectory(tempHomeDirectory);
|
|
||||||
container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home"));
|
|
||||||
container.AddPathTranslateMapping(tempHomeDirectory, "/github/home");
|
|
||||||
container.ContainerEnvironmentVariables["HOME"] = container.TranslateToContainerPath(tempHomeDirectory);
|
|
||||||
|
|
||||||
var tempWorkflowDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_workflow");
|
|
||||||
Directory.CreateDirectory(tempWorkflowDirectory);
|
|
||||||
container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow"));
|
|
||||||
container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow");
|
|
||||||
|
|
||||||
container.ContainerWorkDirectory = container.TranslateToContainerPath(workingDirectory);
|
|
||||||
container.ContainerEntryPoint = "tail";
|
|
||||||
container.ContainerEntryPointArgs = "\"-f\" \"/dev/null\"";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
container.ContainerId = await _dockerManager.DockerCreate(executionContext, container);
|
container.ContainerId = await _dockerManager.DockerCreate(executionContext, container);
|
||||||
@@ -329,6 +255,42 @@ namespace GitHub.Runner.Worker
|
|||||||
executionContext.Output("##[endgroup]");
|
executionContext.Output("##[endgroup]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MountWellKnownDirectories(IExecutionContext executionContext, ContainerInfo container)
|
||||||
|
{
|
||||||
|
// Configure job container - Mount workspace and tools, set up environment, and start long running process
|
||||||
|
var githubContext = executionContext.ExpressionValues["github"] as GitHubContext;
|
||||||
|
ArgUtil.NotNull(githubContext, nameof(githubContext));
|
||||||
|
var workingDirectory = githubContext["workspace"] as StringContextData;
|
||||||
|
ArgUtil.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Work), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Work))));
|
||||||
|
#if OS_WINDOWS
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals))));
|
||||||
|
#else
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
||||||
|
#endif
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Temp), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Temp))));
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Actions), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Actions))));
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Tools), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Tools))));
|
||||||
|
|
||||||
|
var tempHomeDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_home");
|
||||||
|
Directory.CreateDirectory(tempHomeDirectory);
|
||||||
|
container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home"));
|
||||||
|
container.AddPathTranslateMapping(tempHomeDirectory, "/github/home");
|
||||||
|
container.ContainerEnvironmentVariables["HOME"] = container.TranslateToContainerPath(tempHomeDirectory);
|
||||||
|
|
||||||
|
var tempWorkflowDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_workflow");
|
||||||
|
Directory.CreateDirectory(tempWorkflowDirectory);
|
||||||
|
container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow"));
|
||||||
|
container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow");
|
||||||
|
|
||||||
|
container.ContainerWorkDirectory = container.TranslateToContainerPath(workingDirectory);
|
||||||
|
if (!FeatureManager.IsContainerHooksEnabled(executionContext.Global.Variables))
|
||||||
|
{
|
||||||
|
container.ContainerEntryPoint = "tail";
|
||||||
|
container.ContainerEntryPointArgs = "\"-f\" \"/dev/null\"";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task StopContainerAsync(IExecutionContext executionContext, ContainerInfo container)
|
private async Task StopContainerAsync(IExecutionContext executionContext, ContainerInfo container)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
@@ -337,11 +299,11 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(container.ContainerId))
|
if (!string.IsNullOrEmpty(container.ContainerId))
|
||||||
{
|
{
|
||||||
if(!container.IsJobContainer)
|
if (!container.IsJobContainer)
|
||||||
{
|
{
|
||||||
// Print logs for service container jobs (not the "action" job itself b/c that's already logged).
|
// Print logs for service container jobs (not the "action" job itself b/c that's already logged).
|
||||||
executionContext.Output($"Print service container logs: {container.ContainerDisplayName}");
|
executionContext.Output($"Print service container logs: {container.ContainerDisplayName}");
|
||||||
|
|
||||||
int logsExitCode = await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
int logsExitCode = await _dockerManager.DockerLogs(executionContext, container.ContainerId);
|
||||||
if (logsExitCode != 0)
|
if (logsExitCode != 0)
|
||||||
{
|
{
|
||||||
@@ -522,5 +484,74 @@ namespace GitHub.Runner.Worker
|
|||||||
container.RegistryAuthPassword = executionContext.GetGitHubContext("token");
|
container.RegistryAuthPassword = executionContext.GetGitHubContext("token");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task AssertCompatibleOS(IExecutionContext executionContext)
|
||||||
|
{
|
||||||
|
// Check whether we are inside a container.
|
||||||
|
// Our container feature requires to map working directory from host to the container.
|
||||||
|
// If we are already inside a container, we will not able to find out the real working direcotry path on the host.
|
||||||
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
// service CExecSvc is Container Execution Agent.
|
||||||
|
ServiceController[] scServices = ServiceController.GetServices();
|
||||||
|
if (scServices.Any(x => String.Equals(x.ServiceName, "cexecsvc", StringComparison.OrdinalIgnoreCase) && x.Status == ServiceControllerStatus.Running))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||||
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
#else
|
||||||
|
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
||||||
|
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
|
// Check OS version (Windows server 1803 is required)
|
||||||
|
object windowsInstallationType = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "InstallationType", defaultValue: null);
|
||||||
|
ArgUtil.NotNull(windowsInstallationType, nameof(windowsInstallationType));
|
||||||
|
object windowsReleaseId = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion", "ReleaseId", defaultValue: null);
|
||||||
|
ArgUtil.NotNull(windowsReleaseId, nameof(windowsReleaseId));
|
||||||
|
executionContext.Debug($"Current Windows version: '{windowsReleaseId} ({windowsInstallationType})'");
|
||||||
|
|
||||||
|
if (int.TryParse(windowsReleaseId.ToString(), out int releaseId))
|
||||||
|
{
|
||||||
|
if (!windowsInstallationType.ToString().StartsWith("Server", StringComparison.OrdinalIgnoreCase) || releaseId < 1803)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Container feature requires Windows Server 1803 or higher.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ReleaseId");
|
||||||
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Check docker client/server version
|
||||||
|
executionContext.Output("##[group]Checking docker version");
|
||||||
|
DockerVersion dockerVersion = await _dockerManager.DockerVersion(executionContext);
|
||||||
|
executionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
|
ArgUtil.NotNull(dockerVersion.ServerVersion, nameof(dockerVersion.ServerVersion));
|
||||||
|
ArgUtil.NotNull(dockerVersion.ClientVersion, nameof(dockerVersion.ClientVersion));
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
Version requiredDockerEngineAPIVersion = new Version(1, 30); // Docker-EE version 17.6
|
||||||
|
#else
|
||||||
|
Version requiredDockerEngineAPIVersion = new Version(1, 35); // Docker-CE version 17.12
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (dockerVersion.ServerVersion < requiredDockerEngineAPIVersion)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Min required docker engine API server version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') server version is '{dockerVersion.ServerVersion}'");
|
||||||
|
}
|
||||||
|
if (dockerVersion.ClientVersion < requiredDockerEngineAPIVersion)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Min required docker engine API client version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') client version is '{dockerVersion.ClientVersion}'");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
bool IsEmbedded { get; }
|
bool IsEmbedded { get; }
|
||||||
|
|
||||||
|
List<string> StepEnvironmentOverrides { get; }
|
||||||
|
|
||||||
ExecutionContext Root { get; }
|
ExecutionContext Root { get; }
|
||||||
|
|
||||||
// Initialize
|
// Initialize
|
||||||
@@ -237,6 +239,8 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<string> StepEnvironmentOverrides { get; } = new List<string>();
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
@@ -365,6 +369,7 @@ namespace GitHub.Runner.Worker
|
|||||||
child.StepTelemetry.StepId = recordId;
|
child.StepTelemetry.StepId = recordId;
|
||||||
child.StepTelemetry.Stage = stage.ToString();
|
child.StepTelemetry.Stage = stage.ToString();
|
||||||
child.StepTelemetry.IsEmbedded = isEmbedded;
|
child.StepTelemetry.IsEmbedded = isEmbedded;
|
||||||
|
child.StepTelemetry.StepContextName = child.GetFullyQualifiedContextName(); ;
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -955,6 +960,8 @@ namespace GitHub.Runner.Worker
|
|||||||
_record.StartTime != null)
|
_record.StartTime != null)
|
||||||
{
|
{
|
||||||
StepTelemetry.ExecutionTimeInSeconds = (int)Math.Ceiling((_record.FinishTime - _record.StartTime)?.TotalSeconds ?? 0);
|
StepTelemetry.ExecutionTimeInSeconds = (int)Math.Ceiling((_record.FinishTime - _record.StartTime)?.TotalSeconds ?? 0);
|
||||||
|
StepTelemetry.StartTime = _record.StartTime;
|
||||||
|
StepTelemetry.FinishTime = _record.FinishTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsEmbedded &&
|
if (!IsEmbedded &&
|
||||||
@@ -1226,7 +1233,7 @@ namespace GitHub.Runner.Worker
|
|||||||
var value = dict[key].ToString();
|
var value = dict[key].ToString();
|
||||||
if (!string.IsNullOrEmpty(value))
|
if (!string.IsNullOrEmpty(value))
|
||||||
{
|
{
|
||||||
dict[key] = new StringContextData(stepHost.ResolvePathForStepHost(value));
|
dict[key] = new StringContextData(stepHost.ResolvePathForStepHost(context, value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (dict[key] is DictionaryContextData)
|
else if (dict[key] is DictionaryContextData)
|
||||||
|
|||||||
15
src/Runner.Worker/FeatureManager.cs
Normal file
15
src/Runner.Worker/FeatureManager.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
using GitHub.Runner.Common;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Worker
|
||||||
|
{
|
||||||
|
public class FeatureManager
|
||||||
|
{
|
||||||
|
public static bool IsContainerHooksEnabled(Variables variables)
|
||||||
|
{
|
||||||
|
var isContainerHookFeatureFlagSet = variables?.GetBoolean(Constants.Runner.Features.AllowRunnerContainerHooks) ?? false;
|
||||||
|
var isContainerHooksPathSet = !string.IsNullOrEmpty(Environment.GetEnvironmentVariable(Constants.Hooks.ContainerHooksPath));
|
||||||
|
return isContainerHookFeatureFlagSet && isContainerHooksPathSet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -68,7 +66,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
fileCommand.ProcessCommand(context, Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix),container);
|
fileCommand.ProcessCommand(context, Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix), container);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -118,7 +116,7 @@ namespace GitHub.Runner.Worker
|
|||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
var lines = File.ReadAllLines(filePath, Encoding.UTF8);
|
var lines = File.ReadAllLines(filePath, Encoding.UTF8);
|
||||||
foreach(var line in lines)
|
foreach (var line in lines)
|
||||||
{
|
{
|
||||||
if (line == string.Empty)
|
if (line == string.Empty)
|
||||||
{
|
{
|
||||||
@@ -140,74 +138,10 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
||||||
{
|
{
|
||||||
try
|
var pairs = new EnvFileKeyValuePairs(context, filePath);
|
||||||
|
foreach (var pair in pairs)
|
||||||
{
|
{
|
||||||
var text = File.ReadAllText(filePath) ?? string.Empty;
|
SetEnvironmentVariable(context, pair.Key, pair.Value);
|
||||||
var index = 0;
|
|
||||||
var line = ReadLine(text, ref index);
|
|
||||||
while (line != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(line))
|
|
||||||
{
|
|
||||||
var equalsIndex = line.IndexOf("=", StringComparison.Ordinal);
|
|
||||||
var heredocIndex = line.IndexOf("<<", StringComparison.Ordinal);
|
|
||||||
|
|
||||||
// Normal style NAME=VALUE
|
|
||||||
if (equalsIndex >= 0 && (heredocIndex < 0 || equalsIndex < heredocIndex))
|
|
||||||
{
|
|
||||||
var split = line.Split(new[] { '=' }, 2, StringSplitOptions.None);
|
|
||||||
if (string.IsNullOrEmpty(line))
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable format '{line}'. Environment variable name must not be empty");
|
|
||||||
}
|
|
||||||
SetEnvironmentVariable(context, split[0], split[1]);
|
|
||||||
}
|
|
||||||
// Heredoc style NAME<<EOF
|
|
||||||
else if (heredocIndex >= 0 && (equalsIndex < 0 || heredocIndex < equalsIndex))
|
|
||||||
{
|
|
||||||
var split = line.Split(new[] { "<<" }, 2, StringSplitOptions.None);
|
|
||||||
if (string.IsNullOrEmpty(split[0]) || string.IsNullOrEmpty(split[1]))
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable format '{line}'. Environment variable name must not be empty and delimiter must not be empty");
|
|
||||||
}
|
|
||||||
var name = split[0];
|
|
||||||
var delimiter = split[1];
|
|
||||||
var startIndex = index; // Start index of the value (inclusive)
|
|
||||||
var endIndex = index; // End index of the value (exclusive)
|
|
||||||
var tempLine = ReadLine(text, ref index, out var newline);
|
|
||||||
while (!string.Equals(tempLine, delimiter, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
if (tempLine == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable value. Matching delimiter not found '{delimiter}'");
|
|
||||||
}
|
|
||||||
if (newline == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable value. EOF marker missing new line.");
|
|
||||||
}
|
|
||||||
endIndex = index - newline.Length;
|
|
||||||
tempLine = ReadLine(text, ref index, out newline);
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = endIndex > startIndex ? text.Substring(startIndex, endIndex - startIndex) : string.Empty;
|
|
||||||
SetEnvironmentVariable(context, name, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable format '{line}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line = ReadLine(text, ref index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (DirectoryNotFoundException)
|
|
||||||
{
|
|
||||||
context.Debug($"Environment variables file does not exist '{filePath}'");
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException)
|
|
||||||
{
|
|
||||||
context.Debug($"Environment variables file does not exist '{filePath}'");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,48 +154,6 @@ namespace GitHub.Runner.Worker
|
|||||||
context.SetEnvContext(name, value);
|
context.SetEnvContext(name, value);
|
||||||
context.Debug($"{name}='{value}'");
|
context.Debug($"{name}='{value}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ReadLine(
|
|
||||||
string text,
|
|
||||||
ref int index)
|
|
||||||
{
|
|
||||||
return ReadLine(text, ref index, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadLine(
|
|
||||||
string text,
|
|
||||||
ref int index,
|
|
||||||
out string newline)
|
|
||||||
{
|
|
||||||
if (index >= text.Length)
|
|
||||||
{
|
|
||||||
newline = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var originalIndex = index;
|
|
||||||
var lfIndex = text.IndexOf("\n", index, StringComparison.Ordinal);
|
|
||||||
if (lfIndex < 0)
|
|
||||||
{
|
|
||||||
index = text.Length;
|
|
||||||
newline = null;
|
|
||||||
return text.Substring(originalIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
var crLFIndex = text.IndexOf("\r\n", index, StringComparison.Ordinal);
|
|
||||||
if (crLFIndex >= 0 && crLFIndex < lfIndex)
|
|
||||||
{
|
|
||||||
index = crLFIndex + 2; // Skip over CRLF
|
|
||||||
newline = "\r\n";
|
|
||||||
return text.Substring(originalIndex, crLFIndex - originalIndex);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
index = lfIndex + 1; // Skip over LF
|
|
||||||
newline = "\n";
|
|
||||||
return text.Substring(originalIndex, lfIndex - originalIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension
|
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension
|
||||||
@@ -275,12 +167,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
||||||
{
|
{
|
||||||
if (!context.Global.Variables.GetBoolean("DistributedTask.UploadStepSummary") ?? true)
|
|
||||||
{
|
|
||||||
Trace.Info("Step Summary is disabled; skipping attachment upload");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(filePath) || !File.Exists(filePath))
|
if (String.IsNullOrEmpty(filePath) || !File.Exists(filePath))
|
||||||
{
|
{
|
||||||
Trace.Info($"Step Summary file ({filePath}) does not exist; skipping attachment upload");
|
Trace.Info($"Step Summary file ({filePath}) does not exist; skipping attachment upload");
|
||||||
@@ -318,7 +204,9 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachmentName = context.Id.ToString();
|
var attachmentName = !context.IsEmbedded
|
||||||
|
? context.Id.ToString()
|
||||||
|
: context.EmbeddedId.ToString();
|
||||||
|
|
||||||
Trace.Info($"Queueing file ({filePath}) for attachment upload ({attachmentName})");
|
Trace.Info($"Queueing file ({filePath}) for attachment upload ({attachmentName})");
|
||||||
// Attachments must be added to the parent context (job), not the current context (step)
|
// Attachments must be added to the parent context (job), not the current context (step)
|
||||||
@@ -331,4 +219,200 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed class SaveStateFileCommand : RunnerService, IFileCommandExtension
|
||||||
|
{
|
||||||
|
public string ContextName => "state";
|
||||||
|
public string FilePrefix => "save_state_";
|
||||||
|
|
||||||
|
public Type ExtensionType => typeof(IFileCommandExtension);
|
||||||
|
|
||||||
|
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
||||||
|
{
|
||||||
|
var pairs = new EnvFileKeyValuePairs(context, filePath);
|
||||||
|
foreach (var pair in pairs)
|
||||||
|
{
|
||||||
|
// Embedded steps (composite) keep track of the state at the root level
|
||||||
|
if (context.IsEmbedded)
|
||||||
|
{
|
||||||
|
var id = context.EmbeddedId;
|
||||||
|
if (!context.Root.EmbeddedIntraActionState.ContainsKey(id))
|
||||||
|
{
|
||||||
|
context.Root.EmbeddedIntraActionState[id] = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
context.Root.EmbeddedIntraActionState[id][pair.Key] = pair.Value;
|
||||||
|
}
|
||||||
|
// Otherwise modify the ExecutionContext
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.IntraActionState[pair.Key] = pair.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Debug($"Save intra-action state {pair.Key} = {pair.Value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class SetOutputFileCommand : RunnerService, IFileCommandExtension
|
||||||
|
{
|
||||||
|
public string ContextName => "output";
|
||||||
|
public string FilePrefix => "set_output_";
|
||||||
|
|
||||||
|
public Type ExtensionType => typeof(IFileCommandExtension);
|
||||||
|
|
||||||
|
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
||||||
|
{
|
||||||
|
var pairs = new EnvFileKeyValuePairs(context, filePath);
|
||||||
|
foreach (var pair in pairs)
|
||||||
|
{
|
||||||
|
context.SetOutput(pair.Key, pair.Value, out var reference);
|
||||||
|
context.Debug($"Set output {pair.Key} = {pair.Value}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class EnvFileKeyValuePairs: IEnumerable<KeyValuePair<string, string>>
|
||||||
|
{
|
||||||
|
private IExecutionContext _context;
|
||||||
|
private string _filePath;
|
||||||
|
|
||||||
|
public EnvFileKeyValuePairs(IExecutionContext context, string filePath)
|
||||||
|
{
|
||||||
|
_context = context;
|
||||||
|
_filePath = filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<KeyValuePair<string, string>> GetEnumerator()
|
||||||
|
{
|
||||||
|
var text = string.Empty;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
text = File.ReadAllText(_filePath) ?? string.Empty;
|
||||||
|
}
|
||||||
|
catch (DirectoryNotFoundException)
|
||||||
|
{
|
||||||
|
_context.Debug($"File does not exist '{_filePath}'");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
_context.Debug($"File does not exist '{_filePath}'");
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var index = 0;
|
||||||
|
var line = ReadLine(text, ref index);
|
||||||
|
while (line != null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(line))
|
||||||
|
{
|
||||||
|
var key = string.Empty;
|
||||||
|
var output = string.Empty;
|
||||||
|
|
||||||
|
var equalsIndex = line.IndexOf("=", StringComparison.Ordinal);
|
||||||
|
var heredocIndex = line.IndexOf("<<", StringComparison.Ordinal);
|
||||||
|
|
||||||
|
// Normal style NAME=VALUE
|
||||||
|
if (equalsIndex >= 0 && (heredocIndex < 0 || equalsIndex < heredocIndex))
|
||||||
|
{
|
||||||
|
var split = line.Split(new[] { '=' }, 2, StringSplitOptions.None);
|
||||||
|
if (string.IsNullOrEmpty(line))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid format '{line}'. Name must not be empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
key = split[0];
|
||||||
|
output = split[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heredoc style NAME<<EOF
|
||||||
|
else if (heredocIndex >= 0 && (equalsIndex < 0 || heredocIndex < equalsIndex))
|
||||||
|
{
|
||||||
|
var split = line.Split(new[] { "<<" }, 2, StringSplitOptions.None);
|
||||||
|
if (string.IsNullOrEmpty(split[0]) || string.IsNullOrEmpty(split[1]))
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid format '{line}'. Name must not be empty and delimiter must not be empty");
|
||||||
|
}
|
||||||
|
key = split[0];
|
||||||
|
var delimiter = split[1];
|
||||||
|
var startIndex = index; // Start index of the value (inclusive)
|
||||||
|
var endIndex = index; // End index of the value (exclusive)
|
||||||
|
var tempLine = ReadLine(text, ref index, out var newline);
|
||||||
|
while (!string.Equals(tempLine, delimiter, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
if (tempLine == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid value. Matching delimiter not found '{delimiter}'");
|
||||||
|
}
|
||||||
|
if (newline == null)
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid value. EOF marker missing new line.");
|
||||||
|
}
|
||||||
|
endIndex = index - newline.Length;
|
||||||
|
tempLine = ReadLine(text, ref index, out newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
output = endIndex > startIndex ? text.Substring(startIndex, endIndex - startIndex) : string.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception($"Invalid format '{line}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return new KeyValuePair<string, string>(key, output);
|
||||||
|
}
|
||||||
|
|
||||||
|
line = ReadLine(text, ref index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Collections.IEnumerator
|
||||||
|
System.Collections.IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
// Invoke IEnumerator<KeyValuePair<string, string>> GetEnumerator() above.
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadLine(
|
||||||
|
string text,
|
||||||
|
ref int index)
|
||||||
|
{
|
||||||
|
return ReadLine(text, ref index, out _);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadLine(
|
||||||
|
string text,
|
||||||
|
ref int index,
|
||||||
|
out string newline)
|
||||||
|
{
|
||||||
|
if (index >= text.Length)
|
||||||
|
{
|
||||||
|
newline = null;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var originalIndex = index;
|
||||||
|
var lfIndex = text.IndexOf("\n", index, StringComparison.Ordinal);
|
||||||
|
if (lfIndex < 0)
|
||||||
|
{
|
||||||
|
index = text.Length;
|
||||||
|
newline = null;
|
||||||
|
return text.Substring(originalIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
var crLFIndex = text.IndexOf("\r\n", index, StringComparison.Ordinal);
|
||||||
|
if (crLFIndex >= 0 && crLFIndex < lfIndex)
|
||||||
|
{
|
||||||
|
index = crLFIndex + 2; // Skip over CRLF
|
||||||
|
newline = "\r\n";
|
||||||
|
return text.Substring(originalIndex, crLFIndex - originalIndex);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
index = lfIndex + 1; // Skip over LF
|
||||||
|
newline = "\n";
|
||||||
|
return text.Substring(originalIndex, lfIndex - originalIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ namespace GitHub.Runner.Worker
|
|||||||
"graphql_url",
|
"graphql_url",
|
||||||
"head_ref",
|
"head_ref",
|
||||||
"job",
|
"job",
|
||||||
|
"output",
|
||||||
"path",
|
"path",
|
||||||
"ref_name",
|
"ref_name",
|
||||||
"ref_protected",
|
"ref_protected",
|
||||||
@@ -34,6 +35,7 @@ namespace GitHub.Runner.Worker
|
|||||||
"run_number",
|
"run_number",
|
||||||
"server_url",
|
"server_url",
|
||||||
"sha",
|
"sha",
|
||||||
|
"state",
|
||||||
"step_summary",
|
"step_summary",
|
||||||
"triggering_actor",
|
"triggering_actor",
|
||||||
"workflow",
|
"workflow",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -22,5 +23,6 @@ namespace GitHub.Runner.Worker
|
|||||||
public StepsContext StepsContext { get; set; }
|
public StepsContext StepsContext { get; set; }
|
||||||
public Variables Variables { get; set; }
|
public Variables Variables { get; set; }
|
||||||
public bool WriteDebug { get; set; }
|
public bool WriteDebug { get; set; }
|
||||||
|
public JObject ContainerHookState { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
using GitHub.Runner.Worker.Expressions;
|
using GitHub.Runner.Worker.Expressions;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
@@ -264,7 +266,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
#endif
|
#endif
|
||||||
foreach (var pair in dict)
|
foreach (var pair in dict)
|
||||||
{
|
{
|
||||||
envContext[pair.Key] = pair.Value;
|
// Skip global env, otherwise we merge an outdated global env
|
||||||
|
if (ExecutionContext.StepEnvironmentOverrides.Contains(pair.Key))
|
||||||
|
{
|
||||||
|
envContext[pair.Key] = pair.Value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,11 +279,13 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
if (step is IActionRunner actionStep)
|
if (step is IActionRunner actionStep)
|
||||||
{
|
{
|
||||||
// Evaluate and merge embedded-step env
|
// Evaluate and merge embedded-step env
|
||||||
|
step.ExecutionContext.StepEnvironmentOverrides.AddRange(ExecutionContext.StepEnvironmentOverrides);
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, Common.Util.VarUtil.EnvironmentVariableKeyComparer);
|
var actionEnvironment = templateEvaluator.EvaluateStepEnvironment(actionStep.Action.Environment, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, Common.Util.VarUtil.EnvironmentVariableKeyComparer);
|
||||||
foreach (var env in actionEnvironment)
|
foreach (var env in actionEnvironment)
|
||||||
{
|
{
|
||||||
envContext[env.Key] = new StringContextData(env.Value ?? string.Empty);
|
envContext[env.Key] = new StringContextData(env.Value ?? string.Empty);
|
||||||
|
step.ExecutionContext.StepEnvironmentOverrides.Add(env.Key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
@@ -38,6 +39,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
AddInputsToEnvironment();
|
AddInputsToEnvironment();
|
||||||
|
|
||||||
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
|
var containerHookManager = HostContext.GetService<IContainerHookManager>();
|
||||||
|
string dockerFile = null;
|
||||||
|
|
||||||
// container image haven't built/pull
|
// container image haven't built/pull
|
||||||
if (Data.Image.StartsWith("docker://", StringComparison.OrdinalIgnoreCase))
|
if (Data.Image.StartsWith("docker://", StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -47,26 +50,28 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
else if (Data.Image.EndsWith("Dockerfile") || Data.Image.EndsWith("dockerfile"))
|
else if (Data.Image.EndsWith("Dockerfile") || Data.Image.EndsWith("dockerfile"))
|
||||||
{
|
{
|
||||||
// ensure docker file exist
|
// ensure docker file exist
|
||||||
var dockerFile = Path.Combine(ActionDirectory, Data.Image);
|
dockerFile = Path.Combine(ActionDirectory, Data.Image);
|
||||||
ArgUtil.File(dockerFile, nameof(Data.Image));
|
ArgUtil.File(dockerFile, nameof(Data.Image));
|
||||||
|
if (!FeatureManager.IsContainerHooksEnabled(ExecutionContext.Global.Variables))
|
||||||
ExecutionContext.Output($"##[group]Building docker image");
|
|
||||||
ExecutionContext.Output($"Dockerfile for action: '{dockerFile}'.");
|
|
||||||
var imageName = $"{dockerManager.DockerInstanceLabel}:{ExecutionContext.Id.ToString("N")}";
|
|
||||||
var buildExitCode = await dockerManager.DockerBuild(
|
|
||||||
ExecutionContext,
|
|
||||||
ExecutionContext.GetGitHubContext("workspace"),
|
|
||||||
dockerFile,
|
|
||||||
Directory.GetParent(dockerFile).FullName,
|
|
||||||
imageName);
|
|
||||||
ExecutionContext.Output("##[endgroup]");
|
|
||||||
|
|
||||||
if (buildExitCode != 0)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Docker build failed with exit code {buildExitCode}");
|
ExecutionContext.Output($"##[group]Building docker image");
|
||||||
}
|
ExecutionContext.Output($"Dockerfile for action: '{dockerFile}'.");
|
||||||
|
var imageName = $"{dockerManager.DockerInstanceLabel}:{ExecutionContext.Id.ToString("N")}";
|
||||||
|
var buildExitCode = await dockerManager.DockerBuild(
|
||||||
|
ExecutionContext,
|
||||||
|
ExecutionContext.GetGitHubContext("workspace"),
|
||||||
|
dockerFile,
|
||||||
|
Directory.GetParent(dockerFile).FullName,
|
||||||
|
imageName);
|
||||||
|
ExecutionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
Data.Image = imageName;
|
if (buildExitCode != 0)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Docker build failed with exit code {buildExitCode}");
|
||||||
|
}
|
||||||
|
|
||||||
|
Data.Image = imageName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string type = Action.Type == Pipelines.ActionSourceType.Repository ? "Dockerfile" : "DockerHub";
|
string type = Action.Type == Pipelines.ActionSourceType.Repository ? "Dockerfile" : "DockerHub";
|
||||||
@@ -220,14 +225,21 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
container.ContainerEnvironmentVariables[variable.Key] = container.TranslateToContainerPath(variable.Value);
|
container.ContainerEnvironmentVariables[variable.Key] = container.TranslateToContainerPath(variable.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager, container))
|
if (FeatureManager.IsContainerHooksEnabled(ExecutionContext.Global.Variables))
|
||||||
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager, container))
|
|
||||||
{
|
{
|
||||||
var runExitCode = await dockerManager.DockerRun(ExecutionContext, container, stdoutManager.OnDataReceived, stderrManager.OnDataReceived);
|
await containerHookManager.RunContainerStepAsync(ExecutionContext, container, dockerFile);
|
||||||
ExecutionContext.Debug($"Docker Action run completed with exit code {runExitCode}");
|
}
|
||||||
if (runExitCode != 0)
|
else
|
||||||
|
{
|
||||||
|
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager, container))
|
||||||
|
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager, container))
|
||||||
{
|
{
|
||||||
ExecutionContext.Result = TaskResult.Failed;
|
var runExitCode = await dockerManager.DockerRun(ExecutionContext, container, stdoutManager.OnDataReceived, stderrManager.OnDataReceived);
|
||||||
|
ExecutionContext.Debug($"Docker Action run completed with exit code {runExitCode}");
|
||||||
|
if (runExitCode != 0)
|
||||||
|
{
|
||||||
|
ExecutionContext.Result = TaskResult.Failed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ using GitHub.DistributedTask.Pipelines.ContextData;
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
{
|
{
|
||||||
@@ -94,14 +97,24 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
|
workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if OS_OSX
|
#if OS_OSX || OS_WINDOWS
|
||||||
if (string.Equals(Data.NodeVersion, "node12", StringComparison.OrdinalIgnoreCase) &&
|
if (string.Equals(Data.NodeVersion, "node12", StringComparison.OrdinalIgnoreCase) &&
|
||||||
Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.Arm64))
|
Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.Arm64))
|
||||||
{
|
{
|
||||||
|
#if OS_OSX
|
||||||
ExecutionContext.Output($"The node12 is not supported on macOS ARM64 platform. Use node16 instead.");
|
ExecutionContext.Output($"The node12 is not supported on macOS ARM64 platform. Use node16 instead.");
|
||||||
|
#elif OS_WINDOWS
|
||||||
|
ExecutionContext.Output($"The node12 is not supported on windows ARM64 platform. Use node16 instead.");
|
||||||
|
#endif
|
||||||
Data.NodeVersion = "node16";
|
Data.NodeVersion = "node16";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
string forcedNodeVersion = System.Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedActionsNodeVersion);
|
||||||
|
|
||||||
|
if (forcedNodeVersion == "node16" && Data.NodeVersion != "node16")
|
||||||
|
{
|
||||||
|
Data.NodeVersion = "node16";
|
||||||
|
}
|
||||||
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
|
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
|
||||||
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
|
||||||
@@ -109,7 +122,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// 1) Wrap the script file path in double quotes.
|
// 1) Wrap the script file path in double quotes.
|
||||||
// 2) Escape double quotes within the script file path. Double-quote is a valid
|
// 2) Escape double quotes within the script file path. Double-quote is a valid
|
||||||
// file name character on Linux.
|
// file name character on Linux.
|
||||||
string arguments = StepHost.ResolvePathForStepHost(StringUtil.Format(@"""{0}""", target.Replace(@"""", @"\""")));
|
string arguments = StepHost.ResolvePathForStepHost(ExecutionContext, StringUtil.Format(@"""{0}""", target.Replace(@"""", @"\""")));
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
// It appears that node.exe outputs UTF8 when not in TTY mode.
|
// It appears that node.exe outputs UTF8 when not in TTY mode.
|
||||||
@@ -125,11 +138,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
if (Data.NodeVersion == "node12" && (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.Node12Warning) ?? false))
|
if (Data.NodeVersion == "node12" && (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.Node12Warning) ?? false))
|
||||||
{
|
{
|
||||||
if (!ExecutionContext.JobContext.ContainsKey("Node12ActionsWarnings"))
|
if (!ExecutionContext.JobContext.ContainsKey("Node12ActionsWarnings"))
|
||||||
{
|
{
|
||||||
ExecutionContext.JobContext["Node12ActionsWarnings"] = new ArrayContextData();
|
ExecutionContext.JobContext["Node12ActionsWarnings"] = new ArrayContextData();
|
||||||
}
|
}
|
||||||
var repoAction = Action as RepositoryPathReference;
|
var repoAction = Action as RepositoryPathReference;
|
||||||
var actionDisplayName = new StringContextData(repoAction.Name ?? repoAction.Path); // local actions don't have a 'Name'
|
var actionDisplayName = new StringContextData(repoAction.Name ?? repoAction.Path); // local actions don't have a 'Name'
|
||||||
ExecutionContext.JobContext["Node12ActionsWarnings"].AssertArray("Node12ActionsWarnings").Add(actionDisplayName);
|
ExecutionContext.JobContext["Node12ActionsWarnings"].AssertArray("Node12ActionsWarnings").Add(actionDisplayName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,14 +155,16 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Execute the process. Exit code 0 should always be returned.
|
// Execute the process. Exit code 0 should always be returned.
|
||||||
// A non-zero exit code indicates infrastructural failure.
|
// A non-zero exit code indicates infrastructural failure.
|
||||||
// Task failure should be communicated over STDOUT using ## commands.
|
// Task failure should be communicated over STDOUT using ## commands.
|
||||||
Task<int> step = StepHost.ExecuteAsync(workingDirectory: StepHost.ResolvePathForStepHost(workingDirectory),
|
Task<int> step = StepHost.ExecuteAsync(ExecutionContext,
|
||||||
fileName: StepHost.ResolvePathForStepHost(file),
|
workingDirectory: StepHost.ResolvePathForStepHost(ExecutionContext, workingDirectory),
|
||||||
|
fileName: StepHost.ResolvePathForStepHost(ExecutionContext, file),
|
||||||
arguments: arguments,
|
arguments: arguments,
|
||||||
environment: Environment,
|
environment: Environment,
|
||||||
requireExitCodeZero: false,
|
requireExitCodeZero: false,
|
||||||
outputEncoding: outputEncoding,
|
outputEncoding: outputEncoding,
|
||||||
killProcessOnCancel: false,
|
killProcessOnCancel: false,
|
||||||
inheritConsoleHandler: !ExecutionContext.Global.Variables.Retain_Default_Encoding,
|
inheritConsoleHandler: !ExecutionContext.Global.Variables.Retain_Default_Encoding,
|
||||||
|
standardInInput: null,
|
||||||
cancellationToken: ExecutionContext.CancellationToken);
|
cancellationToken: ExecutionContext.CancellationToken);
|
||||||
|
|
||||||
// Wait for either the node exit or force finish through ##vso command
|
// Wait for either the node exit or force finish through ##vso command
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Worker.Container;
|
||||||
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
@@ -202,14 +204,32 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell);
|
// For these shells, we want to use system binaries
|
||||||
shellCommand = parsed.shellCommand;
|
var systemShells = new string[] { "bash", "sh", "powershell", "pwsh" };
|
||||||
// For non-ContainerStepHost, the command must be located on the host by Which
|
if (!IsActionStep && systemShells.Contains(shell))
|
||||||
commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
|
|
||||||
argFormat = $"{parsed.shellArgs}".TrimStart();
|
|
||||||
if (string.IsNullOrEmpty(argFormat))
|
|
||||||
{
|
{
|
||||||
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
|
shellCommand = shell;
|
||||||
|
commandPath = WhichUtil.Which(shell, !isContainerStepHost, Trace, prependPath);
|
||||||
|
if (shell == "bash")
|
||||||
|
{
|
||||||
|
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat("sh");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shell);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var parsed = ScriptHandlerHelpers.ParseShellOptionString(shell);
|
||||||
|
shellCommand = parsed.shellCommand;
|
||||||
|
// For non-ContainerStepHost, the command must be located on the host by Which
|
||||||
|
commandPath = WhichUtil.Which(parsed.shellCommand, !isContainerStepHost, Trace, prependPath);
|
||||||
|
argFormat = $"{parsed.shellArgs}".TrimStart();
|
||||||
|
if (string.IsNullOrEmpty(argFormat))
|
||||||
|
{
|
||||||
|
argFormat = ScriptHandlerHelpers.GetScriptArgumentsFormat(shellCommand);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,7 +249,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
// We do not not the full path until we know what shell is being used, so that we can determine the file extension
|
// We do not not the full path until we know what shell is being used, so that we can determine the file extension
|
||||||
scriptFilePath = Path.Combine(tempDirectory, $"{Guid.NewGuid()}{ScriptHandlerHelpers.GetScriptFileExtension(shellCommand)}");
|
scriptFilePath = Path.Combine(tempDirectory, $"{Guid.NewGuid()}{ScriptHandlerHelpers.GetScriptFileExtension(shellCommand)}");
|
||||||
resolvedScriptPath = $"{StepHost.ResolvePathForStepHost(scriptFilePath).Replace("\"", "\\\"")}";
|
resolvedScriptPath = StepHost.ResolvePathForStepHost(ExecutionContext, scriptFilePath).Replace("\"", "\\\"");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -300,6 +320,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
ExecutionContext.Debug($"{fileName} {arguments}");
|
ExecutionContext.Debug($"{fileName} {arguments}");
|
||||||
|
|
||||||
|
Inputs.TryGetValue("standardInInput", out var standardInInput);
|
||||||
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
using (var stdoutManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||||
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
using (var stderrManager = new OutputManager(ExecutionContext, ActionCommandManager))
|
||||||
{
|
{
|
||||||
@@ -307,7 +328,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
StepHost.ErrorDataReceived += stderrManager.OnDataReceived;
|
StepHost.ErrorDataReceived += stderrManager.OnDataReceived;
|
||||||
|
|
||||||
// Execute
|
// Execute
|
||||||
int exitCode = await StepHost.ExecuteAsync(workingDirectory: StepHost.ResolvePathForStepHost(workingDirectory),
|
int exitCode = await StepHost.ExecuteAsync(ExecutionContext,
|
||||||
|
workingDirectory: StepHost.ResolvePathForStepHost(ExecutionContext, workingDirectory),
|
||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
arguments: arguments,
|
arguments: arguments,
|
||||||
environment: Environment,
|
environment: Environment,
|
||||||
@@ -315,6 +337,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
outputEncoding: null,
|
outputEncoding: null,
|
||||||
killProcessOnCancel: false,
|
killProcessOnCancel: false,
|
||||||
inheritConsoleHandler: !ExecutionContext.Global.Variables.Retain_Default_Encoding,
|
inheritConsoleHandler: !ExecutionContext.Global.Variables.Retain_Default_Encoding,
|
||||||
|
standardInInput: standardInInput,
|
||||||
cancellationToken: ExecutionContext.CancellationToken);
|
cancellationToken: ExecutionContext.CancellationToken);
|
||||||
|
|
||||||
// Error
|
// Error
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
{
|
{
|
||||||
internal class ScriptHandlerHelpers
|
internal static class ScriptHandlerHelpers
|
||||||
{
|
{
|
||||||
private static readonly Dictionary<string, string> _defaultArguments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
private static readonly Dictionary<string, string> _defaultArguments = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
@@ -81,22 +83,5 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
throw new ArgumentException($"Failed to parse COMMAND [..ARGS] from {shellOption}");
|
throw new ArgumentException($"Failed to parse COMMAND [..ARGS] from {shellOption}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetDefaultShellForScript(string path, Common.Tracing trace, string prependPath)
|
|
||||||
{
|
|
||||||
var format = "{0} {1}";
|
|
||||||
switch (Path.GetExtension(path))
|
|
||||||
{
|
|
||||||
case ".sh":
|
|
||||||
// use 'sh' args but prefer bash
|
|
||||||
var pathToShell = WhichUtil.Which("bash", false, trace, prependPath) ?? WhichUtil.Which("sh", true, trace, prependPath);
|
|
||||||
return string.Format(format, pathToShell, _defaultArguments["sh"]);
|
|
||||||
case ".ps1":
|
|
||||||
var pathToPowershell = WhichUtil.Which("pwsh", false, trace, prependPath) ?? WhichUtil.Which("powershell", true, trace, prependPath);
|
|
||||||
return string.Format(format, pathToPowershell, _defaultArguments["powershell"]);
|
|
||||||
default:
|
|
||||||
throw new ArgumentException($"{path} is not a valid path to a script. Make sure it ends in '.sh' or '.ps1'.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -7,7 +8,9 @@ using GitHub.Runner.Worker.Container;
|
|||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.Runner.Worker.Container.ContainerHooks;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker.Handlers
|
namespace GitHub.Runner.Worker.Handlers
|
||||||
{
|
{
|
||||||
@@ -16,11 +19,12 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||||
event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||||
|
|
||||||
string ResolvePathForStepHost(string path);
|
string ResolvePathForStepHost(IExecutionContext executionContext, string path);
|
||||||
|
|
||||||
Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext, string preferredVersion);
|
Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext, string preferredVersion);
|
||||||
|
|
||||||
Task<int> ExecuteAsync(string workingDirectory,
|
Task<int> ExecuteAsync(IExecutionContext context,
|
||||||
|
string workingDirectory,
|
||||||
string fileName,
|
string fileName,
|
||||||
string arguments,
|
string arguments,
|
||||||
IDictionary<string, string> environment,
|
IDictionary<string, string> environment,
|
||||||
@@ -28,6 +32,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
Encoding outputEncoding,
|
Encoding outputEncoding,
|
||||||
bool killProcessOnCancel,
|
bool killProcessOnCancel,
|
||||||
bool inheritConsoleHandler,
|
bool inheritConsoleHandler,
|
||||||
|
string standardInInput,
|
||||||
CancellationToken cancellationToken);
|
CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +53,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||||
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||||
|
|
||||||
public string ResolvePathForStepHost(string path)
|
public string ResolvePathForStepHost(IExecutionContext executionContext, string path)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@@ -58,7 +63,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
return Task.FromResult<string>(preferredVersion);
|
return Task.FromResult<string>(preferredVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> ExecuteAsync(string workingDirectory,
|
public async Task<int> ExecuteAsync(IExecutionContext context,
|
||||||
|
string workingDirectory,
|
||||||
string fileName,
|
string fileName,
|
||||||
string arguments,
|
string arguments,
|
||||||
IDictionary<string, string> environment,
|
IDictionary<string, string> environment,
|
||||||
@@ -66,10 +72,17 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
Encoding outputEncoding,
|
Encoding outputEncoding,
|
||||||
bool killProcessOnCancel,
|
bool killProcessOnCancel,
|
||||||
bool inheritConsoleHandler,
|
bool inheritConsoleHandler,
|
||||||
|
string standardInInput,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
{
|
{
|
||||||
|
Channel<string> redirectStandardIn = null;
|
||||||
|
if (standardInInput != null)
|
||||||
|
{
|
||||||
|
redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
||||||
|
redirectStandardIn.Writer.TryWrite(standardInInput);
|
||||||
|
}
|
||||||
processInvoker.OutputDataReceived += OutputDataReceived;
|
processInvoker.OutputDataReceived += OutputDataReceived;
|
||||||
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
||||||
|
|
||||||
@@ -80,7 +93,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
requireExitCodeZero: requireExitCodeZero,
|
requireExitCodeZero: requireExitCodeZero,
|
||||||
outputEncoding: outputEncoding,
|
outputEncoding: outputEncoding,
|
||||||
killProcessOnCancel: killProcessOnCancel,
|
killProcessOnCancel: killProcessOnCancel,
|
||||||
redirectStandardIn: null,
|
redirectStandardIn: redirectStandardIn,
|
||||||
inheritConsoleHandler: inheritConsoleHandler,
|
inheritConsoleHandler: inheritConsoleHandler,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
@@ -94,11 +107,15 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||||
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||||
|
|
||||||
public string ResolvePathForStepHost(string path)
|
public string ResolvePathForStepHost(IExecutionContext executionContext, string path)
|
||||||
{
|
{
|
||||||
// make sure container exist.
|
// make sure container exist.
|
||||||
ArgUtil.NotNull(Container, nameof(Container));
|
ArgUtil.NotNull(Container, nameof(Container));
|
||||||
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
if (!FeatureManager.IsContainerHooksEnabled(executionContext.Global?.Variables))
|
||||||
|
{
|
||||||
|
// TODO: Remove nullcheck with executionContext.Global? by setting up ExecutionContext.Global at GitHub.Runner.Common.Tests.Worker.ExecutionContextL0.GetExpressionValues_ContainerStepHost
|
||||||
|
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
||||||
|
}
|
||||||
|
|
||||||
// remove double quotes around the path
|
// remove double quotes around the path
|
||||||
path = path.Trim('\"');
|
path = path.Trim('\"');
|
||||||
@@ -120,6 +137,19 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
public async Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext, string preferredVersion)
|
public async Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext, string preferredVersion)
|
||||||
{
|
{
|
||||||
|
// Optimistically use the default
|
||||||
|
string nodeExternal = preferredVersion;
|
||||||
|
|
||||||
|
if (FeatureManager.IsContainerHooksEnabled(executionContext.Global.Variables))
|
||||||
|
{
|
||||||
|
if (Container.IsAlpine)
|
||||||
|
{
|
||||||
|
nodeExternal = CheckPlatformForAlpineContainer(executionContext, preferredVersion);
|
||||||
|
}
|
||||||
|
executionContext.Debug($"Running JavaScript Action with default external tool: {nodeExternal}");
|
||||||
|
return nodeExternal;
|
||||||
|
}
|
||||||
|
|
||||||
// Best effort to determine a compatible node runtime
|
// Best effort to determine a compatible node runtime
|
||||||
// There may be more variation in which libraries are linked than just musl/glibc,
|
// There may be more variation in which libraries are linked than just musl/glibc,
|
||||||
// so determine based on known distribtutions instead
|
// so determine based on known distribtutions instead
|
||||||
@@ -128,7 +158,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
var output = new List<string>();
|
var output = new List<string>();
|
||||||
var execExitCode = await dockerManager.DockerExec(executionContext, Container.ContainerId, string.Empty, osReleaseIdCmd, output);
|
var execExitCode = await dockerManager.DockerExec(executionContext, Container.ContainerId, string.Empty, osReleaseIdCmd, output);
|
||||||
string nodeExternal;
|
|
||||||
if (execExitCode == 0)
|
if (execExitCode == 0)
|
||||||
{
|
{
|
||||||
foreach (var line in output)
|
foreach (var line in output)
|
||||||
@@ -136,26 +165,17 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
executionContext.Debug(line);
|
executionContext.Debug(line);
|
||||||
if (line.ToLower().Contains("alpine"))
|
if (line.ToLower().Contains("alpine"))
|
||||||
{
|
{
|
||||||
if (!Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.X64))
|
nodeExternal = CheckPlatformForAlpineContainer(executionContext, preferredVersion);
|
||||||
{
|
|
||||||
var os = Constants.Runner.Platform.ToString();
|
|
||||||
var arch = Constants.Runner.PlatformArchitecture.ToString();
|
|
||||||
var msg = $"JavaScript Actions in Alpine containers are only supported on x64 Linux runners. Detected {os} {arch}";
|
|
||||||
throw new NotSupportedException(msg);
|
|
||||||
}
|
|
||||||
nodeExternal = $"{preferredVersion}_alpine";
|
|
||||||
executionContext.Debug($"Container distribution is alpine. Running JavaScript Action with external tool: {nodeExternal}");
|
|
||||||
return nodeExternal;
|
return nodeExternal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Optimistically use the default
|
|
||||||
nodeExternal = preferredVersion;
|
|
||||||
executionContext.Debug($"Running JavaScript Action with default external tool: {nodeExternal}");
|
executionContext.Debug($"Running JavaScript Action with default external tool: {nodeExternal}");
|
||||||
return nodeExternal;
|
return nodeExternal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> ExecuteAsync(string workingDirectory,
|
public async Task<int> ExecuteAsync(IExecutionContext context,
|
||||||
|
string workingDirectory,
|
||||||
string fileName,
|
string fileName,
|
||||||
string arguments,
|
string arguments,
|
||||||
IDictionary<string, string> environment,
|
IDictionary<string, string> environment,
|
||||||
@@ -163,12 +183,25 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
Encoding outputEncoding,
|
Encoding outputEncoding,
|
||||||
bool killProcessOnCancel,
|
bool killProcessOnCancel,
|
||||||
bool inheritConsoleHandler,
|
bool inheritConsoleHandler,
|
||||||
|
string standardInInput,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
// make sure container exist.
|
|
||||||
ArgUtil.NotNull(Container, nameof(Container));
|
ArgUtil.NotNull(Container, nameof(Container));
|
||||||
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
var containerHookManager = HostContext.GetService<IContainerHookManager>();
|
||||||
|
if (FeatureManager.IsContainerHooksEnabled(context.Global.Variables))
|
||||||
|
{
|
||||||
|
TranslateToContainerPath(environment);
|
||||||
|
await containerHookManager.RunScriptStepAsync(context,
|
||||||
|
Container,
|
||||||
|
workingDirectory,
|
||||||
|
fileName,
|
||||||
|
arguments,
|
||||||
|
environment,
|
||||||
|
PrependPath);
|
||||||
|
return (int)(context.Result ?? 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
||||||
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
string dockerClientPath = dockerManager.DockerPath;
|
string dockerClientPath = dockerManager.DockerPath;
|
||||||
|
|
||||||
@@ -183,7 +216,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
||||||
// the value directly in the command
|
// the value directly in the command
|
||||||
dockerCommandArgs.Add($"-e {env.Key}");
|
dockerCommandArgs.Add(DockerUtil.CreateEscapedOption("-e", env.Key));
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(PrependPath))
|
if (!string.IsNullOrEmpty(PrependPath))
|
||||||
{
|
{
|
||||||
@@ -202,12 +235,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
dockerCommandArgs.Add(arguments);
|
dockerCommandArgs.Add(arguments);
|
||||||
|
|
||||||
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
|
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
|
||||||
|
TranslateToContainerPath(environment);
|
||||||
// make sure all env are using container path
|
|
||||||
foreach (var envKey in environment.Keys.ToList())
|
|
||||||
{
|
|
||||||
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
{
|
{
|
||||||
@@ -221,7 +249,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Let .NET choose the default.
|
// Let .NET choose the default.
|
||||||
outputEncoding = null;
|
outputEncoding = null;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
||||||
fileName: dockerClientPath,
|
fileName: dockerClientPath,
|
||||||
arguments: dockerCommandArgstring,
|
arguments: dockerCommandArgstring,
|
||||||
@@ -234,5 +261,28 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string CheckPlatformForAlpineContainer(IExecutionContext executionContext, string preferredVersion)
|
||||||
|
{
|
||||||
|
string nodeExternal = preferredVersion;
|
||||||
|
if (!Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.X64))
|
||||||
|
{
|
||||||
|
var os = Constants.Runner.Platform.ToString();
|
||||||
|
var arch = Constants.Runner.PlatformArchitecture.ToString();
|
||||||
|
var msg = $"JavaScript Actions in Alpine containers are only supported on x64 Linux runners. Detected {os} {arch}";
|
||||||
|
throw new NotSupportedException(msg);
|
||||||
|
}
|
||||||
|
nodeExternal = $"{preferredVersion}_alpine";
|
||||||
|
executionContext.Debug($"Container distribution is alpine. Running JavaScript Action with external tool: {nodeExternal}");
|
||||||
|
return nodeExternal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void TranslateToContainerPath(IDictionary<string, string> environment)
|
||||||
|
{
|
||||||
|
foreach (var envKey in environment.Keys.ToList())
|
||||||
|
{
|
||||||
|
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user