mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
157 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c64f26321 | ||
|
|
bbcf9f2145 | ||
|
|
b96b3c58c7 | ||
|
|
529e404063 | ||
|
|
c058208ce4 | ||
|
|
b3b97b7328 | ||
|
|
5f72720698 | ||
|
|
bc0c1263f0 | ||
|
|
82a4ca9a6b | ||
|
|
d081289ed5 | ||
|
|
7d5e9cd70f | ||
|
|
98aa9c1152 | ||
|
|
ddc700e9eb | ||
|
|
a0458aebfe | ||
|
|
b2c6d093b2 | ||
|
|
292a2e0ab3 | ||
|
|
29cee52276 | ||
|
|
ad0d0c4d0a | ||
|
|
2c6064a655 | ||
|
|
af6c8e6edd | ||
|
|
c15d3f10b2 | ||
|
|
bdf1e90503 | ||
|
|
100c99f263 | ||
|
|
e8ccafea63 | ||
|
|
02d2cb8fcd | ||
|
|
0cbf3351f4 | ||
|
|
6abef8199f | ||
|
|
ec9830836b | ||
|
|
460c32a337 | ||
|
|
934027da60 | ||
|
|
28f0027938 | ||
|
|
17153c9b29 | ||
|
|
a65ac083b4 | ||
|
|
882f36dcf8 | ||
|
|
f2578529b0 | ||
|
|
bd77ccf34e | ||
|
|
cb19da9638 | ||
|
|
d64190927f | ||
|
|
101b74cab6 | ||
|
|
c06da82ccd | ||
|
|
374989b280 | ||
|
|
47fee8cd64 | ||
|
|
85dcd93d98 | ||
|
|
bac91075f4 | ||
|
|
9240a1cf6c | ||
|
|
2946801fb6 | ||
|
|
1a0d588d3a | ||
|
|
192ebfeccf | ||
|
|
f2347b7a59 | ||
|
|
8f160bc084 | ||
|
|
47ba1203c9 | ||
|
|
dc8b1b685f | ||
|
|
8eacbdc79f | ||
|
|
6b4a95cdb1 | ||
|
|
c95d5eae30 | ||
|
|
ea67ff9647 | ||
|
|
d7d38e173e | ||
|
|
ac31fd10b2 | ||
|
|
d8251bf912 | ||
|
|
715bb7cca8 | ||
|
|
47dfebdf48 | ||
|
|
7cb198a554 | ||
|
|
7616e9b7aa | ||
|
|
3b8475de3e | ||
|
|
ba9766d544 | ||
|
|
29da60a538 | ||
|
|
f2e210e5f3 | ||
|
|
fa32fcf2a1 | ||
|
|
46da23edb1 | ||
|
|
9bfbc48f45 | ||
|
|
ead1826afb | ||
|
|
9de17f197c | ||
|
|
45decac397 | ||
|
|
55ed60b9fc | ||
|
|
698d3a2e66 | ||
|
|
d0ab54ce45 | ||
|
|
3e65909b81 | ||
|
|
3ec20e989d | ||
|
|
231fdcb19d | ||
|
|
bef164a12f | ||
|
|
a519f96a41 | ||
|
|
b1ecffd707 | ||
|
|
801a02ec89 | ||
|
|
6332f9a42f | ||
|
|
5b8ff174c6 | ||
|
|
e3e977fd84 | ||
|
|
4dc8a09db3 | ||
|
|
dcc5d34ad1 | ||
|
|
3e34fb10c1 | ||
|
|
23a693aa2c | ||
|
|
eb36db8ff9 | ||
|
|
85e1927754 | ||
|
|
b6dbf42746 | ||
|
|
67ba8a7d42 | ||
|
|
e4f9e6ae26 | ||
|
|
854d5e3bf3 | ||
|
|
57dec28f68 | ||
|
|
55a861f089 | ||
|
|
51b2031cbf | ||
|
|
400b2d879c | ||
|
|
c4b6d288d4 | ||
|
|
0699597876 | ||
|
|
a592b14ae3 | ||
|
|
04269f7b1b | ||
|
|
e89d2e84bd | ||
|
|
afe7066e39 | ||
|
|
da79ef4acb | ||
|
|
5afb52b272 | ||
|
|
cf87c55557 | ||
|
|
43fa351980 | ||
|
|
ecfc2cc9e9 | ||
|
|
740fb43731 | ||
|
|
f259e5706f | ||
|
|
5d84918ed5 | ||
|
|
881c521005 | ||
|
|
176e7f5208 | ||
|
|
b6d46c148a | ||
|
|
38e33bb8e3 | ||
|
|
404b3418b7 | ||
|
|
7ffd9af644 | ||
|
|
1b69c279f5 | ||
|
|
567870dbb8 | ||
|
|
72fa2a8a0d | ||
|
|
4359dd605b | ||
|
|
aab936d081 | ||
|
|
777ce5a0dc | ||
|
|
1a62162708 | ||
|
|
9a829995e0 | ||
|
|
c5ce52641c | ||
|
|
e82725b580 | ||
|
|
0464f77de3 | ||
|
|
1fc159e0df | ||
|
|
3615fb6923 | ||
|
|
f61dcad5bb | ||
|
|
62d568674c | ||
|
|
07c00f6a8a | ||
|
|
05b84297b7 | ||
|
|
04679b56a9 | ||
|
|
d2ca24fa43 | ||
|
|
abdaacfa6e | ||
|
|
53fd7161e2 | ||
|
|
ce68f3b167 | ||
|
|
e2c7329292 | ||
|
|
22a9d89772 | ||
|
|
3851acd0cf | ||
|
|
aab4aca8f7 | ||
|
|
5af7b87074 | ||
|
|
110eb3a5de | ||
|
|
bd1341e580 | ||
|
|
85ce33b1d3 | ||
|
|
92ec3d0f29 | ||
|
|
4e95d0d6ad | ||
|
|
5281434f3f | ||
|
|
e9a8bf29df | ||
|
|
a65331e887 | ||
|
|
908a082527 | ||
|
|
10ba74f59b |
8
.editorconfig
Normal file
8
.editorconfig
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# https://editorconfig.org/
|
||||||
|
|
||||||
|
[*]
|
||||||
|
insert_final_newline = true # ensure all files end with a single newline
|
||||||
|
trim_trailing_whitespace = true # attempt to remove trailing whitespace on save
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false # in markdown, "two trailing spaces" is unfortunately meaningful; it means `<br>`
|
||||||
6
.gitattributes
vendored
6
.gitattributes
vendored
@@ -20,7 +20,7 @@
|
|||||||
#
|
#
|
||||||
# Merging from the command prompt will add diff markers to the files if there
|
# Merging from the command prompt will add diff markers to the files if there
|
||||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||||
# the diff markers are never inserted). Diff markers may cause the following
|
# the diff markers are never inserted). Diff markers may cause the following
|
||||||
# file extensions to fail to load in VS. An alternative would be to treat
|
# file extensions to fail to load in VS. An alternative would be to treat
|
||||||
# these files as binary and thus will always conflict and require user
|
# these files as binary and thus will always conflict and require user
|
||||||
# intervention with every merge. To do so, just uncomment the entries below
|
# intervention with every merge. To do so, just uncomment the entries below
|
||||||
@@ -70,9 +70,9 @@
|
|||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# diff behavior for common document formats
|
# diff behavior for common document formats
|
||||||
#
|
#
|
||||||
# Convert binary document formats to text before diffing them. This feature
|
# Convert binary document formats to text before diffing them. This feature
|
||||||
# is only available from the command line. Turn it on by uncommenting the
|
# is only available from the command line. Turn it on by uncommenting the
|
||||||
# entries below.
|
# entries below.
|
||||||
###############################################################################
|
###############################################################################
|
||||||
*.doc diff=astextplain
|
*.doc diff=astextplain
|
||||||
|
|||||||
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
10
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,12 +1,18 @@
|
|||||||
---
|
---
|
||||||
name: Bug report
|
name: 🛑 Report a bug in the runner application
|
||||||
about: Create a report to help us improve
|
about: If you have issues with GitHub Actions, please follow the "support for GitHub Actions" link, below.
|
||||||
title: ''
|
title: ''
|
||||||
labels: bug
|
labels: bug
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
👋 You're opening a bug report against the GitHub Actions **runner application**.
|
||||||
|
|
||||||
|
🛑 Please stop if you're not certain that the bug you're seeing is in the runner application - if you have general problems with actions, workflows, or runners, please see the [GitHub Community Support Forum](https://github.community/c/code-to-cloud/52) which is actively monitored. Using the forum ensures that we route your problem to the correct team. 😃
|
||||||
|
-->
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
A clear and concise description of what the bug is.
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
|
|||||||
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
11
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: ✅ Support for GitHub Actions
|
||||||
|
url: https://github.community/c/code-to-cloud/52
|
||||||
|
about: If you have questions about GitHub Actions or need support writing workflows, please ask in the GitHub Community Support forum.
|
||||||
|
- name: ✅ Feedback and suggestions for GitHub Actions
|
||||||
|
url: https://github.com/github/feedback/discussions/categories/actions-and-packages-feedback
|
||||||
|
about: If you have feedback or suggestions about GitHub Actions, please open a discussion (or add to an existing one) in the GitHub Actions Feedback. GitHub Actions Product Managers and Engineers monitor the feedback forum.
|
||||||
|
- name: ‼️ GitHub Security Bug Bounty
|
||||||
|
url: https://bounty.github.com/
|
||||||
|
about: Please report security vulnerabilities here.
|
||||||
15
.github/ISSUE_TEMPLATE/enhancement_request.md
vendored
15
.github/ISSUE_TEMPLATE/enhancement_request.md
vendored
@@ -1,19 +1,24 @@
|
|||||||
---
|
---
|
||||||
name: Feature Request
|
name: 🛑 Request a feature in the runner application
|
||||||
about: Create a request to help us improve
|
about: If you have feature requests for GitHub Actions, please use the "feedback and suggestions for GitHub Actions" link below.
|
||||||
title: ''
|
title: ''
|
||||||
labels: enhancement
|
labels: enhancement
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Thank you 🙇♀ for wanting to create a feature in this repository. Before you do, please ensure you are filing the issue in the right place. Issues should only be opened on if the issue **relates to code in this repository**.
|
<!--
|
||||||
|
👋 You're opening a request for an enhancement in the GitHub Actions **runner application**.
|
||||||
|
|
||||||
|
🛑 Please stop if you're not certain that the feature you want is in the runner application - if you have a suggestion for improving GitHub Actions, please see the [GitHub Actions Feedback](https://github.com/github/feedback/discussions/categories/actions-and-packages-feedback) discussion forum which is actively monitored. Using the forum ensures that we route your problem to the correct team. 😃
|
||||||
|
|
||||||
|
Some additional useful links:
|
||||||
* If you have found a security issue [please submit it here](https://hackerone.com/github)
|
* If you have found a security issue [please submit it here](https://hackerone.com/github)
|
||||||
* If you have questions or issues with the service, writing workflows or actions, then please [visit the GitHub Community Forum's Actions Board](https://github.community/t5/GitHub-Actions/bd-p/actions)
|
* If you have questions or issues with the service, writing workflows or actions, then please [visit the GitHub Community Forum's Actions Board](https://github.community/t5/GitHub-Actions/bd-p/actions)
|
||||||
* If you are having an issue or question about GitHub Actions then please [contact customer support](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-github-actions#contacting-support)
|
* If you are having an issue or have a question about GitHub Actions then please [contact customer support](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-github-actions#contacting-support)
|
||||||
|
|
||||||
If you have a feature request that is relevant to this repository, the runner, then please include the information below:
|
If you have a feature request that is relevant to this repository, the runner, then please include the information below:
|
||||||
|
-->
|
||||||
|
|
||||||
**Describe the enhancement**
|
**Describe the enhancement**
|
||||||
A clear and concise description of what the features or enhancement you need.
|
A clear and concise description of what the features or enhancement you need.
|
||||||
@@ -24,4 +29,4 @@ If applicable, add a code snippet.
|
|||||||
**Additional information**
|
**Additional information**
|
||||||
Add any other context about the feature here.
|
Add any other context about the feature here.
|
||||||
|
|
||||||
NOTE: if the feature request has been agreed upon then the assignee will create an ADR. See docs/adrs/README.md
|
NOTE: if the feature request has been agreed upon then the assignee will create an ADR. See docs/adrs/README.md
|
||||||
|
|||||||
39
.github/workflows/build.yml
vendored
39
.github/workflows/build.yml
vendored
@@ -7,12 +7,12 @@ on:
|
|||||||
- main
|
- main
|
||||||
- releases/*
|
- releases/*
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- '*'
|
- '*'
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '**.md'
|
- '**.md'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -37,12 +37,12 @@ jobs:
|
|||||||
devScript: ./dev.sh
|
devScript: ./dev.sh
|
||||||
|
|
||||||
- runtime: win-x64
|
- runtime: win-x64
|
||||||
os: windows-latest
|
os: windows-2019
|
||||||
devScript: ./dev
|
devScript: ./dev
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
# Build runner layout
|
# Build runner layout
|
||||||
- name: Build & Layout Release
|
- name: Build & Layout Release
|
||||||
@@ -50,6 +50,29 @@ jobs:
|
|||||||
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
|
# Check runtime/externals hash
|
||||||
|
- name: Compute/Compare runtime and externals Hash
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
echo "Current dotnet runtime hash result: $DOTNET_RUNTIME_HASH"
|
||||||
|
echo "Current Externals hash result: $EXTERNALS_HASH"
|
||||||
|
|
||||||
|
NeedUpdate=0
|
||||||
|
if [ "$EXTERNALS_HASH" != "$(cat ./src/Misc/contentHash/externals/${{ matrix.runtime }})" ] ;then
|
||||||
|
echo Hash mismatch, Update ./src/Misc/contentHash/externals/${{ matrix.runtime }} to $EXTERNALS_HASH
|
||||||
|
NeedUpdate=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$DOTNET_RUNTIME_HASH" != "$(cat ./src/Misc/contentHash/dotnetRuntime/${{ matrix.runtime }})" ] ;then
|
||||||
|
echo Hash mismatch, Update ./src/Misc/contentHash/dotnetRuntime/${{ matrix.runtime }} to $DOTNET_RUNTIME_HASH
|
||||||
|
NeedUpdate=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $NeedUpdate
|
||||||
|
env:
|
||||||
|
DOTNET_RUNTIME_HASH: ${{hashFiles('**/_layout_trims/runtime/**/*')}}
|
||||||
|
EXTERNALS_HASH: ${{hashFiles('**/_layout_trims/externals/**/*')}}
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
- name: L0
|
- name: L0
|
||||||
run: |
|
run: |
|
||||||
@@ -67,7 +90,11 @@ jobs:
|
|||||||
# Upload runner package tar.gz/zip as artifact
|
# Upload runner package tar.gz/zip as artifact
|
||||||
- name: Publish Artifact
|
- name: Publish Artifact
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
uses: actions/upload-artifact@v1
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: runner-package-${{ matrix.runtime }}
|
name: runner-package-${{ matrix.runtime }}
|
||||||
path: _package
|
path: |
|
||||||
|
_package
|
||||||
|
_package_trims/trim_externals
|
||||||
|
_package_trims/trim_runtime
|
||||||
|
_package_trims/trim_runtime_externals
|
||||||
|
|||||||
7
.github/workflows/codeql.yml
vendored
7
.github/workflows/codeql.yml
vendored
@@ -1,7 +1,12 @@
|
|||||||
name: "Code Scanning - Action"
|
name: "Code Scanning - Action"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
security-events: write
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0'
|
- cron: '0 0 * * 0'
|
||||||
@@ -28,7 +33,7 @@ jobs:
|
|||||||
# languages: go, javascript, csharp, python, cpp, java
|
# languages: go, javascript, csharp, python, cpp, java
|
||||||
|
|
||||||
- name: Manual build
|
- name: Manual build
|
||||||
run : |
|
run : |
|
||||||
./dev.sh layout Release linux-x64
|
./dev.sh layout Release linux-x64
|
||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
|
|||||||
375
.github/workflows/release.yml
vendored
375
.github/workflows/release.yml
vendored
@@ -5,7 +5,7 @@ on:
|
|||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- releaseVersion
|
- releaseVersion
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
check:
|
||||||
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
||||||
@@ -13,8 +13,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
# Make sure ./releaseVersion match ./src/runnerversion
|
# Make sure ./releaseVersion match ./src/runnerversion
|
||||||
# Query GitHub release ensure version is not used
|
# Query GitHub release ensure version is not used
|
||||||
- name: Check version
|
- name: Check version
|
||||||
uses: actions/github-script@0.3.0
|
uses: actions/github-script@0.3.0
|
||||||
with:
|
with:
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
needs: check
|
needs: check
|
||||||
outputs:
|
outputs:
|
||||||
@@ -51,6 +51,21 @@ jobs:
|
|||||||
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 }}
|
||||||
osx-x64-sha: ${{ steps.sha.outputs.osx-x64-sha256 }}
|
osx-x64-sha: ${{ steps.sha.outputs.osx-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-arm-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm-sha256 }}
|
||||||
|
win-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.win-x64-sha256 }}
|
||||||
|
osx-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-x64-sha256 }}
|
||||||
|
linux-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-x64-sha256 }}
|
||||||
|
linux-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm64-sha256 }}
|
||||||
|
linux-arm-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm-sha256 }}
|
||||||
|
win-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.win-x64-sha256 }}
|
||||||
|
osx-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-x64-sha256 }}
|
||||||
|
linux-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-x64-sha256 }}
|
||||||
|
linux-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-arm64-sha256 }}
|
||||||
|
linux-arm-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-arm-sha256 }}
|
||||||
|
win-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.win-x64-sha256 }}
|
||||||
|
osx-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-x64-sha256 }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
||||||
@@ -72,12 +87,12 @@ jobs:
|
|||||||
devScript: ./dev.sh
|
devScript: ./dev.sh
|
||||||
|
|
||||||
- runtime: win-x64
|
- runtime: win-x64
|
||||||
os: windows-latest
|
os: windows-2019
|
||||||
devScript: ./dev
|
devScript: ./dev
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
# Build runner layout
|
# Build runner layout
|
||||||
- name: Build & Layout Release
|
- name: Build & Layout Release
|
||||||
@@ -86,11 +101,11 @@ jobs:
|
|||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
- name: L0
|
# - name: L0
|
||||||
run: |
|
# run: |
|
||||||
${{ matrix.devScript }} test
|
# ${{ matrix.devScript }} test
|
||||||
working-directory: src
|
# working-directory: src
|
||||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
# if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
||||||
|
|
||||||
# Create runner package tar.gz/zip
|
# Create runner package tar.gz/zip
|
||||||
- name: Package Release
|
- name: Package Release
|
||||||
@@ -99,14 +114,6 @@ jobs:
|
|||||||
${{ matrix.devScript }} package Release ${{ matrix.runtime }}
|
${{ matrix.devScript }} package Release ${{ matrix.runtime }}
|
||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
# Upload runner package tar.gz/zip as artifact.
|
|
||||||
# Since each package name is unique, so we don't need to put ${{matrix}} info into artifact name
|
|
||||||
- name: Publish Artifact
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: actions/upload-artifact@v1
|
|
||||||
with:
|
|
||||||
name: runner-packages
|
|
||||||
path: _package
|
|
||||||
# compute shas and set as job outputs to use in release notes
|
# compute shas and set as job outputs to use in release notes
|
||||||
- run: brew install coreutils #needed for shasum util
|
- run: brew install coreutils #needed for shasum util
|
||||||
if: ${{ matrix.os == 'macOS-latest' }}
|
if: ${{ matrix.os == 'macOS-latest' }}
|
||||||
@@ -120,6 +127,91 @@ jobs:
|
|||||||
id: sha
|
id: sha
|
||||||
name: Compute SHA256
|
name: Compute SHA256
|
||||||
working-directory: _package
|
working-directory: _package
|
||||||
|
- run: |
|
||||||
|
file=$(ls)
|
||||||
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
|
echo "Computed sha256: $sha for $file"
|
||||||
|
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
||||||
|
echo "::set-output name=sha256::$sha"
|
||||||
|
shell: bash
|
||||||
|
id: sha_noexternals
|
||||||
|
name: Compute SHA256
|
||||||
|
working-directory: _package_trims/trim_externals
|
||||||
|
- run: |
|
||||||
|
file=$(ls)
|
||||||
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
|
echo "Computed sha256: $sha for $file"
|
||||||
|
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
||||||
|
echo "::set-output name=sha256::$sha"
|
||||||
|
shell: bash
|
||||||
|
id: sha_noruntime
|
||||||
|
name: Compute SHA256
|
||||||
|
working-directory: _package_trims/trim_runtime
|
||||||
|
- run: |
|
||||||
|
file=$(ls)
|
||||||
|
sha=$(sha256sum $file | awk '{ print $1 }')
|
||||||
|
echo "Computed sha256: $sha for $file"
|
||||||
|
echo "::set-output name=${{matrix.runtime}}-sha256::$sha"
|
||||||
|
echo "::set-output name=sha256::$sha"
|
||||||
|
shell: bash
|
||||||
|
id: sha_noruntime_noexternals
|
||||||
|
name: Compute SHA256
|
||||||
|
working-directory: _package_trims/trim_runtime_externals
|
||||||
|
|
||||||
|
- name: Create trimmedpackages.json for ${{ matrix.runtime }}
|
||||||
|
if: matrix.runtime == 'win-x64'
|
||||||
|
uses: actions/github-script@0.3.0
|
||||||
|
with:
|
||||||
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
script: |
|
||||||
|
const core = require('@actions/core')
|
||||||
|
const fs = require('fs');
|
||||||
|
const runnerVersion = fs.readFileSync('src/runnerversion', 'utf8').replace(/\n$/g, '')
|
||||||
|
var trimmedPackages = fs.readFileSync('src/Misc/trimmedpackages_zip.json', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion).replace(/<RUNNER_PLATFORM>/g, '${{ matrix.runtime }}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<RUNTIME_HASH>/g, '${{hashFiles('**/_layout_trims/runtime/**/*')}}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<EXTERNALS_HASH>/g, '${{hashFiles('**/_layout_trims/externals/**/*')}}')
|
||||||
|
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<NO_RUNTIME_EXTERNALS_HASH>/g, '${{steps.sha_noruntime_noexternals.outputs.sha256}}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<NO_RUNTIME_HASH>/g, '${{steps.sha_noruntime.outputs.sha256}}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<NO_EXTERNALS_HASH>/g, '${{steps.sha_noexternals.outputs.sha256}}')
|
||||||
|
|
||||||
|
console.log(trimmedPackages)
|
||||||
|
fs.writeFileSync('${{ matrix.runtime }}-trimmedpackages.json', trimmedPackages)
|
||||||
|
|
||||||
|
- name: Create trimmedpackages.json for ${{ matrix.runtime }}
|
||||||
|
if: matrix.runtime != 'win-x64'
|
||||||
|
uses: actions/github-script@0.3.0
|
||||||
|
with:
|
||||||
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
script: |
|
||||||
|
const core = require('@actions/core')
|
||||||
|
const fs = require('fs');
|
||||||
|
const runnerVersion = fs.readFileSync('src/runnerversion', 'utf8').replace(/\n$/g, '')
|
||||||
|
var trimmedPackages = fs.readFileSync('src/Misc/trimmedpackages_targz.json', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion).replace(/<RUNNER_PLATFORM>/g, '${{ matrix.runtime }}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<RUNTIME_HASH>/g, '${{hashFiles('**/_layout_trims/runtime/**/*')}}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<EXTERNALS_HASH>/g, '${{hashFiles('**/_layout_trims/externals/**/*')}}')
|
||||||
|
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<NO_RUNTIME_EXTERNALS_HASH>/g, '${{steps.sha_noruntime_noexternals.outputs.sha256}}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<NO_RUNTIME_HASH>/g, '${{steps.sha_noruntime.outputs.sha256}}')
|
||||||
|
trimmedPackages = trimmedPackages.replace(/<NO_EXTERNALS_HASH>/g, '${{steps.sha_noexternals.outputs.sha256}}')
|
||||||
|
|
||||||
|
console.log(trimmedPackages)
|
||||||
|
fs.writeFileSync('${{ matrix.runtime }}-trimmedpackages.json', trimmedPackages)
|
||||||
|
|
||||||
|
# Upload runner package tar.gz/zip as artifact.
|
||||||
|
# Since each package name is unique, so we don't need to put ${{matrix}} info into artifact name
|
||||||
|
- name: Publish Artifact
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: runner-packages
|
||||||
|
path: |
|
||||||
|
_package
|
||||||
|
_package_trims/trim_externals
|
||||||
|
_package_trims/trim_runtime
|
||||||
|
_package_trims/trim_runtime_externals
|
||||||
|
${{ matrix.runtime }}-trimmedpackages.json
|
||||||
|
|
||||||
release:
|
release:
|
||||||
needs: build
|
needs: build
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -150,9 +242,35 @@ jobs:
|
|||||||
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(/<OSX_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.osx-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_ARM64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm64-sha-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.win-x64-sha-noruntime}}')
|
||||||
|
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.osx-x64-sha-noruntime}}')
|
||||||
|
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-x64-sha-noruntime}}')
|
||||||
|
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-arm-sha-noruntime}}')
|
||||||
|
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-arm64-sha-noruntime}}')
|
||||||
|
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noruntime-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.osx-x64-sha-noruntime-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-x64-sha-noruntime-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm-sha-noruntime-noexternals}}')
|
||||||
|
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm64-sha-noruntime-noexternals}}')
|
||||||
console.log(releaseNote)
|
console.log(releaseNote)
|
||||||
core.setOutput('version', runnerVersion);
|
core.setOutput('version', runnerVersion);
|
||||||
core.setOutput('note', releaseNote);
|
core.setOutput('note', releaseNote);
|
||||||
|
|
||||||
|
- name: Validate Packages HASH
|
||||||
|
working-directory: _package
|
||||||
|
run: |
|
||||||
|
ls -l
|
||||||
|
echo "${{needs.build.outputs.win-x64-sha}} actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip" | shasum -a 256 -c
|
||||||
|
echo "${{needs.build.outputs.osx-x64-sha}} actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||||
|
echo "${{needs.build.outputs.linux-x64-sha}} actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||||
|
echo "${{needs.build.outputs.linux-arm-sha}} actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||||
|
echo "${{needs.build.outputs.linux-arm64-sha}} actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||||
|
|
||||||
# Create GitHub release
|
# Create GitHub release
|
||||||
- uses: actions/create-release@master
|
- uses: actions/create-release@master
|
||||||
id: createRelease
|
id: createRelease
|
||||||
@@ -164,15 +282,16 @@ jobs:
|
|||||||
release_name: "v${{ steps.releaseNote.outputs.version }}"
|
release_name: "v${{ steps.releaseNote.outputs.version }}"
|
||||||
body: |
|
body: |
|
||||||
${{ steps.releaseNote.outputs.note }}
|
${{ steps.releaseNote.outputs.note }}
|
||||||
|
prerelease: true
|
||||||
|
|
||||||
# Upload release assets
|
# Upload release assets (full runner packages)
|
||||||
- name: Upload Release Asset (win-x64)
|
- name: Upload Release Asset (win-x64)
|
||||||
uses: actions/upload-release-asset@v1.0.1
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
asset_path: ${{ github.workspace }}/actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip
|
asset_path: ${{ github.workspace }}/_package/actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip
|
||||||
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
|
||||||
|
|
||||||
@@ -182,7 +301,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
asset_path: ${{ github.workspace }}/actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_path: ${{ github.workspace }}/_package/actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
@@ -192,7 +311,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
asset_path: ${{ github.workspace }}/actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_path: ${{ github.workspace }}/_package/actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
@@ -202,7 +321,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
asset_path: ${{ github.workspace }}/actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_path: ${{ github.workspace }}/_package/actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
@@ -212,6 +331,210 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
asset_path: ${{ github.workspace }}/actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_path: ${{ github.workspace }}/_package/actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trim externals)
|
||||||
|
- name: Upload Release Asset (win-x64-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-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
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-x64-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-linux-x64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (osx-x64-noexternals)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/_package_trims/trim_externals/actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-arm-noexternals)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/_package_trims/trim_externals/actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-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-linux-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trim runtime)
|
||||||
|
- name: Upload Release Asset (win-x64-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-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
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-x64-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-linux-x64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (osx-x64-noruntime)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime/actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-arm-noruntime)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime/actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-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-linux-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trim runtime and externals)
|
||||||
|
- name: Upload Release Asset (win-x64-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-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
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-x64-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-linux-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (osx-x64-noruntime-noexternals)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime_externals/actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-arm-noruntime-noexternals)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime_externals/actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-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-linux-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
# Upload release assets (trimmedpackages.json)
|
||||||
|
- name: Upload Release Asset (win-x64-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-x64-trimmedpackages.json
|
||||||
|
asset_name: actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-x64-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 }}/linux-x64-trimmedpackages.json
|
||||||
|
asset_name: actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (osx-x64-trimmedpackages.json)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/osx-x64-trimmedpackages.json
|
||||||
|
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-arm-trimmedpackages.json)
|
||||||
|
uses: actions/upload-release-asset@v1.0.1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||||
|
asset_path: ${{ github.workspace }}/linux-arm-trimmedpackages.json
|
||||||
|
asset_name: actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
- name: Upload Release Asset (linux-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 }}/linux-arm64-trimmedpackages.json
|
||||||
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -19,7 +19,9 @@
|
|||||||
node_modules
|
node_modules
|
||||||
_downloads
|
_downloads
|
||||||
_layout
|
_layout
|
||||||
|
_layout_trims
|
||||||
_package
|
_package
|
||||||
|
_package_trims
|
||||||
_dotnetsdk
|
_dotnetsdk
|
||||||
TestResults
|
TestResults
|
||||||
TestLogs
|
TestLogs
|
||||||
|
|||||||
8
.vscode/launch.json
vendored
8
.vscode/launch.json
vendored
@@ -13,6 +13,7 @@
|
|||||||
"cwd": "${workspaceFolder}/src",
|
"cwd": "${workspaceFolder}/src",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"requireExactSource": false,
|
"requireExactSource": false,
|
||||||
|
"targetArchitecture": "x86_64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Run",
|
"name": "Run",
|
||||||
@@ -25,6 +26,7 @@
|
|||||||
"cwd": "${workspaceFolder}/src",
|
"cwd": "${workspaceFolder}/src",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"requireExactSource": false,
|
"requireExactSource": false,
|
||||||
|
"targetArchitecture": "x86_64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Configure",
|
"name": "Configure",
|
||||||
@@ -38,6 +40,7 @@
|
|||||||
"cwd": "${workspaceFolder}/src",
|
"cwd": "${workspaceFolder}/src",
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"requireExactSource": false,
|
"requireExactSource": false,
|
||||||
|
"targetArchitecture": "x86_64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Debug Worker",
|
"name": "Debug Worker",
|
||||||
@@ -45,6 +48,7 @@
|
|||||||
"request": "attach",
|
"request": "attach",
|
||||||
"processName": "Runner.Worker",
|
"processName": "Runner.Worker",
|
||||||
"requireExactSource": false,
|
"requireExactSource": false,
|
||||||
|
"targetArchitecture": "x86_64"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Attach Debugger",
|
"name": "Attach Debugger",
|
||||||
@@ -52,6 +56,8 @@
|
|||||||
"request": "attach",
|
"request": "attach",
|
||||||
"processId": "${command:pickProcess}",
|
"processId": "${command:pickProcess}",
|
||||||
"requireExactSource": false,
|
"requireExactSource": false,
|
||||||
|
"targetArchitecture": "x86_64"
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
# GitHub Actions Runner
|
# GitHub Actions Runner
|
||||||
|
|
||||||
[](https://github.com/actions/runner/actions)
|
[](https://github.com/actions/runner/actions)
|
||||||
[](https://github.com/actions/runner/actions)
|
|
||||||
|
|
||||||
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ Compilation failures during a CI build should surface good error messages.
|
|||||||
|
|
||||||
For example, the actual compile errors from the typescript compiler should bubble as issues in the UI. And not simply "tsc exited with exit code 1".
|
For example, the actual compile errors from the typescript compiler should bubble as issues in the UI. And not simply "tsc exited with exit code 1".
|
||||||
|
|
||||||
VSCode has an extensible model for solving this type of problem. VSCode allows users to configure which problems matchers to use, when scanning output. For example, a user can apply the `tsc` problem matcher to receive a rich error output experience in VSCode, when compiling their typescript project.
|
VSCode has an extensible model for solving this type of problem. VSCode allows users to configure which [problems matchers](https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher) to use, when scanning output. For example, a user can apply the `tsc` problem matcher to receive a rich error output experience in VSCode, when compiling their typescript project.
|
||||||
|
|
||||||
The problem-matcher concept fits well with "setup" actions. For example, the `setup-nodejs` action will download node.js, add it to the PATH, and register the `tsc` problem matcher. For the duration of the job, the `tsc` problem matcher will be applied against the output.
|
The problem-matcher concept fits well with "setup" actions. For example, the `setup-nodejs` action will download node.js, add it to the PATH, and register the `tsc` problem matcher. For the duration of the job, the `tsc` problem matcher will be applied against the output.
|
||||||
|
|
||||||
@@ -18,21 +18,23 @@ The problem-matcher concept fits well with "setup" actions. For example, the `se
|
|||||||
|
|
||||||
### Registration
|
### Registration
|
||||||
|
|
||||||
#### Using `##` command
|
#### Using `::` command
|
||||||
|
|
||||||
`##[add-matcher]path-to-problem-matcher-config.json`
|
`::add-matcher::path-to-problem-matcher-config.json`
|
||||||
|
|
||||||
Using a `##` command allows for flexibility:
|
Using a `::` command allows for flexibility:
|
||||||
- Ad hoc scripts can register problem matchers
|
- Ad hoc scripts can register problem matchers
|
||||||
- Allows problem matchers to be conditionally registered
|
- Allows problem matchers to be conditionally registered
|
||||||
|
|
||||||
Note, if a matcher with the same name is registered a second time, it will clobber the first instance.
|
Note, if a matcher with the same name is registered a second time, it will clobber the first instance.
|
||||||
|
|
||||||
#### Unregister using `##` command
|
Note, at some point the syntax changed from `##` to `::`.
|
||||||
|
|
||||||
|
#### Unregister using `::` command
|
||||||
|
|
||||||
A way out for rare cases where scoping is a problem.
|
A way out for rare cases where scoping is a problem.
|
||||||
|
|
||||||
`##[remove-matcher]owner`
|
`::remove-matcher::owner`
|
||||||
|
|
||||||
For this to be usable, the `owner` needs to be discoverable. Therefore, debug print the owner on registration.
|
For this to be usable, the `owner` needs to be discoverable. Therefore, debug print the owner on registration.
|
||||||
|
|
||||||
@@ -104,7 +106,7 @@ message: ; expected
|
|||||||
fromPath: C:\myrepo\myproject\ConsoleApp1\ClassLibrary1\ClassLibrary1.csproj
|
fromPath: C:\myrepo\myproject\ConsoleApp1\ClassLibrary1\ClassLibrary1.csproj
|
||||||
```
|
```
|
||||||
|
|
||||||
Additionally the line will appear red in the web UI (prefix with `##[error]`).
|
Additionally the line will appear red in the web UI (prefix with `::error`).
|
||||||
|
|
||||||
Note, an error does not imply task failure. Exit codes communicate failure.
|
Note, an error does not imply task failure. Exit codes communicate failure.
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ The runner will look for a file `.setup_info` under the runner's root directory,
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
The runner will use `##[group]` and `##[endgroup]` to fold all detail info into an expandable group.
|
The runner will use `::group` and `::endgroup` to fold all detail info into an expandable group.
|
||||||
|
|
||||||
Both [virtual-environments](https://github.com/actions/virtual-environments) and self-hosted runners can use this mechanism to add extra logging info to the `Set up job` step's log.
|
Both [virtual-environments](https://github.com/actions/virtual-environments) and self-hosted runners can use this mechanism to add extra logging info to the `Set up job` step's log.
|
||||||
|
|
||||||
|
|||||||
92
docs/adrs/1144-composite-actions.md
Normal file
92
docs/adrs/1144-composite-actions.md
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
**Date**: 2021-06-10
|
||||||
|
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
We released [composite run steps](https://github.com/actions/runner/pull/554) last year which started our journey of reusing steps across different workflow files. To continue that journey, we want to expand composite run steps into composite actions.
|
||||||
|
|
||||||
|
We want to support the `uses` steps from workflows in composite actions, including:
|
||||||
|
- Container actions
|
||||||
|
- Javascript actions
|
||||||
|
- Other Composite actions (up to a limit of course!)
|
||||||
|
- The pre and post steps these actions can generate
|
||||||
|
|
||||||
|
## Guiding Principles
|
||||||
|
|
||||||
|
- Composite Actions should function as a single step or action, no matter how many steps it is composed of or how many levels of recursion it has
|
||||||
|
- In the future we may add a configurable option to make this no longer the case
|
||||||
|
- A workflow author should not need to understand the inner workings of a composite action in order to use it
|
||||||
|
- Composite actions should leverage inputs to get values they need, they will not have full access to the `context` objects. The secrets context will **not** be available to composite actions, users will need to pass these values in as an input.
|
||||||
|
- Other Actions should **just work** inside a composite action, without any code changes
|
||||||
|
|
||||||
|
## Decisions
|
||||||
|
|
||||||
|
### Composite Recursion Limit
|
||||||
|
|
||||||
|
- We will start with supporting a recursion limit of `10` composite actions deep
|
||||||
|
- We are free to bump this limit in the future, the code will be written to just require updating a variable. If the graph evaluates beyond the recursion limit, the job will fail in the pre-job phase (The `Set up job` step).
|
||||||
|
- A composite actions interface is its inputs and outputs, nothing else is carried over when invoking recursively.
|
||||||
|
|
||||||
|
### Pre/Post Steps in nested Actions
|
||||||
|
|
||||||
|
- We do not plan on adding the ability to configure a customizable pre or post step for composite actions at this time. However, we will execute the pre and post steps of any actions referenced in a composite action.
|
||||||
|
- Composite actions will generate a single pre-step and post-step for the entire composite action, even if there are multiple pre-steps and post-steps in the referenced actions.
|
||||||
|
- These steps will execute following the same ordering rules we have today, first to run has their pre step run first and their post step run last.
|
||||||
|
- For example, if you had a composite action with two pre steps and two posts steps:
|
||||||
|
|
||||||
|
```
|
||||||
|
- uses: action1
|
||||||
|
- uses: composite1
|
||||||
|
- uses: action2
|
||||||
|
```
|
||||||
|
|
||||||
|
The order of execution would be:
|
||||||
|
|
||||||
|
```
|
||||||
|
- prestep-action1
|
||||||
|
- prestep-composite1
|
||||||
|
- prestep-composite1-first-action-referenced
|
||||||
|
- prestep-composite1-second-action-referenced
|
||||||
|
- prestep-action2
|
||||||
|
- the job steps
|
||||||
|
- poststep-action2
|
||||||
|
- poststep-composite1
|
||||||
|
- poststep-composite1-the-second-action-referenced
|
||||||
|
- poststep-composite1-first-action-referenced
|
||||||
|
- poststep-action1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Set-state
|
||||||
|
|
||||||
|
- While the composite action has an individual combined pre/post action, the `set-state` command will not be shared.
|
||||||
|
- If the `set-state` command is used during a composite step, only the action that originally called `set-state` will have access to the env variable during the post run step.
|
||||||
|
- This prevents multiple actions that set the same state from interfering with the execution of another action's post step.
|
||||||
|
|
||||||
|
### Resolve Action Endpoint changes
|
||||||
|
|
||||||
|
- The resolve actions endpoint will now validate policy to ensure that the given workflow run has access to download that action.
|
||||||
|
- Older GHES/GHAE customers with newer runners will be locked out of composite uses steps until they upgrade their instance.
|
||||||
|
|
||||||
|
### Local actions
|
||||||
|
- Local actions will expand the tree, perform policy checks, and download actions Just in Time when the step is running.
|
||||||
|
- Like current local actions, we will not support presteps. If an action is running local, by the time we know that, the time to run presteps have already passed.
|
||||||
|
|
||||||
|
### If, continue-on-error, timeout-minutes - Not being considered at this time
|
||||||
|
|
||||||
|
- `if`, `continue-on-error`, `timeout-minutes` could be supported in composite run/uses steps. These values were not originally supported in our composite run steps implementation.
|
||||||
|
- Browsing the community forums and runner repo, there hasn't been a lot of noise asking for these features, so we will hold off on them.
|
||||||
|
- These values passed as input into the composite action will **not** be carried over as input into the individual steps the composite action runs.
|
||||||
|
|
||||||
|
### Defaults - Not being considered at this time
|
||||||
|
|
||||||
|
- In actions, we have the idea of [defaults](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#defaultsrun) , which allow you to specify a shell and working directory in one location, rather then on each step.
|
||||||
|
- However, `shell` is currently required in composite run steps
|
||||||
|
- In regular run steps, it is optional, and defaults to a different value based on the OS.
|
||||||
|
- We want to prioritize the right experience for the consumer, and make the action author continue to explicitly set these values. We can consider improving this experience in the future.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- Workflows are now more reusable across multiple workflow files
|
||||||
|
- Composite actions implement most of the existing workflow run steps, with room to expand these in the future
|
||||||
|
- Feature flags will control this rollout
|
||||||
71
docs/adrs/1438-conditional-composite.md
Normal file
71
docs/adrs/1438-conditional-composite.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# ADR 1438: Support Conditionals In Composite Actions
|
||||||
|
|
||||||
|
**Date**: 2021-10-13
|
||||||
|
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
We recently shipped composite actions, which allows you to reuse individual steps inside an action.
|
||||||
|
However, one of the [most requested features](https://github.com/actions/runner/issues/834) has been a way to support the `if` keyword.
|
||||||
|
|
||||||
|
### Goals
|
||||||
|
- We want to keep consistent with current behavior
|
||||||
|
- We want to support conditionals via the `if` keyword
|
||||||
|
- Our built in functions like `success` should be implementable without calling them, for example you can do `job.status == success` rather then `success()` currently.
|
||||||
|
|
||||||
|
### How does composite currently work?
|
||||||
|
|
||||||
|
Currently, we have limited conditional support in composite actions for `pre` and `post` steps.
|
||||||
|
These are based on the `job status`, and support keywords like `always()`, `failed()`, `success()` and `cancelled()`.
|
||||||
|
However, generic or main steps do **not** support conditionals.
|
||||||
|
|
||||||
|
By default, in a regular workflow, a step runs on the `success()` condition. Which looks at the **job** **status**, sees if it is successful and runs.
|
||||||
|
|
||||||
|
By default, in a composite action, main steps run until a single step fails in that composite action, then the composite action is halted early. It does **not** care about the job status.
|
||||||
|
Pre, and post steps in composite actions use the job status to determine if they should run.
|
||||||
|
|
||||||
|
### How do we go forward?
|
||||||
|
|
||||||
|
Well, if we think about what composite actions are currently doing when invoking main steps, they are checking if the current composite action is successful.
|
||||||
|
Lets formalize that concept into a "real" idea.
|
||||||
|
|
||||||
|
- We will add an `action_status` field to the github context to mimic the [job's context status](https://docs.github.com/en/actions/learn-github-actions/contexts#job-context).
|
||||||
|
- We have an existing concept that does this `action_path` which is only set for composite actions on the github context.
|
||||||
|
- In a composite action during a main step, the `success()` function will check if `action_status == success`, rather then `job_status == success`. Failure will work the same way.
|
||||||
|
- Pre and post steps in composite actions will not change, they will continue to check the job status.
|
||||||
|
|
||||||
|
|
||||||
|
### Nested Scenario
|
||||||
|
For nested composite actions, we will follow the existing behavior, you only care about your current composite action, not any parents.
|
||||||
|
For example, lets imagine a scenario with a simple nested composite action
|
||||||
|
|
||||||
|
```
|
||||||
|
- Job
|
||||||
|
- Regular Step
|
||||||
|
- Composite Action
|
||||||
|
- runs: exit 1
|
||||||
|
- if: always()
|
||||||
|
uses: A child composite action
|
||||||
|
- if: success()
|
||||||
|
runs: echo "this should print"
|
||||||
|
- runs: echo "this should also print"
|
||||||
|
- if: success()
|
||||||
|
runs: echo "this will not print as the current composite action has failed already"
|
||||||
|
|
||||||
|
```
|
||||||
|
The child composite actions steps should run in this example, the child composite action has not yet failed, so it should run all steps until a step fails. This is consistent with how a composite action currently works in production if the main job fails but a composite action is invoked with `if:always()` or `if: failure()`
|
||||||
|
|
||||||
|
### Other options explored
|
||||||
|
We could add the `current_step_status` to the job context rather then `__status` to the steps context, however this comes with two major downsides:
|
||||||
|
- We need to support the field for every type of step, because its non trivial to remove a field from the job context once it has been added (its readonly)
|
||||||
|
- For all actions besides composite it would only every be `success`
|
||||||
|
- Its weird to have a `current_step` value on the job context
|
||||||
|
- We also explored a `__status` on the steps context.
|
||||||
|
- The `__` is required to prevent us from colliding with a step with id: status
|
||||||
|
- This felt wrong because the naming was not smooth, and did not fit into current conventions.
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
- github context has a new field for the status of the current composite action.
|
||||||
|
- We support conditional's in composite actions
|
||||||
|
- We keep the existing behavior for all users, but allow them to expand that functionality.
|
||||||
@@ -21,16 +21,33 @@ export RUNNER_CFG_PAT=yourPAT
|
|||||||
|
|
||||||
:point_right: [Sample script here](../scripts/create-latest-svc.sh) :point_left:
|
:point_right: [Sample script here](../scripts/create-latest-svc.sh) :point_left:
|
||||||
|
|
||||||
Run as a one-liner. NOTE: replace with yourorg/yourrepo (repo level) or just yourorg (org level)
|
Run as a one-liner. NOTE: replace with yourorg/yourrepo (repo level) or just yourorg (org level)
|
||||||
```bash
|
```bash
|
||||||
curl -s https://raw.githubusercontent.com/actions/runner/main/scripts/create-latest-svc.sh | bash -s yourorg/yourrepo
|
curl -s https://raw.githubusercontent.com/actions/runner/main/scripts/create-latest-svc.sh | bash -s yourorg/yourrepo
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can call the script with additional arguments:
|
||||||
|
```bash
|
||||||
|
# Usage:
|
||||||
|
# export RUNNER_CFG_PAT=<yourPAT>
|
||||||
|
# ./create-latest-svc -s scope -g [ghe_domain] -n [name] -u [user] -l [labels]
|
||||||
|
# -s required scope: repo (:owner/:repo) or org (:organization)
|
||||||
|
# -g optional ghe_hostname: the fully qualified domain name of your GitHub Enterprise Server deployment
|
||||||
|
# -n optional name of the runner, defaults to hostname
|
||||||
|
# -u optional user svc will run as, defaults to current
|
||||||
|
# -l optional list of labels (split by comma) applied on the runner"
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `--` to pass any number of optional named parameters:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -s https://raw.githubusercontent.com/actions/runner/main/scripts/create-latest-svc.sh | bash -s -- -s myorg/myrepo -n myname -l label1,label2
|
||||||
|
```
|
||||||
### Why can't I use a container?
|
### Why can't I use a container?
|
||||||
|
|
||||||
The runner is installed as a service using `systemd` and `systemctl`. Docker does not support `systemd` for service configuration on a container.
|
The runner is installed as a service using `systemd` and `systemctl`. Docker does not support `systemd` for service configuration on a container.
|
||||||
|
|
||||||
## Uninstall running as service
|
## Uninstall running as service
|
||||||
|
|
||||||
**Scenario**: Run on a machine or VM ([not container](#why-cant-i-use-a-container)) which automates:
|
**Scenario**: Run on a machine or VM ([not container](#why-cant-i-use-a-container)) which automates:
|
||||||
|
|
||||||
@@ -40,7 +57,7 @@ The runner is installed as a service using `systemd` and `systemctl`. Docker doe
|
|||||||
|
|
||||||
:point_right: [Sample script here](../scripts/remove-svc.sh) :point_left:
|
:point_right: [Sample script here](../scripts/remove-svc.sh) :point_left:
|
||||||
|
|
||||||
Repo level one liner. NOTE: replace with yourorg/yourrepo (repo level) or just yourorg (org level)
|
Repo level one liner. NOTE: replace with yourorg/yourrepo (repo level) or just yourorg (org level)
|
||||||
```bash
|
```bash
|
||||||
curl -s https://raw.githubusercontent.com/actions/runner/main/scripts/remove-svc.sh | bash -s yourorg/yourrepo
|
curl -s https://raw.githubusercontent.com/actions/runner/main/scripts/remove-svc.sh | bash -s yourorg/yourrepo
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -6,28 +6,50 @@
|
|||||||
Make sure the runner has access to actions service for GitHub.com or GitHub Enterprise Server
|
Make sure the runner has access to actions service for GitHub.com or GitHub Enterprise Server
|
||||||
|
|
||||||
- For GitHub.com
|
- For GitHub.com
|
||||||
- The runner needs to access https://api.github.com for downloading actions.
|
- The runner needs to access `https://api.github.com` for downloading actions.
|
||||||
- The runner needs to access https://vstoken.actions.githubusercontent.com/_apis/.../ for requesting an access token.
|
- The runner needs to access `https://vstoken.actions.githubusercontent.com/_apis/.../` for requesting an access token.
|
||||||
- The runner needs to access https://pipelines.actions.githubusercontent.com/_apis/.../ for receiving workflow jobs.
|
- The runner needs to access `https://pipelines.actions.githubusercontent.com/_apis/.../` for receiving workflow jobs.
|
||||||
|
|
||||||
|
These can by tested by running the following `curl` commands from your self-hosted runner machine:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -v https://api.github.com/api/v3/zen
|
||||||
|
curl -v https://vstoken.actions.githubusercontent.com/_apis/health
|
||||||
|
curl -v https://pipelines.actions.githubusercontent/_apis/health
|
||||||
|
```
|
||||||
|
|
||||||
- For GitHub Enterprise Server
|
- For GitHub Enterprise Server
|
||||||
- The runner needs to access https://myGHES.com/api/v3 for downloading actions.
|
- The runner needs to access `https://[hostname]/api/v3` for downloading actions.
|
||||||
- The runner needs to access https://myGHES.com/_services/vstoken/_apis/.../ for requesting an access token.
|
- The runner needs to access `https://[hostname]/_services/vstoken/_apis/.../` for requesting an access token.
|
||||||
- The runner needs to access https://myGHES.com/_services/pipelines/_apis/.../ for receiving workflow jobs.
|
- The runner needs to access `https://[hostname]/_services/pipelines/_apis/.../` for receiving workflow jobs.
|
||||||
|
|
||||||
|
These can by tested by running the following `curl` commands from your self-hosted runner machine, replacing `[hostname]` with the hostname of your appliance, for instance `github.example.com`:
|
||||||
|
|
||||||
|
```
|
||||||
|
curl -v https://[hostname]/api/v3/zen
|
||||||
|
curl -v https://[hostname]/_services/vstoken/_apis/health
|
||||||
|
curl -v https://[hostname]/_services/pipelines/_apis/health
|
||||||
|
```
|
||||||
|
|
||||||
|
A common cause of this these connectivity issues is if your to GitHub Enterprise Server appliance is using [the self-signed certificate that is enabled the first time](https://docs.github.com/en/enterprise-server/admin/configuration/configuring-network-settings/configuring-tls) your appliance is started. As self-signed certificates are not trusted by web browsers and Git clients, these clients (including the GitHub Actions runner) will report certificate warnings.
|
||||||
|
|
||||||
|
We recommend [upload a certificate signed by a trusted authority](https://docs.github.com/en/enterprise-server/admin/configuration/configuring-network-settings/configuring-tls) to GitHub Enterprise Server, or enabling the built-in ][Let's Encrypt support](https://docs.github.com/en/enterprise-server/admin/configuration/configuring-network-settings/configuring-tls).
|
||||||
|
|
||||||
|
|
||||||
## What is checked?
|
## What is checked?
|
||||||
|
|
||||||
- DNS lookup for api.github.com or myGHES.com using dotnet
|
- DNS lookup for api.github.com or myGHES.com using dotnet
|
||||||
- Ping api.github.com or myGHES.com using dotnet
|
- Ping api.github.com or myGHES.com using dotnet
|
||||||
- Make HTTP GET to https://api.github.com or https://myGHES.com/api/v3 using dotnet, check response headers contains `X-GitHub-Request-Id`
|
- Make HTTP GET to https://api.github.com or https://myGHES.com/api/v3 using dotnet, check response headers contains `X-GitHub-Request-Id`
|
||||||
---
|
---
|
||||||
- DNS lookup for vstoken.actions.githubusercontent.com using dotnet
|
- DNS lookup for vstoken.actions.githubusercontent.com using dotnet
|
||||||
- Ping vstoken.actions.githubusercontent.com using dotnet
|
- Ping vstoken.actions.githubusercontent.com using dotnet
|
||||||
- Make HTTP GET to https://vstoken.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/vstoken/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
- Make HTTP GET to https://vstoken.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/vstoken/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
||||||
---
|
---
|
||||||
- DNS lookup for pipelines.actions.githubusercontent.com using dotnet
|
- DNS lookup for pipelines.actions.githubusercontent.com using dotnet
|
||||||
- Ping pipelines.actions.githubusercontent.com using dotnet
|
- Ping pipelines.actions.githubusercontent.com using dotnet
|
||||||
- Make HTTP GET to https://pipelines.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/pipelines/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
- Make HTTP GET to https://pipelines.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/pipelines/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
||||||
- Make HTTP POST to https://pipelines.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/pipelines/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
- Make HTTP POST to https://pipelines.actions.githubusercontent.com/_apis/health or https://myGHES.com/_services/pipelines/_apis/health using dotnet, check response headers contains `x-vss-e2eid`
|
||||||
|
|
||||||
## How to fix the issue?
|
## How to fix the issue?
|
||||||
|
|
||||||
@@ -42,4 +64,4 @@ Make sure the runner has access to actions service for GitHub.com or GitHub Ente
|
|||||||
|
|
||||||
## Still not working?
|
## Still not working?
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
Contact [GitHub Support](https://support.github.com] if you have further questuons, or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
||||||
|
|||||||
@@ -31,4 +31,4 @@ The test also set environment variable `GIT_TRACE=1` and `GIT_CURL_VERBOSE=1` be
|
|||||||
|
|
||||||
## Still not working?
|
## Still not working?
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ Even the runner is configured to GitHub Enterprise Server, the runner can still
|
|||||||
|
|
||||||
- DNS lookup for api.github.com using dotnet
|
- DNS lookup for api.github.com using dotnet
|
||||||
- Ping api.github.com using dotnet
|
- Ping api.github.com using dotnet
|
||||||
- Make HTTP GET to https://api.github.com using dotnet, check response headers contains `X-GitHub-Request-Id`
|
- Make HTTP GET to https://api.github.com using dotnet, check response headers contains `X-GitHub-Request-Id`
|
||||||
|
|
||||||
## How to fix the issue?
|
## How to fix the issue?
|
||||||
|
|
||||||
@@ -23,4 +23,4 @@ Even the runner is configured to GitHub Enterprise Server, the runner can still
|
|||||||
|
|
||||||
## Still not working?
|
## Still not working?
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
||||||
|
|||||||
@@ -2,17 +2,19 @@
|
|||||||
|
|
||||||
### Common things that can cause the runner to not working properly
|
### Common things that can cause the runner to not working properly
|
||||||
|
|
||||||
- Bug in the runner or the dotnet framework that causes actions runner can't make Http request in a certain network environment.
|
- A bug in the runner or the dotnet framework that causes the actions runner to be unable to make Http requests in a certain network environment.
|
||||||
|
|
||||||
- Proxy/Firewall block certain HTTP method, like it block all POST and PUT calls which the runner will use to upload logs.
|
- A Proxy or Firewall may block certain HTTP method, such as blocking all POST and PUT calls which the runner will use to upload logs.
|
||||||
|
|
||||||
- Proxy/Firewall only allows requests with certain user-agent to pass through and the actions runner user-agent is not in the allow list.
|
- A Proxy or Firewall may only allows requests with certain user-agent to pass through and the actions runner user-agent is not in the allow list.
|
||||||
|
|
||||||
- Proxy try to decrypt and exam HTTPS traffic for security purpose but cause the actions-runner to fail to finish SSL handshake due to the lack of trusting proxy's CA.
|
- A Proxy try to decrypt and exam HTTPS traffic for security purpose but cause the actions-runner to fail to finish SSL handshake due to the lack of trusting proxy's CA.
|
||||||
|
|
||||||
- Proxy try to modify the HTTPS request (like add or change some http headers) and causes the request become incompatible with the Actions Service (ASP.NetCore), Ex: [Nginx](https://github.com/dotnet/aspnetcore/issues/17081)
|
- The SSL handshake may fail if the client and server do not support the same TLS version, or the same cipher suites.
|
||||||
|
|
||||||
- Firewall rules that block action runner from accessing certain hosts, ex: `*.github.com`, `*.actions.githubusercontent.com`, etc.
|
- A Proxy may try to modify the HTTPS request (like add or change some http headers) and causes the request become incompatible with the Actions Service (ASP.NetCore), Ex: [Nginx](https://github.com/dotnet/aspnetcore/issues/17081)
|
||||||
|
|
||||||
|
- Firewall rules that block action runner from accessing certain hosts, ex: `*.github.com`, `*.actions.githubusercontent.com`, etc
|
||||||
|
|
||||||
|
|
||||||
### Identify and solve these problems
|
### Identify and solve these problems
|
||||||
@@ -23,10 +25,38 @@ Use a 3rd party tool to make the same requests as the runner did would be a good
|
|||||||
|
|
||||||
- Use `nslookup` to check DNS
|
- Use `nslookup` to check DNS
|
||||||
- Use `ping` to check Ping
|
- Use `ping` to check Ping
|
||||||
- Use `traceroute`, `tracepath`, or `tracert` to check the network route between the runner and the Actions service
|
- Use `traceroute`, `tracepath`, or `tracert` to check the network route between the runner and the Actions service
|
||||||
- Use `curl -v` to check the network stack, good for verifying default certificate/proxy settings.
|
- Use `curl -v` to check the network stack, good for verifying default certificate/proxy settings.
|
||||||
- Use `Invoke-WebRequest` from `pwsh` (`PowerShell Core`) to check the dotnet network stack, good for verifying bugs in the dotnet framework.
|
- Use `Invoke-WebRequest` from `pwsh` (`PowerShell Core`) to check the dotnet network stack, good for verifying bugs in the dotnet framework.
|
||||||
|
|
||||||
If the 3rd party tool is also experiencing the same error as the runner does, then you might want to contact your network administrator for help.
|
If the 3rd party tool is also experiencing the same error as the runner does, then you might want to contact your network administrator for help.
|
||||||
|
|
||||||
Otherwise, contact GitHub customer support or log an issue at https://github.com/actions/runner
|
Otherwise, contact GitHub customer support or log an issue at https://github.com/actions/runner
|
||||||
|
|
||||||
|
### Troubleshooting: Why can't I configure a runner?
|
||||||
|
|
||||||
|
If you are having trouble connecting, try these steps:
|
||||||
|
|
||||||
|
1. Validate you can reach our endpoints from your web browser. If not, double check your local network connection
|
||||||
|
- For hosted Github:
|
||||||
|
- https://api.github.com/
|
||||||
|
- https://vstoken.actions.githubusercontent.com/_apis/health
|
||||||
|
- https://pipelines.actions.githubusercontent.com/_apis/health
|
||||||
|
- For GHES/GHAE
|
||||||
|
- https://myGHES.com/_services/vstoken/_apis/health
|
||||||
|
- https://myGHES.com/_services/pipelines/_apis/health
|
||||||
|
- https://myGHES.com/api/v3
|
||||||
|
2. Validate you can reach those endpoints in powershell core
|
||||||
|
- The runner runs on .net core, lets validate the local settings for that stack
|
||||||
|
- Open up `pwsh`
|
||||||
|
- Run the command using the urls above `Invoke-WebRequest {url}`
|
||||||
|
3. If not, get a packet trace using a tool like wireshark and start looking at the TLS handshake.
|
||||||
|
- If you see a Client Hello followed by a Server RST:
|
||||||
|
- You may need to configure your TLS settings to use the correct version
|
||||||
|
- You should support TLS version 1.2 or later
|
||||||
|
- You may need to configure your TLS settings to have up to date cipher suites, this may be solved by system updates and patches.
|
||||||
|
- Most notably, on windows server 2012 make sure [the tls cipher suite update](https://support.microsoft.com/en-us/topic/update-adds-new-tls-cipher-suites-and-changes-cipher-suite-priorities-in-windows-8-1-and-windows-server-2012-r2-8e395e43-c8ef-27d8-b60c-0fc57d526d94) is installed
|
||||||
|
- Your firewall, proxy or network configuration may be blocking the connection
|
||||||
|
- You will want to reach out to whoever is in charge of your network with these pcap files to further troubleshoot
|
||||||
|
- If you see a failure later in the handshake:
|
||||||
|
- Try the fix in the [SSLCert Fix](./sslcert.md)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
Make sure the built-in node.js has access to GitHub.com or GitHub Enterprise Server.
|
||||||
|
|
||||||
The runner carries it's own copy of node.js executable under `<runner_root>/externals/node12/`.
|
The runner carries its own copy of node.js executable under `<runner_root>/externals/node16/`.
|
||||||
|
|
||||||
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node12/`.
|
All javascript base Actions will get executed by the built-in `node` at `<runner_root>/externals/node16/`.
|
||||||
|
|
||||||
> Not the `node` from `$PATH`
|
> Not the `node` from `$PATH`
|
||||||
|
|
||||||
@@ -27,4 +27,4 @@ All javascript base Actions will get executed by the built-in `node` at `<runner
|
|||||||
|
|
||||||
## Still not working?
|
## Still not working?
|
||||||
|
|
||||||
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
Contact GitHub customer service or log an issue at https://github.com/actions/runner if you think it's a runner issue.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ As long as your certificate is generated properly, most of the issues should be
|
|||||||
> !!! DO NOT SKIP SSL CERT VALIDATION !!!
|
> !!! DO NOT SKIP SSL CERT VALIDATION !!!
|
||||||
> !!! IT IS A BAD SECURITY PRACTICE !!!
|
> !!! IT IS A BAD SECURITY PRACTICE !!!
|
||||||
|
|
||||||
### Download SSL certificate chain
|
### Download SSL certificate chain
|
||||||
|
|
||||||
Depends on how your SSL server certificate gets configured, you might need to download the whole certificate chain from a machine that has trusted the SSL certificate's CA.
|
Depends on how your SSL server certificate gets configured, you might need to download the whole certificate chain from a machine that has trusted the SSL certificate's CA.
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ The actions runner is a dotnet core application which will follow how dotnet loa
|
|||||||
|
|
||||||
You can get full details documentation at [here](https://docs.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography#x509store)
|
You can get full details documentation at [here](https://docs.microsoft.com/en-us/dotnet/standard/security/cross-platform-cryptography#x509store)
|
||||||
|
|
||||||
In short:
|
In short:
|
||||||
- Windows: Load from Windows certificate store.
|
- Windows: Load from Windows certificate store.
|
||||||
- Linux: Load from OpenSSL CA cert bundle.
|
- Linux: Load from OpenSSL CA cert bundle.
|
||||||
- macOS: Load from macOS KeyChain.
|
- macOS: Load from macOS KeyChain.
|
||||||
@@ -43,13 +43,13 @@ To let the runner trusts your CA certificate, you will need to:
|
|||||||
1. RedHat: https://www.redhat.com/sysadmin/ca-certificates-cli
|
1. RedHat: https://www.redhat.com/sysadmin/ca-certificates-cli
|
||||||
2. Ubuntu: http://manpages.ubuntu.com/manpages/focal/man8/update-ca-certificates.8.html
|
2. Ubuntu: http://manpages.ubuntu.com/manpages/focal/man8/update-ca-certificates.8.html
|
||||||
3. Google search: "trust ca certificate on [linux distribution]"
|
3. Google search: "trust ca certificate on [linux distribution]"
|
||||||
4. If all approaches failed, set environment variable `SSL_CERT_FILE` to the CA bundle `.pem` file we get.
|
4. If all approaches failed, set environment variable `SSL_CERT_FILE` to the CA bundle `.pem` file we get.
|
||||||
> To verify cert gets installed properly on Linux, you can try use `curl -v https://sitewithsslissue.com` and `pwsh -Command \"Invoke-WebRequest -Uri https://sitewithsslissue.com\"`
|
> To verify cert gets installed properly on Linux, you can try use `curl -v https://sitewithsslissue.com` and `pwsh -Command \"Invoke-WebRequest -Uri https://sitewithsslissue.com\"`
|
||||||
|
|
||||||
### Trust CA certificate for Git CLI
|
### Trust CA certificate for Git CLI
|
||||||
|
|
||||||
Git uses various CA bundle file depends on your operation system.
|
Git uses various CA bundle file depends on your operation system.
|
||||||
- Git packaged the CA bundle file within the Git installation on Windows
|
- Git packaged the CA bundle file within the Git installation on Windows
|
||||||
- Git use OpenSSL certificate CA bundle file on Linux and macOS
|
- Git use OpenSSL certificate CA bundle file on Linux and macOS
|
||||||
|
|
||||||
You can check where Git check CA file by running:
|
You can check where Git check CA file by running:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Issues in this repository should be for the runner application. Note that the V
|
|||||||
|
|
||||||
## Enhancements and Feature Requests
|
## Enhancements and Feature Requests
|
||||||
|
|
||||||
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
|
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
|
||||||
|
|
||||||
1. Create a feature request. Once agreed we will take the enhancement
|
1. Create a feature request. Once agreed we will take the enhancement
|
||||||
2. Create an ADR to agree on the details of the change.
|
2. Create an ADR to agree on the details of the change.
|
||||||
@@ -23,6 +23,10 @@ An ADR is an Architectural Decision Record. This allows consensus on the direct
|
|||||||
|
|
||||||
  Git for Windows and Linux [Install Here](https://git-scm.com/downloads) (needed for dev sh script)
|
  Git for Windows and Linux [Install Here](https://git-scm.com/downloads) (needed for dev sh script)
|
||||||
|
|
||||||
|
 cURL [Install here](https://curl.se/download.html) (needed for external sh script)
|
||||||
|
|
||||||
|
 Visual Studio 2017 or newer [Install here](https://visualstudio.microsoft.com) (needed for dev sh script)
|
||||||
|
|
||||||
## 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:
|
||||||
@@ -46,9 +50,9 @@ Tip: Make sure your job can run on this runner. The easiest way is to set `runs-
|
|||||||
|
|
||||||
|
|
||||||
## Development Life Cycle
|
## Development Life Cycle
|
||||||
If you're using VS Code, you can follow [these](contribute/vscode.md) steps instead.
|
If you're using VS Code, you can follow [these](contribute/vscode.md) steps instead.
|
||||||
|
|
||||||
### To Build, Test, Layout
|
### To Build, Test, Layout
|
||||||
|
|
||||||
Navigate to the `src` directory and run the following command:
|
Navigate to the `src` directory and run the following command:
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ These examples use VS Code, but the idea should be similar across all IDEs as lo
|
|||||||
## Configure
|
## Configure
|
||||||
|
|
||||||
To successfully start the runner, you need to register it using a repository and a runner registration token.
|
To successfully start the runner, you need to register it using a repository and a runner registration token.
|
||||||
Run `Configure` first to build the source code and set up the runner in `_layout`.
|
Run `Configure` first to build the source code and set up the runner in `_layout`.
|
||||||
Once it's done creating `_layout`, it asks for the url of your repository and your token in the terminal.
|
Once it's done creating `_layout`, it asks for the url of your repository and your token in the terminal.
|
||||||
|
|
||||||
Check [Quickstart](../contribute.md#quickstart-run-a-job-from-a-real-repository) if you don't know how to get this token.
|
Check [Quickstart](../contribute.md#quickstart-run-a-job-from-a-real-repository) if you don't know how to get this token.
|
||||||
@@ -34,7 +34,7 @@ All the configs below can be found in `.vscode/launch.json`.
|
|||||||
|
|
||||||
If you launch `Run` or `Run [build]`, it starts a process called `Runner.Listener`.
|
If you launch `Run` or `Run [build]`, it starts a process called `Runner.Listener`.
|
||||||
This process will receive any job queued on this repository if the job runs on matching labels (e.g `runs-on: self-hosted`).
|
This process will receive any job queued on this repository if the job runs on matching labels (e.g `runs-on: self-hosted`).
|
||||||
Once a job is received, a `Runner.Listener` starts a new process of `Runner.Worker`.
|
Once a job is received, a `Runner.Listener` starts a new process of `Runner.Worker`.
|
||||||
Since this is a diferent process, you can't use the same debugger session debug it.
|
Since this is a diferent process, you can't use the same debugger session debug it.
|
||||||
Instead, a parallel debugging session has to be started, using a different launch config.
|
Instead, a parallel debugging session has to be started, using a different launch config.
|
||||||
Luckily, VS Code supports multiple parallel debugging sessions.
|
Luckily, VS Code supports multiple parallel debugging sessions.
|
||||||
@@ -45,7 +45,7 @@ Because the worker process is usually started by the listener instead of an IDE,
|
|||||||
For this reason, `Runner.Worker` can be configured to wait for a debugger to be attached before it begins any actual work.
|
For this reason, `Runner.Worker` can be configured to wait for a debugger to be attached before it begins any actual work.
|
||||||
|
|
||||||
Set the environment variable `GITHUB_ACTIONS_RUNNER_ATTACH_DEBUGGER` to `true` or `1` to enable this wait.
|
Set the environment variable `GITHUB_ACTIONS_RUNNER_ATTACH_DEBUGGER` to `true` or `1` to enable this wait.
|
||||||
All worker processes now will wait 20 seconds before they start working on their task.
|
All worker processes now will wait 20 seconds before they start working on their task.
|
||||||
|
|
||||||
This gives enough time to attach a debugger by running `Debug Worker`.
|
This gives enough time to attach a debugger by running `Debug Worker`.
|
||||||
If for some reason you have multiple workers running, run the launch config `Attach` instead.
|
If for some reason you have multiple workers running, run the launch config `Attach` instead.
|
||||||
|
|||||||
@@ -58,4 +58,4 @@ Authentication in a workflow run to github.com can be accomplished by using the
|
|||||||
|
|
||||||
Hosted runner authentication differs from self-hosted authentication in that runners do not undergo a registration process, but instead, the hosted runners get the OAuth token directly by reading the `.credentials` file. The scope of this particular token is limited for a given workflow job execution, and the token is revoked as soon as the job is finished.
|
Hosted runner authentication differs from self-hosted authentication in that runners do not undergo a registration process, but instead, the hosted runners get the OAuth token directly by reading the `.credentials` file. The scope of this particular token is limited for a given workflow job execution, and the token is revoked as soon as the job is finished.
|
||||||
|
|
||||||

|

|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 158 KiB After Width: | Height: | Size: 138 KiB |
@@ -23,11 +23,11 @@ You might see something like this which indicate a dependency's missing.
|
|||||||
./config.sh
|
./config.sh
|
||||||
libunwind.so.8 => not found
|
libunwind.so.8 => not found
|
||||||
libunwind-x86_64.so.8 => not found
|
libunwind-x86_64.so.8 => not found
|
||||||
Dependencies is missing for Dotnet Core 3.0
|
Dependencies is missing for Dotnet Core 6.0
|
||||||
Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies.
|
Execute ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies.
|
||||||
```
|
```
|
||||||
You can easily correct the problem by executing `./bin/installdependencies.sh`.
|
You can easily correct the problem by executing `./bin/installdependencies.sh`.
|
||||||
The `installdependencies.sh` script should install all required dependencies on all supported Linux versions
|
The `installdependencies.sh` script should install all required dependencies on all supported Linux versions
|
||||||
> Note: The `installdependencies.sh` script will try to use the default package management mechanism on your Linux flavor (ex. `yum`/`apt-get`/`apt`).
|
> Note: The `installdependencies.sh` script will try to use the default package management mechanism on your Linux flavor (ex. `yum`/`apt-get`/`apt`).
|
||||||
|
|
||||||
### Full dependencies list
|
### Full dependencies list
|
||||||
@@ -35,15 +35,15 @@ 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-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
|
||||||
- libicu63, libicu60, libicu57 or libicu55
|
- libicu63, libicu60, libicu57 or libicu55
|
||||||
|
|
||||||
Fedora based OS (Fedora, Red Hat Enterprise Linux, CentOS, Oracle Linux 7)
|
Fedora based OS (Fedora, Red Hat Enterprise Linux, CentOS, Oracle Linux 7)
|
||||||
|
|
||||||
- lttng-ust
|
- lttng-ust
|
||||||
- openssl-libs
|
- openssl-libs
|
||||||
- krb5-libs
|
- krb5-libs
|
||||||
- zlib
|
- zlib
|
||||||
- libicu
|
- libicu
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
## Supported Versions
|
## Supported Versions
|
||||||
|
|
||||||
- macOS High Sierra (10.13) and later versions
|
- macOS High Sierra (10.13) and later versions
|
||||||
|
|
||||||
## Apple Silicon M1
|
## Apple Silicon M1
|
||||||
|
|
||||||
The runner is currently not supported on devices with an Apple M1 chip.
|
The runner is currently not supported on devices with an Apple M1 chip.
|
||||||
|
|||||||
@@ -1,21 +1,7 @@
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- Add Job Message size to both Worker and Listener logs for debugging (#1100)
|
|
||||||
- Add notice annotation level (in addition to error and warning) and support more annotation fields (#1175)
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
- Fixed an issue where container environment variables names or values could escape the docker command (#2108)
|
||||||
- Remove the `NODE_ICU_DATA` environment variable that may cause conflicts with node within the runner. (#1060)
|
|
||||||
- Handle cancelled jobs better to prevent orphaned processes (#1083)
|
|
||||||
- No longer fail to remove a `systemd` service with `svc.sh uninstall` if the script had previously been run from the wrong location (#1135)
|
|
||||||
- Send `SIGKILL` to the runner listener if it doesn't respond to `SIGINT` for 30 seconds
|
|
||||||
- Match runner group name when configuring even if there's only a single runner group
|
|
||||||
|
|
||||||
|
|
||||||
## Misc
|
|
||||||
- Fix automation links in documentation (#1089)
|
|
||||||
- Improve developer and first contributor experience by improving tooling for VS Code (#1101, #1117, #1119, #1132)
|
|
||||||
- Fix bug where linux users are not able to run remove-svc.sh as root (#1127)
|
|
||||||
|
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
@@ -28,7 +14,7 @@ mkdir \actions-runner ; cd \actions-runner
|
|||||||
# Download the latest runner package
|
# Download the latest runner package
|
||||||
Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-win-x64-<RUNNER_VERSION>.zip -OutFile actions-runner-win-x64-<RUNNER_VERSION>.zip
|
Invoke-WebRequest -Uri https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-win-x64-<RUNNER_VERSION>.zip -OutFile actions-runner-win-x64-<RUNNER_VERSION>.zip
|
||||||
# Extract the installer
|
# Extract the installer
|
||||||
Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
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")
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -88,3 +74,21 @@ The SHA-256 checksums for the packages included in this build are shown below:
|
|||||||
- 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 -->
|
||||||
- actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm64 --><LINUX_ARM64_SHA><!-- END SHA linux-arm64 -->
|
- actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm64 --><LINUX_ARM64_SHA><!-- END SHA linux-arm64 -->
|
||||||
- actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm --><LINUX_ARM_SHA><!-- END SHA linux-arm -->
|
- actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm --><LINUX_ARM_SHA><!-- END SHA linux-arm -->
|
||||||
|
|
||||||
|
- actions-runner-win-x64-<RUNNER_VERSION>-noexternals.zip <!-- BEGIN SHA win-x64_noexternals --><WIN_X64_SHA_NOEXTERNALS><!-- END SHA win-x64_noexternals -->
|
||||||
|
- actions-runner-osx-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA osx-x64_noexternals --><OSX_X64_SHA_NOEXTERNALS><!-- END SHA osx-x64_noexternals -->
|
||||||
|
- actions-runner-linux-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noexternals --><LINUX_X64_SHA_NOEXTERNALS><!-- END SHA linux-x64_noexternals -->
|
||||||
|
- actions-runner-linux-arm64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-arm64_noexternals --><LINUX_ARM64_SHA_NOEXTERNALS><!-- END SHA linux-arm64_noexternals -->
|
||||||
|
- actions-runner-linux-arm-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-arm_noexternals --><LINUX_ARM_SHA_NOEXTERNALS><!-- END SHA linux-arm_noexternals -->
|
||||||
|
|
||||||
|
- actions-runner-win-x64-<RUNNER_VERSION>-noruntime.zip <!-- BEGIN SHA win-x64_noruntime --><WIN_X64_SHA_NORUNTIME><!-- END SHA win-x64_noruntime -->
|
||||||
|
- actions-runner-osx-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA osx-x64_noruntime --><OSX_X64_SHA_NORUNTIME><!-- END SHA osx-x64_noruntime -->
|
||||||
|
- actions-runner-linux-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-x64_noruntime --><LINUX_X64_SHA_NORUNTIME><!-- END SHA linux-x64_noruntime -->
|
||||||
|
- actions-runner-linux-arm64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-arm64_noruntime --><LINUX_ARM64_SHA_NORUNTIME><!-- END SHA linux-arm64_noruntime -->
|
||||||
|
- actions-runner-linux-arm-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-arm_noruntime --><LINUX_ARM_SHA_NORUNTIME><!-- END SHA linux-arm_noruntime -->
|
||||||
|
|
||||||
|
- actions-runner-win-x64-<RUNNER_VERSION>-noruntime-noexternals.zip <!-- BEGIN SHA win-x64_noruntime_noexternals --><WIN_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA win-x64_noruntime_noexternals -->
|
||||||
|
- actions-runner-osx-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA osx-x64_noruntime_noexternals --><OSX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA osx-x64_noruntime_noexternals -->
|
||||||
|
- actions-runner-linux-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noruntime_noexternals --><LINUX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-x64_noruntime_noexternals -->
|
||||||
|
- actions-runner-linux-arm64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-arm64_noruntime_noexternals --><LINUX_ARM64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-arm64_noruntime_noexternals -->
|
||||||
|
- actions-runner-linux-arm-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-arm_noruntime_noexternals --><LINUX_ARM_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-arm_noruntime_noexternals -->
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<Update to ./src/runnerversion when creating release>
|
2.289.4
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Sample scripts for self-hosted runners
|
# Sample scripts for self-hosted runners
|
||||||
|
|
||||||
Here are some examples to work from if you'd like to automate your use of self-hosted runners.
|
Here are some examples to work from if you'd like to automate your use of self-hosted runners.
|
||||||
See the docs [here](../docs/automate.md).
|
See the docs [here](../docs/automate.md).
|
||||||
|
|||||||
@@ -2,36 +2,73 @@
|
|||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
#
|
|
||||||
# Downloads latest releases (not pre-release) runner
|
|
||||||
# Configures as a service
|
|
||||||
#
|
|
||||||
# Examples:
|
|
||||||
# RUNNER_CFG_PAT=<yourPAT> ./create-latest-svc.sh myuser/myrepo my.ghe.deployment.net
|
|
||||||
# RUNNER_CFG_PAT=<yourPAT> ./create-latest-svc.sh myorg my.ghe.deployment.net
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
# export RUNNER_CFG_PAT=<yourPAT>
|
|
||||||
# ./create-latest-svc scope [ghe_domain] [name] [user] [labels]
|
|
||||||
#
|
|
||||||
# scope required repo (:owner/:repo) or org (:organization)
|
|
||||||
# ghe_domain optional the fully qualified domain name of your GitHub Enterprise Server deployment
|
|
||||||
# name optional defaults to hostname
|
|
||||||
# user optional user svc will run as. defaults to current
|
|
||||||
# labels optional list of labels (split by comma) applied on the runner
|
|
||||||
#
|
|
||||||
# Notes:
|
# Notes:
|
||||||
# PATS over envvars are more secure
|
# PATS over envvars are more secure
|
||||||
|
# Downloads latest runner release (not pre-release)
|
||||||
|
# Configures it as a service more secure
|
||||||
# Should be used on VMs and not containers
|
# Should be used on VMs and not containers
|
||||||
# Works on OSX and Linux
|
# Works on OSX and Linux
|
||||||
# Assumes x64 arch
|
# Assumes x64 arch
|
||||||
#
|
# See EXAMPLES below
|
||||||
|
|
||||||
runner_scope=${1}
|
flags_found=false
|
||||||
ghe_hostname=${2}
|
|
||||||
runner_name=${3:-$(hostname)}
|
while getopts 's:g:n:r:u:l:' opt; do
|
||||||
svc_user=${4:-$USER}
|
flags_found=true
|
||||||
labels=${5}
|
|
||||||
|
case $opt in
|
||||||
|
s)
|
||||||
|
runner_scope=$OPTARG
|
||||||
|
;;
|
||||||
|
g)
|
||||||
|
ghe_hostname=$OPTARG
|
||||||
|
;;
|
||||||
|
n)
|
||||||
|
runner_name=$OPTARG
|
||||||
|
;;
|
||||||
|
r)
|
||||||
|
runner_group=$OPTARG
|
||||||
|
;;
|
||||||
|
u)
|
||||||
|
svc_user=$OPTARG
|
||||||
|
;;
|
||||||
|
l)
|
||||||
|
labels=$OPTARG
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "
|
||||||
|
Runner Service Installer
|
||||||
|
Examples:
|
||||||
|
RUNNER_CFG_PAT=<yourPAT> ./create-latest-svc.sh myuser/myrepo my.ghe.deployment.net
|
||||||
|
RUNNER_CFG_PAT=<yourPAT> ./create-latest-svc.sh -s myorg -u user_name -l label1,label2
|
||||||
|
Usage:
|
||||||
|
export RUNNER_CFG_PAT=<yourPAT>
|
||||||
|
./create-latest-svc scope [ghe_domain] [name] [user] [labels]
|
||||||
|
-s required scope: repo (:owner/:repo) or org (:organization)
|
||||||
|
-g optional ghe_hostname: the fully qualified domain name of your GitHub Enterprise Server deployment
|
||||||
|
-n optional name of the runner, defaults to hostname
|
||||||
|
-r optional name of the runner group to add the runner to, defaults to the Default group
|
||||||
|
-u optional user svc will run as, defaults to current
|
||||||
|
-l optional list of labels (split by comma) applied on the runner"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
shift "$((OPTIND - 1))"
|
||||||
|
|
||||||
|
if ! "$flags_found"; then
|
||||||
|
runner_scope=${1}
|
||||||
|
ghe_hostname=${2}
|
||||||
|
runner_name=${3:-$(hostname)}
|
||||||
|
svc_user=${4:-$USER}
|
||||||
|
labels=${5}
|
||||||
|
runner_group=${6}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# apply defaults
|
||||||
|
runner_name=${runner_name:-$(hostname)}
|
||||||
|
svc_user=${svc_user:-$USER}
|
||||||
|
|
||||||
echo "Configuring runner @ ${runner_scope}"
|
echo "Configuring runner @ ${runner_scope}"
|
||||||
sudo echo
|
sudo echo
|
||||||
@@ -132,8 +169,8 @@ fi
|
|||||||
|
|
||||||
echo
|
echo
|
||||||
echo "Configuring ${runner_name} @ $runner_url"
|
echo "Configuring ${runner_name} @ $runner_url"
|
||||||
echo "./config.sh --unattended --url $runner_url --token *** --name $runner_name --labels $labels"
|
echo "./config.sh --unattended --url $runner_url --token *** --name $runner_name ${labels:+--labels $labels} ${runner_group:+--runnergroup \"$runner_group\"}"
|
||||||
sudo -E -u ${svc_user} ./config.sh --unattended --url $runner_url --token $RUNNER_TOKEN --name $runner_name --labels $labels
|
sudo -E -u ${svc_user} ./config.sh --unattended --url $runner_url --token $RUNNER_TOKEN --name $runner_name ${labels:+--labels $labels} ${runner_group:+--runnergroup "$runner_group"}
|
||||||
|
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
# Configuring as a service
|
# Configuring as a service
|
||||||
@@ -142,7 +179,7 @@ echo
|
|||||||
echo "Configuring as a service ..."
|
echo "Configuring as a service ..."
|
||||||
prefix=""
|
prefix=""
|
||||||
if [ "${runner_plat}" == "linux" ]; then
|
if [ "${runner_plat}" == "linux" ]; then
|
||||||
prefix="sudo "
|
prefix="sudo "
|
||||||
fi
|
fi
|
||||||
|
|
||||||
${prefix}./svc.sh install ${svc_user}
|
${prefix}./svc.sh install ${svc_user}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ fi
|
|||||||
# Ensure offline
|
# Ensure offline
|
||||||
#--------------------------------------
|
#--------------------------------------
|
||||||
runner_status=$(curl -s -X GET ${base_api_url}/${runner_scope}/actions/runners?per_page=100 -H "accept: application/vnd.github.everest-preview+json" -H "authorization: token ${RUNNER_CFG_PAT}" \
|
runner_status=$(curl -s -X GET ${base_api_url}/${runner_scope}/actions/runners?per_page=100 -H "accept: application/vnd.github.everest-preview+json" -H "authorization: token ${RUNNER_CFG_PAT}" \
|
||||||
| jq -M -j ".runners | .[] | [select(.name == \"${runner_name}\")] | .[0].status")
|
| jq -M -j ".runners | .[] | select(.name == \"${runner_name}\") | .status")
|
||||||
|
|
||||||
if [ -z "${runner_status}" ]; then
|
if [ -z "${runner_status}" ]; then
|
||||||
fatal "Could not find runner with name ${runner_name}"
|
fatal "Could not find runner with name ${runner_name}"
|
||||||
@@ -67,7 +67,7 @@ fi
|
|||||||
# Get id of runner to remove
|
# Get id of runner to remove
|
||||||
#--------------------------------------
|
#--------------------------------------
|
||||||
runner_id=$(curl -s -X GET ${base_api_url}/${runner_scope}/actions/runners?per_page=100 -H "accept: application/vnd.github.everest-preview+json" -H "authorization: token ${RUNNER_CFG_PAT}" \
|
runner_id=$(curl -s -X GET ${base_api_url}/${runner_scope}/actions/runners?per_page=100 -H "accept: application/vnd.github.everest-preview+json" -H "authorization: token ${RUNNER_CFG_PAT}" \
|
||||||
| jq -M -j ".runners | .[] | [select(.name == \"${runner_name}\")] | .[0].id")
|
| jq -M -j ".runners | .[] | select(.name == \"${runner_name}\") | .id")
|
||||||
|
|
||||||
if [ -z "${runner_id}" ]; then
|
if [ -z "${runner_id}" ]; then
|
||||||
fatal "Could not find runner with name ${runner_name}"
|
fatal "Could not find runner with name ${runner_name}"
|
||||||
|
|||||||
1
src/Misc/contentHash/dotnetRuntime/linux-arm
Normal file
1
src/Misc/contentHash/dotnetRuntime/linux-arm
Normal file
@@ -0,0 +1 @@
|
|||||||
|
de62d296708908cfd1236e58869aebbc2bae8a8c3d629276968542626c508e37
|
||||||
1
src/Misc/contentHash/dotnetRuntime/linux-arm64
Normal file
1
src/Misc/contentHash/dotnetRuntime/linux-arm64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
44fcd0422dd98ed17d2c8e9057ff2260c50165f20674236a4ae7d2645a07df25
|
||||||
1
src/Misc/contentHash/dotnetRuntime/linux-x64
Normal file
1
src/Misc/contentHash/dotnetRuntime/linux-x64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
e57652cf322ee16ce3af4f9e58f80858746b9e1e60279e991a3b3d9a6baf8d79
|
||||||
1
src/Misc/contentHash/dotnetRuntime/osx-x64
Normal file
1
src/Misc/contentHash/dotnetRuntime/osx-x64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
bdd247b2ff3f51095524412e2ac588e7a87af805e114d6caf2368366ee7be1ea
|
||||||
1
src/Misc/contentHash/dotnetRuntime/win-x64
Normal file
1
src/Misc/contentHash/dotnetRuntime/win-x64
Normal file
@@ -0,0 +1 @@
|
|||||||
|
d23a0cb9f20c0aa1cddb7a39567cd097020cdeb06a1e952940601d1a405c53b8
|
||||||
1
src/Misc/contentHash/externals/linux-arm
vendored
Normal file
1
src/Misc/contentHash/externals/linux-arm
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
6ed30a2c1ee403a610d63e82bb230b9ba846a9c25cec9e4ea8672fb6ed4e1a51
|
||||||
1
src/Misc/contentHash/externals/linux-arm64
vendored
Normal file
1
src/Misc/contentHash/externals/linux-arm64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
711c30c51ec52c9b7a9a2eb399d6ab2ab5ee1dc72de11879f2f36f919f163d78
|
||||||
1
src/Misc/contentHash/externals/linux-x64
vendored
Normal file
1
src/Misc/contentHash/externals/linux-x64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
a49479ca4b4988a06c097e8d22c51fd08a11c13f40807366236213d0e008cf6a
|
||||||
1
src/Misc/contentHash/externals/osx-x64
vendored
Normal file
1
src/Misc/contentHash/externals/osx-x64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8e97df75230b843462a9b4c578ccec604ee4b4a1066120c85b04374317fa372b
|
||||||
1
src/Misc/contentHash/externals/win-x64
vendored
Normal file
1
src/Misc/contentHash/externals/win-x64
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
f75a671e5a188c76680739689aa75331a2c09d483dce9c80023518c48fd67a18
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"plugins": ["jest", "@typescript-eslint"],
|
"plugins": ["@typescript-eslint"],
|
||||||
"extends": ["plugin:github/es6"],
|
"extends": ["plugin:github/recommended"],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 9,
|
"ecmaVersion": 9,
|
||||||
@@ -17,13 +17,16 @@
|
|||||||
"@typescript-eslint/no-require-imports": "error",
|
"@typescript-eslint/no-require-imports": "error",
|
||||||
"@typescript-eslint/array-type": "error",
|
"@typescript-eslint/array-type": "error",
|
||||||
"@typescript-eslint/await-thenable": "error",
|
"@typescript-eslint/await-thenable": "error",
|
||||||
"@typescript-eslint/ban-ts-ignore": "error",
|
"@typescript-eslint/naming-convention": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"selector": "default",
|
||||||
|
"format": ["camelCase"]
|
||||||
|
}
|
||||||
|
],
|
||||||
"camelcase": "off",
|
"camelcase": "off",
|
||||||
"@typescript-eslint/camelcase": "error",
|
|
||||||
"@typescript-eslint/class-name-casing": "error",
|
|
||||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
|
||||||
"@typescript-eslint/no-array-constructor": "error",
|
"@typescript-eslint/no-array-constructor": "error",
|
||||||
"@typescript-eslint/no-empty-interface": "error",
|
"@typescript-eslint/no-empty-interface": "error",
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
"@typescript-eslint/no-explicit-any": "error",
|
||||||
@@ -33,7 +36,6 @@
|
|||||||
"@typescript-eslint/no-misused-new": "error",
|
"@typescript-eslint/no-misused-new": "error",
|
||||||
"@typescript-eslint/no-namespace": "error",
|
"@typescript-eslint/no-namespace": "error",
|
||||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||||
"@typescript-eslint/no-useless-constructor": "error",
|
"@typescript-eslint/no-useless-constructor": "error",
|
||||||
@@ -41,19 +43,19 @@
|
|||||||
"@typescript-eslint/prefer-for-of": "warn",
|
"@typescript-eslint/prefer-for-of": "warn",
|
||||||
"@typescript-eslint/prefer-function-type": "warn",
|
"@typescript-eslint/prefer-function-type": "warn",
|
||||||
"@typescript-eslint/prefer-includes": "error",
|
"@typescript-eslint/prefer-includes": "error",
|
||||||
"@typescript-eslint/prefer-interface": "error",
|
|
||||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||||
"@typescript-eslint/promise-function-async": "error",
|
"@typescript-eslint/promise-function-async": "error",
|
||||||
"@typescript-eslint/require-array-sort-compare": "error",
|
"@typescript-eslint/require-array-sort-compare": "error",
|
||||||
"@typescript-eslint/restrict-plus-operands": "error",
|
"@typescript-eslint/restrict-plus-operands": "error",
|
||||||
"semi": "off",
|
|
||||||
"@typescript-eslint/semi": ["error", "never"],
|
"@typescript-eslint/semi": ["error", "never"],
|
||||||
"@typescript-eslint/type-annotation-spacing": "error",
|
"@typescript-eslint/type-annotation-spacing": "error",
|
||||||
"@typescript-eslint/unbound-method": "error"
|
"@typescript-eslint/unbound-method": "error",
|
||||||
|
"filenames/match-regex" : "off",
|
||||||
|
"github/no-then" : 1, // warning
|
||||||
|
"semi": "off"
|
||||||
},
|
},
|
||||||
"env": {
|
"env": {
|
||||||
"node": true,
|
"node": true,
|
||||||
"es6": true,
|
"es6": true
|
||||||
"jest/globals": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
5175
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
5175
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -25,10 +25,10 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^12.7.12",
|
"@types/node": "^12.7.12",
|
||||||
"@typescript-eslint/parser": "^2.8.0",
|
"@typescript-eslint/parser": "^5.15.0",
|
||||||
"@zeit/ncc": "^0.20.5",
|
"@zeit/ncc": "^0.20.5",
|
||||||
"eslint": "^6.8.0",
|
"eslint": "^8.11.0",
|
||||||
"eslint-plugin-github": "^2.0.0",
|
"eslint-plugin-github": "^4.3.5",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
"typescript": "^3.6.4"
|
"typescript": "^3.6.4"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import * as glob from '@actions/glob'
|
|
||||||
import * as crypto from 'crypto'
|
import * as crypto from 'crypto'
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
|
import * as glob from '@actions/glob'
|
||||||
|
import * as path from 'path'
|
||||||
import * as stream from 'stream'
|
import * as stream from 'stream'
|
||||||
import * as util from 'util'
|
import * as util from 'util'
|
||||||
import * as path from 'path'
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
// arg0 -> node
|
// arg0 -> node
|
||||||
@@ -45,7 +45,7 @@ async function run(): Promise<void> {
|
|||||||
result.end()
|
result.end()
|
||||||
|
|
||||||
if (hasMatch) {
|
if (hasMatch) {
|
||||||
console.log(`Find ${count} files to hash.`)
|
console.log(`Found ${count} files to hash.`)
|
||||||
console.error(`__OUTPUT__${result.digest('hex')}__OUTPUT__`)
|
console.error(`__OUTPUT__${result.digest('hex')}__OUTPUT__`)
|
||||||
} else {
|
} else {
|
||||||
console.error(`__OUTPUT____OUTPUT__`)
|
console.error(`__OUTPUT____OUTPUT__`)
|
||||||
@@ -53,3 +53,11 @@ async function run(): Promise<void> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
run()
|
run()
|
||||||
|
.then(out => {
|
||||||
|
console.log(out)
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ PACKAGERUNTIME=$1
|
|||||||
PRECACHE=$2
|
PRECACHE=$2
|
||||||
|
|
||||||
NODE_URL=https://nodejs.org/dist
|
NODE_URL=https://nodejs.org/dist
|
||||||
NODE12_VERSION="12.13.1"
|
NODE12_VERSION="12.22.7"
|
||||||
|
NODE16_VERSION="16.13.0"
|
||||||
|
|
||||||
get_abs_path() {
|
get_abs_path() {
|
||||||
# exploits the fact that pwd will print abs path when no args
|
# exploits the fact that pwd will print abs path when no args
|
||||||
@@ -126,6 +127,8 @@ function acquireExternalTool() {
|
|||||||
if [[ "$PACKAGERUNTIME" == "win-x64" || "$PACKAGERUNTIME" == "win-x86" ]]; then
|
if [[ "$PACKAGERUNTIME" == "win-x64" || "$PACKAGERUNTIME" == "win-x86" ]]; then
|
||||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/$PACKAGERUNTIME/node.exe" node12/bin
|
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/$PACKAGERUNTIME/node.exe" node12/bin
|
||||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/$PACKAGERUNTIME/node.lib" node12/bin
|
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/$PACKAGERUNTIME/node.lib" node12/bin
|
||||||
|
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/$PACKAGERUNTIME/node.exe" node16/bin
|
||||||
|
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/$PACKAGERUNTIME/node.lib" node16/bin
|
||||||
if [[ "$PRECACHE" != "" ]]; then
|
if [[ "$PRECACHE" != "" ]]; then
|
||||||
acquireExternalTool "https://github.com/microsoft/vswhere/releases/download/2.6.7/vswhere.exe" vswhere
|
acquireExternalTool "https://github.com/microsoft/vswhere/releases/download/2.6.7/vswhere.exe" vswhere
|
||||||
fi
|
fi
|
||||||
@@ -134,18 +137,23 @@ 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
|
||||||
|
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-x64.tar.gz" node16 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Download the external tools for Linux PACKAGERUNTIMEs.
|
# Download the external tools for Linux PACKAGERUNTIMEs.
|
||||||
if [[ "$PACKAGERUNTIME" == "linux-x64" ]]; then
|
if [[ "$PACKAGERUNTIME" == "linux-x64" ]]; then
|
||||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-x64.tar.gz" node12 fix_nested_dir
|
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-x64.tar.gz" node12 fix_nested_dir
|
||||||
acquireExternalTool "https://vstsagenttools.blob.core.windows.net/tools/nodejs/${NODE12_VERSION}/alpine/x64/node-${NODE12_VERSION}-alpine-x64.tar.gz" node12_alpine
|
acquireExternalTool "https://vstsagenttools.blob.core.windows.net/tools/nodejs/${NODE12_VERSION}/alpine/x64/node-v${NODE12_VERSION}-alpine-x64.tar.gz" node12_alpine
|
||||||
|
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-linux-x64.tar.gz" node16 fix_nested_dir
|
||||||
|
acquireExternalTool "https://vstsagenttools.blob.core.windows.net/tools/nodejs/${NODE16_VERSION}/alpine/x64/node-v${NODE16_VERSION}-alpine-x64.tar.gz" node16_alpine
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$PACKAGERUNTIME" == "linux-arm64" ]]; then
|
if [[ "$PACKAGERUNTIME" == "linux-arm64" ]]; then
|
||||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-arm64.tar.gz" node12 fix_nested_dir
|
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-arm64.tar.gz" node12 fix_nested_dir
|
||||||
|
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-linux-arm64.tar.gz" node16 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "$PACKAGERUNTIME" == "linux-arm" ]]; then
|
if [[ "$PACKAGERUNTIME" == "linux-arm" ]]; then
|
||||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-armv7l.tar.gz" node12 fix_nested_dir
|
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-armv7l.tar.gz" node12 fix_nested_dir
|
||||||
|
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-linux-armv7l.tar.gz" node16 fix_nested_dir
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -3,94 +3,135 @@
|
|||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
var childProcess = require("child_process");
|
var childProcess = require("child_process");
|
||||||
var path = require("path")
|
var path = require("path");
|
||||||
|
|
||||||
var supported = ['linux', 'darwin']
|
var supported = ["linux", "darwin"];
|
||||||
|
|
||||||
if (supported.indexOf(process.platform) == -1) {
|
if (supported.indexOf(process.platform) == -1) {
|
||||||
console.log('Unsupported platform: ' + process.platform);
|
console.log("Unsupported platform: " + process.platform);
|
||||||
console.log('Supported platforms are: ' + supported.toString());
|
console.log("Supported platforms are: " + supported.toString());
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var stopping = false;
|
var stopping = false;
|
||||||
var listener = null;
|
var listener = null;
|
||||||
|
|
||||||
var runService = function () {
|
var exitServiceAfterNFailures = Number(
|
||||||
var listenerExePath = path.join(__dirname, '../bin/Runner.Listener');
|
process.env.GITHUB_ACTIONS_SERVICE_EXIT_AFTER_N_FAILURES
|
||||||
var interactive = process.argv[2] === "interactive";
|
);
|
||||||
|
|
||||||
if (!stopping) {
|
if (exitServiceAfterNFailures <= 0) {
|
||||||
try {
|
exitServiceAfterNFailures = NaN;
|
||||||
if (interactive) {
|
|
||||||
console.log('Starting Runner listener interactively');
|
|
||||||
listener = childProcess.spawn(listenerExePath, ['run'], { env: process.env });
|
|
||||||
} else {
|
|
||||||
console.log('Starting Runner listener with startup type: service');
|
|
||||||
listener = childProcess.spawn(listenerExePath, ['run', '--startuptype', 'service'], { env: process.env });
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(`Started listener process, pid: ${listener.pid}`);
|
|
||||||
|
|
||||||
listener.stdout.on('data', (data) => {
|
|
||||||
process.stdout.write(data.toString('utf8'));
|
|
||||||
});
|
|
||||||
|
|
||||||
listener.stderr.on('data', (data) => {
|
|
||||||
process.stdout.write(data.toString('utf8'));
|
|
||||||
});
|
|
||||||
|
|
||||||
listener.on("error", (err) => {
|
|
||||||
console.log(`Runner listener fail to start with error ${err.message}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
listener.on('close', (code) => {
|
|
||||||
console.log(`Runner listener exited with error code ${code}`);
|
|
||||||
|
|
||||||
if (code === 0) {
|
|
||||||
console.log('Runner listener exit with 0 return code, stop the service, no retry needed.');
|
|
||||||
stopping = true;
|
|
||||||
} else if (code === 1) {
|
|
||||||
console.log('Runner listener exit with terminated error, stop the service, no retry needed.');
|
|
||||||
stopping = true;
|
|
||||||
} else if (code === 2) {
|
|
||||||
console.log('Runner listener exit with retryable error, re-launch runner in 5 seconds.');
|
|
||||||
} else if (code === 3) {
|
|
||||||
console.log('Runner listener exit because of updating, re-launch runner in 5 seconds.');
|
|
||||||
} else {
|
|
||||||
console.log('Runner listener exit with undefined return code, re-launch runner in 5 seconds.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stopping) {
|
|
||||||
setTimeout(runService, 5000);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (ex) {
|
|
||||||
console.log(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var consecutiveFailureCount = 0;
|
||||||
|
|
||||||
|
var gracefulShutdown = function () {
|
||||||
|
console.log("Shutting down runner listener");
|
||||||
|
stopping = true;
|
||||||
|
if (listener) {
|
||||||
|
console.log("Sending SIGINT to runner listener to stop");
|
||||||
|
listener.kill("SIGINT");
|
||||||
|
|
||||||
|
console.log("Sending SIGKILL to runner listener");
|
||||||
|
setTimeout(() => listener.kill("SIGKILL"), 30000).unref();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var runService = function () {
|
||||||
|
var listenerExePath = path.join(__dirname, "../bin/Runner.Listener");
|
||||||
|
var interactive = process.argv[2] === "interactive";
|
||||||
|
|
||||||
|
if (!stopping) {
|
||||||
|
try {
|
||||||
|
if (interactive) {
|
||||||
|
console.log("Starting Runner listener interactively");
|
||||||
|
listener = childProcess.spawn(listenerExePath, ["run"], {
|
||||||
|
env: process.env,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log("Starting Runner listener with startup type: service");
|
||||||
|
listener = childProcess.spawn(
|
||||||
|
listenerExePath,
|
||||||
|
["run", "--startuptype", "service"],
|
||||||
|
{ env: process.env }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Started listener process, pid: ${listener.pid}`);
|
||||||
|
|
||||||
|
listener.stdout.on("data", (data) => {
|
||||||
|
if (data.toString("utf8").includes("Listening for Jobs")) {
|
||||||
|
consecutiveFailureCount = 0;
|
||||||
|
}
|
||||||
|
process.stdout.write(data.toString("utf8"));
|
||||||
|
});
|
||||||
|
|
||||||
|
listener.stderr.on("data", (data) => {
|
||||||
|
process.stdout.write(data.toString("utf8"));
|
||||||
|
});
|
||||||
|
|
||||||
|
listener.on("error", (err) => {
|
||||||
|
console.log(`Runner listener fail to start with error ${err.message}`);
|
||||||
|
});
|
||||||
|
|
||||||
|
listener.on("close", (code) => {
|
||||||
|
console.log(`Runner listener exited with error code ${code}`);
|
||||||
|
|
||||||
|
if (code === 0) {
|
||||||
|
console.log(
|
||||||
|
"Runner listener exit with 0 return code, stop the service, no retry needed."
|
||||||
|
);
|
||||||
|
stopping = true;
|
||||||
|
} else if (code === 1) {
|
||||||
|
console.log(
|
||||||
|
"Runner listener exit with terminated error, stop the service, no retry needed."
|
||||||
|
);
|
||||||
|
stopping = true;
|
||||||
|
} else if (code === 2) {
|
||||||
|
console.log(
|
||||||
|
"Runner listener exit with retryable error, re-launch runner in 5 seconds."
|
||||||
|
);
|
||||||
|
consecutiveFailureCount = 0;
|
||||||
|
} else if (code === 3 || code === 4) {
|
||||||
|
console.log(
|
||||||
|
"Runner listener exit because of updating, re-launch runner in 5 seconds."
|
||||||
|
);
|
||||||
|
consecutiveFailureCount = 0;
|
||||||
|
} else {
|
||||||
|
var messagePrefix = "Runner listener exit with undefined return code";
|
||||||
|
consecutiveFailureCount++;
|
||||||
|
if (
|
||||||
|
!isNaN(exitServiceAfterNFailures) &&
|
||||||
|
consecutiveFailureCount >= exitServiceAfterNFailures
|
||||||
|
) {
|
||||||
|
console.error(
|
||||||
|
`${messagePrefix}, exiting service after ${consecutiveFailureCount} consecutive failures`
|
||||||
|
);
|
||||||
|
gracefulShutdown();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.log(`${messagePrefix}, re-launch runner in 5 seconds.`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stopping) {
|
||||||
|
setTimeout(runService, 5000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (ex) {
|
||||||
|
console.log(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
runService();
|
runService();
|
||||||
console.log('Started running service');
|
console.log("Started running service");
|
||||||
|
|
||||||
var gracefulShutdown = function (code) {
|
process.on("SIGINT", () => {
|
||||||
console.log('Shutting down runner listener');
|
gracefulShutdown();
|
||||||
stopping = true;
|
|
||||||
if (listener) {
|
|
||||||
console.log('Sending SIGINT to runner listener to stop');
|
|
||||||
listener.kill('SIGINT');
|
|
||||||
|
|
||||||
console.log('Sending SIGKILL to runner listener');
|
|
||||||
setTimeout(() => listener.kill('SIGKILL'), 30000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
gracefulShutdown(0);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
process.on('SIGTERM', () => {
|
process.on("SIGTERM", () => {
|
||||||
gracefulShutdown(0);
|
gracefulShutdown();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,5 +25,7 @@
|
|||||||
</dict>
|
</dict>
|
||||||
<key>ProcessType</key>
|
<key>ProcessType</key>
|
||||||
<string>Interactive</string>
|
<string>Interactive</string>
|
||||||
|
<key>SessionCreate</key>
|
||||||
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ RUNNER_ROOT=`pwd`
|
|||||||
|
|
||||||
LAUNCH_PATH="${HOME}/Library/LaunchAgents"
|
LAUNCH_PATH="${HOME}/Library/LaunchAgents"
|
||||||
PLIST_PATH="${LAUNCH_PATH}/${SVC_NAME}.plist"
|
PLIST_PATH="${LAUNCH_PATH}/${SVC_NAME}.plist"
|
||||||
TEMPLATE_PATH=./bin/actions.runner.plist.template
|
TEMPLATE_PATH=$GITHUB_ACTIONS_RUNNER_SERVICE_TEMPLATE
|
||||||
|
IS_CUSTOM_TEMPLATE=0
|
||||||
|
if [[ -z $TEMPLATE_PATH ]]; then
|
||||||
|
TEMPLATE_PATH=./bin/actions.runner.plist.template
|
||||||
|
else
|
||||||
|
IS_CUSTOM_TEMPLATE=1
|
||||||
|
fi
|
||||||
TEMP_PATH=./bin/actions.runner.plist.temp
|
TEMP_PATH=./bin/actions.runner.plist.temp
|
||||||
CONFIG_PATH=.service
|
CONFIG_PATH=.service
|
||||||
|
|
||||||
@@ -29,7 +35,11 @@ function failed()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if [ ! -f "${TEMPLATE_PATH}" ]; then
|
if [ ! -f "${TEMPLATE_PATH}" ]; then
|
||||||
failed "Must run from runner root or install is corrupt"
|
if [[ $IS_CUSTOM_TEMPLATE = 0 ]]; then
|
||||||
|
failed "Must run from runner root or install is corrupt"
|
||||||
|
else
|
||||||
|
failed "Service file at '$GITHUB_ACTIONS_RUNNER_SERVICE_TEMPLATE' using GITHUB_ACTIONS_RUNNER_SERVICE_TEMPLATE env variable is not found"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
function install()
|
function install()
|
||||||
@@ -53,7 +63,7 @@ function install()
|
|||||||
mkdir -p "${log_path}" || failed "failed to create ${log_path}"
|
mkdir -p "${log_path}" || failed "failed to create ${log_path}"
|
||||||
|
|
||||||
echo Creating ${PLIST_PATH}
|
echo Creating ${PLIST_PATH}
|
||||||
sed "s/{{User}}/${SUDO_USER:-$USER}/g; s/{{SvcName}}/$SVC_NAME/g; s@{{RunnerRoot}}@${RUNNER_ROOT}@g; s@{{UserHome}}@$HOME@g;" "${TEMPLATE_PATH}" > "${TEMP_PATH}" || failed "failed to create replacement temp file"
|
sed "s/{{User}}/${USER:-$SUDO_USER}/g; s/{{SvcName}}/$SVC_NAME/g; s@{{RunnerRoot}}@${RUNNER_ROOT}@g; s@{{UserHome}}@$HOME@g;" "${TEMPLATE_PATH}" > "${TEMP_PATH}" || failed "failed to create replacement temp file"
|
||||||
mv "${TEMP_PATH}" "${PLIST_PATH}" || failed "failed to copy plist"
|
mv "${TEMP_PATH}" "${PLIST_PATH}" || failed "failed to copy plist"
|
||||||
|
|
||||||
# Since we started with sudo, runsvc.sh will be owned by root. Change this to current login user.
|
# Since we started with sudo, runsvc.sh will be owned by root. Change this to current login user.
|
||||||
|
|||||||
@@ -43,6 +43,32 @@ module.exports =
|
|||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
/******/ ({
|
/******/ ({
|
||||||
|
|
||||||
|
/***/ 82:
|
||||||
|
/***/ (function(__unusedmodule, exports) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// We use any as a valid input type
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
/**
|
||||||
|
* Sanitizes an input into a string so it can be passed into issueCommand safely
|
||||||
|
* @param input input to sanitize into a string
|
||||||
|
*/
|
||||||
|
function toCommandValue(input) {
|
||||||
|
if (input === null || input === undefined) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
else if (typeof input === 'string' || input instanceof String) {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
return JSON.stringify(input);
|
||||||
|
}
|
||||||
|
exports.toCommandValue = toCommandValue;
|
||||||
|
//# sourceMappingURL=utils.js.map
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
/***/ 87:
|
/***/ 87:
|
||||||
/***/ (function(module) {
|
/***/ (function(module) {
|
||||||
|
|
||||||
@@ -978,6 +1004,42 @@ function regExpEscape (s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }),
|
||||||
|
|
||||||
|
/***/ 102:
|
||||||
|
/***/ (function(__unusedmodule, exports, __webpack_require__) {
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
// For internal use, subject to change.
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
// We use any as a valid input type
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
const fs = __importStar(__webpack_require__(747));
|
||||||
|
const os = __importStar(__webpack_require__(87));
|
||||||
|
const utils_1 = __webpack_require__(82);
|
||||||
|
function issueCommand(command, message) {
|
||||||
|
const filePath = process.env[`GITHUB_${command}`];
|
||||||
|
if (!filePath) {
|
||||||
|
throw new Error(`Unable to find environment variable for file command ${command}`);
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(filePath)) {
|
||||||
|
throw new Error(`Missing file at path: ${filePath}`);
|
||||||
|
}
|
||||||
|
fs.appendFileSync(filePath, `${utils_1.toCommandValue(message)}${os.EOL}`, {
|
||||||
|
encoding: 'utf8'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
exports.issueCommand = issueCommand;
|
||||||
|
//# sourceMappingURL=file-command.js.map
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 281:
|
/***/ 281:
|
||||||
@@ -1495,12 +1557,12 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const glob = __importStar(__webpack_require__(281));
|
|
||||||
const crypto = __importStar(__webpack_require__(417));
|
const crypto = __importStar(__webpack_require__(417));
|
||||||
const fs = __importStar(__webpack_require__(747));
|
const fs = __importStar(__webpack_require__(747));
|
||||||
|
const glob = __importStar(__webpack_require__(281));
|
||||||
|
const path = __importStar(__webpack_require__(622));
|
||||||
const stream = __importStar(__webpack_require__(413));
|
const stream = __importStar(__webpack_require__(413));
|
||||||
const util = __importStar(__webpack_require__(669));
|
const util = __importStar(__webpack_require__(669));
|
||||||
const path = __importStar(__webpack_require__(622));
|
|
||||||
function run() {
|
function run() {
|
||||||
var e_1, _a;
|
var e_1, _a;
|
||||||
return __awaiter(this, void 0, void 0, function* () {
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
@@ -1551,7 +1613,7 @@ function run() {
|
|||||||
}
|
}
|
||||||
result.end();
|
result.end();
|
||||||
if (hasMatch) {
|
if (hasMatch) {
|
||||||
console.log(`Find ${count} files to hash.`);
|
console.log(`Found ${count} files to hash.`);
|
||||||
console.error(`__OUTPUT__${result.digest('hex')}__OUTPUT__`);
|
console.error(`__OUTPUT__${result.digest('hex')}__OUTPUT__`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -1559,7 +1621,15 @@ function run() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
run();
|
run()
|
||||||
|
.then(out => {
|
||||||
|
console.log(out);
|
||||||
|
process.exit(0);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
@@ -1687,17 +1757,25 @@ module.exports = require("crypto");
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const os = __webpack_require__(87);
|
const os = __importStar(__webpack_require__(87));
|
||||||
|
const utils_1 = __webpack_require__(82);
|
||||||
/**
|
/**
|
||||||
* Commands
|
* Commands
|
||||||
*
|
*
|
||||||
* Command Format:
|
* Command Format:
|
||||||
* ##[name key=value;key=value]message
|
* ::name key=value,key=value::message
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* ##[warning]This is the user warning message
|
* ::warning::This is the message
|
||||||
* ##[set-secret name=mypassword]definitelyNotAPassword!
|
* ::set-env name=MY_VAR::some value
|
||||||
*/
|
*/
|
||||||
function issueCommand(command, properties, message) {
|
function issueCommand(command, properties, message) {
|
||||||
const cmd = new Command(command, properties, message);
|
const cmd = new Command(command, properties, message);
|
||||||
@@ -1722,34 +1800,39 @@ class Command {
|
|||||||
let cmdStr = CMD_STRING + this.command;
|
let cmdStr = CMD_STRING + this.command;
|
||||||
if (this.properties && Object.keys(this.properties).length > 0) {
|
if (this.properties && Object.keys(this.properties).length > 0) {
|
||||||
cmdStr += ' ';
|
cmdStr += ' ';
|
||||||
|
let first = true;
|
||||||
for (const key in this.properties) {
|
for (const key in this.properties) {
|
||||||
if (this.properties.hasOwnProperty(key)) {
|
if (this.properties.hasOwnProperty(key)) {
|
||||||
const val = this.properties[key];
|
const val = this.properties[key];
|
||||||
if (val) {
|
if (val) {
|
||||||
// safely append the val - avoid blowing up when attempting to
|
if (first) {
|
||||||
// call .replace() if message is not a string for some reason
|
first = false;
|
||||||
cmdStr += `${key}=${escape(`${val || ''}`)},`;
|
}
|
||||||
|
else {
|
||||||
|
cmdStr += ',';
|
||||||
|
}
|
||||||
|
cmdStr += `${key}=${escapeProperty(val)}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmdStr += CMD_STRING;
|
cmdStr += `${CMD_STRING}${escapeData(this.message)}`;
|
||||||
// safely append the message - avoid blowing up when attempting to
|
|
||||||
// call .replace() if message is not a string for some reason
|
|
||||||
const message = `${this.message || ''}`;
|
|
||||||
cmdStr += escapeData(message);
|
|
||||||
return cmdStr;
|
return cmdStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function escapeData(s) {
|
function escapeData(s) {
|
||||||
return s.replace(/\r/g, '%0D').replace(/\n/g, '%0A');
|
return utils_1.toCommandValue(s)
|
||||||
|
.replace(/%/g, '%25')
|
||||||
|
.replace(/\r/g, '%0D')
|
||||||
|
.replace(/\n/g, '%0A');
|
||||||
}
|
}
|
||||||
function escape(s) {
|
function escapeProperty(s) {
|
||||||
return s
|
return utils_1.toCommandValue(s)
|
||||||
|
.replace(/%/g, '%25')
|
||||||
.replace(/\r/g, '%0D')
|
.replace(/\r/g, '%0D')
|
||||||
.replace(/\n/g, '%0A')
|
.replace(/\n/g, '%0A')
|
||||||
.replace(/]/g, '%5D')
|
.replace(/:/g, '%3A')
|
||||||
.replace(/;/g, '%3B');
|
.replace(/,/g, '%2C');
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=command.js.map
|
//# sourceMappingURL=command.js.map
|
||||||
|
|
||||||
@@ -1769,10 +1852,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|||||||
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
var __importStar = (this && this.__importStar) || function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
|
||||||
|
result["default"] = mod;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
const command_1 = __webpack_require__(431);
|
const command_1 = __webpack_require__(431);
|
||||||
const os = __webpack_require__(87);
|
const file_command_1 = __webpack_require__(102);
|
||||||
const path = __webpack_require__(622);
|
const utils_1 = __webpack_require__(82);
|
||||||
|
const os = __importStar(__webpack_require__(87));
|
||||||
|
const path = __importStar(__webpack_require__(622));
|
||||||
/**
|
/**
|
||||||
* The code to exit an action
|
* The code to exit an action
|
||||||
*/
|
*/
|
||||||
@@ -1793,11 +1885,21 @@ var ExitCode;
|
|||||||
/**
|
/**
|
||||||
* Sets env variable for this action and future actions in the job
|
* Sets env variable for this action and future actions in the job
|
||||||
* @param name the name of the variable to set
|
* @param name the name of the variable to set
|
||||||
* @param val the value of the variable
|
* @param val the value of the variable. Non-string values will be converted to a string via JSON.stringify
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function exportVariable(name, val) {
|
function exportVariable(name, val) {
|
||||||
process.env[name] = val;
|
const convertedVal = utils_1.toCommandValue(val);
|
||||||
command_1.issueCommand('set-env', { name }, val);
|
process.env[name] = convertedVal;
|
||||||
|
const filePath = process.env['GITHUB_ENV'] || '';
|
||||||
|
if (filePath) {
|
||||||
|
const delimiter = '_GitHubActionsFileCommandDelimeter_';
|
||||||
|
const commandValue = `${name}<<${delimiter}${os.EOL}${convertedVal}${os.EOL}${delimiter}`;
|
||||||
|
file_command_1.issueCommand('ENV', commandValue);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
command_1.issueCommand('set-env', { name }, convertedVal);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.exportVariable = exportVariable;
|
exports.exportVariable = exportVariable;
|
||||||
/**
|
/**
|
||||||
@@ -1813,7 +1915,13 @@ exports.setSecret = setSecret;
|
|||||||
* @param inputPath
|
* @param inputPath
|
||||||
*/
|
*/
|
||||||
function addPath(inputPath) {
|
function addPath(inputPath) {
|
||||||
command_1.issueCommand('add-path', {}, inputPath);
|
const filePath = process.env['GITHUB_PATH'] || '';
|
||||||
|
if (filePath) {
|
||||||
|
file_command_1.issueCommand('PATH', inputPath);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
command_1.issueCommand('add-path', {}, inputPath);
|
||||||
|
}
|
||||||
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
|
process.env['PATH'] = `${inputPath}${path.delimiter}${process.env['PATH']}`;
|
||||||
}
|
}
|
||||||
exports.addPath = addPath;
|
exports.addPath = addPath;
|
||||||
@@ -1836,12 +1944,22 @@ exports.getInput = getInput;
|
|||||||
* Sets the value of an output.
|
* Sets the value of an output.
|
||||||
*
|
*
|
||||||
* @param name name of the output to set
|
* @param name name of the output to set
|
||||||
* @param value value to store
|
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function setOutput(name, value) {
|
function setOutput(name, value) {
|
||||||
command_1.issueCommand('set-output', { name }, value);
|
command_1.issueCommand('set-output', { name }, value);
|
||||||
}
|
}
|
||||||
exports.setOutput = setOutput;
|
exports.setOutput = setOutput;
|
||||||
|
/**
|
||||||
|
* Enables or disables the echoing of commands into stdout for the rest of the step.
|
||||||
|
* Echoing is disabled by default if ACTIONS_STEP_DEBUG is not set.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function setCommandEcho(enabled) {
|
||||||
|
command_1.issue('echo', enabled ? 'on' : 'off');
|
||||||
|
}
|
||||||
|
exports.setCommandEcho = setCommandEcho;
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// Results
|
// Results
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
@@ -1858,6 +1976,13 @@ exports.setFailed = setFailed;
|
|||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
// Logging Commands
|
// Logging Commands
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
/**
|
||||||
|
* Gets whether Actions Step Debug is on or not
|
||||||
|
*/
|
||||||
|
function isDebug() {
|
||||||
|
return process.env['RUNNER_DEBUG'] === '1';
|
||||||
|
}
|
||||||
|
exports.isDebug = isDebug;
|
||||||
/**
|
/**
|
||||||
* Writes debug message to user log
|
* Writes debug message to user log
|
||||||
* @param message debug message
|
* @param message debug message
|
||||||
@@ -1868,18 +1993,18 @@ function debug(message) {
|
|||||||
exports.debug = debug;
|
exports.debug = debug;
|
||||||
/**
|
/**
|
||||||
* Adds an error issue
|
* Adds an error issue
|
||||||
* @param message error issue message
|
* @param message error issue message. Errors will be converted to string via toString()
|
||||||
*/
|
*/
|
||||||
function error(message) {
|
function error(message) {
|
||||||
command_1.issue('error', message);
|
command_1.issue('error', message instanceof Error ? message.toString() : message);
|
||||||
}
|
}
|
||||||
exports.error = error;
|
exports.error = error;
|
||||||
/**
|
/**
|
||||||
* Adds an warning issue
|
* Adds an warning issue
|
||||||
* @param message warning issue message
|
* @param message warning issue message. Errors will be converted to string via toString()
|
||||||
*/
|
*/
|
||||||
function warning(message) {
|
function warning(message) {
|
||||||
command_1.issue('warning', message);
|
command_1.issue('warning', message instanceof Error ? message.toString() : message);
|
||||||
}
|
}
|
||||||
exports.warning = warning;
|
exports.warning = warning;
|
||||||
/**
|
/**
|
||||||
@@ -1937,8 +2062,9 @@ exports.group = group;
|
|||||||
* Saves state for current action, the state can only be retrieved by this action's post job execution.
|
* Saves state for current action, the state can only be retrieved by this action's post job execution.
|
||||||
*
|
*
|
||||||
* @param name name of the state to store
|
* @param name name of the state to store
|
||||||
* @param value value to store
|
* @param value value to store. Non-string values will be converted to a string via JSON.stringify
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function saveState(name, value) {
|
function saveState(name, value) {
|
||||||
command_1.issueCommand('save-state', { name }, value);
|
command_1.issueCommand('save-state', { name }, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,6 @@ then
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# libssl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
|
||||||
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
|
||||||
@@ -103,8 +102,7 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
apt_get_with_fallbacks libicu72 libicu71 libicu70 libicu69 libicu68 libicu67 libicu66 libicu65 libicu63 libicu60 libicu57 libicu55 libicu52
|
||||||
apt_get_with_fallbacks libicu66 libicu63 libicu60 libicu57 libicu55 libicu52
|
|
||||||
if [ $? -ne 0 ]
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
echo "'$apt_get' failed with exit code '$?'"
|
||||||
|
|||||||
@@ -10,10 +10,11 @@ if [ -f ".path" ]; then
|
|||||||
echo ".path=${PATH}"
|
echo ".path=${PATH}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# insert anything to setup env when running as a service
|
nodever=${GITHUB_ACTIONS_RUNNER_FORCED_NODE_VERSION:-node16}
|
||||||
|
|
||||||
|
# insert anything to setup env when running as a service
|
||||||
# run the host process which keep the listener alive
|
# run the host process which keep the listener alive
|
||||||
./externals/node12/bin/node ./bin/RunnerService.js &
|
./externals/$nodever/bin/node ./bin/RunnerService.js &
|
||||||
PID=$!
|
PID=$!
|
||||||
wait $PID
|
wait $PID
|
||||||
trap - TERM INT
|
trap - TERM INT
|
||||||
|
|||||||
@@ -10,7 +10,13 @@ arg_2=${2}
|
|||||||
RUNNER_ROOT=`pwd`
|
RUNNER_ROOT=`pwd`
|
||||||
|
|
||||||
UNIT_PATH=/etc/systemd/system/${SVC_NAME}
|
UNIT_PATH=/etc/systemd/system/${SVC_NAME}
|
||||||
TEMPLATE_PATH=./bin/actions.runner.service.template
|
TEMPLATE_PATH=$GITHUB_ACTIONS_RUNNER_SERVICE_TEMPLATE
|
||||||
|
IS_CUSTOM_TEMPLATE=0
|
||||||
|
if [[ -z $TEMPLATE_PATH ]]; then
|
||||||
|
TEMPLATE_PATH=./bin/actions.runner.service.template
|
||||||
|
else
|
||||||
|
IS_CUSTOM_TEMPLATE=1
|
||||||
|
fi
|
||||||
TEMP_PATH=./bin/actions.runner.service.temp
|
TEMP_PATH=./bin/actions.runner.service.temp
|
||||||
CONFIG_PATH=.service
|
CONFIG_PATH=.service
|
||||||
|
|
||||||
@@ -31,7 +37,11 @@ function failed()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if [ ! -f "${TEMPLATE_PATH}" ]; then
|
if [ ! -f "${TEMPLATE_PATH}" ]; then
|
||||||
failed "Must run from runner root or install is corrupt"
|
if [[ $IS_CUSTOM_TEMPLATE = 0 ]]; then
|
||||||
|
failed "Must run from runner root or install is corrupt"
|
||||||
|
else
|
||||||
|
failed "Service file at '$GITHUB_ACTIONS_RUNNER_SERVICE_TEMPLATE' using GITHUB_ACTIONS_RUNNER_SERVICE_TEMPLATE env variable is not found"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#check if we run as root
|
#check if we run as root
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ downloadrunnerversion=_DOWNLOAD_RUNNER_VERSION_
|
|||||||
logfile="_UPDATE_LOG_"
|
logfile="_UPDATE_LOG_"
|
||||||
restartinteractiverunner=_RESTART_INTERACTIVE_RUNNER_
|
restartinteractiverunner=_RESTART_INTERACTIVE_RUNNER_
|
||||||
|
|
||||||
|
telemetryfile="$rootfolder/_diag/.telemetry"
|
||||||
|
|
||||||
# log user who run the script
|
# log user who run the script
|
||||||
date "+[%F %T-%4N] --------whoami--------" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] --------whoami--------" >> "$logfile" 2>&1
|
||||||
whoami >> "$logfile" 2>&1
|
whoami >> "$logfile" 2>&1
|
||||||
@@ -28,13 +30,13 @@ date "+[%F %T-%4N] Waiting for $runnerprocessname ($runnerpid) to complete" >> "
|
|||||||
while [ -e /proc/$runnerpid ]
|
while [ -e /proc/$runnerpid ]
|
||||||
do
|
do
|
||||||
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
||||||
sleep 2
|
"$rootfolder"/safe_sleep.sh 2
|
||||||
done
|
done
|
||||||
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
||||||
|
|
||||||
# start re-organize folders
|
# start re-organize folders
|
||||||
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
||||||
sleep 1
|
"$rootfolder"/safe_sleep.sh 1
|
||||||
|
|
||||||
# the folder structure under runner root will be
|
# the folder structure under runner root will be
|
||||||
# ./bin -> bin.2.100.0 (junction folder)
|
# ./bin -> bin.2.100.0 (junction folder)
|
||||||
@@ -118,6 +120,64 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# fix upgrade issue with macOS when running as a service
|
||||||
|
attemptedtargetedfix=0
|
||||||
|
currentplatform=$(uname | awk '{print tolower($0)}')
|
||||||
|
if [[ "$currentplatform" == 'darwin' && restartinteractiverunner -eq 0 ]]; then
|
||||||
|
# We needed a fix for https://github.com/actions/runner/issues/743
|
||||||
|
# We will recreate the ./externals/nodeXY/bin/node of the past runner version that launched the runnerlistener service
|
||||||
|
# Otherwise mac gatekeeper kills the processes we spawn on creation as we are running a process with no backing file
|
||||||
|
|
||||||
|
# We need the pid for the nodejs loop, get that here, its the parent of the runner C# pid
|
||||||
|
# assumption here is only one process is invoking rootfolder/runsvc.sh
|
||||||
|
procgroup=$(ps x -o pgid,command | grep "$rootfolder/runsvc.sh" | grep -v grep | awk '{print $1}')
|
||||||
|
if [[ $? -eq 0 && -n "$procgroup" ]]
|
||||||
|
then
|
||||||
|
# inspect the open file handles to find the node process
|
||||||
|
# we can't actually inspect the process using ps because it uses relative paths and doesn't follow symlinks
|
||||||
|
nodever="node16"
|
||||||
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
|
if [[ $? -ne 0 || -z "$path" ]] # Fallback if RunnerService.js was started with node12
|
||||||
|
then
|
||||||
|
nodever="node12"
|
||||||
|
path=$(lsof -a -g "$procgroup" -F n | grep $nodever/bin/node | grep externals | tail -1 | cut -c2-)
|
||||||
|
fi
|
||||||
|
if [[ $? -eq 0 && -n "$path" ]]
|
||||||
|
then
|
||||||
|
# trim the last 5 characters of the path '/node'
|
||||||
|
trimmedpath=$(dirname "$path")
|
||||||
|
if [[ $? -eq 0 && -n "$trimmedpath" ]]
|
||||||
|
then
|
||||||
|
attemptedtargetedfix=1
|
||||||
|
# Create the path if it does not exist
|
||||||
|
if [[ ! -e "$path" ]]
|
||||||
|
then
|
||||||
|
date "+[%F %T-%4N] Creating fallback node at path $path" >> "$logfile" 2>&1
|
||||||
|
mkdir -p "$trimmedpath"
|
||||||
|
cp "$rootfolder/externals/$nodever/bin/node" "$path"
|
||||||
|
else
|
||||||
|
date "+[%F %T-%4N] Path for fallback node exists, skipping creating $path" >> "$logfile" 2>&1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to trim runner path. TrimmedPath: $trimmedpath, path: $path, pgid: $procgroup, root: $rootfolder" >> "$logfile" 2>&1
|
||||||
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to trim runner path. TrimmedPath: $trimmedpath, path: $path, pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner path. Path: $path, pgid: $procgroup, root: $rootfolder" >> "$logfile" 2>&1
|
||||||
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner path. Path: $path, pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
runproc=$(ps x -o pgid,command | grep "run.sh" | grep -v grep | awk '{print $1}')
|
||||||
|
if [[ $? -eq 0 && -n "$runproc" ]]
|
||||||
|
then
|
||||||
|
date "+[%F %T-%4N] Running as ephemeral using run.sh, no need to recreate node folder" >> "$logfile" 2>&1
|
||||||
|
else
|
||||||
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup, root: $rootfolder" >> "$logfile" 2>&1
|
||||||
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
date "+[%F %T-%4N] Update succeed" >> "$logfile"
|
date "+[%F %T-%4N] Update succeed" >> "$logfile"
|
||||||
|
|
||||||
# rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
# rename the update log file with %logfile%.succeed/.failed/succeedneedrestart
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ if [ $user_id -eq 0 -a -z "$RUNNER_ALLOW_RUNASROOT" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check dotnet core 3.0 dependencies for Linux
|
# Check dotnet Core 6.0 dependencies for Linux
|
||||||
if [[ (`uname` == "Linux") ]]
|
if [[ (`uname` == "Linux") ]]
|
||||||
then
|
then
|
||||||
command -v ldd > /dev/null
|
command -v ldd > /dev/null
|
||||||
@@ -18,25 +18,25 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
message="Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
message="Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 6.0 dependencies."
|
||||||
|
|
||||||
ldd ./bin/libcoreclr.so | grep 'not found'
|
ldd ./bin/libcoreclr.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 6.0"
|
||||||
echo $message
|
echo $message
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ldd ./bin/System.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
ldd ./bin/libSystem.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 6.0"
|
||||||
echo $message
|
echo $message
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ldd ./bin/System.IO.Compression.Native.so | grep 'not found'
|
ldd ./bin/libSystem.IO.Compression.Native.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 6.0"
|
||||||
echo $message
|
echo $message
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -54,7 +54,7 @@ then
|
|||||||
libpath=${LD_LIBRARY_PATH:-}
|
libpath=${LD_LIBRARY_PATH:-}
|
||||||
$LDCONFIG_COMMAND -NXv ${libpath//:/ } 2>&1 | grep libicu >/dev/null 2>&1
|
$LDCONFIG_COMMAND -NXv ${libpath//:/ } 2>&1 | grep libicu >/dev/null 2>&1
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Libicu's dependencies is missing for Dotnet Core 3.0"
|
echo "Libicu's dependencies is missing for Dotnet Core 6.0"
|
||||||
echo $message
|
echo $message
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -43,6 +43,21 @@ else
|
|||||||
else
|
else
|
||||||
sleep 5
|
sleep 5
|
||||||
fi
|
fi
|
||||||
|
elif [[ $returnCode == 4 ]]; then
|
||||||
|
if [ ! -x "$(command -v sleep)" ]; then
|
||||||
|
if [ ! -x "$(command -v ping)" ]; then
|
||||||
|
COUNT="0"
|
||||||
|
while [[ $COUNT != 5000 ]]; do
|
||||||
|
echo "SLEEP" > /dev/null
|
||||||
|
COUNT=$[$COUNT+1]
|
||||||
|
done
|
||||||
|
else
|
||||||
|
ping -c 5 127.0.0.1 > /dev/null
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
sleep 5
|
||||||
|
fi
|
||||||
|
"$DIR"/bin/Runner.Listener run $*
|
||||||
else
|
else
|
||||||
exit $returnCode
|
exit $returnCode
|
||||||
fi
|
fi
|
||||||
|
|||||||
6
src/Misc/layoutroot/safe_sleep.sh
Normal file
6
src/Misc/layoutroot/safe_sleep.sh
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SECONDS=0
|
||||||
|
while [[ $SECONDS != $1 ]]; do
|
||||||
|
:
|
||||||
|
done
|
||||||
57
src/Misc/runnercoreassets
Normal file
57
src/Misc/runnercoreassets
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
actions.runner.plist.template
|
||||||
|
actions.runner.service.template
|
||||||
|
checkScripts/downloadCert.js
|
||||||
|
checkScripts/makeWebRequest.js
|
||||||
|
darwin.svc.sh.template
|
||||||
|
hashFiles/index.js
|
||||||
|
installdependencies.sh
|
||||||
|
macos-run-invoker.js
|
||||||
|
Microsoft.IdentityModel.Logging.dll
|
||||||
|
Microsoft.IdentityModel.Tokens.dll
|
||||||
|
Minimatch.dll
|
||||||
|
Newtonsoft.Json.Bson.dll
|
||||||
|
Newtonsoft.Json.dll
|
||||||
|
Runner.Common.deps.json
|
||||||
|
Runner.Common.dll
|
||||||
|
Runner.Common.pdb
|
||||||
|
Runner.Listener
|
||||||
|
Runner.Listener.deps.json
|
||||||
|
Runner.Listener.dll
|
||||||
|
Runner.Listener.exe
|
||||||
|
Runner.Listener.pdb
|
||||||
|
Runner.Listener.runtimeconfig.json
|
||||||
|
Runner.PluginHost
|
||||||
|
Runner.PluginHost.deps.json
|
||||||
|
Runner.PluginHost.dll
|
||||||
|
Runner.PluginHost.exe
|
||||||
|
Runner.PluginHost.pdb
|
||||||
|
Runner.PluginHost.runtimeconfig.json
|
||||||
|
Runner.Plugins.deps.json
|
||||||
|
Runner.Plugins.dll
|
||||||
|
Runner.Plugins.pdb
|
||||||
|
Runner.Sdk.deps.json
|
||||||
|
Runner.Sdk.dll
|
||||||
|
Runner.Sdk.pdb
|
||||||
|
Runner.Worker
|
||||||
|
Runner.Worker.deps.json
|
||||||
|
Runner.Worker.dll
|
||||||
|
Runner.Worker.exe
|
||||||
|
Runner.Worker.pdb
|
||||||
|
Runner.Worker.runtimeconfig.json
|
||||||
|
RunnerService.exe
|
||||||
|
RunnerService.exe.config
|
||||||
|
RunnerService.js
|
||||||
|
RunnerService.pdb
|
||||||
|
runsvc.sh
|
||||||
|
Sdk.deps.json
|
||||||
|
Sdk.dll
|
||||||
|
Sdk.pdb
|
||||||
|
System.IdentityModel.Tokens.Jwt.dll
|
||||||
|
System.Net.Http.Formatting.dll
|
||||||
|
System.Security.Cryptography.Pkcs.dll
|
||||||
|
System.Security.Cryptography.ProtectedData.dll
|
||||||
|
System.ServiceProcess.ServiceController.dll
|
||||||
|
systemd.svc.sh.template
|
||||||
|
update.cmd.template
|
||||||
|
update.sh.template
|
||||||
|
YamlDotNet.dll
|
||||||
263
src/Misc/runnerdotnetruntimeassets
Normal file
263
src/Misc/runnerdotnetruntimeassets
Normal file
@@ -0,0 +1,263 @@
|
|||||||
|
api-ms-win-core-console-l1-1-0.dll
|
||||||
|
api-ms-win-core-console-l1-2-0.dll
|
||||||
|
api-ms-win-core-datetime-l1-1-0.dll
|
||||||
|
api-ms-win-core-debug-l1-1-0.dll
|
||||||
|
api-ms-win-core-errorhandling-l1-1-0.dll
|
||||||
|
api-ms-win-core-file-l1-1-0.dll
|
||||||
|
api-ms-win-core-file-l1-2-0.dll
|
||||||
|
api-ms-win-core-file-l2-1-0.dll
|
||||||
|
api-ms-win-core-handle-l1-1-0.dll
|
||||||
|
api-ms-win-core-heap-l1-1-0.dll
|
||||||
|
api-ms-win-core-interlocked-l1-1-0.dll
|
||||||
|
api-ms-win-core-libraryloader-l1-1-0.dll
|
||||||
|
api-ms-win-core-localization-l1-2-0.dll
|
||||||
|
api-ms-win-core-memory-l1-1-0.dll
|
||||||
|
api-ms-win-core-namedpipe-l1-1-0.dll
|
||||||
|
api-ms-win-core-processenvironment-l1-1-0.dll
|
||||||
|
api-ms-win-core-processthreads-l1-1-0.dll
|
||||||
|
api-ms-win-core-processthreads-l1-1-1.dll
|
||||||
|
api-ms-win-core-profile-l1-1-0.dll
|
||||||
|
api-ms-win-core-rtlsupport-l1-1-0.dll
|
||||||
|
api-ms-win-core-string-l1-1-0.dll
|
||||||
|
api-ms-win-core-synch-l1-1-0.dll
|
||||||
|
api-ms-win-core-synch-l1-2-0.dll
|
||||||
|
api-ms-win-core-sysinfo-l1-1-0.dll
|
||||||
|
api-ms-win-core-timezone-l1-1-0.dll
|
||||||
|
api-ms-win-core-util-l1-1-0.dll
|
||||||
|
api-ms-win-crt-conio-l1-1-0.dll
|
||||||
|
api-ms-win-crt-convert-l1-1-0.dll
|
||||||
|
api-ms-win-crt-environment-l1-1-0.dll
|
||||||
|
api-ms-win-crt-filesystem-l1-1-0.dll
|
||||||
|
api-ms-win-crt-heap-l1-1-0.dll
|
||||||
|
api-ms-win-crt-locale-l1-1-0.dll
|
||||||
|
api-ms-win-crt-math-l1-1-0.dll
|
||||||
|
api-ms-win-crt-multibyte-l1-1-0.dll
|
||||||
|
api-ms-win-crt-private-l1-1-0.dll
|
||||||
|
api-ms-win-crt-process-l1-1-0.dll
|
||||||
|
api-ms-win-crt-runtime-l1-1-0.dll
|
||||||
|
api-ms-win-crt-stdio-l1-1-0.dll
|
||||||
|
api-ms-win-crt-string-l1-1-0.dll
|
||||||
|
api-ms-win-crt-time-l1-1-0.dll
|
||||||
|
api-ms-win-crt-utility-l1-1-0.dll
|
||||||
|
clrcompression.dll
|
||||||
|
clretwrc.dll
|
||||||
|
clrjit.dll
|
||||||
|
coreclr.dll
|
||||||
|
createdump
|
||||||
|
createdump.exe
|
||||||
|
dbgshim.dll
|
||||||
|
hostfxr.dll
|
||||||
|
hostpolicy.dll
|
||||||
|
libclrjit.dylib
|
||||||
|
libclrjit.so
|
||||||
|
libcoreclr.dylib
|
||||||
|
libcoreclr.so
|
||||||
|
libcoreclrtraceptprovider.so
|
||||||
|
libdbgshim.dylib
|
||||||
|
libdbgshim.so
|
||||||
|
libhostfxr.dylib
|
||||||
|
libhostfxr.so
|
||||||
|
libhostpolicy.dylib
|
||||||
|
libhostpolicy.so
|
||||||
|
libmscordaccore.dylib
|
||||||
|
libmscordaccore.so
|
||||||
|
libmscordbi.dylib
|
||||||
|
libmscordbi.so
|
||||||
|
Microsoft.CSharp.dll
|
||||||
|
Microsoft.DiaSymReader.Native.amd64.dll
|
||||||
|
Microsoft.VisualBasic.Core.dll
|
||||||
|
Microsoft.VisualBasic.dll
|
||||||
|
Microsoft.Win32.Primitives.dll
|
||||||
|
Microsoft.Win32.Registry.dll
|
||||||
|
mscordaccore.dll
|
||||||
|
mscordaccore_amd64_amd64_6.0.21.52210.dll
|
||||||
|
mscordbi.dll
|
||||||
|
mscorlib.dll
|
||||||
|
mscorrc.debug.dll
|
||||||
|
mscorrc.dll
|
||||||
|
msquic.dll
|
||||||
|
netstandard.dll
|
||||||
|
SOS_README.md
|
||||||
|
System.AppContext.dll
|
||||||
|
System.Buffers.dll
|
||||||
|
System.Collections.Concurrent.dll
|
||||||
|
System.Collections.dll
|
||||||
|
System.Collections.Immutable.dll
|
||||||
|
System.Collections.NonGeneric.dll
|
||||||
|
System.Collections.Specialized.dll
|
||||||
|
System.ComponentModel.Annotations.dll
|
||||||
|
System.ComponentModel.DataAnnotations.dll
|
||||||
|
System.ComponentModel.dll
|
||||||
|
System.ComponentModel.EventBasedAsync.dll
|
||||||
|
System.ComponentModel.Primitives.dll
|
||||||
|
System.ComponentModel.TypeConverter.dll
|
||||||
|
System.Configuration.dll
|
||||||
|
System.Console.dll
|
||||||
|
System.Core.dll
|
||||||
|
System.Data.Common.dll
|
||||||
|
System.Data.DataSetExtensions.dll
|
||||||
|
System.Data.dll
|
||||||
|
System.Diagnostics.Contracts.dll
|
||||||
|
System.Diagnostics.Debug.dll
|
||||||
|
System.Diagnostics.DiagnosticSource.dll
|
||||||
|
System.Diagnostics.FileVersionInfo.dll
|
||||||
|
System.Diagnostics.Process.dll
|
||||||
|
System.Diagnostics.StackTrace.dll
|
||||||
|
System.Diagnostics.TextWriterTraceListener.dll
|
||||||
|
System.Diagnostics.Tools.dll
|
||||||
|
System.Diagnostics.TraceSource.dll
|
||||||
|
System.Diagnostics.Tracing.dll
|
||||||
|
System.dll
|
||||||
|
System.Drawing.dll
|
||||||
|
System.Drawing.Primitives.dll
|
||||||
|
System.Dynamic.Runtime.dll
|
||||||
|
System.Formats.Asn1.dll
|
||||||
|
System.Globalization.Calendars.dll
|
||||||
|
System.Globalization.dll
|
||||||
|
System.Globalization.Extensions.dll
|
||||||
|
System.Globalization.Native.dylib
|
||||||
|
System.Globalization.Native.so
|
||||||
|
System.IO.Compression.Brotli.dll
|
||||||
|
System.IO.Compression.dll
|
||||||
|
System.IO.Compression.FileSystem.dll
|
||||||
|
System.IO.Compression.Native.a
|
||||||
|
System.IO.Compression.Native.dll
|
||||||
|
System.IO.Compression.Native.dylib
|
||||||
|
System.IO.Compression.Native.so
|
||||||
|
System.IO.Compression.ZipFile.dll
|
||||||
|
System.IO.dll
|
||||||
|
System.IO.FileSystem.AccessControl.dll
|
||||||
|
System.IO.FileSystem.dll
|
||||||
|
System.IO.FileSystem.DriveInfo.dll
|
||||||
|
System.IO.FileSystem.Primitives.dll
|
||||||
|
System.IO.FileSystem.Watcher.dll
|
||||||
|
System.IO.IsolatedStorage.dll
|
||||||
|
System.IO.MemoryMappedFiles.dll
|
||||||
|
System.IO.Pipes.AccessControl.dll
|
||||||
|
System.IO.Pipes.dll
|
||||||
|
System.IO.UnmanagedMemoryStream.dll
|
||||||
|
System.Linq.dll
|
||||||
|
System.Linq.Expressions.dll
|
||||||
|
System.Linq.Parallel.dll
|
||||||
|
System.Linq.Queryable.dll
|
||||||
|
System.Memory.dll
|
||||||
|
System.Native.a
|
||||||
|
System.Native.dylib
|
||||||
|
System.Native.so
|
||||||
|
System.Net.dll
|
||||||
|
System.Net.Http.dll
|
||||||
|
System.Net.Http.Json.dll
|
||||||
|
System.Net.Http.Native.a
|
||||||
|
System.Net.Http.Native.dylib
|
||||||
|
System.Net.Http.Native.so
|
||||||
|
System.Net.HttpListener.dll
|
||||||
|
System.Net.Mail.dll
|
||||||
|
System.Net.NameResolution.dll
|
||||||
|
System.Net.NetworkInformation.dll
|
||||||
|
System.Net.Ping.dll
|
||||||
|
System.Net.Primitives.dll
|
||||||
|
System.Net.Quic.dll
|
||||||
|
System.Net.Requests.dll
|
||||||
|
System.Net.Security.dll
|
||||||
|
System.Net.Security.Native.a
|
||||||
|
System.Net.Security.Native.dylib
|
||||||
|
System.Net.Security.Native.so
|
||||||
|
System.Net.ServicePoint.dll
|
||||||
|
System.Net.Sockets.dll
|
||||||
|
System.Net.WebClient.dll
|
||||||
|
System.Net.WebHeaderCollection.dll
|
||||||
|
System.Net.WebProxy.dll
|
||||||
|
System.Net.WebSockets.Client.dll
|
||||||
|
System.Net.WebSockets.dll
|
||||||
|
System.Numerics.dll
|
||||||
|
System.Numerics.Vectors.dll
|
||||||
|
System.ObjectModel.dll
|
||||||
|
System.Private.CoreLib.dll
|
||||||
|
System.Private.DataContractSerialization.dll
|
||||||
|
System.Private.Uri.dll
|
||||||
|
System.Private.Xml.dll
|
||||||
|
System.Private.Xml.Linq.dll
|
||||||
|
System.Reflection.DispatchProxy.dll
|
||||||
|
System.Reflection.dll
|
||||||
|
System.Reflection.Emit.dll
|
||||||
|
System.Reflection.Emit.ILGeneration.dll
|
||||||
|
System.Reflection.Emit.Lightweight.dll
|
||||||
|
System.Reflection.Extensions.dll
|
||||||
|
System.Reflection.Metadata.dll
|
||||||
|
System.Reflection.Primitives.dll
|
||||||
|
System.Reflection.TypeExtensions.dll
|
||||||
|
System.Resources.Reader.dll
|
||||||
|
System.Resources.ResourceManager.dll
|
||||||
|
System.Resources.Writer.dll
|
||||||
|
System.Runtime.CompilerServices.Unsafe.dll
|
||||||
|
System.Runtime.CompilerServices.VisualC.dll
|
||||||
|
System.Runtime.dll
|
||||||
|
System.Runtime.Extensions.dll
|
||||||
|
System.Runtime.Handles.dll
|
||||||
|
System.Runtime.InteropServices.dll
|
||||||
|
System.Runtime.InteropServices.RuntimeInformation.dll
|
||||||
|
System.Runtime.InteropServices.WindowsRuntime.dll
|
||||||
|
System.Runtime.Intrinsics.dll
|
||||||
|
System.Runtime.Loader.dll
|
||||||
|
System.Runtime.Numerics.dll
|
||||||
|
System.Runtime.Serialization.dll
|
||||||
|
System.Runtime.Serialization.Formatters.dll
|
||||||
|
System.Runtime.Serialization.Json.dll
|
||||||
|
System.Runtime.Serialization.Primitives.dll
|
||||||
|
System.Runtime.Serialization.Xml.dll
|
||||||
|
System.Runtime.WindowsRuntime.dll
|
||||||
|
System.Runtime.WindowsRuntime.UI.Xaml.dll
|
||||||
|
System.Security.AccessControl.dll
|
||||||
|
System.Security.Claims.dll
|
||||||
|
System.Security.Cryptography.Algorithms.dll
|
||||||
|
System.Security.Cryptography.Cng.dll
|
||||||
|
System.Security.Cryptography.Csp.dll
|
||||||
|
System.Security.Cryptography.Encoding.dll
|
||||||
|
System.Security.Cryptography.Native.Apple.a
|
||||||
|
System.Security.Cryptography.Native.Apple.dylib
|
||||||
|
System.Security.Cryptography.Native.OpenSsl.a
|
||||||
|
System.Security.Cryptography.Native.OpenSsl.dylib
|
||||||
|
System.Security.Cryptography.Native.OpenSsl.so
|
||||||
|
System.Security.Cryptography.OpenSsl.dll
|
||||||
|
System.Security.Cryptography.Primitives.dll
|
||||||
|
System.Security.Cryptography.X509Certificates.dll
|
||||||
|
System.Security.Cryptography.XCertificates.dll
|
||||||
|
System.Security.dll
|
||||||
|
System.Security.Principal.dll
|
||||||
|
System.Security.Principal.Windows.dll
|
||||||
|
System.Security.SecureString.dll
|
||||||
|
System.ServiceModel.Web.dll
|
||||||
|
System.ServiceProcess.dll
|
||||||
|
System.Text.Encoding.CodePages.dll
|
||||||
|
System.Text.Encoding.dll
|
||||||
|
System.Text.Encoding.Extensions.dll
|
||||||
|
System.Text.Encodings.Web.dll
|
||||||
|
System.Text.Json.dll
|
||||||
|
System.Text.RegularExpressions.dll
|
||||||
|
System.Threading.Channels.dll
|
||||||
|
System.Threading.dll
|
||||||
|
System.Threading.Overlapped.dll
|
||||||
|
System.Threading.Tasks.Dataflow.dll
|
||||||
|
System.Threading.Tasks.dll
|
||||||
|
System.Threading.Tasks.Extensions.dll
|
||||||
|
System.Threading.Tasks.Parallel.dll
|
||||||
|
System.Threading.Thread.dll
|
||||||
|
System.Threading.ThreadPool.dll
|
||||||
|
System.Threading.Timer.dll
|
||||||
|
System.Transactions.dll
|
||||||
|
System.Transactions.Local.dll
|
||||||
|
System.ValueTuple.dll
|
||||||
|
System.Web.dll
|
||||||
|
System.Web.HttpUtility.dll
|
||||||
|
System.Windows.dll
|
||||||
|
System.Xml.dll
|
||||||
|
System.Xml.Linq.dll
|
||||||
|
System.Xml.ReaderWriter.dll
|
||||||
|
System.Xml.Serialization.dll
|
||||||
|
System.Xml.XDocument.dll
|
||||||
|
System.Xml.XmlDocument.dll
|
||||||
|
System.Xml.XmlSerializer.dll
|
||||||
|
System.Xml.XPath.dll
|
||||||
|
System.Xml.XPath.XDocument.dll
|
||||||
|
ucrtbase.dll
|
||||||
|
WindowsBase.dll
|
||||||
24
src/Misc/trimmedpackages_targz.json
Normal file
24
src/Misc/trimmedpackages_targz.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"HashValue": "<NO_RUNTIME_EXTERNALS_HASH>",
|
||||||
|
"DownloadUrl": "https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-<RUNNER_PLATFORM>-<RUNNER_VERSION>-noruntime-noexternals.tar.gz",
|
||||||
|
"TrimmedContents": {
|
||||||
|
"dotnetRuntime": "<RUNTIME_HASH>",
|
||||||
|
"externals": "<EXTERNALS_HASH>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"HashValue": "<NO_RUNTIME_HASH>",
|
||||||
|
"DownloadUrl": "https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-<RUNNER_PLATFORM>-<RUNNER_VERSION>-noruntime.tar.gz",
|
||||||
|
"TrimmedContents": {
|
||||||
|
"dotnetRuntime": "<RUNTIME_HASH>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"HashValue": "<NO_EXTERNALS_HASH>",
|
||||||
|
"DownloadUrl": "https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-<RUNNER_PLATFORM>-<RUNNER_VERSION>-noexternals.tar.gz",
|
||||||
|
"TrimmedContents": {
|
||||||
|
"externals": "<EXTERNALS_HASH>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
24
src/Misc/trimmedpackages_zip.json
Normal file
24
src/Misc/trimmedpackages_zip.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"HashValue": "<NO_RUNTIME_EXTERNALS_HASH>",
|
||||||
|
"DownloadUrl": "https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-<RUNNER_PLATFORM>-<RUNNER_VERSION>-noruntime-noexternals.zip",
|
||||||
|
"TrimmedContents": {
|
||||||
|
"dotnetRuntime": "<RUNTIME_HASH>",
|
||||||
|
"externals": "<EXTERNALS_HASH>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"HashValue": "<NO_RUNTIME_HASH>",
|
||||||
|
"DownloadUrl": "https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-<RUNNER_PLATFORM>-<RUNNER_VERSION>-noruntime.zip",
|
||||||
|
"TrimmedContents": {
|
||||||
|
"dotnetRuntime": "<RUNTIME_HASH>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"HashValue": "<NO_EXTERNALS_HASH>",
|
||||||
|
"DownloadUrl": "https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-<RUNNER_PLATFORM>-<RUNNER_VERSION>-noexternals.zip",
|
||||||
|
"TrimmedContents": {
|
||||||
|
"externals": "<EXTERNALS_HASH>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -33,6 +33,12 @@ namespace GitHub.Runner.Common
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string PoolName { get; set; }
|
public string PoolName { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public bool DisableUpdate { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public bool Ephemeral { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string ServerUrl { get; set; }
|
public string ServerUrl { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ namespace GitHub.Runner.Common
|
|||||||
Certificates,
|
Certificates,
|
||||||
Options,
|
Options,
|
||||||
SetupInfo,
|
SetupInfo,
|
||||||
|
Telemetry
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Constants
|
public static class Constants
|
||||||
@@ -125,9 +126,11 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
public static readonly string Check = "check";
|
public static readonly string Check = "check";
|
||||||
public static readonly string Commit = "commit";
|
public static readonly string Commit = "commit";
|
||||||
|
public static readonly string Ephemeral = "ephemeral";
|
||||||
public static readonly string Help = "help";
|
public static readonly string Help = "help";
|
||||||
public static readonly string Replace = "replace";
|
public static readonly string Replace = "replace";
|
||||||
public static readonly string Once = "once";
|
public static readonly string DisableUpdate = "disableupdate";
|
||||||
|
public static readonly string Once = "once"; // Keep this around since customers still relies on it
|
||||||
public static readonly string RunAsService = "runasservice";
|
public static readonly string RunAsService = "runasservice";
|
||||||
public static readonly string Unattended = "unattended";
|
public static readonly string Unattended = "unattended";
|
||||||
public static readonly string Version = "version";
|
public static readonly string Version = "version";
|
||||||
@@ -153,6 +156,8 @@ namespace GitHub.Runner.Common
|
|||||||
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 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 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 class RunnerEvent
|
public static class RunnerEvent
|
||||||
@@ -184,6 +189,12 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string Success = "success";
|
public static readonly string Success = "success";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class Hooks
|
||||||
|
{
|
||||||
|
public static readonly string JobStartedStepName = "Set up runner";
|
||||||
|
public static readonly string JobCompletedStepName = "Complete runner";
|
||||||
|
}
|
||||||
|
|
||||||
public static class Path
|
public static class Path
|
||||||
{
|
{
|
||||||
public static readonly string ActionsDirectory = "_actions";
|
public static readonly string ActionsDirectory = "_actions";
|
||||||
@@ -212,13 +223,18 @@ namespace GitHub.Runner.Common
|
|||||||
// Keep alphabetical
|
// Keep alphabetical
|
||||||
//
|
//
|
||||||
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 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 class Agent
|
public static class Agent
|
||||||
{
|
{
|
||||||
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
public static readonly string ToolsDirectory = "agent.ToolsDirectory";
|
||||||
|
|
||||||
|
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
||||||
|
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class System
|
public static class System
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ namespace GitHub.Runner.Common
|
|||||||
case "GitHub.Runner.Worker.IFileCommandExtension":
|
case "GitHub.Runner.Worker.IFileCommandExtension":
|
||||||
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");
|
||||||
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");
|
||||||
|
|||||||
@@ -90,20 +90,22 @@ namespace GitHub.Runner.Common
|
|||||||
this.SecretMasker.AddValueEncoder(ValueEncoders.UriDataEscape);
|
this.SecretMasker.AddValueEncoder(ValueEncoders.UriDataEscape);
|
||||||
this.SecretMasker.AddValueEncoder(ValueEncoders.XmlDataEscape);
|
this.SecretMasker.AddValueEncoder(ValueEncoders.XmlDataEscape);
|
||||||
this.SecretMasker.AddValueEncoder(ValueEncoders.TrimDoubleQuotes);
|
this.SecretMasker.AddValueEncoder(ValueEncoders.TrimDoubleQuotes);
|
||||||
|
this.SecretMasker.AddValueEncoder(ValueEncoders.PowerShellPreAmpersandEscape);
|
||||||
|
this.SecretMasker.AddValueEncoder(ValueEncoders.PowerShellPostAmpersandEscape);
|
||||||
|
|
||||||
// Create the trace manager.
|
// Create the trace manager.
|
||||||
if (string.IsNullOrEmpty(logFile))
|
if (string.IsNullOrEmpty(logFile))
|
||||||
{
|
{
|
||||||
int logPageSize;
|
int logPageSize;
|
||||||
string logSizeEnv = Environment.GetEnvironmentVariable($"{hostType.ToUpperInvariant()}_LOGSIZE");
|
string logSizeEnv = Environment.GetEnvironmentVariable($"{hostType.ToUpperInvariant()}_LOGSIZE");
|
||||||
if (!string.IsNullOrEmpty(logSizeEnv) || !int.TryParse(logSizeEnv, out logPageSize))
|
if (string.IsNullOrEmpty(logSizeEnv) || !int.TryParse(logSizeEnv, out logPageSize))
|
||||||
{
|
{
|
||||||
logPageSize = _defaultLogPageSize;
|
logPageSize = _defaultLogPageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int logRetentionDays;
|
int logRetentionDays;
|
||||||
string logRetentionDaysEnv = Environment.GetEnvironmentVariable($"{hostType.ToUpperInvariant()}_LOGRETENTION");
|
string logRetentionDaysEnv = Environment.GetEnvironmentVariable($"{hostType.ToUpperInvariant()}_LOGRETENTION");
|
||||||
if (!string.IsNullOrEmpty(logRetentionDaysEnv) || !int.TryParse(logRetentionDaysEnv, out logRetentionDays))
|
if (string.IsNullOrEmpty(logRetentionDaysEnv) || !int.TryParse(logRetentionDaysEnv, out logRetentionDays))
|
||||||
{
|
{
|
||||||
logRetentionDays = _defaultLogRetentionDays;
|
logRetentionDays = _defaultLogRetentionDays;
|
||||||
}
|
}
|
||||||
@@ -191,6 +193,11 @@ namespace GitHub.Runner.Common
|
|||||||
_trace.Info($"No proxy settings were found based on environmental variables (http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY)");
|
_trace.Info($"No proxy settings were found based on environmental variables (http_proxy/https_proxy/HTTP_PROXY/HTTPS_PROXY)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
|
||||||
|
{
|
||||||
|
_trace.Warning($"Runner is running under insecure mode: HTTPS server certifcate validation has been turned off by GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY environment variable.");
|
||||||
|
}
|
||||||
|
|
||||||
var credFile = GetConfigFile(WellKnownConfigFile.Credentials);
|
var credFile = GetConfigFile(WellKnownConfigFile.Credentials);
|
||||||
if (File.Exists(credFile))
|
if (File.Exists(credFile))
|
||||||
{
|
{
|
||||||
@@ -198,9 +205,19 @@ namespace GitHub.Runner.Common
|
|||||||
if (credData != null &&
|
if (credData != null &&
|
||||||
credData.Data.TryGetValue("clientId", out var clientId))
|
credData.Data.TryGetValue("clientId", out var clientId))
|
||||||
{
|
{
|
||||||
_userAgents.Add(new ProductInfoHeaderValue($"RunnerId", clientId));
|
_userAgents.Add(new ProductInfoHeaderValue("ClientId", clientId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var runnerFile = GetConfigFile(WellKnownConfigFile.Runner);
|
||||||
|
if (File.Exists(runnerFile))
|
||||||
|
{
|
||||||
|
var runnerSettings = IOUtil.LoadObject<RunnerSettings>(runnerFile);
|
||||||
|
_userAgents.Add(new ProductInfoHeaderValue("RunnerId", runnerSettings.AgentId.ToString(CultureInfo.InvariantCulture)));
|
||||||
|
_userAgents.Add(new ProductInfoHeaderValue("GroupId", runnerSettings.PoolId.ToString(CultureInfo.InvariantCulture)));
|
||||||
|
}
|
||||||
|
|
||||||
|
_userAgents.Add(new ProductInfoHeaderValue("CommitSHA", BuildConstants.Source.CommitHash));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetDirectory(WellKnownDirectory directory)
|
public string GetDirectory(WellKnownDirectory directory)
|
||||||
@@ -341,6 +358,12 @@ namespace GitHub.Runner.Common
|
|||||||
".setup_info");
|
".setup_info");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WellKnownConfigFile.Telemetry:
|
||||||
|
path = Path.Combine(
|
||||||
|
GetDirectory(WellKnownDirectory.Diag),
|
||||||
|
".telemetry");
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new NotSupportedException($"Unexpected well known config file: '{configFile}'");
|
throw new NotSupportedException($"Unexpected well known config file: '{configFile}'");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|
||||||
@@ -13,7 +14,14 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
public HttpClientHandler CreateClientHandler(RunnerWebProxy webProxy)
|
public HttpClientHandler CreateClientHandler(RunnerWebProxy webProxy)
|
||||||
{
|
{
|
||||||
return new HttpClientHandler() { Proxy = webProxy };
|
var client = new HttpClientHandler() { Proxy = webProxy };
|
||||||
|
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
|
||||||
|
{
|
||||||
|
client.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return client;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,29 +1,36 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
[ServiceLocator(Default = typeof(JobServer))]
|
[ServiceLocator(Default = typeof(JobServer))]
|
||||||
public interface IJobServer : IRunnerService
|
public interface IJobServer : IRunnerService, IAsyncDisposable
|
||||||
{
|
{
|
||||||
Task ConnectAsync(VssConnection jobConnection);
|
Task ConnectAsync(VssConnection jobConnection);
|
||||||
|
|
||||||
|
void InitializeWebsocketClient(ServiceEndpoint serviceEndpoint);
|
||||||
|
|
||||||
// logging and console
|
// logging and console
|
||||||
Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken);
|
Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken);
|
||||||
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, CancellationToken cancellationToken);
|
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long? startLine, CancellationToken cancellationToken);
|
||||||
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long startLine, CancellationToken cancellationToken);
|
|
||||||
Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken);
|
Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken);
|
||||||
Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken);
|
Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken);
|
||||||
Task<Timeline> CreateTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
Task<Timeline> CreateTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
||||||
Task<List<TimelineRecord>> UpdateTimelineRecordsAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, IEnumerable<TimelineRecord> records, CancellationToken cancellationToken);
|
Task<List<TimelineRecord>> UpdateTimelineRecordsAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, IEnumerable<TimelineRecord> records, CancellationToken cancellationToken);
|
||||||
Task RaisePlanEventAsync<T>(Guid scopeIdentifier, string hubName, Guid planId, T eventData, CancellationToken cancellationToken) where T : JobEvent;
|
Task RaisePlanEventAsync<T>(Guid scopeIdentifier, string hubName, Guid planId, T eventData, CancellationToken cancellationToken) where T : JobEvent;
|
||||||
Task<Timeline> GetTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
Task<Timeline> GetTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
||||||
Task<ActionDownloadInfoCollection> ResolveActionDownloadInfoAsync(Guid scopeIdentifier, string hubName, Guid planId, ActionReferenceList actions, CancellationToken cancellationToken);
|
Task<ActionDownloadInfoCollection> ResolveActionDownloadInfoAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid jobId, ActionReferenceList actions, CancellationToken cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class JobServer : RunnerService, IJobServer
|
public sealed class JobServer : RunnerService, IJobServer
|
||||||
@@ -31,11 +38,29 @@ namespace GitHub.Runner.Common
|
|||||||
private bool _hasConnection;
|
private bool _hasConnection;
|
||||||
private VssConnection _connection;
|
private VssConnection _connection;
|
||||||
private TaskHttpClient _taskClient;
|
private TaskHttpClient _taskClient;
|
||||||
|
private ClientWebSocket _websocketClient;
|
||||||
|
|
||||||
|
private ServiceEndpoint _serviceEndpoint;
|
||||||
|
|
||||||
|
private int totalBatchedLinesAttemptedByWebsocket = 0;
|
||||||
|
private int failedAttemptsToPostBatchedLinesByWebsocket = 0;
|
||||||
|
|
||||||
|
|
||||||
|
private static readonly TimeSpan _minDelayForWebsocketReconnect = TimeSpan.FromMilliseconds(100);
|
||||||
|
private static readonly TimeSpan _maxDelayForWebsocketReconnect = TimeSpan.FromMilliseconds(500);
|
||||||
|
private static readonly int _minWebsocketFailurePercentageAllowed = 50;
|
||||||
|
private static readonly int _minWebsocketBatchedLinesCountToConsider = 5;
|
||||||
|
|
||||||
|
private Task _websocketConnectTask;
|
||||||
|
|
||||||
public async Task ConnectAsync(VssConnection jobConnection)
|
public async Task ConnectAsync(VssConnection jobConnection)
|
||||||
{
|
{
|
||||||
_connection = jobConnection;
|
_connection = jobConnection;
|
||||||
int attemptCount = 5;
|
int totalAttempts = 5;
|
||||||
|
int attemptCount = totalAttempts;
|
||||||
|
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
||||||
|
var runnerSettings = configurationStore.GetSettings();
|
||||||
|
|
||||||
while (!_connection.HasAuthenticated && attemptCount-- > 0)
|
while (!_connection.HasAuthenticated && attemptCount-- > 0)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -45,17 +70,86 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
catch (Exception ex) when (attemptCount > 0)
|
catch (Exception ex) when (attemptCount > 0)
|
||||||
{
|
{
|
||||||
Trace.Info($"Catch exception during connect. {attemptCount} attemp left.");
|
Trace.Info($"Catch exception during connect. {attemptCount} attempts left.");
|
||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
|
|
||||||
|
if (runnerSettings.IsHostedServer)
|
||||||
|
{
|
||||||
|
await CheckNetworkEndpointsAsync(attemptCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(100);
|
int attempt = totalAttempts - attemptCount;
|
||||||
|
TimeSpan backoff = BackoffTimerHelper.GetExponentialBackoff(attempt, TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(3.2), TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
await Task.Delay(backoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
_taskClient = _connection.GetClient<TaskHttpClient>();
|
_taskClient = _connection.GetClient<TaskHttpClient>();
|
||||||
_hasConnection = true;
|
_hasConnection = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task CheckNetworkEndpointsAsync(int attemptsLeft)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Trace.Info("Requesting Actions Service health endpoint status");
|
||||||
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
|
using (var actionsClient = new HttpClient(httpClientHandler))
|
||||||
|
{
|
||||||
|
var baseUri = new Uri(_connection.Uri.GetLeftPart(UriPartial.Authority));
|
||||||
|
|
||||||
|
actionsClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
|
||||||
|
// Call the _apis/health endpoint, and include how many attempts are left as a URL query for easy tracking
|
||||||
|
var response = await actionsClient.GetAsync(new Uri(baseUri, $"_apis/health?_internalRunnerAttemptsLeft={attemptsLeft}"));
|
||||||
|
Trace.Info($"Actions health status code: {response.StatusCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log error, but continue as this call is best-effort
|
||||||
|
Trace.Info($"Actions Service health endpoint failed due to {ex.GetType().Name}");
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Trace.Info("Requesting Github API endpoint status");
|
||||||
|
// This is a dotcom public API... just call it directly
|
||||||
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
|
using (var gitHubClient = new HttpClient(httpClientHandler))
|
||||||
|
{
|
||||||
|
gitHubClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
|
||||||
|
// Call the api.github.com endpoint, and include how many attempts are left as a URL query for easy tracking
|
||||||
|
var response = await gitHubClient.GetAsync($"https://api.github.com?_internalRunnerAttemptsLeft={attemptsLeft}");
|
||||||
|
Trace.Info($"api.github.com status code: {response.StatusCode}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Log error, but continue as this call is best-effort
|
||||||
|
Trace.Info($"Github API endpoint failed due to {ex.GetType().Name}");
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeWebsocketClient(ServiceEndpoint serviceEndpoint)
|
||||||
|
{
|
||||||
|
this._serviceEndpoint = serviceEndpoint;
|
||||||
|
InitializeWebsocketClient(TimeSpan.Zero);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTask DisposeAsync()
|
||||||
|
{
|
||||||
|
CloseWebSocket(WebSocketCloseStatus.NormalClosure, CancellationToken.None);
|
||||||
|
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
private void CheckConnection()
|
private void CheckConnection()
|
||||||
{
|
{
|
||||||
if (!_hasConnection)
|
if (!_hasConnection)
|
||||||
@@ -64,6 +158,48 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeWebsocketClient(TimeSpan delay)
|
||||||
|
{
|
||||||
|
if (_serviceEndpoint.Authorization != null &&
|
||||||
|
_serviceEndpoint.Authorization.Parameters.TryGetValue(EndpointAuthorizationParameters.AccessToken, out var accessToken) &&
|
||||||
|
!string.IsNullOrEmpty(accessToken))
|
||||||
|
{
|
||||||
|
if (_serviceEndpoint.Data.TryGetValue("FeedStreamUrl", out var feedStreamUrl) && !string.IsNullOrEmpty(feedStreamUrl))
|
||||||
|
{
|
||||||
|
// let's ensure we use the right scheme
|
||||||
|
feedStreamUrl = feedStreamUrl.Replace("https://", "wss://").Replace("http://", "ws://");
|
||||||
|
Trace.Info($"Creating websocket client ..." + feedStreamUrl);
|
||||||
|
this._websocketClient = new ClientWebSocket();
|
||||||
|
this._websocketClient.Options.SetRequestHeader("Authorization", $"Bearer {accessToken}");
|
||||||
|
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.Info($"No FeedStreamUrl found, so we will use Rest API calls for sending feed data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.Info($"No access token from the service endpoint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ConnectWebSocketClient(string feedStreamUrl, TimeSpan delay)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Trace.Info($"Attempting to start websocket client with delay {delay}.");
|
||||||
|
await Task.Delay(delay);
|
||||||
|
await this._websocketClient.ConnectAsync(new Uri(feedStreamUrl), default(CancellationToken));
|
||||||
|
Trace.Info($"Successfully started websocket client.");
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Info("Exception caught during websocket client connect, fallback of HTTP would be used now instead of websocket.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
// Feedback: WebConsole, TimelineRecords and Logs
|
// Feedback: WebConsole, TimelineRecords and Logs
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
@@ -74,16 +210,86 @@ namespace GitHub.Runner.Common
|
|||||||
return _taskClient.AppendLogContentAsync(scopeIdentifier, hubName, planId, logId, uploadStream, cancellationToken: cancellationToken);
|
return _taskClient.AppendLogContentAsync(scopeIdentifier, hubName, planId, logId, uploadStream, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, CancellationToken cancellationToken)
|
public async Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long? startLine, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
return _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, cancellationToken: cancellationToken);
|
var pushedLinesViaWebsocket = false;
|
||||||
|
if (_websocketConnectTask != null)
|
||||||
|
{
|
||||||
|
await _websocketConnectTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
// "_websocketClient != null" implies either: We have a successful connection OR we have to attempt sending again and then reconnect
|
||||||
|
// ...in other words, if websocket client is null, we will skip sending to websocket and just use rest api calls to send data
|
||||||
|
if (_websocketClient != null)
|
||||||
|
{
|
||||||
|
var linesWrapper = startLine.HasValue? new TimelineRecordFeedLinesWrapper(stepId, lines, startLine.Value): new TimelineRecordFeedLinesWrapper(stepId, lines);
|
||||||
|
var jsonData = StringUtil.ConvertToJson(linesWrapper);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
totalBatchedLinesAttemptedByWebsocket++;
|
||||||
|
var jsonDataBytes = Encoding.UTF8.GetBytes(jsonData);
|
||||||
|
// break the message into chunks of 1024 bytes
|
||||||
|
for (var i = 0; i < jsonDataBytes.Length; i += 1 * 1024)
|
||||||
|
{
|
||||||
|
var lastChunk = i + (1 * 1024) >= jsonDataBytes.Length;
|
||||||
|
var chunk = new ArraySegment<byte>(jsonDataBytes, i, Math.Min(1 * 1024, jsonDataBytes.Length - i));
|
||||||
|
await _websocketClient.SendAsync(chunk, WebSocketMessageType.Text, endOfMessage:lastChunk, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
pushedLinesViaWebsocket = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
failedAttemptsToPostBatchedLinesByWebsocket++;
|
||||||
|
Trace.Info($"Caught exception during append web console line to websocket, let's fallback to sending via non-websocket call (total calls: {totalBatchedLinesAttemptedByWebsocket}, failed calls: {failedAttemptsToPostBatchedLinesByWebsocket}, websocket state: {this._websocketClient?.State}).");
|
||||||
|
Trace.Error(ex);
|
||||||
|
if (totalBatchedLinesAttemptedByWebsocket > _minWebsocketBatchedLinesCountToConsider)
|
||||||
|
{
|
||||||
|
// let's consider failure percentage
|
||||||
|
if (failedAttemptsToPostBatchedLinesByWebsocket * 100 / totalBatchedLinesAttemptedByWebsocket > _minWebsocketFailurePercentageAllowed)
|
||||||
|
{
|
||||||
|
Trace.Info($"Exhausted websocket allowed retries, we will not attempt websocket connection for this job to post lines again.");
|
||||||
|
CloseWebSocket(WebSocketCloseStatus.InternalServerError, cancellationToken);
|
||||||
|
|
||||||
|
// By setting it to null, we will ensure that we never try websocket path again for this job
|
||||||
|
_websocketClient = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_websocketClient != null)
|
||||||
|
{
|
||||||
|
var delay = BackoffTimerHelper.GetRandomBackoff(_minDelayForWebsocketReconnect, _maxDelayForWebsocketReconnect);
|
||||||
|
Trace.Info($"Websocket is not open, let's attempt to connect back again with random backoff {delay} ms (total calls: {totalBatchedLinesAttemptedByWebsocket}, failed calls: {failedAttemptsToPostBatchedLinesByWebsocket}).");
|
||||||
|
InitializeWebsocketClient(delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pushedLinesViaWebsocket)
|
||||||
|
{
|
||||||
|
if (startLine.HasValue)
|
||||||
|
{
|
||||||
|
await _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, startLine.Value, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long startLine, CancellationToken cancellationToken)
|
private void CloseWebSocket(WebSocketCloseStatus closeStatus, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
try
|
||||||
return _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, startLine, cancellationToken: cancellationToken);
|
{
|
||||||
|
_websocketClient?.CloseOutputAsync(closeStatus, "Closing websocket", cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception websocketEx)
|
||||||
|
{
|
||||||
|
// In some cases this might be okay since the websocket might be open yet, so just close and don't trace exceptions
|
||||||
|
Trace.Info($"Failed to close websocket gracefully {websocketEx.GetType().Name}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, string type, string name, Stream uploadStream, CancellationToken cancellationToken)
|
public Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, string type, string name, Stream uploadStream, CancellationToken cancellationToken)
|
||||||
@@ -125,10 +331,10 @@ namespace GitHub.Runner.Common
|
|||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
// Action download info
|
// Action download info
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
public Task<ActionDownloadInfoCollection> ResolveActionDownloadInfoAsync(Guid scopeIdentifier, string hubName, Guid planId, ActionReferenceList actions, CancellationToken cancellationToken)
|
public Task<ActionDownloadInfoCollection> ResolveActionDownloadInfoAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid jobId, ActionReferenceList actions, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
return _taskClient.ResolveActionDownloadInfoAsync(scopeIdentifier, hubName, planId, actions, cancellationToken: cancellationToken);
|
return _taskClient.ResolveActionDownloadInfoAsync(scopeIdentifier, hubName, planId, jobId, actions, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
[ServiceLocator(Default = typeof(JobServerQueue))]
|
[ServiceLocator(Default = typeof(JobServerQueue))]
|
||||||
public interface IJobServerQueue : IRunnerService, IThrottlingReporter
|
public interface IJobServerQueue : IRunnerService, IThrottlingReporter
|
||||||
{
|
{
|
||||||
|
TaskCompletionSource<int> JobRecordUpdated { get; }
|
||||||
event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
||||||
Task ShutdownAsync();
|
Task ShutdownAsync();
|
||||||
void Start(Pipelines.AgentJobRequestMessage jobRequest);
|
void Start(Pipelines.AgentJobRequestMessage jobRequest);
|
||||||
@@ -62,16 +62,20 @@ namespace GitHub.Runner.Common
|
|||||||
private IJobServer _jobServer;
|
private IJobServer _jobServer;
|
||||||
private Task[] _allDequeueTasks;
|
private Task[] _allDequeueTasks;
|
||||||
private readonly TaskCompletionSource<int> _jobCompletionSource = new TaskCompletionSource<int>();
|
private readonly TaskCompletionSource<int> _jobCompletionSource = new TaskCompletionSource<int>();
|
||||||
|
private readonly TaskCompletionSource<int> _jobRecordUpdated = new TaskCompletionSource<int>();
|
||||||
private bool _queueInProcess = false;
|
private bool _queueInProcess = false;
|
||||||
|
|
||||||
|
public TaskCompletionSource<int> JobRecordUpdated => _jobRecordUpdated;
|
||||||
|
|
||||||
public event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
public event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
||||||
|
|
||||||
// Web console dequeue will start with process queue every 250ms for the first 60*4 times (~60 seconds).
|
// Web console dequeue will start with process queue every 250ms for the first 60*4 times (~60 seconds).
|
||||||
// Then the dequeue will happen every 500ms.
|
// Then the dequeue will happen every 500ms.
|
||||||
// In this way, customer still can get instance live console output on job start,
|
// In this way, customer still can get instance live console output on job start,
|
||||||
// at the same time we can cut the load to server after the build run for more than 60s
|
// at the same time we can cut the load to server after the build run for more than 60s
|
||||||
private int _webConsoleLineAggressiveDequeueCount = 0;
|
private int _webConsoleLineAggressiveDequeueCount = 0;
|
||||||
private const int _webConsoleLineAggressiveDequeueLimit = 4 * 60;
|
private const int _webConsoleLineAggressiveDequeueLimit = 4 * 60;
|
||||||
|
private const int _webConsoleLineQueueSizeLimit = 1024;
|
||||||
private bool _webConsoleLineAggressiveDequeue = true;
|
private bool _webConsoleLineAggressiveDequeue = true;
|
||||||
private bool _firstConsoleOutputs = true;
|
private bool _firstConsoleOutputs = true;
|
||||||
|
|
||||||
@@ -85,6 +89,10 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
|
var serviceEndPoint = jobRequest.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
_jobServer.InitializeWebsocketClient(serviceEndPoint);
|
||||||
|
|
||||||
if (_queueInProcess)
|
if (_queueInProcess)
|
||||||
{
|
{
|
||||||
Trace.Info("No-opt, all queue process tasks are running.");
|
Trace.Info("No-opt, all queue process tasks are running.");
|
||||||
@@ -152,13 +160,28 @@ namespace GitHub.Runner.Common
|
|||||||
await ProcessTimelinesUpdateQueueAsync(runOnce: true);
|
await ProcessTimelinesUpdateQueueAsync(runOnce: true);
|
||||||
Trace.Info("Timeline update queue drained.");
|
Trace.Info("Timeline update queue drained.");
|
||||||
|
|
||||||
|
Trace.Info($"Disposing job server ...");
|
||||||
|
await _jobServer.DisposeAsync();
|
||||||
|
|
||||||
Trace.Info("All queue process tasks have been stopped, and all queues are drained.");
|
Trace.Info("All queue process tasks have been stopped, and all queues are drained.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber)
|
public void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber)
|
||||||
{
|
{
|
||||||
Trace.Verbose("Enqueue web console line queue: {0}", line);
|
// We only process 500 lines of the queue everytime.
|
||||||
_webConsoleLineQueue.Enqueue(new ConsoleLineInfo(stepRecordId, line, lineNumber));
|
// If the queue is backing up due to slow Http request or flood of output from step,
|
||||||
|
// we will drop the output to avoid extra memory consumption from the runner since the live console feed is best effort.
|
||||||
|
if (!string.IsNullOrEmpty(line) && _webConsoleLineQueue.Count < _webConsoleLineQueueSizeLimit)
|
||||||
|
{
|
||||||
|
Trace.Verbose("Enqueue web console line queue: {0}", line);
|
||||||
|
if (line.Length > 1024)
|
||||||
|
{
|
||||||
|
Trace.Verbose("Web console line is more than 1024 chars, truncate to first 1024 chars");
|
||||||
|
line = $"{line.Substring(0, 1024)}...";
|
||||||
|
}
|
||||||
|
|
||||||
|
_webConsoleLineQueue.Enqueue(new ConsoleLineInfo(stepRecordId, line, lineNumber));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource)
|
public void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource)
|
||||||
@@ -226,12 +249,6 @@ namespace GitHub.Runner.Common
|
|||||||
stepRecordIds.Add(lineInfo.StepRecordId);
|
stepRecordIds.Add(lineInfo.StepRecordId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(lineInfo.Line) && lineInfo.Line.Length > 1024)
|
|
||||||
{
|
|
||||||
Trace.Verbose("Web console line is more than 1024 chars, truncate to first 1024 chars");
|
|
||||||
lineInfo.Line = $"{lineInfo.Line.Substring(0, 1024)}...";
|
|
||||||
}
|
|
||||||
|
|
||||||
stepsConsoleLines[lineInfo.StepRecordId].Add(new TimelineRecordLogLine(lineInfo.Line, lineInfo.LineNumber));
|
stepsConsoleLines[lineInfo.StepRecordId].Add(new TimelineRecordLogLine(lineInfo.Line, lineInfo.LineNumber));
|
||||||
linesCounter++;
|
linesCounter++;
|
||||||
|
|
||||||
@@ -282,16 +299,8 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// we will not requeue failed batch, since the web console lines are time sensitive.
|
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, default(CancellationToken));
|
||||||
if (batch[0].LineNumber.HasValue)
|
|
||||||
{
|
|
||||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber.Value, default(CancellationToken));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), default(CancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_firstConsoleOutputs)
|
if (_firstConsoleOutputs)
|
||||||
{
|
{
|
||||||
HostContext.WritePerfCounter($"WorkerJobServerQueueAppendFirstConsoleOutput_{_planId.ToString()}");
|
HostContext.WritePerfCounter($"WorkerJobServerQueueAppendFirstConsoleOutput_{_planId.ToString()}");
|
||||||
@@ -455,6 +464,14 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
Trace.Verbose("Cleanup buffered timeline record for timeline: {0}.", update.TimelineId);
|
Trace.Verbose("Cleanup buffered timeline record for timeline: {0}.", update.TimelineId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_jobRecordUpdated.Task.IsCompleted &&
|
||||||
|
update.PendingRecords.Any(x => x.Id == _jobTimelineRecordId && x.State != null))
|
||||||
|
{
|
||||||
|
// We have changed the state of the job
|
||||||
|
Trace.Info("Job timeline record has been updated for the first time.");
|
||||||
|
_jobRecordUpdated.TrySetResult(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -471,8 +488,8 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
if (runOnce)
|
if (runOnce)
|
||||||
{
|
{
|
||||||
// continue process timeline records update,
|
// continue process timeline records update,
|
||||||
// we might have more records need update,
|
// we might have more records need update,
|
||||||
// since we just create a new sub-timeline
|
// since we just create a new sub-timeline
|
||||||
if (pendingSubtimelineUpdate)
|
if (pendingSubtimelineUpdate)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -29,8 +29,10 @@ namespace GitHub.Runner.Common
|
|||||||
// Configuration
|
// Configuration
|
||||||
Task<TaskAgent> AddAgentAsync(Int32 agentPoolId, TaskAgent agent);
|
Task<TaskAgent> AddAgentAsync(Int32 agentPoolId, TaskAgent agent);
|
||||||
Task DeleteAgentAsync(int agentPoolId, int agentId);
|
Task DeleteAgentAsync(int agentPoolId, int agentId);
|
||||||
|
Task DeleteAgentAsync(int agentId);
|
||||||
Task<List<TaskAgentPool>> GetAgentPoolsAsync(string agentPoolName = null, TaskAgentPoolType poolType = TaskAgentPoolType.Automation);
|
Task<List<TaskAgentPool>> GetAgentPoolsAsync(string agentPoolName = null, TaskAgentPoolType poolType = TaskAgentPoolType.Automation);
|
||||||
Task<List<TaskAgent>> GetAgentsAsync(int agentPoolId, string agentName = null);
|
Task<List<TaskAgent>> GetAgentsAsync(int agentPoolId, string agentName = null);
|
||||||
|
Task<List<TaskAgent>> GetAgentsAsync(string agentName);
|
||||||
Task<TaskAgent> ReplaceAgentAsync(int agentPoolId, TaskAgent agent);
|
Task<TaskAgent> ReplaceAgentAsync(int agentPoolId, TaskAgent agent);
|
||||||
|
|
||||||
// messagequeue
|
// messagequeue
|
||||||
@@ -49,7 +51,7 @@ namespace GitHub.Runner.Common
|
|||||||
Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken);
|
Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken);
|
||||||
|
|
||||||
// agent update
|
// agent update
|
||||||
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState);
|
Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState, string trace);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RunnerServer : RunnerService, IRunnerServer
|
public sealed class RunnerServer : RunnerService, IRunnerServer
|
||||||
@@ -252,6 +254,11 @@ namespace GitHub.Runner.Common
|
|||||||
return _genericTaskAgentClient.GetAgentsAsync(agentPoolId, agentName, false);
|
return _genericTaskAgentClient.GetAgentsAsync(agentPoolId, agentName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<List<TaskAgent>> GetAgentsAsync(string agentName)
|
||||||
|
{
|
||||||
|
return GetAgentsAsync(0, agentName); // search in all all agentPools
|
||||||
|
}
|
||||||
|
|
||||||
public Task<TaskAgent> ReplaceAgentAsync(int agentPoolId, TaskAgent agent)
|
public Task<TaskAgent> ReplaceAgentAsync(int agentPoolId, TaskAgent agent)
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.Generic);
|
CheckConnection(RunnerConnectionType.Generic);
|
||||||
@@ -264,6 +271,11 @@ namespace GitHub.Runner.Common
|
|||||||
return _genericTaskAgentClient.DeleteAgentAsync(agentPoolId, agentId);
|
return _genericTaskAgentClient.DeleteAgentAsync(agentPoolId, agentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task DeleteAgentAsync(int agentId)
|
||||||
|
{
|
||||||
|
return DeleteAgentAsync(0, agentId); // agentPool is ignored server side
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
// MessageQueue
|
// MessageQueue
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
@@ -329,25 +341,10 @@ namespace GitHub.Runner.Common
|
|||||||
return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, includeToken, cancellationToken: cancellationToken);
|
return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, includeToken, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState)
|
public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState, string trace)
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.Generic);
|
CheckConnection(RunnerConnectionType.Generic);
|
||||||
return _genericTaskAgentClient.UpdateAgentUpdateStateAsync(agentPoolId, agentId, currentState);
|
return _genericTaskAgentClient.UpdateAgentUpdateStateAsync(agentPoolId, agentId, currentState, trace);
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
|
||||||
// Runner Auth Url
|
|
||||||
//-----------------------------------------------------------------
|
|
||||||
public Task<string> GetRunnerAuthUrlAsync(int runnerPoolId, int runnerId)
|
|
||||||
{
|
|
||||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
|
||||||
return _messageTaskAgentClient.GetAgentAuthUrlAsync(runnerPoolId, runnerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task ReportRunnerAuthUrlErrorAsync(int runnerPoolId, int runnerId, string error)
|
|
||||||
{
|
|
||||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
|
||||||
return _messageTaskAgentClient.ReportAgentAuthUrlMigrationErrorAsync(runnerPoolId, runnerId, error);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,9 +164,8 @@ namespace GitHub.Runner.Common
|
|||||||
if (!Silent)
|
if (!Silent)
|
||||||
{
|
{
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
|
||||||
Console.WriteLine($"# {message}");
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
|
Console.WriteLine($"# {message}");
|
||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -177,9 +176,8 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
Console.Write("√ ");
|
Console.Write("√ ");
|
||||||
Console.ForegroundColor = ConsoleColor.White;
|
|
||||||
Console.WriteLine(message);
|
|
||||||
Console.ResetColor();
|
Console.ResetColor();
|
||||||
|
Console.WriteLine(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
src/Runner.Common/Util/NodeUtil.cs
Normal file
16
src/Runner.Common/Util/NodeUtil.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common.Util
|
||||||
|
{
|
||||||
|
public static class NodeUtil
|
||||||
|
{
|
||||||
|
private const string _defaultNodeVersion = "node16";
|
||||||
|
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] {"node12", "node16"});
|
||||||
|
public static string GetInternalNodeVersion()
|
||||||
|
{
|
||||||
|
var forcedNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
||||||
|
return !string.IsNullOrEmpty(forcedNodeVersion) && BuiltInNodeVersions.Contains(forcedNodeVersion) ? forcedNodeVersion : _defaultNodeVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ using System.Net.NetworkInformation;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
|
|
||||||
@@ -314,12 +315,12 @@ namespace GitHub.Runner.Listener.Check
|
|||||||
});
|
});
|
||||||
|
|
||||||
var downloadCertScript = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Bin), "checkScripts", "downloadCert");
|
var downloadCertScript = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Bin), "checkScripts", "downloadCert");
|
||||||
var node12 = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}");
|
var node = Path.Combine(hostContext.GetDirectory(WellKnownDirectory.Externals), NodeUtil.GetInternalNodeVersion(), "bin", $"node{IOUtil.ExeExtension}");
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run '{node12} \"{downloadCertScript}\"' ");
|
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run '{node} \"{downloadCertScript}\"' ");
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {StringUtil.ConvertToJson(env)}");
|
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {StringUtil.ConvertToJson(env)}");
|
||||||
await processInvoker.ExecuteAsync(
|
await processInvoker.ExecuteAsync(
|
||||||
hostContext.GetDirectory(WellKnownDirectory.Root),
|
hostContext.GetDirectory(WellKnownDirectory.Root),
|
||||||
node12,
|
node,
|
||||||
$"\"{downloadCertScript}\"",
|
$"\"{downloadCertScript}\"",
|
||||||
env,
|
env,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Check
|
namespace GitHub.Runner.Listener.Check
|
||||||
@@ -144,12 +145,12 @@ namespace GitHub.Runner.Listener.Check
|
|||||||
});
|
});
|
||||||
|
|
||||||
var makeWebRequestScript = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "checkScripts", "makeWebRequest.js");
|
var makeWebRequestScript = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "checkScripts", "makeWebRequest.js");
|
||||||
var node12 = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}");
|
var node = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), NodeUtil.GetInternalNodeVersion(), "bin", $"node{IOUtil.ExeExtension}");
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run '{node12} \"{makeWebRequestScript}\"' ");
|
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} Run '{node} \"{makeWebRequestScript}\"' ");
|
||||||
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {StringUtil.ConvertToJson(env)}");
|
result.Logs.Add($"{DateTime.UtcNow.ToString("O")} {StringUtil.ConvertToJson(env)}");
|
||||||
await processInvoker.ExecuteAsync(
|
await processInvoker.ExecuteAsync(
|
||||||
HostContext.GetDirectory(WellKnownDirectory.Root),
|
HostContext.GetDirectory(WellKnownDirectory.Root),
|
||||||
node12,
|
node,
|
||||||
$"\"{makeWebRequestScript}\"",
|
$"\"{makeWebRequestScript}\"",
|
||||||
env,
|
env,
|
||||||
true,
|
true,
|
||||||
|
|||||||
@@ -29,10 +29,12 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Flags.Check,
|
Constants.Runner.CommandLine.Flags.Check,
|
||||||
Constants.Runner.CommandLine.Flags.Commit,
|
Constants.Runner.CommandLine.Flags.Commit,
|
||||||
|
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
||||||
|
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||||
Constants.Runner.CommandLine.Flags.Help,
|
Constants.Runner.CommandLine.Flags.Help,
|
||||||
|
Constants.Runner.CommandLine.Flags.Once,
|
||||||
Constants.Runner.CommandLine.Flags.Replace,
|
Constants.Runner.CommandLine.Flags.Replace,
|
||||||
Constants.Runner.CommandLine.Flags.RunAsService,
|
Constants.Runner.CommandLine.Flags.RunAsService,
|
||||||
Constants.Runner.CommandLine.Flags.Once,
|
|
||||||
Constants.Runner.CommandLine.Flags.Unattended,
|
Constants.Runner.CommandLine.Flags.Unattended,
|
||||||
Constants.Runner.CommandLine.Flags.Version
|
Constants.Runner.CommandLine.Flags.Version
|
||||||
};
|
};
|
||||||
@@ -66,7 +68,10 @@ namespace GitHub.Runner.Listener
|
|||||||
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
||||||
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
||||||
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
||||||
|
public bool Ephemeral => TestFlag(Constants.Runner.CommandLine.Flags.Ephemeral);
|
||||||
|
public bool DisableUpdate => TestFlag(Constants.Runner.CommandLine.Flags.DisableUpdate);
|
||||||
|
|
||||||
|
// Keep this around since customers still relies on it
|
||||||
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
|
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
|
||||||
|
|
||||||
// Constructor.
|
// Constructor.
|
||||||
@@ -240,6 +245,7 @@ namespace GitHub.Runner.Listener
|
|||||||
validator: Validators.ServerUrlValidator);
|
validator: Validators.ServerUrlValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
public string GetWindowsLogonAccount(string defaultValue, string descriptionMsg)
|
public string GetWindowsLogonAccount(string defaultValue, string descriptionMsg)
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
@@ -257,7 +263,7 @@ namespace GitHub.Runner.Listener
|
|||||||
defaultValue: string.Empty,
|
defaultValue: string.Empty,
|
||||||
validator: Validators.NonEmptyValidator);
|
validator: Validators.NonEmptyValidator);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
public string GetWork()
|
public string GetWork()
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
bool IsConfigured();
|
bool IsConfigured();
|
||||||
Task ConfigureAsync(CommandSettings command);
|
Task ConfigureAsync(CommandSettings command);
|
||||||
Task UnconfigureAsync(CommandSettings command);
|
Task UnconfigureAsync(CommandSettings command);
|
||||||
|
void DeleteLocalRunnerConfig();
|
||||||
RunnerSettings LoadSettings();
|
RunnerSettings LoadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,18 +66,18 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
public async Task ConfigureAsync(CommandSettings command)
|
public async Task ConfigureAsync(CommandSettings command)
|
||||||
{
|
{
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
_term.WriteLine("--------------------------------------------------------------------------------", ConsoleColor.White);
|
_term.WriteLine("--------------------------------------------------------------------------------");
|
||||||
_term.WriteLine("| ____ _ _ _ _ _ _ _ _ |", ConsoleColor.White);
|
_term.WriteLine("| ____ _ _ _ _ _ _ _ _ |");
|
||||||
_term.WriteLine("| / ___(_) |_| | | |_ _| |__ / \\ ___| |_(_) ___ _ __ ___ |", ConsoleColor.White);
|
_term.WriteLine("| / ___(_) |_| | | |_ _| |__ / \\ ___| |_(_) ___ _ __ ___ |");
|
||||||
_term.WriteLine("| | | _| | __| |_| | | | | '_ \\ / _ \\ / __| __| |/ _ \\| '_ \\/ __| |", ConsoleColor.White);
|
_term.WriteLine("| | | _| | __| |_| | | | | '_ \\ / _ \\ / __| __| |/ _ \\| '_ \\/ __| |");
|
||||||
_term.WriteLine("| | |_| | | |_| _ | |_| | |_) | / ___ \\ (__| |_| | (_) | | | \\__ \\ |", ConsoleColor.White);
|
_term.WriteLine("| | |_| | | |_| _ | |_| | |_) | / ___ \\ (__| |_| | (_) | | | \\__ \\ |");
|
||||||
_term.WriteLine("| \\____|_|\\__|_| |_|\\__,_|_.__/ /_/ \\_\\___|\\__|_|\\___/|_| |_|___/ |", ConsoleColor.White);
|
_term.WriteLine("| \\____|_|\\__|_| |_|\\__,_|_.__/ /_/ \\_\\___|\\__|_|\\___/|_| |_|___/ |");
|
||||||
_term.WriteLine("| |", ConsoleColor.White);
|
_term.WriteLine("| |");
|
||||||
_term.Write("| ", ConsoleColor.White);
|
_term.Write("| ");
|
||||||
_term.Write("Self-hosted runner registration", ConsoleColor.Cyan);
|
_term.Write("Self-hosted runner registration", ConsoleColor.Cyan);
|
||||||
_term.WriteLine(" |", ConsoleColor.White);
|
_term.WriteLine(" |");
|
||||||
_term.WriteLine("| |", ConsoleColor.White);
|
_term.WriteLine("| |");
|
||||||
_term.WriteLine("--------------------------------------------------------------------------------", ConsoleColor.White);
|
_term.WriteLine("--------------------------------------------------------------------------------");
|
||||||
|
|
||||||
Trace.Info(nameof(ConfigureAsync));
|
Trace.Info(nameof(ConfigureAsync));
|
||||||
if (IsConfigured())
|
if (IsConfigured())
|
||||||
@@ -117,6 +118,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
||||||
|
// Hosted usually means github.com or localhost, while OnPremises means GHES or GHAE
|
||||||
runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || UrlUtil.IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));
|
runnerSettings.IsHostedServer = runnerSettings.GitHubUrl == null || UrlUtil.IsHostedServer(new UriBuilder(runnerSettings.GitHubUrl));
|
||||||
|
|
||||||
// Warn if the Actions server url and GHES server url has different Host
|
// Warn if the Actions server url and GHES server url has different Host
|
||||||
@@ -186,7 +188,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Trace.Info("Found a self-hosted runner group with id {1} and name {2}", agentPool.Id, agentPool.Name);
|
Trace.Info($"Found a self-hosted runner group with id {agentPool.Id} and name {agentPool.Name}");
|
||||||
runnerSettings.PoolId = agentPool.Id;
|
runnerSettings.PoolId = agentPool.Id;
|
||||||
runnerSettings.PoolName = agentPool.Name;
|
runnerSettings.PoolName = agentPool.Name;
|
||||||
}
|
}
|
||||||
@@ -194,6 +196,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
TaskAgent agent;
|
TaskAgent agent;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
runnerSettings.DisableUpdate = command.DisableUpdate;
|
||||||
|
runnerSettings.Ephemeral = command.Ephemeral;
|
||||||
runnerSettings.AgentName = command.GetRunnerName();
|
runnerSettings.AgentName = command.GetRunnerName();
|
||||||
|
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
@@ -210,11 +214,22 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
if (command.GetReplace())
|
if (command.GetReplace())
|
||||||
{
|
{
|
||||||
// Update existing agent with new PublicKey, agent version.
|
// Update existing agent with new PublicKey, agent version.
|
||||||
agent = UpdateExistingAgent(agent, publicKey, userLabels);
|
agent = UpdateExistingAgent(agent, publicKey, userLabels, runnerSettings.Ephemeral, command.DisableUpdate);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
agent = await _runnerServer.ReplaceAgentAsync(runnerSettings.PoolId, agent);
|
agent = await _runnerServer.ReplaceAgentAsync(runnerSettings.PoolId, agent);
|
||||||
|
if (command.DisableUpdate &&
|
||||||
|
command.DisableUpdate != agent.DisableUpdate)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.");
|
||||||
|
}
|
||||||
|
if (command.Ephemeral &&
|
||||||
|
command.Ephemeral != agent.Ephemeral)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'Ephemeral' flag.");
|
||||||
|
}
|
||||||
|
|
||||||
_term.WriteSuccessMessage("Successfully replaced the runner");
|
_term.WriteSuccessMessage("Successfully replaced the runner");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -233,11 +248,22 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create a new agent.
|
// Create a new agent.
|
||||||
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels);
|
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels, runnerSettings.Ephemeral, command.DisableUpdate);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
agent = await _runnerServer.AddAgentAsync(runnerSettings.PoolId, agent);
|
agent = await _runnerServer.AddAgentAsync(runnerSettings.PoolId, agent);
|
||||||
|
if (command.DisableUpdate &&
|
||||||
|
command.DisableUpdate != agent.DisableUpdate)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'DisableUpdate' flag.");
|
||||||
|
}
|
||||||
|
if (command.Ephemeral &&
|
||||||
|
command.Ephemeral != agent.Ephemeral)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("The GitHub server does not support configuring a self-hosted runner with 'Ephemeral' flag.");
|
||||||
|
}
|
||||||
|
|
||||||
_term.WriteSuccessMessage("Runner successfully added");
|
_term.WriteSuccessMessage("Runner successfully added");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -327,6 +353,38 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete .runner and .credentials files
|
||||||
|
public void DeleteLocalRunnerConfig()
|
||||||
|
{
|
||||||
|
bool isConfigured = _store.IsConfigured();
|
||||||
|
bool hasCredentials = _store.HasCredentials();
|
||||||
|
//delete credential config files
|
||||||
|
var currentAction = "Removing .credentials";
|
||||||
|
if (hasCredentials)
|
||||||
|
{
|
||||||
|
_store.DeleteCredential();
|
||||||
|
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
||||||
|
keyManager.DeleteKey();
|
||||||
|
_term.WriteSuccessMessage("Removed .credentials");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_term.WriteLine("Does not exist. Skipping " + currentAction);
|
||||||
|
}
|
||||||
|
|
||||||
|
//delete settings config file
|
||||||
|
currentAction = "Removing .runner";
|
||||||
|
if (isConfigured)
|
||||||
|
{
|
||||||
|
_store.DeleteSettings();
|
||||||
|
_term.WriteSuccessMessage("Removed .runner");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_term.WriteLine("Does not exist. Skipping " + currentAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task UnconfigureAsync(CommandSettings command)
|
public async Task UnconfigureAsync(CommandSettings command)
|
||||||
{
|
{
|
||||||
string currentAction = string.Empty;
|
string currentAction = string.Empty;
|
||||||
@@ -346,12 +404,9 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
_term.WriteSuccessMessage("Runner service removed");
|
_term.WriteSuccessMessage("Runner service removed");
|
||||||
#elif OS_LINUX
|
#else
|
||||||
// unconfig system D service first
|
// unconfig systemd or osx service first
|
||||||
throw new Exception("Unconfigure service first");
|
throw new Exception("Uninstall service first");
|
||||||
#elif OS_OSX
|
|
||||||
// unconfig osx service first
|
|
||||||
throw new Exception("Unconfigure service first");
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,7 +438,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
// Determine the service deployment type based on connection data. (Hosted/OnPremises)
|
||||||
await _runnerServer.ConnectAsync(new Uri(settings.ServerUrl), creds);
|
await _runnerServer.ConnectAsync(new Uri(settings.ServerUrl), creds);
|
||||||
|
|
||||||
var agents = await _runnerServer.GetAgentsAsync(settings.PoolId, settings.AgentName);
|
var agents = await _runnerServer.GetAgentsAsync(settings.AgentName);
|
||||||
Trace.Verbose("Returns {0} agents", agents.Count);
|
Trace.Verbose("Returns {0} agents", agents.Count);
|
||||||
TaskAgent agent = agents.FirstOrDefault();
|
TaskAgent agent = agents.FirstOrDefault();
|
||||||
if (agent == null)
|
if (agent == null)
|
||||||
@@ -392,7 +447,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await _runnerServer.DeleteAgentAsync(settings.PoolId, settings.AgentId);
|
await _runnerServer.DeleteAgentAsync(settings.AgentId);
|
||||||
|
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
_term.WriteSuccessMessage("Runner removed successfully");
|
_term.WriteSuccessMessage("Runner removed successfully");
|
||||||
@@ -403,31 +458,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
_term.WriteLine("Cannot connect to server, because config files are missing. Skipping removing runner from the server.");
|
_term.WriteLine("Cannot connect to server, because config files are missing. Skipping removing runner from the server.");
|
||||||
}
|
}
|
||||||
|
|
||||||
//delete credential config files
|
DeleteLocalRunnerConfig();
|
||||||
currentAction = "Removing .credentials";
|
|
||||||
if (hasCredentials)
|
|
||||||
{
|
|
||||||
_store.DeleteCredential();
|
|
||||||
var keyManager = HostContext.GetService<IRSAKeyManager>();
|
|
||||||
keyManager.DeleteKey();
|
|
||||||
_term.WriteSuccessMessage("Removed .credentials");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_term.WriteLine("Does not exist. Skipping " + currentAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
//delete settings config file
|
|
||||||
currentAction = "Removing .runner";
|
|
||||||
if (isConfigured)
|
|
||||||
{
|
|
||||||
_store.DeleteSettings();
|
|
||||||
_term.WriteSuccessMessage("Removed .runner");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_term.WriteLine("Does not exist. Skipping " + currentAction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
@@ -458,7 +489,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels)
|
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral, bool disableUpdate)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(agent, nameof(agent));
|
ArgUtil.NotNull(agent, nameof(agent));
|
||||||
agent.Authorization = new TaskAgentAuthorization
|
agent.Authorization = new TaskAgentAuthorization
|
||||||
@@ -469,6 +500,9 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// update should replace the existing labels
|
// update should replace the existing labels
|
||||||
agent.Version = BuildConstants.RunnerPackage.Version;
|
agent.Version = BuildConstants.RunnerPackage.Version;
|
||||||
agent.OSDescription = RuntimeInformation.OSDescription;
|
agent.OSDescription = RuntimeInformation.OSDescription;
|
||||||
|
agent.Ephemeral = ephemeral;
|
||||||
|
agent.DisableUpdate = disableUpdate;
|
||||||
|
agent.MaxParallelism = 1;
|
||||||
|
|
||||||
agent.Labels.Clear();
|
agent.Labels.Clear();
|
||||||
|
|
||||||
@@ -484,7 +518,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels)
|
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral, bool disableUpdate)
|
||||||
{
|
{
|
||||||
TaskAgent agent = new TaskAgent(agentName)
|
TaskAgent agent = new TaskAgent(agentName)
|
||||||
{
|
{
|
||||||
@@ -495,6 +529,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
MaxParallelism = 1,
|
MaxParallelism = 1,
|
||||||
Version = BuildConstants.RunnerPackage.Version,
|
Version = BuildConstants.RunnerPackage.Version,
|
||||||
OSDescription = RuntimeInformation.OSDescription,
|
OSDescription = RuntimeInformation.OSDescription,
|
||||||
|
Ephemeral = ephemeral,
|
||||||
|
DisableUpdate = disableUpdate
|
||||||
};
|
};
|
||||||
|
|
||||||
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
||||||
@@ -577,32 +613,52 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
throw new ArgumentException($"'{githubUrl}' should point to an org or repository.");
|
throw new ArgumentException($"'{githubUrl}' should point to an org or repository.");
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
int retryCount = 0;
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
while(retryCount < 3)
|
||||||
{
|
{
|
||||||
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"github:{githubToken}"));
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
HostContext.SecretMasker.AddValue(base64EncodingToken);
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
|
||||||
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
|
||||||
|
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
|
||||||
{
|
{
|
||||||
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"github:{githubToken}"));
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
HostContext.SecretMasker.AddValue(base64EncodingToken);
|
||||||
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
||||||
}
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
else
|
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
||||||
{
|
try
|
||||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
{
|
||||||
var errorResponse = await response.Content.ReadAsStringAsync();
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
||||||
_term.WriteError(errorResponse);
|
|
||||||
response.EnsureSuccessStatusCode();
|
if (response.IsSuccessStatusCode)
|
||||||
return null;
|
{
|
||||||
|
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
||||||
|
}
|
||||||
|
else if(response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
|
{
|
||||||
|
// It doesn't make sense to retry in this case, so just stop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
|
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
_term.WriteError(errorResponse);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex) when (retryCount < 2)
|
||||||
|
{
|
||||||
|
retryCount++;
|
||||||
|
Trace.Error($"Failed to get JIT runner token -- Atempt: {retryCount}");
|
||||||
|
Trace.Error(ex);
|
||||||
|
Trace.Info("Retrying in 5 seconds");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));
|
||||||
|
await Task.Delay(backOff);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
||||||
@@ -618,35 +674,57 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/actions/runner-registration";
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/actions/runner-registration";
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
int retryCount = 0;
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
while (retryCount < 3)
|
||||||
{
|
{
|
||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("RemoteAuth", githubToken);
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
|
|
||||||
var bodyObject = new Dictionary<string, string>()
|
|
||||||
{
|
{
|
||||||
{"url", githubUrl},
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("RemoteAuth", githubToken);
|
||||||
{"runner_event", runnerEvent}
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
};
|
|
||||||
|
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
var bodyObject = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{"url", githubUrl},
|
||||||
|
{"runner_event", runnerEvent}
|
||||||
|
};
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
try
|
||||||
{
|
{
|
||||||
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
|
||||||
return StringUtil.ConvertFromJson<GitHubAuthResult>(jsonResponse);
|
if(response.IsSuccessStatusCode)
|
||||||
}
|
{
|
||||||
else
|
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
{
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
return StringUtil.ConvertFromJson<GitHubAuthResult>(jsonResponse);
|
||||||
var errorResponse = await response.Content.ReadAsStringAsync();
|
}
|
||||||
_term.WriteError(errorResponse);
|
else if(response.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||||
response.EnsureSuccessStatusCode();
|
{
|
||||||
return null;
|
// It doesn't make sense to retry in this case, so just stop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
|
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
_term.WriteError(errorResponse);
|
||||||
|
// Something else bad happened, let's go to our retry logic
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(Exception ex) when (retryCount < 2)
|
||||||
|
{
|
||||||
|
retryCount++;
|
||||||
|
Trace.Error($"Failed to get tenant credentials -- Atempt: {retryCount}");
|
||||||
|
Trace.Error(ex);
|
||||||
|
Trace.Info("Retrying in 5 seconds");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(5));
|
||||||
|
await Task.Delay(backOff);
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -141,7 +142,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
LocalGroupInfo groupInfo = new LocalGroupInfo();
|
LocalGroupInfo groupInfo = new LocalGroupInfo();
|
||||||
groupInfo.Name = groupName;
|
groupInfo.Name = groupName;
|
||||||
groupInfo.Comment = StringUtil.Format("Built-in group used by Team Foundation Server.");
|
groupInfo.Comment = StringUtil.Format("Built-in group used by GitHub Actions Runner.");
|
||||||
|
|
||||||
int returnCode = NetLocalGroupAdd(null, // computer name
|
int returnCode = NetLocalGroupAdd(null, // computer name
|
||||||
1, // 1 means include comment
|
1, // 1 means include comment
|
||||||
@@ -1327,4 +1328,5 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
public IntPtr hProfile;
|
public IntPtr hProfile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Write the message prompt.
|
// Write the message prompt.
|
||||||
_terminal.Write($"{description} ", ConsoleColor.White);
|
_terminal.Write($"{description} ");
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(defaultValue))
|
if(!string.IsNullOrEmpty(defaultValue))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -48,13 +48,12 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
string repoOrOrgName = regex.Replace(settings.RepoOrOrgName, "-");
|
string repoOrOrgName = regex.Replace(settings.RepoOrOrgName, "-");
|
||||||
|
|
||||||
serviceName = StringUtil.Format(serviceNamePattern, repoOrOrgName, settings.AgentName);
|
serviceName = StringUtil.Format(serviceNamePattern, repoOrOrgName, settings.AgentName);
|
||||||
|
if (serviceName.Length > MaxServiceNameLength)
|
||||||
if (serviceName.Length > 80)
|
|
||||||
{
|
{
|
||||||
Trace.Verbose($"Calculated service name is too long (> 80 chars). Trying again by calculating a shorter name.");
|
Trace.Verbose($"Calculated service name is too long (> {MaxServiceNameLength} chars). Trying again by calculating a shorter name.");
|
||||||
|
// Add 5 to add -xxxx random number on the end
|
||||||
int exceededCharLength = serviceName.Length - 80;
|
int exceededCharLength = serviceName.Length - MaxServiceNameLength + 5;
|
||||||
string repoOrOrgNameSubstring = StringUtil.SubstringPrefix(repoOrOrgName, 45);
|
string repoOrOrgNameSubstring = StringUtil.SubstringPrefix(repoOrOrgName, MaxRepoOrgCharacters);
|
||||||
|
|
||||||
exceededCharLength -= repoOrOrgName.Length - repoOrOrgNameSubstring.Length;
|
exceededCharLength -= repoOrOrgName.Length - repoOrOrgNameSubstring.Length;
|
||||||
|
|
||||||
@@ -66,6 +65,10 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
runnerNameSubstring = StringUtil.SubstringPrefix(settings.AgentName, settings.AgentName.Length - exceededCharLength);
|
runnerNameSubstring = StringUtil.SubstringPrefix(settings.AgentName, settings.AgentName.Length - exceededCharLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lets add a suffix with a random number to reduce the chance of collisions between runner names once we truncate
|
||||||
|
var random = new Random();
|
||||||
|
var num = random.Next(1000, 9999).ToString();
|
||||||
|
runnerNameSubstring +=$"-{num}";
|
||||||
serviceName = StringUtil.Format(serviceNamePattern, repoOrOrgNameSubstring, runnerNameSubstring);
|
serviceName = StringUtil.Format(serviceNamePattern, repoOrOrgNameSubstring, runnerNameSubstring);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,5 +76,12 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
Trace.Info($"Service name '{serviceName}' display name '{serviceDisplayName}' will be used for service configuration.");
|
Trace.Info($"Service name '{serviceName}' display name '{serviceDisplayName}' will be used for service configuration.");
|
||||||
}
|
}
|
||||||
|
#if (OS_LINUX || OS_OSX)
|
||||||
|
const int MaxServiceNameLength = 150;
|
||||||
|
const int MaxRepoOrgCharacters = 70;
|
||||||
|
#elif OS_WINDOWS
|
||||||
|
const int MaxServiceNameLength = 80;
|
||||||
|
const int MaxRepoOrgCharacters = 45;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,6 +67,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return !string.IsNullOrEmpty(value);
|
return !string.IsNullOrEmpty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
public static bool NTAccountValidator(string arg)
|
public static bool NTAccountValidator(string arg)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(arg) || String.IsNullOrEmpty(arg.TrimStart('.', '\\')))
|
if (string.IsNullOrEmpty(arg) || String.IsNullOrEmpty(arg.TrimStart('.', '\\')))
|
||||||
@@ -87,5 +89,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
#pragma warning disable CA1416
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -169,4 +170,5 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#pragma warning restore CA1416
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -2,17 +2,19 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
|
||||||
using System.Linq;
|
|
||||||
using GitHub.Services.Common;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Services.WebApi;
|
||||||
using GitHub.Services.WebApi.Jwt;
|
using GitHub.Services.WebApi.Jwt;
|
||||||
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -34,9 +36,13 @@ namespace GitHub.Runner.Listener
|
|||||||
// and the server will not send another job while this one is still running.
|
// and the server will not send another job while this one is still running.
|
||||||
public sealed class JobDispatcher : RunnerService, IJobDispatcher
|
public sealed class JobDispatcher : RunnerService, IJobDispatcher
|
||||||
{
|
{
|
||||||
|
private static Regex _invalidJsonRegex = new Regex(@"invalid\ Json\ at\ position\ '(\d+)':", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||||
private readonly Lazy<Dictionary<long, TaskResult>> _localRunJobResult = new Lazy<Dictionary<long, TaskResult>>();
|
private readonly Lazy<Dictionary<long, TaskResult>> _localRunJobResult = new Lazy<Dictionary<long, TaskResult>>();
|
||||||
private int _poolId;
|
private int _poolId;
|
||||||
RunnerSettings _runnerSetting;
|
|
||||||
|
IConfigurationStore _configurationStore;
|
||||||
|
|
||||||
|
RunnerSettings _runnerSettings;
|
||||||
private static readonly string _workerProcessName = $"Runner.Worker{IOUtil.ExeExtension}";
|
private static readonly string _workerProcessName = $"Runner.Worker{IOUtil.ExeExtension}";
|
||||||
|
|
||||||
// this is not thread-safe
|
// this is not thread-safe
|
||||||
@@ -54,9 +60,9 @@ namespace GitHub.Runner.Listener
|
|||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
|
|
||||||
// get pool id from config
|
// get pool id from config
|
||||||
var configurationStore = hostContext.GetService<IConfigurationStore>();
|
_configurationStore = hostContext.GetService<IConfigurationStore>();
|
||||||
_runnerSetting = configurationStore.GetSettings();
|
_runnerSettings = _configurationStore.GetSettings();
|
||||||
_poolId = _runnerSetting.PoolId;
|
_poolId = _runnerSettings.PoolId;
|
||||||
|
|
||||||
int channelTimeoutSeconds;
|
int channelTimeoutSeconds;
|
||||||
if (!int.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_CHANNEL_TIMEOUT") ?? string.Empty, out channelTimeoutSeconds))
|
if (!int.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_CHANNEL_TIMEOUT") ?? string.Empty, out channelTimeoutSeconds))
|
||||||
@@ -279,7 +285,7 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
// at this point, the job execution might encounter some dead lock and even not able to be cancelled.
|
// at this point, the job execution might encounter some dead lock and even not able to be cancelled.
|
||||||
// no need to localize the exception string should never happen.
|
// no need to localize the exception string should never happen.
|
||||||
throw new InvalidOperationException($"Job dispatch process for {jobDispatch.JobId} has encountered unexpected error, the dispatch task is not able to be canceled within 45 seconds.");
|
throw new InvalidOperationException($"Job dispatch process for {jobDispatch.JobId} has encountered unexpected error, the dispatch task is not able to be cancelled within 45 seconds.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -357,7 +363,7 @@ namespace GitHub.Runner.Listener
|
|||||||
Trace.Info($"Start renew job request {requestId} for job {message.JobId}.");
|
Trace.Info($"Start renew job request {requestId} for job {message.JobId}.");
|
||||||
Task renewJobRequest = RenewJobRequestAsync(_poolId, requestId, lockToken, orchestrationId, firstJobRequestRenewed, lockRenewalTokenSource.Token);
|
Task renewJobRequest = RenewJobRequestAsync(_poolId, requestId, lockToken, orchestrationId, firstJobRequestRenewed, lockRenewalTokenSource.Token);
|
||||||
|
|
||||||
// wait till first renew succeed or job request is canceled
|
// wait till first renew succeed or job request is cancelled
|
||||||
// not even start worker if the first renew fail
|
// not even start worker if the first renew fail
|
||||||
await Task.WhenAny(firstJobRequestRenewed.Task, renewJobRequest, Task.Delay(-1, jobRequestCancellationToken));
|
await Task.WhenAny(firstJobRequestRenewed.Task, renewJobRequest, Task.Delay(-1, jobRequestCancellationToken));
|
||||||
|
|
||||||
@@ -507,7 +513,20 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
detailInfo = string.Join(Environment.NewLine, workerOutput);
|
detailInfo = string.Join(Environment.NewLine, workerOutput);
|
||||||
Trace.Info($"Return code {returnCode} indicate worker encounter an unhandled exception or app crash, attach worker stdout/stderr to JobRequest result.");
|
Trace.Info($"Return code {returnCode} indicate worker encounter an unhandled exception or app crash, attach worker stdout/stderr to JobRequest result.");
|
||||||
await LogWorkerProcessUnhandledException(message, detailInfo);
|
|
||||||
|
var jobServer = HostContext.GetService<IJobServer>();
|
||||||
|
VssCredentials jobServerCredential = VssUtil.GetVssCredential(systemConnection);
|
||||||
|
VssConnection jobConnection = VssUtil.CreateConnection(systemConnection.Url, jobServerCredential);
|
||||||
|
await jobServer.ConnectAsync(jobConnection);
|
||||||
|
|
||||||
|
await LogWorkerProcessUnhandledException(jobServer, message, detailInfo);
|
||||||
|
|
||||||
|
// Go ahead to finish the job with result 'Failed' if the STDERR from worker is System.IO.IOException, since it typically means we are running out of disk space.
|
||||||
|
if (detailInfo.Contains(typeof(System.IO.IOException).ToString(), StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
Trace.Info($"Finish job with result 'Failed' due to IOException.");
|
||||||
|
await ForceFailJob(jobServer, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskResult result = TaskResultUtil.TranslateFromReturnCode(returnCode);
|
TaskResult result = TaskResultUtil.TranslateFromReturnCode(returnCode);
|
||||||
@@ -648,13 +667,15 @@ namespace GitHub.Runner.Listener
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token);
|
request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token);
|
||||||
|
|
||||||
Trace.Info($"Successfully renew job request {requestId}, job is valid till {request.LockedUntil.Value}");
|
Trace.Info($"Successfully renew job request {requestId}, job is valid till {request.LockedUntil.Value}");
|
||||||
|
|
||||||
if (!firstJobRequestRenewed.Task.IsCompleted)
|
if (!firstJobRequestRenewed.Task.IsCompleted)
|
||||||
{
|
{
|
||||||
// fire first renew succeed event.
|
// fire first renew succeed event.
|
||||||
firstJobRequestRenewed.TrySetResult(0);
|
firstJobRequestRenewed.TrySetResult(0);
|
||||||
|
|
||||||
|
// Update settings if the runner name has been changed server-side
|
||||||
|
UpdateAgentNameIfNeeded(request.ReservedAgent?.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (encounteringError > 0)
|
if (encounteringError > 0)
|
||||||
@@ -683,7 +704,7 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
// OperationCanceledException may caused by http timeout or _lockRenewalTokenSource.Cance();
|
// OperationCanceledException may caused by http timeout or _lockRenewalTokenSource.Cance();
|
||||||
// Stop renew only on cancellation token fired.
|
// Stop renew only on cancellation token fired.
|
||||||
Trace.Info($"job renew has been canceled, stop renew job request {requestId}.");
|
Trace.Info($"job renew has been cancelled, stop renew job request {requestId}.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -741,7 +762,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Trace.Info($"job renew has been canceled, stop renew job request {requestId}.");
|
Trace.Info($"job renew has been cancelled, stop renew job request {requestId}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -754,6 +775,27 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateAgentNameIfNeeded(string agentName)
|
||||||
|
{
|
||||||
|
var isNewAgentName = !string.Equals(_runnerSettings.AgentName, agentName, StringComparison.Ordinal);
|
||||||
|
if (!isNewAgentName || string.IsNullOrEmpty(agentName))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_runnerSettings.AgentName = agentName;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_configurationStore.SaveSettings(_runnerSettings);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error("Cannot update the settings file:");
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Best effort upload any logs for this job.
|
// Best effort upload any logs for this job.
|
||||||
private async Task TryUploadUnfinishedLogs(Pipelines.AgentJobRequestMessage message)
|
private async Task TryUploadUnfinishedLogs(Pipelines.AgentJobRequestMessage message)
|
||||||
{
|
{
|
||||||
@@ -915,53 +957,40 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
// log an error issue to job level timeline record
|
// log an error issue to job level timeline record
|
||||||
private async Task LogWorkerProcessUnhandledException(Pipelines.AgentJobRequestMessage message, string errorMessage)
|
private async Task LogWorkerProcessUnhandledException(IJobServer jobServer, Pipelines.AgentJobRequestMessage message, string errorMessage)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var systemConnection = message.Resources.Endpoints.SingleOrDefault(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection));
|
|
||||||
ArgUtil.NotNull(systemConnection, nameof(systemConnection));
|
|
||||||
|
|
||||||
var jobServer = HostContext.GetService<IJobServer>();
|
|
||||||
VssCredentials jobServerCredential = VssUtil.GetVssCredential(systemConnection);
|
|
||||||
VssConnection jobConnection = VssUtil.CreateConnection(systemConnection.Url, jobServerCredential);
|
|
||||||
|
|
||||||
/* Below is the legacy 'OnPremises' code that is currently unused by the runner
|
|
||||||
ToDo: re-implement code as appropriate once GHES support is added.
|
|
||||||
// Make sure SystemConnection Url match Config Url base for OnPremises server
|
|
||||||
if (!message.Variables.ContainsKey(Constants.Variables.System.ServerType) ||
|
|
||||||
string.Equals(message.Variables[Constants.Variables.System.ServerType]?.Value, "OnPremises", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Uri result = null;
|
|
||||||
Uri configUri = new Uri(_runnerSetting.ServerUrl);
|
|
||||||
if (Uri.TryCreate(new Uri(configUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped)), jobServerUrl.PathAndQuery, out result))
|
|
||||||
{
|
|
||||||
//replace the schema and host portion of messageUri with the host from the
|
|
||||||
//server URI (which was set at config time)
|
|
||||||
jobServerUrl = result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (InvalidOperationException ex)
|
|
||||||
{
|
|
||||||
//cannot parse the Uri - not a fatal error
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
catch (UriFormatException ex)
|
|
||||||
{
|
|
||||||
//cannot parse the Uri - not a fatal error
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
|
|
||||||
await jobServer.ConnectAsync(jobConnection);
|
|
||||||
|
|
||||||
var timeline = await jobServer.GetTimelineAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, CancellationToken.None);
|
var timeline = await jobServer.GetTimelineAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, CancellationToken.None);
|
||||||
|
|
||||||
ArgUtil.NotNull(timeline, nameof(timeline));
|
ArgUtil.NotNull(timeline, nameof(timeline));
|
||||||
|
|
||||||
TimelineRecord jobRecord = timeline.Records.FirstOrDefault(x => x.Id == message.JobId && x.RecordType == "Job");
|
TimelineRecord jobRecord = timeline.Records.FirstOrDefault(x => x.Id == message.JobId && x.RecordType == "Job");
|
||||||
ArgUtil.NotNull(jobRecord, nameof(jobRecord));
|
ArgUtil.NotNull(jobRecord, nameof(jobRecord));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(errorMessage) &&
|
||||||
|
message.Variables.TryGetValue("DistributedTask.EnableRunnerIPCDebug", out var enableRunnerIPCDebug) &&
|
||||||
|
StringUtil.ConvertToBoolean(enableRunnerIPCDebug.Value))
|
||||||
|
{
|
||||||
|
// the trace should be best effort and not affect any job result
|
||||||
|
var match = _invalidJsonRegex.Match(errorMessage);
|
||||||
|
if (match.Success &&
|
||||||
|
match.Groups.Count == 2)
|
||||||
|
{
|
||||||
|
var jsonPosition = int.Parse(match.Groups[1].Value);
|
||||||
|
var serializedJobMessage = JsonUtility.ToString(message);
|
||||||
|
var originalJson = serializedJobMessage.Substring(jsonPosition - 10, 20);
|
||||||
|
errorMessage = $"Runner sent Json at position '{jsonPosition}': {originalJson} ({Convert.ToBase64String(Encoding.UTF8.GetBytes(originalJson))})\n{errorMessage}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error(ex);
|
||||||
|
errorMessage = $"Fail to check json IPC error: {ex.Message}\n{errorMessage}";
|
||||||
|
}
|
||||||
|
|
||||||
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = errorMessage };
|
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = errorMessage };
|
||||||
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
|
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
|
||||||
jobRecord.ErrorCount++;
|
jobRecord.ErrorCount++;
|
||||||
@@ -975,6 +1004,21 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// raise job completed event to fail the job.
|
||||||
|
private async Task ForceFailJob(IJobServer jobServer, Pipelines.AgentJobRequestMessage message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, TaskResult.Failed);
|
||||||
|
await jobServer.RaisePlanEventAsync<JobCompletedEvent>(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, jobCompletedEvent, CancellationToken.None);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error("Fail to raise JobCompletedEvent back to service.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class WorkerDispatcher : IDisposable
|
private class WorkerDispatcher : IDisposable
|
||||||
{
|
{
|
||||||
public long RequestId { get; }
|
public long RequestId { get; }
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Listener.Configuration;
|
|
||||||
using GitHub.Services.Common;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Security.Cryptography;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
using GitHub.Services.OAuth;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Listener.Configuration;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Services.OAuth;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -33,6 +33,7 @@ namespace GitHub.Runner.Listener
|
|||||||
private IRunnerServer _runnerServer;
|
private IRunnerServer _runnerServer;
|
||||||
private TaskAgentSession _session;
|
private TaskAgentSession _session;
|
||||||
private TimeSpan _getNextMessageRetryInterval;
|
private TimeSpan _getNextMessageRetryInterval;
|
||||||
|
private bool _accessTokenRevoked = false;
|
||||||
private readonly TimeSpan _sessionCreationRetryInterval = TimeSpan.FromSeconds(30);
|
private readonly TimeSpan _sessionCreationRetryInterval = TimeSpan.FromSeconds(30);
|
||||||
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);
|
||||||
@@ -111,6 +112,7 @@ namespace GitHub.Runner.Listener
|
|||||||
catch (TaskAgentAccessTokenExpiredException)
|
catch (TaskAgentAccessTokenExpiredException)
|
||||||
{
|
{
|
||||||
Trace.Info("Runner OAuth token has been revoked. Session creation failed.");
|
Trace.Info("Runner OAuth token has been revoked. Session creation failed.");
|
||||||
|
_accessTokenRevoked = true;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -154,9 +156,16 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
if (_session != null && _session.SessionId != Guid.Empty)
|
if (_session != null && _session.SessionId != Guid.Empty)
|
||||||
{
|
{
|
||||||
using (var ts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
|
if (!_accessTokenRevoked)
|
||||||
{
|
{
|
||||||
await _runnerServer.DeleteAgentSessionAsync(_settings.PoolId, _session.SessionId, ts.Token);
|
using (var ts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
|
||||||
|
{
|
||||||
|
await _runnerServer.DeleteAgentSessionAsync(_settings.PoolId, _session.SessionId, ts.Token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Trace.Warning("Runner OAuth token has been revoked. Skip deleting session.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,6 +214,7 @@ namespace GitHub.Runner.Listener
|
|||||||
catch (TaskAgentAccessTokenExpiredException)
|
catch (TaskAgentAccessTokenExpiredException)
|
||||||
{
|
{
|
||||||
Trace.Info("Runner OAuth token has been revoked. Unable to pull message.");
|
Trace.Info("Runner OAuth token has been revoked. Unable to pull message.");
|
||||||
|
_accessTokenRevoked = true;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -26,6 +25,12 @@
|
|||||||
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
|
<PackageReference Include="System.ServiceProcess.ServiceController" Version="4.4.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Include="..\Misc\runnercoreassets">
|
||||||
|
<LogicalName>GitHub.Runner.Listener.runnercoreassets</LogicalName>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||||
<DebugType>portable</DebugType>
|
<DebugType>portable</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using GitHub.Runner.Common;
|
|||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GitHub.Runner.Listener.Check;
|
using GitHub.Runner.Listener.Check;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener
|
namespace GitHub.Runner.Listener
|
||||||
{
|
{
|
||||||
@@ -214,7 +215,7 @@ namespace GitHub.Runner.Listener
|
|||||||
var startupTypeAsString = command.GetStartupType();
|
var startupTypeAsString = command.GetStartupType();
|
||||||
if (string.IsNullOrEmpty(startupTypeAsString) && configuredAsService)
|
if (string.IsNullOrEmpty(startupTypeAsString) && configuredAsService)
|
||||||
{
|
{
|
||||||
// We need try our best to make the startup type accurate
|
// We need try our best to make the startup type accurate
|
||||||
// The problem is coming from runner autoupgrade, which result an old version service host binary but a newer version runner binary
|
// The problem is coming from runner autoupgrade, which result an old version service host binary but a newer version runner binary
|
||||||
// At that time the servicehost won't pass --startuptype to Runner.Listener while the runner is actually running as service.
|
// At that time the servicehost won't pass --startuptype to Runner.Listener while the runner is actually running as service.
|
||||||
// We will guess the startup type only when the runner is configured as service and the guess will based on whether STDOUT/STDERR/STDIN been redirect or not
|
// We will guess the startup type only when the runner is configured as service and the guess will based on whether STDOUT/STDERR/STDIN been redirect or not
|
||||||
@@ -233,8 +234,14 @@ namespace GitHub.Runner.Listener
|
|||||||
Trace.Info($"Set runner startup type - {startType}");
|
Trace.Info($"Set runner startup type - {startType}");
|
||||||
HostContext.StartupType = startType;
|
HostContext.StartupType = startType;
|
||||||
|
|
||||||
|
if (command.RunOnce)
|
||||||
|
{
|
||||||
|
_term.WriteLine("Warning: '--once' is going to be deprecated in the future, please consider using '--ephemeral' during runner registration.", ConsoleColor.Yellow);
|
||||||
|
_term.WriteLine("https://docs.github.com/en/actions/hosting-your-own-runners/autoscaling-with-self-hosted-runners#using-ephemeral-runners-for-autoscaling", ConsoleColor.Yellow);
|
||||||
|
}
|
||||||
|
|
||||||
// Run the runner interactively or as service
|
// Run the runner interactively or as service
|
||||||
return await RunAsync(settings, command.RunOnce);
|
return await RunAsync(settings, command.RunOnce || settings.Ephemeral);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -306,10 +313,15 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
HostContext.WritePerfCounter("SessionCreated");
|
HostContext.WritePerfCounter("SessionCreated");
|
||||||
|
|
||||||
|
_term.WriteLine($"Current runner version: '{BuildConstants.RunnerPackage.Version}'");
|
||||||
_term.WriteLine($"{DateTime.UtcNow:u}: Listening for Jobs");
|
_term.WriteLine($"{DateTime.UtcNow:u}: Listening for Jobs");
|
||||||
|
|
||||||
IJobDispatcher jobDispatcher = null;
|
IJobDispatcher jobDispatcher = null;
|
||||||
CancellationTokenSource messageQueueLoopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(HostContext.RunnerShutdownToken);
|
CancellationTokenSource messageQueueLoopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(HostContext.RunnerShutdownToken);
|
||||||
|
|
||||||
|
// Should we try to cleanup ephemeral runners
|
||||||
|
bool runOnceJobCompleted = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var notification = HostContext.GetService<IJobNotification>();
|
var notification = HostContext.GetService<IJobNotification>();
|
||||||
@@ -371,6 +383,7 @@ namespace GitHub.Runner.Listener
|
|||||||
Task completeTask = await Task.WhenAny(getNextMessage, jobDispatcher.RunOnceJobCompleted.Task);
|
Task completeTask = await Task.WhenAny(getNextMessage, jobDispatcher.RunOnceJobCompleted.Task);
|
||||||
if (completeTask == jobDispatcher.RunOnceJobCompleted.Task)
|
if (completeTask == jobDispatcher.RunOnceJobCompleted.Task)
|
||||||
{
|
{
|
||||||
|
runOnceJobCompleted = true;
|
||||||
Trace.Info("Job has finished at backend, the runner will exit since it is running under onetime use mode.");
|
Trace.Info("Job has finished at backend, the runner will exit since it is running under onetime use mode.");
|
||||||
Trace.Info("Stop message queue looping.");
|
Trace.Info("Stop message queue looping.");
|
||||||
messageQueueLoopTokenSource.Cancel();
|
messageQueueLoopTokenSource.Cancel();
|
||||||
@@ -395,6 +408,27 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
autoUpdateInProgress = true;
|
autoUpdateInProgress = true;
|
||||||
var runnerUpdateMessage = JsonUtility.FromString<AgentRefreshMessage>(message.Body);
|
var runnerUpdateMessage = JsonUtility.FromString<AgentRefreshMessage>(message.Body);
|
||||||
|
#if DEBUG
|
||||||
|
// Can mock the update for testing
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_IS_MOCK_UPDATE")))
|
||||||
|
{
|
||||||
|
|
||||||
|
// The mock_update_messages.json file should be an object with keys being the current version and values being the targeted mock version object
|
||||||
|
// Example: { "2.283.2": {"targetVersion":"2.284.1"}, "2.284.1": {"targetVersion":"2.285.0"}}
|
||||||
|
var mockUpdatesPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), "mock_update_messages.json");
|
||||||
|
if (File.Exists(mockUpdatesPath))
|
||||||
|
{
|
||||||
|
var mockUpdateMessages = JsonUtility.FromString<Dictionary<string, AgentRefreshMessage>>(File.ReadAllText(mockUpdatesPath));
|
||||||
|
if (mockUpdateMessages.ContainsKey(BuildConstants.RunnerPackage.Version))
|
||||||
|
{
|
||||||
|
var mockTargetVersion = mockUpdateMessages[BuildConstants.RunnerPackage.Version].TargetVersion;
|
||||||
|
_term.WriteLine($"Mocking update, using version {mockTargetVersion} instead of {runnerUpdateMessage.TargetVersion}");
|
||||||
|
Trace.Info($"Mocking update, using version {mockTargetVersion} instead of {runnerUpdateMessage.TargetVersion}");
|
||||||
|
runnerUpdateMessage = new AgentRefreshMessage(runnerUpdateMessage.AgentId, mockTargetVersion, runnerUpdateMessage.Timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
var selfUpdater = HostContext.GetService<ISelfUpdater>();
|
var selfUpdater = HostContext.GetService<ISelfUpdater>();
|
||||||
selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, !runOnce && HostContext.StartupType != StartupType.Service, HostContext.RunnerShutdownToken);
|
selfUpdateTask = selfUpdater.SelfUpdate(runnerUpdateMessage, jobDispatcher, !runOnce && HostContext.StartupType != StartupType.Service, HostContext.RunnerShutdownToken);
|
||||||
Trace.Info("Refresh message received, kick-off selfupdate background process.");
|
Trace.Info("Refresh message received, kick-off selfupdate background process.");
|
||||||
@@ -413,6 +447,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
Trace.Info($"Received job message of length {message.Body.Length} from service, with hash '{IOUtil.GetSha256Hash(message.Body)}'");
|
||||||
var jobMessage = StringUtil.ConvertFromJson<Pipelines.AgentJobRequestMessage>(message.Body);
|
var jobMessage = StringUtil.ConvertFromJson<Pipelines.AgentJobRequestMessage>(message.Body);
|
||||||
jobDispatcher.Run(jobMessage, runOnce);
|
jobDispatcher.Run(jobMessage, runOnce);
|
||||||
if (runOnce)
|
if (runOnce)
|
||||||
@@ -466,10 +501,24 @@ namespace GitHub.Runner.Listener
|
|||||||
await jobDispatcher.ShutdownAsync();
|
await jobDispatcher.ShutdownAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: make sure we don't mask more important exception
|
try
|
||||||
await _listener.DeleteSessionAsync();
|
{
|
||||||
|
await _listener.DeleteSessionAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (runOnce)
|
||||||
|
{
|
||||||
|
// 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();
|
||||||
|
|
||||||
|
if (settings.Ephemeral && runOnceJobCompleted)
|
||||||
|
{
|
||||||
|
var configManager = HostContext.GetService<IConfigurationManager>();
|
||||||
|
configManager.DeleteLocalRunnerConfig();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (TaskAgentAccessTokenExpiredException)
|
catch (TaskAgentAccessTokenExpiredException)
|
||||||
@@ -512,13 +561,16 @@ 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 used for checking network connectivity when executing `.{separator}run.{ext} --check`
|
||||||
|
--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)");
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
_term.WriteLine($@" --runasservice Run the runner as a service");
|
_term.WriteLine($@" --runasservice Run the runner as a service");
|
||||||
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");
|
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");
|
||||||
_term.WriteLine($@" --windowslogonpassword string Password for the service account. Requires runasservice");
|
_term.WriteLine($@" --windowslogonpassword string Password for the service account. Requires runasservice");
|
||||||
#endif
|
#endif
|
||||||
_term.WriteLine($@"
|
_term.WriteLine($@"
|
||||||
Examples:
|
Examples:
|
||||||
Check GitHub server network connectivity:
|
Check GitHub server network connectivity:
|
||||||
.{separator}run.{ext} --check --url <url> --pat <pat>
|
.{separator}run.{ext} --check --url <url> --pat <pat>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,15 +1,14 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<PredefinedCulturesOnly>false</PredefinedCulturesOnly>
|
||||||
<PublishReadyToRun>true</PublishReadyToRun>
|
<PublishReadyToRunComposite>true</PublishReadyToRunComposite>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ namespace GitHub.Runner.Plugins.Artifact
|
|||||||
{
|
{
|
||||||
// We should never
|
// We should never
|
||||||
context.Error($"Error '{ex.Message}' when downloading file '{fileToDownload}'. (Downloader {downloaderId})");
|
context.Error($"Error '{ex.Message}' when downloading file '{fileToDownload}'. (Downloader {downloaderId})");
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -469,7 +469,7 @@ namespace GitHub.Runner.Plugins.Artifact
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
uploadTimer.Restart();
|
uploadTimer.Restart();
|
||||||
using (HttpResponseMessage response = await _fileContainerHttpClient.UploadFileAsync(_containerId, itemPath, fs, _projectId, cancellationToken: token, chunkSize: 4 * 1024 * 1024))
|
using (HttpResponseMessage response = await _fileContainerHttpClient.UploadFileAsync(_containerId, itemPath, fs, _projectId, cancellationToken: token))
|
||||||
{
|
{
|
||||||
if (response == null || response.StatusCode != HttpStatusCode.Created)
|
if (response == null || response.StatusCode != HttpStatusCode.Created)
|
||||||
{
|
{
|
||||||
@@ -528,7 +528,7 @@ namespace GitHub.Runner.Plugins.Artifact
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
context.Output($"File error '{ex.Message}' when uploading file '{fileToUpload}'.");
|
context.Output($"File error '{ex.Message}' when uploading file '{fileToUpload}'.");
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ namespace GitHub.Runner.Plugins.Repository.v1_0
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// delete the index.lock file left by previous canceled build or any operation cause git.exe crash last time.
|
// delete the index.lock file left by previous cancelled build or any operation cause git.exe crash last time.
|
||||||
string lockFile = Path.Combine(targetPath, ".git\\index.lock");
|
string lockFile = Path.Combine(targetPath, ".git\\index.lock");
|
||||||
if (File.Exists(lockFile))
|
if (File.Exists(lockFile))
|
||||||
{
|
{
|
||||||
@@ -181,7 +181,7 @@ namespace GitHub.Runner.Plugins.Repository.v1_0
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the shallow.lock file left by previous canceled build or any operation cause git.exe crash last time.
|
// delete the shallow.lock file left by previous cancelled build or any operation cause git.exe crash last time.
|
||||||
string shallowLockFile = Path.Combine(targetPath, ".git\\shallow.lock");
|
string shallowLockFile = Path.Combine(targetPath, ".git\\shallow.lock");
|
||||||
if (File.Exists(shallowLockFile))
|
if (File.Exists(shallowLockFile))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ namespace GitHub.Runner.Plugins.Repository.v1_1
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// delete the index.lock file left by previous canceled build or any operation cause git.exe crash last time.
|
// delete the index.lock file left by previous cancelled build or any operation cause git.exe crash last time.
|
||||||
string lockFile = Path.Combine(targetPath, ".git\\index.lock");
|
string lockFile = Path.Combine(targetPath, ".git\\index.lock");
|
||||||
if (File.Exists(lockFile))
|
if (File.Exists(lockFile))
|
||||||
{
|
{
|
||||||
@@ -165,7 +165,7 @@ namespace GitHub.Runner.Plugins.Repository.v1_1
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete the shallow.lock file left by previous canceled build or any operation cause git.exe crash last time.
|
// delete the shallow.lock file left by previous cancelled build or any operation cause git.exe crash last time.
|
||||||
string shallowLockFile = Path.Combine(targetPath, ".git\\shallow.lock");
|
string shallowLockFile = Path.Combine(targetPath, ".git\\shallow.lock");
|
||||||
if (File.Exists(shallowLockFile))
|
if (File.Exists(shallowLockFile))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new token source for the parallel query. The parallel query should be
|
// Create a new token source for the parallel query. The parallel query should be
|
||||||
// canceled after the first error is encountered. Otherwise the number of exceptions
|
// cancelled after the first error is encountered. Otherwise the number of exceptions
|
||||||
// could get out of control for a large directory with access denied on every file.
|
// could get out of control for a large directory with access denied on every file.
|
||||||
using (var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
|
using (var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ namespace GitHub.Runner.Sdk
|
|||||||
|
|
||||||
VssClientHttpRequestSettings.Default.UserAgent = headerValues;
|
VssClientHttpRequestSettings.Default.UserAgent = headerValues;
|
||||||
VssHttpMessageHandler.DefaultWebProxy = proxy;
|
VssHttpMessageHandler.DefaultWebProxy = proxy;
|
||||||
|
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_TLS_NO_VERIFY")))
|
||||||
|
{
|
||||||
|
VssClientHttpRequestSettings.Default.ServerCertificateValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static VssConnection CreateConnection(Uri serverUri, VssCredentials credentials, IEnumerable<DelegatingHandler> additionalDelegatingHandler = null, TimeSpan? timeout = null)
|
public static VssConnection CreateConnection(Uri serverUri, VssCredentials credentials, IEnumerable<DelegatingHandler> additionalDelegatingHandler = null, TimeSpan? timeout = null)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -110,11 +108,18 @@ namespace GitHub.Runner.Worker
|
|||||||
// Stop command
|
// Stop command
|
||||||
if (string.Equals(actionCommand.Command, _stopCommand, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(actionCommand.Command, _stopCommand, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
context.Output(input);
|
ValidateStopToken(context, actionCommand.Data);
|
||||||
context.Debug("Paused processing commands until '##[{actionCommand.Data}]' is received");
|
|
||||||
_stopToken = actionCommand.Data;
|
_stopToken = actionCommand.Data;
|
||||||
_stopProcessCommand = true;
|
_stopProcessCommand = true;
|
||||||
_registeredCommands.Add(_stopToken);
|
_registeredCommands.Add(_stopToken);
|
||||||
|
if (_stopToken.Length > 6)
|
||||||
|
{
|
||||||
|
HostContext.SecretMasker.AddValue(_stopToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
context.Output(input);
|
||||||
|
context.Debug("Paused processing commands until the token you called ::stopCommands:: with is received");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Found command
|
// Found command
|
||||||
@@ -148,7 +153,42 @@ namespace GitHub.Runner.Worker
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool EnhancedAnnotationsEnabled(IExecutionContext context) {
|
private void ValidateStopToken(IExecutionContext context, string stopToken)
|
||||||
|
{
|
||||||
|
#if OS_WINDOWS
|
||||||
|
var envContext = context.ExpressionValues["env"] as DictionaryContextData;
|
||||||
|
#else
|
||||||
|
var envContext = context.ExpressionValues["env"] as CaseSensitiveDictionaryContextData;
|
||||||
|
#endif
|
||||||
|
var allowUnsecureStopCommandTokens = false;
|
||||||
|
allowUnsecureStopCommandTokens = StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedStopCommandTokens));
|
||||||
|
if (!allowUnsecureStopCommandTokens && envContext.ContainsKey(Constants.Variables.Actions.AllowUnsupportedStopCommandTokens))
|
||||||
|
{
|
||||||
|
allowUnsecureStopCommandTokens = StringUtil.ConvertToBoolean(envContext[Constants.Variables.Actions.AllowUnsupportedStopCommandTokens].ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTokenInvalid = _registeredCommands.Contains(stopToken)
|
||||||
|
|| string.IsNullOrEmpty(stopToken)
|
||||||
|
|| string.Equals(stopToken, "pause-logging", StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
if (isTokenInvalid)
|
||||||
|
{
|
||||||
|
var telemetry = new JobTelemetry
|
||||||
|
{
|
||||||
|
Message = $"Invoked ::stopCommand:: with token: [{stopToken}]",
|
||||||
|
Type = JobTelemetryType.ActionCommand
|
||||||
|
};
|
||||||
|
context.Global.JobTelemetry.Add(telemetry);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTokenInvalid && !allowUnsecureStopCommandTokens)
|
||||||
|
{
|
||||||
|
throw new Exception(Constants.Runner.UnsupportedStopCommandTokenDisabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static bool EnhancedAnnotationsEnabled(IExecutionContext context)
|
||||||
|
{
|
||||||
return context.Global.Variables.GetBoolean("DistributedTask.EnhancedAnnotations") ?? false;
|
return context.Global.Variables.GetBoolean("DistributedTask.EnhancedAnnotations") ?? false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,7 +292,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public const String Name = "name";
|
public const String Name = "name";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] _setEnvBlockList =
|
private string[] _setEnvBlockList =
|
||||||
{
|
{
|
||||||
"NODE_OPTIONS"
|
"NODE_OPTIONS"
|
||||||
};
|
};
|
||||||
@@ -295,8 +335,21 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
throw new Exception("Required field 'name' is missing in ##[save-state] command.");
|
throw new Exception("Required field 'name' is missing in ##[save-state] command.");
|
||||||
}
|
}
|
||||||
|
// Embedded steps (composite) keep track of the state at the root level
|
||||||
context.IntraActionState[stateName] = command.Data;
|
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][stateName] = command.Data;
|
||||||
|
}
|
||||||
|
// Otherwise modify the ExecutionContext
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.IntraActionState[stateName] = command.Data;
|
||||||
|
}
|
||||||
context.Debug($"Save intra-action state {stateName} = {command.Data}");
|
context.Debug($"Save intra-action state {stateName} = {command.Data}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -328,6 +381,13 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
HostContext.SecretMasker.AddValue(command.Data);
|
HostContext.SecretMasker.AddValue(command.Data);
|
||||||
Trace.Info($"Add new secret mask with length of {command.Data.Length}");
|
Trace.Info($"Add new secret mask with length of {command.Data.Length}");
|
||||||
|
|
||||||
|
// Also add each individual line. Typically individual lines are processed from STDOUT of child processes.
|
||||||
|
var split = command.Data.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
foreach (var item in split)
|
||||||
|
{
|
||||||
|
HostContext.SecretMasker.AddValue(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -340,7 +400,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
var allowUnsecureCommands = false;
|
var allowUnsecureCommands = false;
|
||||||
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
||||||
|
|
||||||
@@ -529,11 +589,11 @@ namespace GitHub.Runner.Worker
|
|||||||
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);
|
||||||
|
|
||||||
if (!ActionCommandManager.EnhancedAnnotationsEnabled(context))
|
if (!ActionCommandManager.EnhancedAnnotationsEnabled(context))
|
||||||
{
|
{
|
||||||
context.Debug("Enhanced Annotations not enabled on the server. The 'title', 'end_line', and 'end_column' fields are unsupported.");
|
context.Debug("Enhanced Annotations not enabled on the server. The 'title', 'end_line', and 'end_column' fields are unsupported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Issue issue = new Issue()
|
Issue issue = new Issue()
|
||||||
{
|
{
|
||||||
Category = "General",
|
Category = "General",
|
||||||
@@ -585,7 +645,7 @@ namespace GitHub.Runner.Worker
|
|||||||
context.AddIssue(issue);
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ValidateLinesAndColumns(ActionCommand command, IExecutionContext context)
|
public static void ValidateLinesAndColumns(ActionCommand command, IExecutionContext context)
|
||||||
{
|
{
|
||||||
command.Properties.TryGetValue(IssueCommandProperties.Line, out string line);
|
command.Properties.TryGetValue(IssueCommandProperties.Line, out string line);
|
||||||
command.Properties.TryGetValue(IssueCommandProperties.EndLine, out string endLine);
|
command.Properties.TryGetValue(IssueCommandProperties.EndLine, out string endLine);
|
||||||
@@ -614,28 +674,28 @@ namespace GitHub.Runner.Worker
|
|||||||
column = endColumn;
|
column = endColumn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasStartLine && hasColumn)
|
if (!hasStartLine && hasColumn)
|
||||||
{
|
{
|
||||||
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.Column}' and '{IssueCommandProperties.EndColumn}' can only be set if '{IssueCommandProperties.Line}' value is provided.");
|
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.Column}' and '{IssueCommandProperties.EndColumn}' can only be set if '{IssueCommandProperties.Line}' value is provided.");
|
||||||
command.Properties.Remove(IssueCommandProperties.Column);
|
command.Properties.Remove(IssueCommandProperties.Column);
|
||||||
command.Properties.Remove(IssueCommandProperties.EndColumn);
|
command.Properties.Remove(IssueCommandProperties.EndColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasEndLine && line != endLine && hasColumn)
|
if (hasEndLine && line != endLine && hasColumn)
|
||||||
{
|
{
|
||||||
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.Column}' and '{IssueCommandProperties.EndColumn}' cannot be set if '{IssueCommandProperties.Line}' and '{IssueCommandProperties.EndLine}' are different values.");
|
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.Column}' and '{IssueCommandProperties.EndColumn}' cannot be set if '{IssueCommandProperties.Line}' and '{IssueCommandProperties.EndLine}' are different values.");
|
||||||
command.Properties.Remove(IssueCommandProperties.Column);
|
command.Properties.Remove(IssueCommandProperties.Column);
|
||||||
command.Properties.Remove(IssueCommandProperties.EndColumn);
|
command.Properties.Remove(IssueCommandProperties.EndColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasStartLine && hasEndLine && endLineNumber < lineNumber)
|
if (hasStartLine && hasEndLine && endLineNumber < lineNumber)
|
||||||
{
|
{
|
||||||
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.EndLine}' cannot be less than '{IssueCommandProperties.Line}'.");
|
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.EndLine}' cannot be less than '{IssueCommandProperties.Line}'.");
|
||||||
command.Properties.Remove(IssueCommandProperties.Line);
|
command.Properties.Remove(IssueCommandProperties.Line);
|
||||||
command.Properties.Remove(IssueCommandProperties.EndLine);
|
command.Properties.Remove(IssueCommandProperties.EndLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasStartColumn && hasEndColumn && endColumnNumber < columnNumber)
|
if (hasStartColumn && hasEndColumn && endColumnNumber < columnNumber)
|
||||||
{
|
{
|
||||||
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.EndColumn}' cannot be less than '{IssueCommandProperties.Column}'.");
|
context.Debug($"Invalid {command.Command} command value. '{IssueCommandProperties.EndColumn}' cannot be less than '{IssueCommandProperties.Column}'.");
|
||||||
command.Properties.Remove(IssueCommandProperties.Column);
|
command.Properties.Remove(IssueCommandProperties.Column);
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ namespace GitHub.Runner.Worker
|
|||||||
public interface IActionManager : IRunnerService
|
public interface IActionManager : IRunnerService
|
||||||
{
|
{
|
||||||
Dictionary<Guid, ContainerInfo> CachedActionContainers { get; }
|
Dictionary<Guid, ContainerInfo> CachedActionContainers { get; }
|
||||||
Task<PrepareResult> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps);
|
Dictionary<Guid, List<Pipelines.ActionStep>> CachedEmbeddedPreSteps { get; }
|
||||||
|
Dictionary<Guid, List<Guid>> CachedEmbeddedStepIds { get; }
|
||||||
|
Dictionary<Guid, Stack<Pipelines.ActionStep>> CachedEmbeddedPostSteps { get; }
|
||||||
|
Task<PrepareResult> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps, Guid rootStepId = default(Guid));
|
||||||
Definition LoadAction(IExecutionContext executionContext, Pipelines.ActionStep action);
|
Definition LoadAction(IExecutionContext executionContext, Pipelines.ActionStep action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,10 +51,20 @@ namespace GitHub.Runner.Worker
|
|||||||
//81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k).
|
//81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k).
|
||||||
private const int _defaultCopyBufferSize = 81920;
|
private const int _defaultCopyBufferSize = 81920;
|
||||||
private const string _dotcomApiUrl = "https://api.github.com";
|
private const string _dotcomApiUrl = "https://api.github.com";
|
||||||
private readonly Dictionary<Guid, ContainerInfo> _cachedActionContainers = new Dictionary<Guid, ContainerInfo>();
|
|
||||||
|
|
||||||
|
private readonly Dictionary<Guid, ContainerInfo> _cachedActionContainers = new Dictionary<Guid, ContainerInfo>();
|
||||||
public Dictionary<Guid, ContainerInfo> CachedActionContainers => _cachedActionContainers;
|
public Dictionary<Guid, ContainerInfo> CachedActionContainers => _cachedActionContainers;
|
||||||
public async Task<PrepareResult> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps)
|
|
||||||
|
private readonly Dictionary<Guid, List<Pipelines.ActionStep>> _cachedEmbeddedPreSteps = new Dictionary<Guid, List<Pipelines.ActionStep>>();
|
||||||
|
public Dictionary<Guid, List<Pipelines.ActionStep>> CachedEmbeddedPreSteps => _cachedEmbeddedPreSteps;
|
||||||
|
|
||||||
|
private readonly Dictionary<Guid, List<Guid>> _cachedEmbeddedStepIds = new Dictionary<Guid, List<Guid>>();
|
||||||
|
public Dictionary<Guid, List<Guid>> CachedEmbeddedStepIds => _cachedEmbeddedStepIds;
|
||||||
|
|
||||||
|
private readonly Dictionary<Guid, Stack<Pipelines.ActionStep>> _cachedEmbeddedPostSteps = new Dictionary<Guid, Stack<Pipelines.ActionStep>>();
|
||||||
|
public Dictionary<Guid, Stack<Pipelines.ActionStep>> CachedEmbeddedPostSteps => _cachedEmbeddedPostSteps;
|
||||||
|
|
||||||
|
public async Task<PrepareResult> PrepareActionsAsync(IExecutionContext executionContext, IEnumerable<Pipelines.JobStep> steps, Guid rootStepId = default(Guid))
|
||||||
{
|
{
|
||||||
// Assert inputs
|
// Assert inputs
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
@@ -64,10 +77,30 @@ namespace GitHub.Runner.Worker
|
|||||||
PreStepTracker = new Dictionary<Guid, IActionRunner>()
|
PreStepTracker = new Dictionary<Guid, IActionRunner>()
|
||||||
};
|
};
|
||||||
var containerSetupSteps = new List<JobExtensionRunner>();
|
var containerSetupSteps = new List<JobExtensionRunner>();
|
||||||
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
var depth = 0;
|
||||||
|
// We are running at the start of a job
|
||||||
|
if (rootStepId == default(Guid))
|
||||||
|
{
|
||||||
|
IOUtil.DeleteDirectory(HostContext.GetDirectory(WellKnownDirectory.Actions), executionContext.CancellationToken);
|
||||||
|
}
|
||||||
|
// We are running mid job due to a local composite action
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_cachedEmbeddedStepIds.ContainsKey(rootStepId))
|
||||||
|
{
|
||||||
|
_cachedEmbeddedStepIds[rootStepId] = new List<Guid>();
|
||||||
|
foreach (var compositeStep in steps)
|
||||||
|
{
|
||||||
|
var guid = Guid.NewGuid();
|
||||||
|
compositeStep.Id = guid;
|
||||||
|
_cachedEmbeddedStepIds[rootStepId].Add(guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
depth = 1;
|
||||||
|
}
|
||||||
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, 0);
|
var result = await PrepareActionsRecursiveAsync(executionContext, state, actions, depth, rootStepId);
|
||||||
if (state.ImagesToPull.Count > 0)
|
if (state.ImagesToPull.Count > 0)
|
||||||
{
|
{
|
||||||
foreach (var imageToPull in result.ImagesToPull)
|
foreach (var imageToPull in result.ImagesToPull)
|
||||||
@@ -103,7 +136,7 @@ namespace GitHub.Runner.Worker
|
|||||||
return new PrepareResult(containerSetupSteps, result.PreStepTracker);
|
return new PrepareResult(containerSetupSteps, result.PreStepTracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<PrepareActionsState> PrepareActionsRecursiveAsync(IExecutionContext executionContext, PrepareActionsState state, IEnumerable<Pipelines.ActionStep> actions, Int32 depth = 0)
|
private async Task<PrepareActionsState> PrepareActionsRecursiveAsync(IExecutionContext executionContext, PrepareActionsState state, IEnumerable<Pipelines.ActionStep> actions, Int32 depth = 0, Guid parentStepId = default(Guid))
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
if (depth > Constants.CompositeActionsMaxDepth)
|
if (depth > Constants.CompositeActionsMaxDepth)
|
||||||
@@ -187,25 +220,65 @@ namespace GitHub.Runner.Worker
|
|||||||
state.ImagesToBuildInfo[setupInfo.Container.ActionRepository] = setupInfo.Container;
|
state.ImagesToBuildInfo[setupInfo.Container.ActionRepository] = setupInfo.Container;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(setupInfo != null && setupInfo.Steps != null && setupInfo.Steps.Count > 0)
|
else if (setupInfo != null && setupInfo.Steps != null && setupInfo.Steps.Count > 0)
|
||||||
{
|
{
|
||||||
state = await PrepareActionsRecursiveAsync(executionContext, state, setupInfo.Steps, depth + 1);
|
state = await PrepareActionsRecursiveAsync(executionContext, state, setupInfo.Steps, depth + 1, action.Id);
|
||||||
}
|
}
|
||||||
var repoAction = action.Reference as Pipelines.RepositoryPathReference;
|
var repoAction = action.Reference as Pipelines.RepositoryPathReference;
|
||||||
if (repoAction.RepositoryType != Pipelines.PipelineConstants.SelfAlias)
|
if (repoAction.RepositoryType != Pipelines.PipelineConstants.SelfAlias)
|
||||||
{
|
{
|
||||||
var definition = LoadAction(executionContext, action);
|
var definition = LoadAction(executionContext, action);
|
||||||
// TODO: Support pre's in composite actions
|
if (definition.Data.Execution.HasPre)
|
||||||
if (definition.Data.Execution.HasPre && depth < 1)
|
|
||||||
{
|
{
|
||||||
var actionRunner = HostContext.CreateService<IActionRunner>();
|
|
||||||
actionRunner.Action = action;
|
|
||||||
actionRunner.Stage = ActionRunStage.Pre;
|
|
||||||
actionRunner.Condition = definition.Data.Execution.InitCondition;
|
|
||||||
|
|
||||||
Trace.Info($"Add 'pre' execution for {action.Id}");
|
Trace.Info($"Add 'pre' execution for {action.Id}");
|
||||||
state.PreStepTracker[action.Id] = actionRunner;
|
// Root Step
|
||||||
|
if (depth < 1)
|
||||||
|
{
|
||||||
|
var actionRunner = HostContext.CreateService<IActionRunner>();
|
||||||
|
actionRunner.Action = action;
|
||||||
|
actionRunner.Stage = ActionRunStage.Pre;
|
||||||
|
actionRunner.Condition = definition.Data.Execution.InitCondition;
|
||||||
|
state.PreStepTracker[action.Id] = actionRunner;
|
||||||
|
}
|
||||||
|
// Embedded Step
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!_cachedEmbeddedPreSteps.ContainsKey(parentStepId))
|
||||||
|
{
|
||||||
|
_cachedEmbeddedPreSteps[parentStepId] = new List<Pipelines.ActionStep>();
|
||||||
|
}
|
||||||
|
// Clone action so we can modify the condition without affecting the original
|
||||||
|
var clonedAction = action.Clone() as Pipelines.ActionStep;
|
||||||
|
clonedAction.Condition = definition.Data.Execution.InitCondition;
|
||||||
|
_cachedEmbeddedPreSteps[parentStepId].Add(clonedAction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (definition.Data.Execution.HasPost && depth > 0)
|
||||||
|
{
|
||||||
|
if (!_cachedEmbeddedPostSteps.ContainsKey(parentStepId))
|
||||||
|
{
|
||||||
|
// If we haven't done so already, add the parent to the post steps
|
||||||
|
_cachedEmbeddedPostSteps[parentStepId] = new Stack<Pipelines.ActionStep>();
|
||||||
|
}
|
||||||
|
// Clone action so we can modify the condition without affecting the original
|
||||||
|
var clonedAction = action.Clone() as Pipelines.ActionStep;
|
||||||
|
clonedAction.Condition = definition.Data.Execution.CleanupCondition;
|
||||||
|
_cachedEmbeddedPostSteps[parentStepId].Push(clonedAction);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (depth > 0)
|
||||||
|
{
|
||||||
|
// if we're in a composite action and haven't loaded the local action yet
|
||||||
|
// we assume it has a post step
|
||||||
|
if (!_cachedEmbeddedPostSteps.ContainsKey(parentStepId))
|
||||||
|
{
|
||||||
|
// If we haven't done so already, add the parent to the post steps
|
||||||
|
_cachedEmbeddedPostSteps[parentStepId] = new Stack<Pipelines.ActionStep>();
|
||||||
|
}
|
||||||
|
// Clone action so we can modify the condition without affecting the original
|
||||||
|
var clonedAction = action.Clone() as Pipelines.ActionStep;
|
||||||
|
_cachedEmbeddedPostSteps[parentStepId].Push(clonedAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,6 +428,39 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Verbose($"Details: {StringUtil.ConvertToJson(compositeAction?.Steps)}");
|
Trace.Verbose($"Details: {StringUtil.ConvertToJson(compositeAction?.Steps)}");
|
||||||
Trace.Info($"Load: {compositeAction.Outputs?.Count ?? 0} number of outputs");
|
Trace.Info($"Load: {compositeAction.Outputs?.Count ?? 0} number of outputs");
|
||||||
Trace.Info($"Details: {StringUtil.ConvertToJson(compositeAction?.Outputs)}");
|
Trace.Info($"Details: {StringUtil.ConvertToJson(compositeAction?.Outputs)}");
|
||||||
|
|
||||||
|
if (CachedEmbeddedPreSteps.TryGetValue(action.Id, out var preSteps))
|
||||||
|
{
|
||||||
|
compositeAction.PreSteps = preSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CachedEmbeddedPostSteps.TryGetValue(action.Id, out var postSteps))
|
||||||
|
{
|
||||||
|
compositeAction.PostSteps = postSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cachedEmbeddedStepIds.ContainsKey(action.Id))
|
||||||
|
{
|
||||||
|
for (var i = 0; i < compositeAction.Steps.Count; i++)
|
||||||
|
{
|
||||||
|
// Load stored Ids for later load actions
|
||||||
|
compositeAction.Steps[i].Id = _cachedEmbeddedStepIds[action.Id][i];
|
||||||
|
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && compositeAction.Steps[i].Reference.Type != Pipelines.ActionSourceType.Script)
|
||||||
|
{
|
||||||
|
throw new Exception("`uses:` keyword is not currently supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_cachedEmbeddedStepIds[action.Id] = new List<Guid>();
|
||||||
|
foreach (var compositeStep in compositeAction.Steps)
|
||||||
|
{
|
||||||
|
var guid = Guid.NewGuid();
|
||||||
|
compositeStep.Id = guid;
|
||||||
|
_cachedEmbeddedStepIds[action.Id].Add(guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -527,6 +633,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
NameWithOwner = repositoryReference.Name,
|
NameWithOwner = repositoryReference.Name,
|
||||||
Ref = repositoryReference.Ref,
|
Ref = repositoryReference.Ref,
|
||||||
|
Path = repositoryReference.Path,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
@@ -544,12 +651,17 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
actionDownloadInfos = await jobServer.ResolveActionDownloadInfoAsync(executionContext.Global.Plan.ScopeIdentifier, executionContext.Global.Plan.PlanType, executionContext.Global.Plan.PlanId, new WebApi.ActionReferenceList { Actions = actionReferences }, executionContext.CancellationToken);
|
actionDownloadInfos = await jobServer.ResolveActionDownloadInfoAsync(executionContext.Global.Plan.ScopeIdentifier, executionContext.Global.Plan.PlanType, executionContext.Global.Plan.PlanId, executionContext.Root.Id, new WebApi.ActionReferenceList { Actions = actionReferences }, executionContext.CancellationToken);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (!executionContext.CancellationToken.IsCancellationRequested) // Do not retry if the run is canceled.
|
catch (Exception ex) when (!executionContext.CancellationToken.IsCancellationRequested) // Do not retry if the run is cancelled.
|
||||||
{
|
{
|
||||||
if (attempt < 3)
|
// UnresolvableActionDownloadInfoException is a 422 client error, don't retry
|
||||||
|
// Some possible cases are:
|
||||||
|
// * Repo is rate limited
|
||||||
|
// * Repo or tag doesn't exist, or isn't public
|
||||||
|
// * Policy validation failed
|
||||||
|
if (attempt < 3 && !(ex is WebApi.UnresolvableActionDownloadInfoException))
|
||||||
{
|
{
|
||||||
executionContext.Output($"Failed to resolve action download info. Error: {ex.Message}");
|
executionContext.Output($"Failed to resolve action download info. Error: {ex.Message}");
|
||||||
executionContext.Debug(ex.ToString());
|
executionContext.Debug(ex.ToString());
|
||||||
@@ -565,6 +677,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// Some possible cases are:
|
// Some possible cases are:
|
||||||
// * Repo is rate limited
|
// * Repo is rate limited
|
||||||
// * Repo or tag doesn't exist, or isn't public
|
// * Repo or tag doesn't exist, or isn't public
|
||||||
|
// * Policy validation failed
|
||||||
if (ex is WebApi.UnresolvableActionDownloadInfoException)
|
if (ex is WebApi.UnresolvableActionDownloadInfoException)
|
||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
@@ -620,7 +733,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// make sure we get a clean folder ready to use.
|
// make sure we get a clean folder ready to use.
|
||||||
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
|
IOUtil.DeleteDirectory(destDirectory, executionContext.CancellationToken);
|
||||||
Directory.CreateDirectory(destDirectory);
|
Directory.CreateDirectory(destDirectory);
|
||||||
executionContext.Output($"Download action repository '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}'");
|
executionContext.Output($"Download action repository '{downloadInfo.NameWithOwner}@{downloadInfo.Ref}' (SHA:{downloadInfo.ResolvedSha})");
|
||||||
}
|
}
|
||||||
|
|
||||||
await DownloadRepositoryActionAsync(executionContext, downloadInfo, destDirectory);
|
await DownloadRepositoryActionAsync(executionContext, downloadInfo, destDirectory);
|
||||||
@@ -928,20 +1041,29 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
else if (actionDefinitionData.Execution.ExecutionType == ActionExecutionType.Composite)
|
else if (actionDefinitionData.Execution.ExecutionType == ActionExecutionType.Composite)
|
||||||
{
|
{
|
||||||
// TODO: we need to generate unique Id's for composite steps
|
|
||||||
Trace.Info($"Loading Composite steps");
|
Trace.Info($"Loading Composite steps");
|
||||||
var compositeAction = actionDefinitionData.Execution as CompositeActionExecutionData;
|
var compositeAction = actionDefinitionData.Execution as CompositeActionExecutionData;
|
||||||
setupInfo.Steps = compositeAction.Steps;
|
setupInfo.Steps = compositeAction.Steps;
|
||||||
|
|
||||||
|
// cache steps ids if not done so already
|
||||||
|
if (!_cachedEmbeddedStepIds.ContainsKey(repositoryAction.Id))
|
||||||
|
{
|
||||||
|
_cachedEmbeddedStepIds[repositoryAction.Id] = new List<Guid>();
|
||||||
|
foreach (var compositeStep in compositeAction.Steps)
|
||||||
|
{
|
||||||
|
var guid = Guid.NewGuid();
|
||||||
|
compositeStep.Id = guid;
|
||||||
|
_cachedEmbeddedStepIds[repositoryAction.Id].Add(guid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var step in compositeAction.Steps)
|
foreach (var step in compositeAction.Steps)
|
||||||
{
|
{
|
||||||
step.Id = Guid.NewGuid();
|
|
||||||
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && step.Reference.Type != Pipelines.ActionSourceType.Script)
|
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && step.Reference.Type != Pipelines.ActionSourceType.Script)
|
||||||
{
|
{
|
||||||
throw new Exception("`uses:` keyword is not currently supported.");
|
throw new Exception("`uses:` keyword is not currently supported.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return setupInfo;
|
return setupInfo;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1077,6 +1199,8 @@ namespace GitHub.Runner.Worker
|
|||||||
public string Pre { get; set; }
|
public string Pre { get; set; }
|
||||||
|
|
||||||
public string Post { get; set; }
|
public string Post { get; set; }
|
||||||
|
|
||||||
|
public string NodeVersion { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class PluginActionExecutionData : ActionExecutionData
|
public sealed class PluginActionExecutionData : ActionExecutionData
|
||||||
@@ -1102,9 +1226,11 @@ namespace GitHub.Runner.Worker
|
|||||||
public sealed class CompositeActionExecutionData : ActionExecutionData
|
public sealed class CompositeActionExecutionData : ActionExecutionData
|
||||||
{
|
{
|
||||||
public override ActionExecutionType ExecutionType => ActionExecutionType.Composite;
|
public override ActionExecutionType ExecutionType => ActionExecutionType.Composite;
|
||||||
public override bool HasPre => false;
|
public override bool HasPre => PreSteps.Count > 0;
|
||||||
public override bool HasPost => false;
|
public override bool HasPost => PostSteps.Count > 0;
|
||||||
|
public List<Pipelines.ActionStep> PreSteps { get; set; }
|
||||||
public List<Pipelines.ActionStep> Steps { get; set; }
|
public List<Pipelines.ActionStep> Steps { get; set; }
|
||||||
|
public Stack<Pipelines.ActionStep> PostSteps { get; set; }
|
||||||
public MappingToken Outputs { get; set; }
|
public MappingToken Outputs { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1168,7 +1294,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public class ActionSetupInfo
|
public class ActionSetupInfo
|
||||||
{
|
{
|
||||||
public ActionContainer Container { get; set; }
|
public ActionContainer Container { get; set; }
|
||||||
public List<Pipelines.ActionStep> Steps {get; set;}
|
public List<Pipelines.ActionStep> Steps { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PrepareActionsState
|
public class PrepareActionsState
|
||||||
|
|||||||
@@ -451,7 +451,8 @@ namespace GitHub.Runner.Worker
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string.Equals(usingToken.Value, "node12", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(usingToken.Value, "node12", StringComparison.OrdinalIgnoreCase)||
|
||||||
|
string.Equals(usingToken.Value, "node16", StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(mainToken?.Value))
|
if (string.IsNullOrEmpty(mainToken?.Value))
|
||||||
{
|
{
|
||||||
@@ -461,6 +462,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
return new NodeJSActionExecutionData()
|
return new NodeJSActionExecutionData()
|
||||||
{
|
{
|
||||||
|
NodeVersion = usingToken.Value,
|
||||||
Script = mainToken.Value,
|
Script = mainToken.Value,
|
||||||
Pre = preToken?.Value,
|
Pre = preToken?.Value,
|
||||||
InitCondition = preIfToken?.Value ?? "always()",
|
InitCondition = preIfToken?.Value ?? "always()",
|
||||||
@@ -480,13 +482,17 @@ namespace GitHub.Runner.Worker
|
|||||||
return new CompositeActionExecutionData()
|
return new CompositeActionExecutionData()
|
||||||
{
|
{
|
||||||
Steps = steps.Cast<Pipelines.ActionStep>().ToList(),
|
Steps = steps.Cast<Pipelines.ActionStep>().ToList(),
|
||||||
|
PreSteps = new List<Pipelines.ActionStep>(),
|
||||||
|
PostSteps = new Stack<Pipelines.ActionStep>(),
|
||||||
|
InitCondition = "always()",
|
||||||
|
CleanupCondition = "always()",
|
||||||
Outputs = outputs
|
Outputs = outputs
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException($"'using: {usingToken.Value}' is not supported, use 'docker' or 'node12' instead.");
|
throw new ArgumentOutOfRangeException($"'using: {usingToken.Value}' is not supported, use 'docker', 'node12' or 'node16' instead.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pluginToken != null)
|
else if (pluginToken != null)
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
|
||||||
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;
|
||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
@@ -82,6 +81,28 @@ namespace GitHub.Runner.Worker
|
|||||||
ActionExecutionData handlerData = definition.Data?.Execution;
|
ActionExecutionData handlerData = definition.Data?.Execution;
|
||||||
ArgUtil.NotNull(handlerData, nameof(handlerData));
|
ArgUtil.NotNull(handlerData, nameof(handlerData));
|
||||||
|
|
||||||
|
List<JobExtensionRunner> localActionContainerSetupSteps = null;
|
||||||
|
// Handle Composite Local Actions
|
||||||
|
// Need to download and expand the tree of referenced actions
|
||||||
|
if (handlerData.ExecutionType == ActionExecutionType.Composite &&
|
||||||
|
handlerData is CompositeActionExecutionData compositeHandlerData &&
|
||||||
|
Stage == ActionRunStage.Main &&
|
||||||
|
Action.Reference is Pipelines.RepositoryPathReference localAction &&
|
||||||
|
string.Equals(localAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var actionManager = HostContext.GetService<IActionManager>();
|
||||||
|
var prepareResult = await actionManager.PrepareActionsAsync(ExecutionContext, compositeHandlerData.Steps, ExecutionContext.Id);
|
||||||
|
|
||||||
|
// Reload definition since post may exist now (from embedded steps that were JIT downloaded)
|
||||||
|
definition = taskManager.LoadAction(ExecutionContext, Action);
|
||||||
|
ArgUtil.NotNull(definition, nameof(definition));
|
||||||
|
handlerData = definition.Data?.Execution;
|
||||||
|
ArgUtil.NotNull(handlerData, nameof(handlerData));
|
||||||
|
|
||||||
|
// Save container setup steps so we can reference them later
|
||||||
|
localActionContainerSetupSteps = prepareResult.ContainerSetupSteps;
|
||||||
|
}
|
||||||
|
|
||||||
if (handlerData.HasPre &&
|
if (handlerData.HasPre &&
|
||||||
Action.Reference is Pipelines.RepositoryPathReference repoAction &&
|
Action.Reference is Pipelines.RepositoryPathReference repoAction &&
|
||||||
string.Equals(repoAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
string.Equals(repoAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
||||||
@@ -119,21 +140,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
IStepHost stepHost = HostContext.CreateService<IDefaultStepHost>();
|
IStepHost stepHost = HostContext.CreateService<IDefaultStepHost>();
|
||||||
|
|
||||||
// Makes directory for event_path data
|
ExecutionContext.WriteWebhookPayload();
|
||||||
var tempDirectory = HostContext.GetDirectory(WellKnownDirectory.Temp);
|
|
||||||
var workflowDirectory = Path.Combine(tempDirectory, "_github_workflow");
|
|
||||||
Directory.CreateDirectory(workflowDirectory);
|
|
||||||
|
|
||||||
var gitHubEvent = ExecutionContext.GetGitHubContext("event");
|
|
||||||
|
|
||||||
// adds the GitHub event path/file if the event exists
|
|
||||||
if (gitHubEvent != null)
|
|
||||||
{
|
|
||||||
var workflowFile = Path.Combine(workflowDirectory, "event.json");
|
|
||||||
Trace.Info($"Write event payload to {workflowFile}");
|
|
||||||
File.WriteAllText(workflowFile, gitHubEvent, new UTF8Encoding(false));
|
|
||||||
ExecutionContext.SetGitHubContext("event_path", workflowFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set GITHUB_ACTION_REPOSITORY if this Action is from a repository
|
// Set GITHUB_ACTION_REPOSITORY if this Action is from a repository
|
||||||
if (Action.Reference is Pipelines.RepositoryPathReference repoPathReferenceAction &&
|
if (Action.Reference is Pipelines.RepositoryPathReference repoPathReferenceAction &&
|
||||||
@@ -249,10 +256,11 @@ namespace GitHub.Runner.Worker
|
|||||||
inputs,
|
inputs,
|
||||||
environment,
|
environment,
|
||||||
ExecutionContext.Global.Variables,
|
ExecutionContext.Global.Variables,
|
||||||
actionDirectory: definition.Directory);
|
actionDirectory: definition.Directory,
|
||||||
|
localActionContainerSetupSteps: localActionContainerSetupSteps);
|
||||||
|
|
||||||
// Print out action details
|
// Print out action details and log telemetry
|
||||||
handler.PrintActionDetails(Stage);
|
handler.PrepareExecution(Stage);
|
||||||
|
|
||||||
// Run the task.
|
// Run the task.
|
||||||
try
|
try
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user