mirror of
https://github.com/actions/runner.git
synced 2025-12-11 04:46:58 +00:00
Compare commits
7 Commits
thboop/con
...
broker_bak
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04ece46c6a | ||
|
|
e75d502ab1 | ||
|
|
5686904fbe | ||
|
|
c278fb1736 | ||
|
|
332b8f9240 | ||
|
|
25f6cc100f | ||
|
|
6ec30ea522 |
10
.github/workflows/build.yml
vendored
10
.github/workflows/build.yml
vendored
@@ -18,7 +18,7 @@ jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64 ]
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
||||
include:
|
||||
- runtime: linux-x64
|
||||
os: ubuntu-latest
|
||||
@@ -36,17 +36,13 @@ jobs:
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: osx-arm64
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: win-x64
|
||||
os: windows-2019
|
||||
devScript: ./dev
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Build runner layout
|
||||
- name: Build & Layout Release
|
||||
@@ -82,7 +78,7 @@ jobs:
|
||||
run: |
|
||||
${{ matrix.devScript }} test
|
||||
working-directory: src
|
||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm' && matrix.runtime != 'osx-arm64'
|
||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
||||
|
||||
# Create runner package tar.gz/zip
|
||||
- name: Package Release
|
||||
|
||||
2
.github/workflows/codeql.yml
vendored
2
.github/workflows/codeql.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
|
||||
78
.github/workflows/release.yml
vendored
78
.github/workflows/release.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
if: startsWith(github.ref, 'refs/heads/releases/') || github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Make sure ./releaseVersion match ./src/runnerversion
|
||||
# Query GitHub release ensure version is not used
|
||||
@@ -51,28 +51,24 @@ jobs:
|
||||
linux-arm-sha: ${{ steps.sha.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha: ${{ steps.sha.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha: ${{ steps.sha.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha: ${{ steps.sha.outputs.osx-arm64-sha256 }}
|
||||
linux-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-x64-sha256 }}
|
||||
linux-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm64-sha256 }}
|
||||
linux-arm-sha-noexternals: ${{ steps.sha_noexternals.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha-noexternals: ${{ steps.sha_noexternals.outputs.osx-arm64-sha256 }}
|
||||
linux-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-x64-sha256 }}
|
||||
linux-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm64-sha256 }}
|
||||
linux-arm-sha-noruntime: ${{ steps.sha_noruntime.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha-noruntime: ${{ steps.sha_noruntime.outputs.osx-arm64-sha256 }}
|
||||
linux-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-x64-sha256 }}
|
||||
linux-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-arm64-sha256 }}
|
||||
linux-arm-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.linux-arm-sha256 }}
|
||||
win-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.win-x64-sha256 }}
|
||||
osx-x64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-x64-sha256 }}
|
||||
osx-arm64-sha-noruntime-noexternals: ${{ steps.sha_noruntime_noexternals.outputs.osx-arm64-sha256 }}
|
||||
strategy:
|
||||
matrix:
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64, osx-arm64 ]
|
||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
||||
include:
|
||||
- runtime: linux-x64
|
||||
os: ubuntu-latest
|
||||
@@ -89,10 +85,6 @@ jobs:
|
||||
- runtime: osx-x64
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: osx-arm64
|
||||
os: macOS-latest
|
||||
devScript: ./dev.sh
|
||||
|
||||
- runtime: win-x64
|
||||
os: windows-2019
|
||||
@@ -100,7 +92,7 @@ jobs:
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Build runner layout
|
||||
- name: Build & Layout Release
|
||||
@@ -108,6 +100,13 @@ jobs:
|
||||
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
||||
working-directory: src
|
||||
|
||||
# Run tests
|
||||
- name: L0
|
||||
run: |
|
||||
${{ matrix.devScript }} test
|
||||
working-directory: src
|
||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
||||
|
||||
# Create runner package tar.gz/zip
|
||||
- name: Package Release
|
||||
if: github.event_name != 'pull_request'
|
||||
@@ -218,7 +217,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Download runner package tar.gz/zip produced by 'build' job
|
||||
- name: Download Artifact
|
||||
@@ -240,25 +239,21 @@ jobs:
|
||||
var releaseNote = fs.readFileSync('${{ github.workspace }}/releaseNote.md', 'utf8').replace(/<RUNNER_VERSION>/g, runnerVersion)
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA>/g, '${{needs.build.outputs.win-x64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA>/g, '${{needs.build.outputs.osx-x64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA>/g, '${{needs.build.outputs.osx-arm64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA>/g, '${{needs.build.outputs.linux-x64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA>/g, '${{needs.build.outputs.linux-arm-sha}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA>/g, '${{needs.build.outputs.linux-arm64-sha}}')
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.osx-x64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.osx-arm64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-x64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm64-sha-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.win-x64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.osx-x64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA_NORUNTIME>/g, '${{needs.build.outputs.osx-arm64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-x64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-arm-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NORUNTIME>/g, '${{needs.build.outputs.linux-arm64-sha-noruntime}}')
|
||||
releaseNote = releaseNote.replace(/<WIN_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.win-x64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.osx-x64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<OSX_ARM64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.osx-arm64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_X64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-x64-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm-sha-noruntime-noexternals}}')
|
||||
releaseNote = releaseNote.replace(/<LINUX_ARM64_SHA_NORUNTIME_NOEXTERNALS>/g, '${{needs.build.outputs.linux-arm64-sha-noruntime-noexternals}}')
|
||||
@@ -272,7 +267,6 @@ jobs:
|
||||
ls -l
|
||||
echo "${{needs.build.outputs.win-x64-sha}} actions-runner-win-x64-${{ steps.releaseNote.outputs.version }}.zip" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.osx-x64-sha}} actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.osx-arm64-sha}} actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.linux-x64-sha}} actions-runner-linux-x64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.linux-arm-sha}} actions-runner-linux-arm-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
echo "${{needs.build.outputs.linux-arm64-sha}} actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz" | shasum -a 256 -c
|
||||
@@ -320,16 +314,6 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -381,16 +365,6 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package_trims/trim_externals/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -442,16 +416,6 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-noruntime)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-noruntime)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -503,16 +467,6 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-noruntime-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/_package_trims/trim_runtime_externals/actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-noruntime-noexternals.tar.gz
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-noruntime-noexternals)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
@@ -564,16 +518,6 @@ jobs:
|
||||
asset_name: actions-runner-osx-x64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (osx-arm64-trimmedpackages.json)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.createRelease.outputs.upload_url }}
|
||||
asset_path: ${{ github.workspace }}/osx-arm64-trimmedpackages.json
|
||||
asset_name: actions-runner-osx-arm64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||
asset_content_type: application/octet-stream
|
||||
|
||||
- name: Upload Release Asset (linux-arm-trimmedpackages.json)
|
||||
uses: actions/upload-release-asset@v1.0.1
|
||||
env:
|
||||
|
||||
15
.vscode/launch.json
vendored
15
.vscode/launch.json
vendored
@@ -12,7 +12,8 @@
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src",
|
||||
"console": "integratedTerminal",
|
||||
"requireExactSource": false
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
},
|
||||
{
|
||||
"name": "Run",
|
||||
@@ -24,7 +25,8 @@
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src",
|
||||
"console": "integratedTerminal",
|
||||
"requireExactSource": false
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
},
|
||||
{
|
||||
"name": "Configure",
|
||||
@@ -37,21 +39,24 @@
|
||||
],
|
||||
"cwd": "${workspaceFolder}/src",
|
||||
"console": "integratedTerminal",
|
||||
"requireExactSource": false
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
},
|
||||
{
|
||||
"name": "Debug Worker",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processName": "Runner.Worker",
|
||||
"requireExactSource": false
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
},
|
||||
{
|
||||
"name": "Attach Debugger",
|
||||
"type": "coreclr",
|
||||
"request": "attach",
|
||||
"processId": "${command:pickProcess}",
|
||||
"requireExactSource": false
|
||||
"requireExactSource": false,
|
||||
"targetArchitecture": "x86_64"
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# ADR: Notification Hooks for Runners
|
||||
|
||||
## Context
|
||||
|
||||
This ADR details the design changes for supporting custom configurable hooks for on various runner events. This has been a long requested user feature [here](https://github.com/actions/runner/issues/1543), [here](https://github.com/actions/runner/issues/699) and [here](https://github.com/actions/runner/issues/1116) for users to have more information on runner observability, and for the ability to run cleanup and teardown jobs.
|
||||
|
||||
This feature is mainly intended for self hosted runner administrators.
|
||||
|
||||
**What we hope to solve with this feature**
|
||||
1. A runner admininstrator is able to add custom scripts to cleanup their runner environment at the start or end of a job
|
||||
2. A runner admininstrator is able to add custom scripts to help setup their runner environment at the beginning of a job, for reasons like [caching](https://github.com/actions/runner/issues/1543#issuecomment-1050346279)
|
||||
3. A runner administrator is able to grab custom telemetry of jobs running on their self hosted runner
|
||||
|
||||
**What we don't think this will solve**
|
||||
- Policy features that require certain steps run at the beginning or end of all jobs
|
||||
- This would be better solved to in a central place in settings, rather then decentralized on each runner.
|
||||
- The Proposed `Notification Hooks for Runners` is limited to self hosted runners, we don't beileve Policy features should be
|
||||
- Reuse scenarios between jobs are covered by [composite actions](https://docs.github.com/en/actions/creating-actions/creating-a-composite-action) and [resuable workflows](https://docs.github.com/en/actions/using-workflows/reusing-workflows)
|
||||
- Security applications, security should be handled on the policy side on the server, not decentralized on each runner
|
||||
|
||||
## Hooks
|
||||
- We will expose 2 variables that users can set to enable hooks
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_STARTED`
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_COMPLETED`
|
||||
|
||||
You can set these variables to the **absolute** path of a a `.sh` or `.ps1` file.
|
||||
|
||||
We will execute `pwsh` (fallback to `powershell`) or `bash` (fallback to `sh`) as appropriate.
|
||||
- `.sh` files will execute with the args `-e {pathtofile}`
|
||||
- `.ps1` files will execute with the args `-command \". '{pathtofile}'\"`
|
||||
|
||||
We will **not** set the [standard flags we typically set](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell) for `runs` commands. So, if you want to set `pipefail` on `bash` for example, you will need to do that in your script.
|
||||
|
||||
### UI
|
||||
We want to ensure the experience for users invoking workflows is good, if hooks take too long, you may feel your job is delayed or broken. So, much like `Set Up Job`, we will generate two new steps automatically in your job, one for each configured hook:
|
||||
- `Set up runner`
|
||||
- `Complete runner`
|
||||
|
||||
These steps will contain all of the output from invoking your hook, so you will have visibility into the runtime. We will also provide information on the path to the hook, and what shell we are invoking it as, much like we do for `run: ` steps.
|
||||
|
||||
### Contexts
|
||||
When running your hooks, some context on your job may be helpful.
|
||||
- The scripts will have access to the standard [default environment variables](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables)
|
||||
- Some of these variables are step specific like `GITHUB_ACTION`, in which case they will not be set
|
||||
- You can pull the full webhook event payload from `GITHUB_EVENT_PATH`
|
||||
|
||||
### Commands
|
||||
Should we expose [Commands](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions) and [Environment Files](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files)
|
||||
|
||||
**Yes**. Imagine a scenario where a runner administrator is deprecating a runner pool, and they need to [warn users](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-a-warning-message) to swap to a different pool, we should support them in doing this. However, there are some limitations:
|
||||
- [save-state](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#sending-values-to-the-pre-and-post-actions) will **not** be supported, these are not traditional steps with pre and post actions
|
||||
- [set-output](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#using-workflow-commands-to-access-toolkit-functions) will **not** be supported, there is no `id` as this is not a traditional step
|
||||
|
||||
|
||||
### Environment Files
|
||||
We will also enable [Environment Files](https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#environment-files) to support setup scenarios for the runner environment.
|
||||
|
||||
While a self hosted runner admin can [set env variables](https://docs.github.com/en/actions/hosting-your-own-runners/using-a-proxy-server-with-self-hosted-runners#using-a-env-file-to-set-the-proxy-configuration), these apply to all jobs. By enabling the ability to `add a path` and `set an env` we give runner admins the ability to do this dynamically based on the [workflows environment variables](https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables) to empower setup scenarios.
|
||||
|
||||
|
||||
### Exit codes
|
||||
These are **synchronous** hooks, so they will block job execution while they are being run. Exit code 0 will indicate a successful run of the hook and we will proceed with the job, any other exit code will fail the job with an appropriate annotation.
|
||||
- There will be no support for `continue-on-error`
|
||||
|
||||
## Key Decisions
|
||||
- We will expose 2 variables that users can set to enable hooks
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_STARTED`
|
||||
- `ACTIONS_RUNNER_HOOK_JOB_COMPLETED`
|
||||
- Users can set these variables to the path of a `.sh` or `.ps1` file, which we will execute when Jobs are started or completed.
|
||||
- Output from these will be added to a new step at the start/end of a job named `Set up runner` or `Complete runner`.
|
||||
- These steps will only be generated on runs with these hooks
|
||||
- These hooks `always()` execute if the env variable is set
|
||||
- These files will execute as the Runner user, outside of any container specification on the job
|
||||
- These are **synchronous** hooks
|
||||
- Runner admins can execute a background process for async hooks if they want
|
||||
- We will fail the job and halt execution on any exit code that is not 0. The Runner admin is responsible for returning the correct exit code and ensuring resilency.
|
||||
- This includes that the runner user needs access to the file in the env and the file must exist
|
||||
- There will be no `continue-on-error` type option on launch
|
||||
- There will be no `timeout` option on launch
|
||||
|
||||
## Consequences
|
||||
- Runner admins have the ability to tie into the runner job execution to publish their own telemetry or perform their own cleanup or setup
|
||||
- New steps will be added to the UI showcasing the output of these hooks
|
||||
@@ -5,6 +5,12 @@
|
||||
## Supported Versions
|
||||
|
||||
- macOS High Sierra (10.13) and later versions
|
||||
- x64 and arm64 (Apple Silicon)
|
||||
|
||||
## Apple Silicon M1
|
||||
|
||||
The runner is currently not supported on devices with an Apple M1 chip.
|
||||
We are waiting for official .NET support. You can read more here about the [current state of support here](https://github.com/orgs/dotnet/projects/18#card-56812463).
|
||||
Current .NET project board about M1 support:
|
||||
https://github.com/orgs/dotnet/projects/18#card-56812463
|
||||
|
||||
## [More .Net Core Prerequisites Information](https://docs.microsoft.com/en-us/dotnet/core/macos-prerequisites?tabs=netcore30)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
**/__tests__/**
|
||||
@@ -1,56 +0,0 @@
|
||||
{
|
||||
"plugins": ["@typescript-eslint"],
|
||||
"extends": ["plugin:github/recommended"],
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 9,
|
||||
"sourceType": "module",
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"rules": {
|
||||
"eslint-comments/no-use": "off",
|
||||
"import/no-namespace": "off",
|
||||
"no-constant-condition": "off",
|
||||
"no-unused-vars": "off",
|
||||
"i18n-text/no-en": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
||||
"@typescript-eslint/no-require-imports": "error",
|
||||
"@typescript-eslint/array-type": "error",
|
||||
"@typescript-eslint/await-thenable": "error",
|
||||
"camelcase": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
||||
"@typescript-eslint/no-array-constructor": "error",
|
||||
"@typescript-eslint/no-empty-interface": "error",
|
||||
"@typescript-eslint/no-explicit-any": "warn",
|
||||
"@typescript-eslint/no-extraneous-class": "error",
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-for-in-array": "error",
|
||||
"@typescript-eslint/no-inferrable-types": "error",
|
||||
"@typescript-eslint/no-misused-new": "error",
|
||||
"@typescript-eslint/no-namespace": "error",
|
||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"@typescript-eslint/no-useless-constructor": "error",
|
||||
"@typescript-eslint/no-var-requires": "error",
|
||||
"@typescript-eslint/prefer-for-of": "warn",
|
||||
"@typescript-eslint/prefer-function-type": "warn",
|
||||
"@typescript-eslint/prefer-includes": "error",
|
||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
||||
"@typescript-eslint/promise-function-async": "error",
|
||||
"@typescript-eslint/require-array-sort-compare": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "error",
|
||||
"semi": "off",
|
||||
"@typescript-eslint/semi": ["error", "never"],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "error",
|
||||
"no-shadow": "off",
|
||||
"@typescript-eslint/no-shadow": ["error"]
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
}
|
||||
}
|
||||
3
hooks/container/.gitignore
vendored
3
hooks/container/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
node_modules/
|
||||
lib/
|
||||
dist/
|
||||
@@ -1,3 +0,0 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "none",
|
||||
"bracketSpacing": false,
|
||||
"arrowParens": "avoid",
|
||||
"parser": "typescript"
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
# Basic setup
|
||||
You'll need a runner compatible with hooks, a repository with container workflows to which you can register the runner and the hooks from this repository.
|
||||
|
||||
|
||||
|
||||
## Getting Started
|
||||
- Run ` npm install && npm run bootstrap` to setup your environment and install all the needed packages
|
||||
- Run `npm run lint` and `npm run format` to ensure your charges will pass CI
|
||||
- Run `npm run build-all` to build and test end to end.
|
||||
|
||||
|
||||
## E2E
|
||||
- You'll need a runner compatible with hooks, a repository with container workflows to which you can register the runner and the hooks from this repository.
|
||||
- See [the runner contributing.md](../../github/CONTRIBUTING.MD) for how to get started with runner development.
|
||||
- Build your hook using `npm run build`
|
||||
- Enable the hooks by setting `ACTIONS_RUNNER_CONTAINER_HOOK=./src/{libraryname}/dist/index.js` file generated by [ncc](https://github.com/vercel/ncc)
|
||||
- Configure your self hosted runner against the a repository you have admin access
|
||||
- Run a workflow with a container job, for example
|
||||
```
|
||||
name: myjob
|
||||
on:
|
||||
workflow_dispatch:
|
||||
jobs:
|
||||
my_job:
|
||||
runs-on: self-hosted
|
||||
services:
|
||||
redis:
|
||||
image: redis
|
||||
container:
|
||||
image: alpine:3.15
|
||||
options: --cpus 1
|
||||
steps:
|
||||
- run: pwd
|
||||
```
|
||||
@@ -1,10 +0,0 @@
|
||||
# Container Hooks
|
||||
This repo contains example implementation of the container hook feature across various container providers. More information on how to implement your own hooks can be found in the [github docs]().
|
||||
|
||||
Three projects are included in the `src` folder
|
||||
- k8s: A kubernetes hook implementation that spins up pods dynamically to run a job
|
||||
- docker: A hook implementation of the runner's docker implementation
|
||||
- hooklib: a shared library which contains typescript definitions and utilities that the other projects consume
|
||||
|
||||
### Want to contribute
|
||||
We welcome contributions. See [how to contribute](CONTRIBUTING.md).
|
||||
@@ -1,3 +0,0 @@
|
||||
dist/
|
||||
lib/
|
||||
node_modules/
|
||||
4350
hooks/container/hooklib/package-lock.json
generated
4350
hooks/container/hooklib/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
{
|
||||
"name": "hooklib",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "lib/index.js",
|
||||
"types": "index.d.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "tsc && ncc build",
|
||||
"format": "prettier --write '**/*.ts'",
|
||||
"format-check": "prettier --check '**/*.ts'",
|
||||
"lint": "eslint src/**/*.ts"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.23",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"@zeit/ncc": "^0.22.3",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-github": "^4.3.6",
|
||||
"prettier": "^2.6.2",
|
||||
"typescript": "^4.6.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.6.0"
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
export * from './interfaces'
|
||||
export * from './utils'
|
||||
@@ -1,87 +0,0 @@
|
||||
export enum Command {
|
||||
PrepareJob = 'prepare_job',
|
||||
CleanupJob = 'cleanup_job',
|
||||
RunContainerStep = 'run_container_step',
|
||||
RunScriptStep = 'run_script_step'
|
||||
}
|
||||
|
||||
export interface HookData {
|
||||
command: Command
|
||||
responseFile: string
|
||||
args?: PrepareJobArgs | RunContainerStepArgs | RunScriptStepArgs
|
||||
state?: object
|
||||
}
|
||||
|
||||
export interface PrepareJobArgs {
|
||||
container?: JobContainerInfo
|
||||
services?: ServiceContainerInfo[]
|
||||
}
|
||||
|
||||
export type RunContainerStepArgs = StepContainerInfo
|
||||
|
||||
export interface RunScriptStepArgs {
|
||||
entrypoint: string
|
||||
entrypointArgs: string[]
|
||||
environmentVariables?: {[key: string]: string}
|
||||
prependPath?: string[]
|
||||
workingDirectory: string
|
||||
}
|
||||
|
||||
export interface ContainerInfo {
|
||||
entrypoint?: string
|
||||
entrypointArgs?: string[]
|
||||
createOptions?: string
|
||||
environmentVariables?: {[key: string]: string}
|
||||
userMountVolumes?: Mount[]
|
||||
registry?: Registry
|
||||
portMappings?: string[]
|
||||
}
|
||||
|
||||
export interface ServiceContainerInfo extends ContainerInfo {
|
||||
contextName: string
|
||||
image: string
|
||||
}
|
||||
|
||||
export interface JobContainerInfo extends ContainerInfo {
|
||||
image: string
|
||||
workingDirectory: string
|
||||
systemMountVolumes: Mount[]
|
||||
}
|
||||
|
||||
export interface StepContainerInfo extends ContainerInfo {
|
||||
prependPath?: string[]
|
||||
workingDirectory: string
|
||||
dockerfile?: string
|
||||
image?: string
|
||||
systemMountVolumes: Mount[]
|
||||
}
|
||||
|
||||
export interface Mount {
|
||||
sourceVolumePath: string
|
||||
targetVolumePath: string
|
||||
readOnly: boolean
|
||||
}
|
||||
|
||||
export interface Registry {
|
||||
username?: string
|
||||
password?: string
|
||||
serverUrl: string
|
||||
}
|
||||
|
||||
export enum Protocol {
|
||||
TCP = 'tcp',
|
||||
UDP = 'udp'
|
||||
}
|
||||
|
||||
export interface PrepareJobResponse {
|
||||
state?: object
|
||||
context?: ContainerContext
|
||||
services?: {[key: string]: ContainerContext}
|
||||
alpine: boolean
|
||||
}
|
||||
|
||||
export interface ContainerContext {
|
||||
id?: string
|
||||
network?: string
|
||||
ports?: {[key: string]: string}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
import * as core from '@actions/core'
|
||||
import * as events from 'events'
|
||||
import * as fs from 'fs'
|
||||
import * as os from 'os'
|
||||
import * as readline from 'readline'
|
||||
import {HookData} from './interfaces'
|
||||
|
||||
export async function getInputFromStdin(): Promise<HookData> {
|
||||
let input = ''
|
||||
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin
|
||||
})
|
||||
|
||||
rl.on('line', line => {
|
||||
core.debug(`Line from STDIN: ${line}`)
|
||||
input = line
|
||||
})
|
||||
await events.default.once(rl, 'close')
|
||||
const inputJson = JSON.parse(input)
|
||||
return inputJson as HookData
|
||||
}
|
||||
|
||||
export function writeToResponseFile(filePath: string, message: any): void {
|
||||
if (!filePath) {
|
||||
throw new Error(`Expected file path`)
|
||||
}
|
||||
if (!fs.existsSync(filePath)) {
|
||||
throw new Error(`Missing file at path: ${filePath}`)
|
||||
}
|
||||
|
||||
fs.appendFileSync(filePath, `${toCommandValue(message)}${os.EOL}`, {
|
||||
encoding: 'utf8'
|
||||
})
|
||||
}
|
||||
|
||||
function toCommandValue(input: any): string {
|
||||
if (input === null || input === undefined) {
|
||||
return ''
|
||||
} else if (typeof input === 'string' || input instanceof String) {
|
||||
return input as string
|
||||
}
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": [
|
||||
"./src"
|
||||
]
|
||||
}
|
||||
4368
hooks/container/package-lock.json
generated
4368
hooks/container/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"name": "hooks",
|
||||
"version": "1.0.0",
|
||||
"description": "Three projects are included - k8s: a kubernetes hook implementation that spins up pods dynamically to run a job - docker: A hook implementation of the runner's docker implementation - A hook lib, which contains shared typescript definitions and utilities that the other packages consume",
|
||||
"main": "",
|
||||
"directories": {
|
||||
"doc": "docs"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"bootstrap": "npm install --prefix src/hooklib && npm install --prefix src/k8s && npm install --prefix src/docker",
|
||||
"format": "prettier --write '**/*.ts'",
|
||||
"format-check": "prettier --check '**/*.ts'",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"build-all": "npm run build --prefix src/hooklib && npm run build --prefix src/k8s && npm run build --prefix src/docker"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions/runner.git"
|
||||
},
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions/runner/issues"
|
||||
},
|
||||
"homepage": "https://github.com/actions/runner#readme",
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.23",
|
||||
"@typescript-eslint/parser": "^5.18.0",
|
||||
"eslint": "^8.12.0",
|
||||
"eslint-plugin-github": "^4.3.6",
|
||||
"prettier": "^2.6.2",
|
||||
"typescript": "^4.6.3"
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
"outDir": "./lib",
|
||||
"rootDir": "./src",
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
// "sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
// "outDir": "./", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
"noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,8 @@
|
||||
## Features
|
||||
- Added a pre-release package for the `macOS-arm64` architecture
|
||||
- Note that this packages is pre-release status and may not work with all existing actions
|
||||
|
||||
## Bugs
|
||||
- Fixed an issue where live console logs would fail to close (#1903)
|
||||
- Fixed an issue where websockets failed to successfully close when posting log lines (#1790)
|
||||
|
||||
## Misc
|
||||
|
||||
## Windows x64
|
||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||
@@ -21,7 +18,7 @@ Add-Type -AssemblyName System.IO.Compression.FileSystem ;
|
||||
[System.IO.Compression.ZipFile]::ExtractToDirectory("$PWD\actions-runner-win-x64-<RUNNER_VERSION>.zip", "$PWD")
|
||||
```
|
||||
|
||||
## OSX x64
|
||||
## OSX
|
||||
|
||||
``` bash
|
||||
# Create a folder
|
||||
@@ -32,17 +29,6 @@ curl -O -L https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>
|
||||
tar xzf ./actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz
|
||||
```
|
||||
|
||||
## [Pre-release] OSX arm64 (Apple silicon)
|
||||
|
||||
``` bash
|
||||
# Create a folder
|
||||
mkdir actions-runner && cd actions-runner
|
||||
# Download the latest runner package
|
||||
curl -O -L https://github.com/actions/runner/releases/download/v<RUNNER_VERSION>/actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz
|
||||
# Extract the installer
|
||||
tar xzf ./actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz
|
||||
```
|
||||
|
||||
## Linux x64
|
||||
|
||||
``` bash
|
||||
@@ -85,28 +71,24 @@ The SHA-256 checksums for the packages included in this build are shown below:
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>.zip <!-- BEGIN SHA win-x64 --><WIN_X64_SHA><!-- END SHA win-x64 -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA osx-x64 --><OSX_X64_SHA><!-- END SHA osx-x64 -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA osx-arm64 --><OSX_ARM64_SHA><!-- END SHA osx-arm64 -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-x64 --><LINUX_X64_SHA><!-- END SHA linux-x64 -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm64 --><LINUX_ARM64_SHA><!-- END SHA linux-arm64 -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>.tar.gz <!-- BEGIN SHA linux-arm --><LINUX_ARM_SHA><!-- END SHA linux-arm -->
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>-noexternals.zip <!-- BEGIN SHA win-x64_noexternals --><WIN_X64_SHA_NOEXTERNALS><!-- END SHA win-x64_noexternals -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA osx-x64_noexternals --><OSX_X64_SHA_NOEXTERNALS><!-- END SHA osx-x64_noexternals -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA osx-arm64_noexternals --><OSX_ARM64_SHA_NOEXTERNALS><!-- END SHA osx-arm64_noexternals -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noexternals --><LINUX_X64_SHA_NOEXTERNALS><!-- END SHA linux-x64_noexternals -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-arm64_noexternals --><LINUX_ARM64_SHA_NOEXTERNALS><!-- END SHA linux-arm64_noexternals -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>-noexternals.tar.gz <!-- BEGIN SHA linux-arm_noexternals --><LINUX_ARM_SHA_NOEXTERNALS><!-- END SHA linux-arm_noexternals -->
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>-noruntime.zip <!-- BEGIN SHA win-x64_noruntime --><WIN_X64_SHA_NORUNTIME><!-- END SHA win-x64_noruntime -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA osx-x64_noruntime --><OSX_X64_SHA_NORUNTIME><!-- END SHA osx-x64_noruntime -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA osx-arm64_noruntime --><OSX_ARM64_SHA_NORUNTIME><!-- END SHA osx-arm64_noruntime -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-x64_noruntime --><LINUX_X64_SHA_NORUNTIME><!-- END SHA linux-x64_noruntime -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-arm64_noruntime --><LINUX_ARM64_SHA_NORUNTIME><!-- END SHA linux-arm64_noruntime -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>-noruntime.tar.gz <!-- BEGIN SHA linux-arm_noruntime --><LINUX_ARM_SHA_NORUNTIME><!-- END SHA linux-arm_noruntime -->
|
||||
|
||||
- actions-runner-win-x64-<RUNNER_VERSION>-noruntime-noexternals.zip <!-- BEGIN SHA win-x64_noruntime_noexternals --><WIN_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA win-x64_noruntime_noexternals -->
|
||||
- actions-runner-osx-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA osx-x64_noruntime_noexternals --><OSX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA osx-x64_noruntime_noexternals -->
|
||||
- actions-runner-osx-arm64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA osx-arm64_noruntime_noexternals --><OSX_ARM64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA osx-arm64_noruntime_noexternals -->
|
||||
- actions-runner-linux-x64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-x64_noruntime_noexternals --><LINUX_X64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-x64_noruntime_noexternals -->
|
||||
- actions-runner-linux-arm64-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-arm64_noruntime_noexternals --><LINUX_ARM64_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-arm64_noruntime_noexternals -->
|
||||
- actions-runner-linux-arm-<RUNNER_VERSION>-noruntime-noexternals.tar.gz <!-- BEGIN SHA linux-arm_noruntime_noexternals --><LINUX_ARM_SHA_NORUNTIME_NOEXTERNALS><!-- END SHA linux-arm_noruntime_noexternals -->
|
||||
|
||||
@@ -25,12 +25,9 @@
|
||||
<DefineConstants>$(DefineConstants);X86</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX' AND '$(PackageRuntime)' == 'osx-x64'">
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX'">
|
||||
<DefineConstants>$(DefineConstants);X64</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'OSX' AND '$(PackageRuntime)' == 'osx-arm64'">
|
||||
<DefineConstants>$(DefineConstants);ARM64</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(BUILD_OS)' == 'Linux' AND ('$(PackageRuntime)' == 'linux-x64' OR '$(PackageRuntime)' == '')">
|
||||
<DefineConstants>$(DefineConstants);X64</DefineConstants>
|
||||
@@ -50,6 +47,11 @@
|
||||
<DefineConstants>$(DefineConstants);DEBUG</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Set USE_BROKER vars -->
|
||||
<PropertyGroup Condition="'$(USE_BROKER)' == 'true'">
|
||||
<DefineConstants>$(DefineConstants);USE_BROKER</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- Set Treat tarnings as errors -->
|
||||
<PropertyGroup>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
|
||||
@@ -1 +1 @@
|
||||
1d709d93e5d3c6c6c656a61aa6c1781050224788a05b0e6ecc4c3c0408bdf89c
|
||||
de62d296708908cfd1236e58869aebbc2bae8a8c3d629276968542626c508e37
|
||||
@@ -1 +1 @@
|
||||
b92a47cfeaad02255b1f7a377060651b73ae5e5db22a188dbbcb4183ab03a03d
|
||||
44fcd0422dd98ed17d2c8e9057ff2260c50165f20674236a4ae7d2645a07df25
|
||||
@@ -1 +1 @@
|
||||
68a9a8ef0843a8bb74241894f6f63fd76241a82295c5337d3cc7a940a314c78e
|
||||
e57652cf322ee16ce3af4f9e58f80858746b9e1e60279e991a3b3d9a6baf8d79
|
||||
@@ -1 +0,0 @@
|
||||
02c7126ff4d63ee2a0ae390c81434c125630522aadf35903bbeebb1a99d8af99
|
||||
@@ -1 +1 @@
|
||||
c9d5a542f8d765168855a89e83ae0a8970d00869041c4f9a766651c04c72b212
|
||||
bdd247b2ff3f51095524412e2ac588e7a87af805e114d6caf2368366ee7be1ea
|
||||
@@ -1 +1 @@
|
||||
d94f2fbaf210297162bc9f3add819d73682c3aa6899e321c3872412b924d5504
|
||||
d23a0cb9f20c0aa1cddb7a39567cd097020cdeb06a1e952940601d1a405c53b8
|
||||
1
src/Misc/contentHash/externals/osx-arm64
vendored
1
src/Misc/contentHash/externals/osx-arm64
vendored
@@ -1 +0,0 @@
|
||||
cc4708962a80325de0baa5ae8484e0cb9ae976ac6a4178c1c0d448b8c52bd7f7
|
||||
@@ -140,11 +140,6 @@ if [[ "$PACKAGERUNTIME" == "osx-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-x64.tar.gz" node16 fix_nested_dir
|
||||
fi
|
||||
|
||||
if [[ "$PACKAGERUNTIME" == "osx-arm64" ]]; then
|
||||
# node.js v12 doesn't support macOS on arm64.
|
||||
acquireExternalTool "$NODE_URL/v${NODE16_VERSION}/node-v${NODE16_VERSION}-darwin-arm64.tar.gz" node16 fix_nested_dir
|
||||
fi
|
||||
|
||||
# Download the external tools for Linux PACKAGERUNTIMEs.
|
||||
if [[ "$PACKAGERUNTIME" == "linux-x64" ]]; then
|
||||
acquireExternalTool "$NODE_URL/v${NODE12_VERSION}/node-v${NODE12_VERSION}-linux-x64.tar.gz" node12 fix_nested_dir
|
||||
|
||||
@@ -3,7 +3,6 @@ api-ms-win-core-console-l1-2-0.dll
|
||||
api-ms-win-core-datetime-l1-1-0.dll
|
||||
api-ms-win-core-debug-l1-1-0.dll
|
||||
api-ms-win-core-errorhandling-l1-1-0.dll
|
||||
api-ms-win-core-fibers-l1-1-0.dll
|
||||
api-ms-win-core-file-l1-1-0.dll
|
||||
api-ms-win-core-file-l1-2-0.dll
|
||||
api-ms-win-core-file-l2-1-0.dll
|
||||
@@ -71,7 +70,7 @@ Microsoft.VisualBasic.dll
|
||||
Microsoft.Win32.Primitives.dll
|
||||
Microsoft.Win32.Registry.dll
|
||||
mscordaccore.dll
|
||||
mscordaccore_amd64_amd64_6.0.522.21309.dll
|
||||
mscordaccore_amd64_amd64_6.0.21.52210.dll
|
||||
mscordbi.dll
|
||||
mscorlib.dll
|
||||
mscorrc.debug.dll
|
||||
|
||||
59
src/Runner.Common/BrokerServer.cs
Normal file
59
src/Runner.Common/BrokerServer.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Services.WebApi;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
|
||||
namespace GitHub.Runner.Common
|
||||
{
|
||||
[ServiceLocator(Default = typeof(BrokerServer))]
|
||||
public interface IBrokerServer : IRunnerService
|
||||
{
|
||||
Task ConnectAsync(Uri serverUrl, CancellationToken cancellationToken);
|
||||
Task<string> GetMessageAsync(TaskAgentSession session, RunnerSettings settings, long? lastMessageId, CancellationToken cancellationToken);
|
||||
}
|
||||
|
||||
public sealed class BrokerServer : RunnerService, IBrokerServer
|
||||
{
|
||||
private HttpClient _httpClient;
|
||||
|
||||
public async Task ConnectAsync(Uri serverUrl, CancellationToken cancellationToken)
|
||||
{
|
||||
_httpClient = new HttpClient();
|
||||
_httpClient.BaseAddress = serverUrl;
|
||||
_httpClient.Timeout = TimeSpan.FromSeconds(100);
|
||||
await _httpClient.GetAsync("health", cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<string> GetMessageAsync(TaskAgentSession session, RunnerSettings settings, long? lastMessageId, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _httpClient.GetAsync($"message?tenant=org:github&root_tenant=org:github&group_id={settings.PoolId}&group_name={settings.PoolName}&runner_id={settings.AgentId}&runner_name={settings.AgentName}&labels=self-hosted,linux", cancellationToken);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = default(string);
|
||||
try
|
||||
{
|
||||
content = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
var error = $"HTTP {(int)response.StatusCode} {Enum.GetName(typeof(HttpStatusCode), response.StatusCode)}";
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
error = $"{error}: {content}";
|
||||
}
|
||||
throw new Exception(error);
|
||||
}
|
||||
|
||||
return await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace GitHub.Runner.Common
|
||||
public static class CommandLine
|
||||
{
|
||||
//if you are adding a new arg, please make sure you update the
|
||||
//validOptions dictionary as well present in the CommandSettings.cs
|
||||
//validArgs array as well present in the CommandSettings.cs
|
||||
public static class Args
|
||||
{
|
||||
public static readonly string Auth = "auth";
|
||||
@@ -121,7 +121,7 @@ namespace GitHub.Runner.Common
|
||||
}
|
||||
|
||||
//if you are adding a new flag, please make sure you update the
|
||||
//validOptions dictionary as well present in the CommandSettings.cs
|
||||
//validFlags array as well present in the CommandSettings.cs
|
||||
public static class Flags
|
||||
{
|
||||
public static readonly string Check = "check";
|
||||
@@ -150,7 +150,6 @@ namespace GitHub.Runner.Common
|
||||
{
|
||||
public static readonly string DiskSpaceWarning = "runner.diskspace.warning";
|
||||
public static readonly string Node12Warning = "DistributedTask.AddWarningToNode12Action";
|
||||
public static readonly string UseContainerPathForTemplate = "DistributedTask.UseContainerPathForTemplate";
|
||||
}
|
||||
|
||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -8,7 +9,6 @@ using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.WebApi;
|
||||
@@ -140,8 +140,8 @@ namespace GitHub.Runner.Common
|
||||
|
||||
public void InitializeWebsocketClient(ServiceEndpoint serviceEndpoint)
|
||||
{
|
||||
this._serviceEndpoint = serviceEndpoint;
|
||||
InitializeWebsocketClient(TimeSpan.Zero);
|
||||
this._serviceEndpoint = serviceEndpoint;
|
||||
InitializeWebsocketClient(TimeSpan.Zero);
|
||||
}
|
||||
|
||||
public ValueTask DisposeAsync()
|
||||
@@ -163,9 +163,9 @@ 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.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))
|
||||
{
|
||||
@@ -177,7 +177,7 @@ namespace GitHub.Runner.Common
|
||||
var userAgentValues = new List<ProductInfoHeaderValue>();
|
||||
userAgentValues.AddRange(UserAgentUtility.GetDefaultRestUserAgent());
|
||||
userAgentValues.AddRange(HostContext.UserAgents);
|
||||
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x => x.ToString())));
|
||||
this._websocketClient.Options.SetRequestHeader("User-Agent", string.Join(" ", userAgentValues.Select(x=>x.ToString())));
|
||||
|
||||
this._websocketConnectTask = ConnectWebSocketClient(feedStreamUrl, delay);
|
||||
}
|
||||
@@ -201,7 +201,7 @@ namespace GitHub.Runner.Common
|
||||
await this._websocketClient.ConnectAsync(new Uri(feedStreamUrl), default(CancellationToken));
|
||||
Trace.Info($"Successfully started websocket client.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch(Exception ex)
|
||||
{
|
||||
Trace.Info("Exception caught during websocket client connect, fallback of HTTP would be used now instead of websocket.");
|
||||
Trace.Error(ex);
|
||||
@@ -231,7 +231,7 @@ namespace GitHub.Runner.Common
|
||||
// ...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 linesWrapper = startLine.HasValue? new TimelineRecordFeedLinesWrapper(stepId, lines, startLine.Value): new TimelineRecordFeedLinesWrapper(stepId, lines);
|
||||
var jsonData = StringUtil.ConvertToJson(linesWrapper);
|
||||
try
|
||||
{
|
||||
@@ -242,7 +242,7 @@ namespace GitHub.Runner.Common
|
||||
{
|
||||
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);
|
||||
await _websocketClient.SendAsync(chunk, WebSocketMessageType.Text, endOfMessage:lastChunk, cancellationToken);
|
||||
}
|
||||
|
||||
pushedLinesViaWebsocket = true;
|
||||
@@ -274,7 +274,7 @@ namespace GitHub.Runner.Common
|
||||
}
|
||||
}
|
||||
|
||||
if (!pushedLinesViaWebsocket && !cancellationToken.IsCancellationRequested)
|
||||
if (!pushedLinesViaWebsocket)
|
||||
{
|
||||
if (startLine.HasValue)
|
||||
{
|
||||
|
||||
@@ -299,11 +299,7 @@ namespace GitHub.Runner.Common
|
||||
{
|
||||
try
|
||||
{
|
||||
// Give at most 60s for each request.
|
||||
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60)))
|
||||
{
|
||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, timeoutTokenSource.Token);
|
||||
}
|
||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, default(CancellationToken));
|
||||
|
||||
if (_firstConsoleOutputs)
|
||||
{
|
||||
|
||||
120
src/Runner.Common/RunServer.cs
Normal file
120
src/Runner.Common/RunServer.cs
Normal file
@@ -0,0 +1,120 @@
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Services.WebApi;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Common
|
||||
{
|
||||
[ServiceLocator(Default = typeof(RunServer))]
|
||||
public interface IRunServer : IRunnerService
|
||||
{
|
||||
Task ConnectAsync(Uri serverUrl, VssCredentials credentials);
|
||||
|
||||
Task<AgentJobRequestMessage> GetJobMessageAsync(Guid scopeId, Guid hostId, string planType, string planGroup, Guid planId, IList<InstanceRef> instanceRefsJson);
|
||||
}
|
||||
|
||||
public sealed class RunServer : RunnerService, IRunServer
|
||||
{
|
||||
private bool _hasConnection;
|
||||
private VssConnection _connection;
|
||||
private TaskAgentHttpClient _taskAgentClient;
|
||||
|
||||
public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials)
|
||||
{
|
||||
// System.Console.WriteLine("RunServer.ConnectAsync");
|
||||
_connection = await EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||
_taskAgentClient = _connection.GetClient<TaskAgentHttpClient>();
|
||||
_hasConnection = true;
|
||||
}
|
||||
|
||||
private async Task<VssConnection> EstablishVssConnection(Uri serverUrl, VssCredentials credentials, TimeSpan timeout)
|
||||
{
|
||||
// System.Console.WriteLine("EstablishVssConnection");
|
||||
Trace.Info($"EstablishVssConnection");
|
||||
Trace.Info($"Establish connection with {timeout.TotalSeconds} seconds timeout.");
|
||||
int attemptCount = 5;
|
||||
while (attemptCount-- > 0)
|
||||
{
|
||||
var connection = VssUtil.CreateConnection(serverUrl, credentials, timeout: timeout);
|
||||
try
|
||||
{
|
||||
await connection.ConnectAsync();
|
||||
return connection;
|
||||
}
|
||||
catch (Exception ex) when (attemptCount > 0)
|
||||
{
|
||||
Trace.Info($"Catch exception during connect. {attemptCount} attempt left.");
|
||||
Trace.Error(ex);
|
||||
|
||||
await HostContext.Delay(TimeSpan.FromMilliseconds(100), CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
// should never reach here.
|
||||
throw new InvalidOperationException(nameof(EstablishVssConnection));
|
||||
}
|
||||
|
||||
private void CheckConnection()
|
||||
{
|
||||
if (!_hasConnection)
|
||||
{
|
||||
throw new InvalidOperationException($"SetConnection");
|
||||
}
|
||||
}
|
||||
|
||||
public Task<AgentJobRequestMessage> GetJobMessageAsync(
|
||||
Guid scopeId,
|
||||
Guid hostId,
|
||||
string planType,
|
||||
string planGroup,
|
||||
Guid planId,
|
||||
IList<InstanceRef> instanceRefsJson)
|
||||
{
|
||||
// System.Console.WriteLine("RunServer.GetMessageAsync");
|
||||
CheckConnection();
|
||||
return _taskAgentClient.GetJobMessageAsync(scopeId, hostId, planType, planGroup, planId, StringUtil.ConvertToJson(instanceRefsJson, Newtonsoft.Json.Formatting.None));
|
||||
}
|
||||
}
|
||||
|
||||
// todo: move to SDK?
|
||||
[DataContract]
|
||||
public sealed class MessageRef
|
||||
{
|
||||
[DataMember(Name = "url")]
|
||||
public string Url { get; set; }
|
||||
[DataMember(Name = "token")]
|
||||
public string Token { get; set; }
|
||||
[DataMember(Name = "scopeId")]
|
||||
public Guid ScopeId { get; set; }
|
||||
[DataMember(Name = "hostId")]
|
||||
public Guid HostId { get; set; }
|
||||
[DataMember(Name = "planType")]
|
||||
public string PlanType { get; set; }
|
||||
[DataMember(Name = "planGroup")]
|
||||
public string PlanGroup { get; set; }
|
||||
[DataMember(Name = "planId")]
|
||||
public Guid PlanId { get; set; }
|
||||
[DataMember(Name = "instanceRefs")]
|
||||
public InstanceRef[] InstanceRefs { get; set; }
|
||||
[DataMember(Name = "labels")]
|
||||
public string[] Labels { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public sealed class InstanceRef
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
[DataMember(Name = "instanceType")]
|
||||
public string InstanceType { get; set; }
|
||||
[DataMember(Name = "attempt")]
|
||||
public int Attempt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace GitHub.Runner.Common
|
||||
// job request
|
||||
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
||||
Task<TaskAgentJobRequest> RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId, CancellationToken cancellationToken);
|
||||
Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken);
|
||||
Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, Guid targetHostId, CancellationToken cancellationToken);
|
||||
|
||||
// agent package
|
||||
Task<List<PackageMetadata>> GetPackagesAsync(string packageType, string platform, int top, bool includeToken, CancellationToken cancellationToken);
|
||||
@@ -68,11 +68,23 @@ namespace GitHub.Runner.Common
|
||||
|
||||
public async Task ConnectAsync(Uri serverUrl, VssCredentials credentials)
|
||||
{
|
||||
var createGenericConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||
// System.Console.WriteLine("RunnerServer.ConnectAsync: Create message connection");
|
||||
var createMessageConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60));
|
||||
var createRequestConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60));
|
||||
await Task.WhenAll(createMessageConnection);
|
||||
|
||||
await Task.WhenAll(createGenericConnection, createMessageConnection, createRequestConnection);
|
||||
// System.Console.WriteLine("RunnerServer.ConnectAsync: Create generic connection");
|
||||
var createGenericConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||
await Task.WhenAll(createGenericConnection);
|
||||
|
||||
// System.Console.WriteLine("RunnerServer.ConnectAsync: Create request connection");
|
||||
var createRequestConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60));
|
||||
await Task.WhenAll(createRequestConnection);
|
||||
|
||||
// var createGenericConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(100));
|
||||
// var createMessageConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60));
|
||||
// var createRequestConnection = EstablishVssConnection(serverUrl, credentials, TimeSpan.FromSeconds(60));
|
||||
|
||||
// await Task.WhenAll(createGenericConnection, createMessageConnection, createRequestConnection);
|
||||
|
||||
_genericConnection = await createGenericConnection;
|
||||
_messageConnection = await createMessageConnection;
|
||||
@@ -182,6 +194,8 @@ namespace GitHub.Runner.Common
|
||||
|
||||
private async Task<VssConnection> EstablishVssConnection(Uri serverUrl, VssCredentials credentials, TimeSpan timeout)
|
||||
{
|
||||
// System.Console.WriteLine("EstablishVssConnection");
|
||||
Trace.Info($"EstablishVssConnection");
|
||||
Trace.Info($"Establish connection with {timeout.TotalSeconds} seconds timeout.");
|
||||
int attemptCount = 5;
|
||||
while (attemptCount-- > 0)
|
||||
@@ -238,41 +252,48 @@ namespace GitHub.Runner.Common
|
||||
|
||||
public Task<List<TaskAgentPool>> GetAgentPoolsAsync(string agentPoolName = null, TaskAgentPoolType poolType = TaskAgentPoolType.Automation)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetAgentPoolsAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.GetAgentPoolsAsync(agentPoolName, poolType: poolType);
|
||||
}
|
||||
|
||||
public Task<TaskAgent> AddAgentAsync(Int32 agentPoolId, TaskAgent agent)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.AddAgentAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.AddAgentAsync(agentPoolId, agent);
|
||||
}
|
||||
|
||||
public Task<List<TaskAgent>> GetAgentsAsync(int agentPoolId, string agentName = null)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetAgentsAsync 1");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.GetAgentsAsync(agentPoolId, agentName, false);
|
||||
}
|
||||
|
||||
public Task<List<TaskAgent>> GetAgentsAsync(string agentName)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetAgentsAsync 2");
|
||||
return GetAgentsAsync(0, agentName); // search in all all agentPools
|
||||
}
|
||||
|
||||
public Task<TaskAgent> ReplaceAgentAsync(int agentPoolId, TaskAgent agent)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.ReplaceAgentAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.ReplaceAgentAsync(agentPoolId, agent);
|
||||
}
|
||||
|
||||
public Task DeleteAgentAsync(int agentPoolId, int agentId)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.DeleteAgentAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.DeleteAgentAsync(agentPoolId, agentId);
|
||||
}
|
||||
|
||||
public Task DeleteAgentAsync(int agentId)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.DeleteAgentAsync");
|
||||
return DeleteAgentAsync(0, agentId); // agentPool is ignored server side
|
||||
}
|
||||
|
||||
@@ -282,24 +303,28 @@ namespace GitHub.Runner.Common
|
||||
|
||||
public Task<TaskAgentSession> CreateAgentSessionAsync(Int32 poolId, TaskAgentSession session, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.CreateAgentSessionAsync");
|
||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
||||
return _messageTaskAgentClient.CreateAgentSessionAsync(poolId, session, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task DeleteAgentMessageAsync(Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.DeleteAgentMessageAsync");
|
||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
||||
return _messageTaskAgentClient.DeleteMessageAsync(poolId, messageId, sessionId, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task DeleteAgentSessionAsync(Int32 poolId, Guid sessionId, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.DeleteAgentSessionAsync");
|
||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
||||
return _messageTaskAgentClient.DeleteAgentSessionAsync(poolId, sessionId, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetAgentMessageAsync");
|
||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
||||
return _messageTaskAgentClient.GetMessageAsync(poolId, sessionId, lastMessageId, cancellationToken: cancellationToken);
|
||||
}
|
||||
@@ -310,18 +335,21 @@ namespace GitHub.Runner.Common
|
||||
|
||||
public Task<TaskAgentJobRequest> RenewAgentRequestAsync(int poolId, long requestId, Guid lockToken, string orchestrationId = null, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.RenewAgentRequestAsync");
|
||||
CheckConnection(RunnerConnectionType.JobRequest);
|
||||
return _requestTaskAgentClient.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId: orchestrationId, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, CancellationToken cancellationToken = default(CancellationToken))
|
||||
public Task<TaskAgentJobRequest> FinishAgentRequestAsync(int poolId, long requestId, Guid lockToken, DateTime finishTime, TaskResult result, Guid targetHostId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.FinishAgentRequestAsync");
|
||||
CheckConnection(RunnerConnectionType.JobRequest);
|
||||
return _requestTaskAgentClient.FinishAgentRequestAsync(poolId, requestId, lockToken, finishTime, result, cancellationToken: cancellationToken);
|
||||
return _requestTaskAgentClient.FinishAgentRequestAsync(poolId, requestId, lockToken, finishTime, result, targetHostId, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetAgentRequestAsync");
|
||||
CheckConnection(RunnerConnectionType.JobRequest);
|
||||
return _requestTaskAgentClient.GetAgentRequestAsync(poolId, requestId, cancellationToken: cancellationToken);
|
||||
}
|
||||
@@ -331,18 +359,21 @@ namespace GitHub.Runner.Common
|
||||
//-----------------------------------------------------------------
|
||||
public Task<List<PackageMetadata>> GetPackagesAsync(string packageType, string platform, int top, bool includeToken, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetPackagesAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.GetPackagesAsync(packageType, platform, top, includeToken, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task<PackageMetadata> GetPackageAsync(string packageType, string platform, string version, bool includeToken, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.GetPackageAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.GetPackageAsync(packageType, platform, version, includeToken, cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
public Task<TaskAgent> UpdateAgentUpdateStateAsync(int agentPoolId, int agentId, string currentState, string trace)
|
||||
{
|
||||
// System.Console.WriteLine("RunnerServer.UpdateAgentUpdateStateAsync");
|
||||
CheckConnection(RunnerConnectionType.Generic);
|
||||
return _genericTaskAgentClient.UpdateAgentUpdateStateAsync(agentPoolId, agentId, currentState, trace);
|
||||
}
|
||||
|
||||
@@ -6,13 +6,7 @@ namespace GitHub.Runner.Common.Util
|
||||
public static class NodeUtil
|
||||
{
|
||||
private const string _defaultNodeVersion = "node16";
|
||||
|
||||
#if OS_OSX && ARM64
|
||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node16" });
|
||||
#else
|
||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] { "node12", "node16" });
|
||||
#endif
|
||||
|
||||
public static readonly ReadOnlyCollection<string> BuiltInNodeVersions = new(new[] {"node12", "node16"});
|
||||
public static string GetInternalNodeVersion()
|
||||
{
|
||||
var forcedNodeVersion = Environment.GetEnvironmentVariable(Constants.Variables.Agent.ForcedInternalNodeVersion);
|
||||
|
||||
@@ -17,57 +17,43 @@ namespace GitHub.Runner.Listener
|
||||
private readonly IPromptManager _promptManager;
|
||||
private readonly Tracing _trace;
|
||||
|
||||
// Valid flags for all commands
|
||||
private readonly string[] genericOptions =
|
||||
private readonly string[] validCommands =
|
||||
{
|
||||
Constants.Runner.CommandLine.Flags.Help,
|
||||
Constants.Runner.CommandLine.Flags.Version,
|
||||
Constants.Runner.CommandLine.Flags.Commit,
|
||||
Constants.Runner.CommandLine.Flags.Check
|
||||
Constants.Runner.CommandLine.Commands.Configure,
|
||||
Constants.Runner.CommandLine.Commands.Remove,
|
||||
Constants.Runner.CommandLine.Commands.Run,
|
||||
Constants.Runner.CommandLine.Commands.Warmup,
|
||||
};
|
||||
|
||||
// Valid flags and args for specific command - key: command, value: array of valid flags and args
|
||||
private readonly Dictionary<string, string[]> validOptions = new Dictionary<string, string[]>
|
||||
private readonly string[] validFlags =
|
||||
{
|
||||
// Valid configure flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Configure] =
|
||||
new string[]
|
||||
{
|
||||
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
||||
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||
Constants.Runner.CommandLine.Flags.Replace,
|
||||
Constants.Runner.CommandLine.Flags.RunAsService,
|
||||
Constants.Runner.CommandLine.Flags.Unattended,
|
||||
Constants.Runner.CommandLine.Args.Auth,
|
||||
Constants.Runner.CommandLine.Args.Labels,
|
||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||
Constants.Runner.CommandLine.Args.Name,
|
||||
Constants.Runner.CommandLine.Args.PAT,
|
||||
Constants.Runner.CommandLine.Args.RunnerGroup,
|
||||
Constants.Runner.CommandLine.Args.Token,
|
||||
Constants.Runner.CommandLine.Args.Url,
|
||||
Constants.Runner.CommandLine.Args.UserName,
|
||||
Constants.Runner.CommandLine.Args.WindowsLogonAccount,
|
||||
Constants.Runner.CommandLine.Args.WindowsLogonPassword,
|
||||
Constants.Runner.CommandLine.Args.Work
|
||||
},
|
||||
// Valid remove flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Remove] =
|
||||
new string[]
|
||||
{
|
||||
Constants.Runner.CommandLine.Args.Token,
|
||||
Constants.Runner.CommandLine.Args.PAT
|
||||
},
|
||||
// Valid run flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Run] =
|
||||
new string[]
|
||||
{
|
||||
Constants.Runner.CommandLine.Flags.Once,
|
||||
Constants.Runner.CommandLine.Args.StartupType
|
||||
},
|
||||
// valid warmup flags and args
|
||||
[Constants.Runner.CommandLine.Commands.Warmup] =
|
||||
new string[] { }
|
||||
Constants.Runner.CommandLine.Flags.Check,
|
||||
Constants.Runner.CommandLine.Flags.Commit,
|
||||
Constants.Runner.CommandLine.Flags.DisableUpdate,
|
||||
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||
Constants.Runner.CommandLine.Flags.Help,
|
||||
Constants.Runner.CommandLine.Flags.Once,
|
||||
Constants.Runner.CommandLine.Flags.Replace,
|
||||
Constants.Runner.CommandLine.Flags.RunAsService,
|
||||
Constants.Runner.CommandLine.Flags.Unattended,
|
||||
Constants.Runner.CommandLine.Flags.Version
|
||||
};
|
||||
|
||||
private readonly string[] validArgs =
|
||||
{
|
||||
Constants.Runner.CommandLine.Args.Auth,
|
||||
Constants.Runner.CommandLine.Args.Labels,
|
||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||
Constants.Runner.CommandLine.Args.Name,
|
||||
Constants.Runner.CommandLine.Args.PAT,
|
||||
Constants.Runner.CommandLine.Args.RunnerGroup,
|
||||
Constants.Runner.CommandLine.Args.StartupType,
|
||||
Constants.Runner.CommandLine.Args.Token,
|
||||
Constants.Runner.CommandLine.Args.Url,
|
||||
Constants.Runner.CommandLine.Args.UserName,
|
||||
Constants.Runner.CommandLine.Args.WindowsLogonAccount,
|
||||
Constants.Runner.CommandLine.Args.WindowsLogonPassword,
|
||||
Constants.Runner.CommandLine.Args.Work
|
||||
};
|
||||
|
||||
// Commands.
|
||||
@@ -140,48 +126,17 @@ namespace GitHub.Runner.Listener
|
||||
List<string> unknowns = new List<string>();
|
||||
|
||||
// detect unknown commands
|
||||
unknowns.AddRange(_parser.Commands.Where(x => !validOptions.Keys.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
unknowns.AddRange(_parser.Commands.Where(x => !validCommands.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
|
||||
if (unknowns.Count == 0)
|
||||
{
|
||||
// detect unknown flags and args for valid commands
|
||||
foreach (var command in _parser.Commands)
|
||||
{
|
||||
if (validOptions.TryGetValue(command, out string[] options))
|
||||
{
|
||||
unknowns.AddRange(_parser.Flags.Where(x => !options.Contains(x, StringComparer.OrdinalIgnoreCase) && !genericOptions.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
unknowns.AddRange(_parser.Args.Keys.Where(x => !options.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
}
|
||||
}
|
||||
}
|
||||
// detect unknown flags
|
||||
unknowns.AddRange(_parser.Flags.Where(x => !validFlags.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
|
||||
// detect unknown args
|
||||
unknowns.AddRange(_parser.Args.Keys.Where(x => !validArgs.Contains(x, StringComparer.OrdinalIgnoreCase)));
|
||||
|
||||
return unknowns;
|
||||
}
|
||||
|
||||
public string GetCommandName()
|
||||
{
|
||||
string command = string.Empty;
|
||||
|
||||
if (Configure)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Configure;
|
||||
}
|
||||
else if (Remove)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Remove;
|
||||
}
|
||||
else if (Run)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Run;
|
||||
}
|
||||
else if (Warmup)
|
||||
{
|
||||
command = Constants.Runner.CommandLine.Commands.Warmup;
|
||||
}
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
//
|
||||
// Interactive flags.
|
||||
//
|
||||
|
||||
@@ -40,6 +40,12 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
return creds;
|
||||
}
|
||||
|
||||
#if USE_BROKER
|
||||
public VssCredentials LoadCredentials()
|
||||
{
|
||||
return new VssCredentials();
|
||||
}
|
||||
#else
|
||||
public VssCredentials LoadCredentials()
|
||||
{
|
||||
IConfigurationStore store = HostContext.GetService<IConfigurationStore>();
|
||||
@@ -69,6 +75,7 @@ namespace GitHub.Runner.Listener.Configuration
|
||||
|
||||
return creds;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace GitHub.Runner.Listener
|
||||
{
|
||||
bool Busy { get; }
|
||||
TaskCompletionSource<bool> RunOnceJobCompleted { get; }
|
||||
void Run(Pipelines.AgentJobRequestMessage message, bool runOnce = false);
|
||||
void Run(Guid targetHostId, Pipelines.AgentJobRequestMessage message, bool runOnce = false);
|
||||
bool Cancel(JobCancelMessage message);
|
||||
Task WaitAsync(CancellationToken token);
|
||||
Task ShutdownAsync();
|
||||
@@ -79,7 +79,7 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
public bool Busy { get; private set; }
|
||||
|
||||
public void Run(Pipelines.AgentJobRequestMessage jobRequestMessage, bool runOnce = false)
|
||||
public void Run(Guid targetHostId, Pipelines.AgentJobRequestMessage jobRequestMessage, bool runOnce = false)
|
||||
{
|
||||
Trace.Info($"Job request {jobRequestMessage.RequestId} for plan {jobRequestMessage.Plan.PlanId} job {jobRequestMessage.JobId} received.");
|
||||
|
||||
@@ -112,11 +112,11 @@ namespace GitHub.Runner.Listener
|
||||
if (runOnce)
|
||||
{
|
||||
Trace.Info("Start dispatcher for one time used runner.");
|
||||
newDispatch.WorkerDispatch = RunOnceAsync(jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
||||
newDispatch.WorkerDispatch = RunOnceAsync(targetHostId, jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
||||
}
|
||||
else
|
||||
{
|
||||
newDispatch.WorkerDispatch = RunAsync(jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
||||
newDispatch.WorkerDispatch = RunAsync(targetHostId, jobRequestMessage, orchestrationId, currentDispatch, newDispatch.WorkerCancellationTokenSource.Token, newDispatch.WorkerCancelTimeoutKillTokenSource.Token);
|
||||
}
|
||||
|
||||
_jobInfos.TryAdd(newDispatch.JobId, newDispatch);
|
||||
@@ -317,11 +317,11 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunOnceAsync(Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
||||
private async Task RunOnceAsync(Guid targetHostId, Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
await RunAsync(message, orchestrationId, previousJobDispatch, jobRequestCancellationToken, workerCancelTimeoutKillToken);
|
||||
await RunAsync(targetHostId, message, orchestrationId, previousJobDispatch, jobRequestCancellationToken, workerCancelTimeoutKillToken);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -330,7 +330,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RunAsync(Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
||||
private async Task RunAsync(Guid targetHostId, Pipelines.AgentJobRequestMessage message, string orchestrationId, WorkerDispatcher previousJobDispatch, CancellationToken jobRequestCancellationToken, CancellationToken workerCancelTimeoutKillToken)
|
||||
{
|
||||
Busy = true;
|
||||
try
|
||||
@@ -383,7 +383,7 @@ namespace GitHub.Runner.Listener
|
||||
await renewJobRequest;
|
||||
|
||||
// complete job request with result Cancelled
|
||||
await CompleteJobRequestAsync(_poolId, message, lockToken, TaskResult.Canceled);
|
||||
await CompleteJobRequestAsync(targetHostId, _poolId, message, lockToken, TaskResult.Canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -540,7 +540,7 @@ namespace GitHub.Runner.Listener
|
||||
await renewJobRequest;
|
||||
|
||||
// complete job request
|
||||
await CompleteJobRequestAsync(_poolId, message, lockToken, result, detailInfo);
|
||||
await CompleteJobRequestAsync(targetHostId, _poolId, message, lockToken, result, detailInfo);
|
||||
|
||||
// print out unhandled exception happened in worker after we complete job request.
|
||||
// when we run out of disk space, report back to server has higher priority.
|
||||
@@ -637,7 +637,7 @@ namespace GitHub.Runner.Listener
|
||||
await renewJobRequest;
|
||||
|
||||
// complete job request
|
||||
await CompleteJobRequestAsync(_poolId, message, lockToken, resultOnAbandonOrCancel);
|
||||
await CompleteJobRequestAsync(targetHostId, _poolId, message, lockToken, resultOnAbandonOrCancel);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -666,17 +666,25 @@ namespace GitHub.Runner.Listener
|
||||
{
|
||||
try
|
||||
{
|
||||
request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token);
|
||||
Trace.Info($"Successfully renew job request {requestId}, job is valid till {request.LockedUntil.Value}");
|
||||
|
||||
// #if USE_BROKER
|
||||
if (!firstJobRequestRenewed.Task.IsCompleted)
|
||||
{
|
||||
// fire first renew succeed event.
|
||||
firstJobRequestRenewed.TrySetResult(0);
|
||||
|
||||
// Update settings if the runner name has been changed server-side
|
||||
UpdateAgentNameIfNeeded(request.ReservedAgent?.Name);
|
||||
}
|
||||
// #else
|
||||
// request = await runnerServer.RenewAgentRequestAsync(poolId, requestId, lockToken, orchestrationId, token);
|
||||
// Trace.Info($"Successfully renew job request {requestId}, job is valid till {request?.LockedUntil.Value}");
|
||||
|
||||
// if (!firstJobRequestRenewed.Task.IsCompleted)
|
||||
// {
|
||||
// // fire first renew succeed event.
|
||||
// firstJobRequestRenewed.TrySetResult(0);
|
||||
|
||||
// // Update settings if the runner name has been changed server-side
|
||||
// UpdateAgentNameIfNeeded(request.ReservedAgent?.Name);
|
||||
// }
|
||||
// #endif
|
||||
|
||||
if (encounteringError > 0)
|
||||
{
|
||||
@@ -911,7 +919,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CompleteJobRequestAsync(int poolId, Pipelines.AgentJobRequestMessage message, Guid lockToken, TaskResult result, string detailInfo = null)
|
||||
private async Task CompleteJobRequestAsync(Guid targetHostId, int poolId, Pipelines.AgentJobRequestMessage message, Guid lockToken, TaskResult result, string detailInfo = null)
|
||||
{
|
||||
Trace.Entering();
|
||||
|
||||
@@ -928,7 +936,7 @@ namespace GitHub.Runner.Listener
|
||||
{
|
||||
try
|
||||
{
|
||||
await runnerServer.FinishAgentRequestAsync(poolId, message.RequestId, lockToken, DateTime.UtcNow, result, CancellationToken.None);
|
||||
await runnerServer.FinishAgentRequestAsync(poolId, message.RequestId, lockToken, DateTime.UtcNow, result, targetHostId, CancellationToken.None);
|
||||
return;
|
||||
}
|
||||
catch (TaskAgentJobNotFoundException)
|
||||
|
||||
@@ -2,7 +2,11 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
@@ -27,10 +31,13 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
public sealed class MessageListener : RunnerService, IMessageListener
|
||||
{
|
||||
#if !USE_BROKER
|
||||
private long? _lastMessageId;
|
||||
#endif
|
||||
private RunnerSettings _settings;
|
||||
private ITerminal _term;
|
||||
private IRunnerServer _runnerServer;
|
||||
private IBrokerServer _brokerServer;
|
||||
private TaskAgentSession _session;
|
||||
private TimeSpan _getNextMessageRetryInterval;
|
||||
private bool _accessTokenRevoked = false;
|
||||
@@ -45,8 +52,44 @@ namespace GitHub.Runner.Listener
|
||||
|
||||
_term = HostContext.GetService<ITerminal>();
|
||||
_runnerServer = HostContext.GetService<IRunnerServer>();
|
||||
_brokerServer = HostContext.GetService<IBrokerServer>();
|
||||
}
|
||||
|
||||
#if USE_BROKER
|
||||
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||
{
|
||||
Trace.Entering();
|
||||
|
||||
// Settings
|
||||
var configManager = HostContext.GetService<IConfigurationManager>();
|
||||
_settings = configManager.LoadSettings();
|
||||
var serverUrl = _settings.ServerUrl;
|
||||
Trace.Info(_settings);
|
||||
|
||||
// Connect
|
||||
token.ThrowIfCancellationRequested();
|
||||
Trace.Info($"Attempt to create session.");
|
||||
Trace.Info("Connecting to the Runner Server...");
|
||||
_term.WriteLine($"Connecting to {new Uri(serverUrl)}");
|
||||
await _brokerServer.ConnectAsync(new Uri(serverUrl), token);
|
||||
_term.WriteLine();
|
||||
_term.WriteSuccessMessage("Connected to GitHub");
|
||||
_term.WriteLine();
|
||||
|
||||
// Session info
|
||||
var agent = new TaskAgentReference
|
||||
{
|
||||
Id = _settings.AgentId,
|
||||
Name = _settings.AgentName,
|
||||
Version = BuildConstants.RunnerPackage.Version,
|
||||
OSDescription = RuntimeInformation.OSDescription,
|
||||
};
|
||||
string sessionName = $"{Environment.MachineName ?? "RUNNER"}";
|
||||
_session = new TaskAgentSession(sessionName, agent);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
public async Task<Boolean> CreateSessionAsync(CancellationToken token)
|
||||
{
|
||||
Trace.Entering();
|
||||
@@ -81,6 +124,7 @@ namespace GitHub.Runner.Listener
|
||||
Trace.Info($"Attempt to create session.");
|
||||
try
|
||||
{
|
||||
Trace.Info("Connecting to the Runner Server...");
|
||||
Trace.Info("Connecting to the Runner Server...");
|
||||
await _runnerServer.ConnectAsync(new Uri(serverUrl), creds);
|
||||
Trace.Info("VssConnection created");
|
||||
@@ -151,6 +195,7 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public async Task DeleteSessionAsync()
|
||||
{
|
||||
@@ -170,6 +215,167 @@ namespace GitHub.Runner.Listener
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_BROKER
|
||||
[DataContract]
|
||||
public sealed class MessageRef
|
||||
{
|
||||
[DataMember(Name = "url")]
|
||||
public string Url { get; set; }
|
||||
[DataMember(Name = "token")]
|
||||
public string Token { get; set; }
|
||||
[DataMember(Name = "scopeId")]
|
||||
public string ScopeId { get; set; }
|
||||
[DataMember(Name = "planType")]
|
||||
public string PlanType { get; set; }
|
||||
[DataMember(Name = "planGroup")]
|
||||
public string PlanGroup { get; set; }
|
||||
[DataMember(Name = "instanceRefs")]
|
||||
public InstanceRef[] InstanceRefs { get; set; }
|
||||
[DataMember(Name = "labels")]
|
||||
public string[] Labels { get; set; }
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public sealed class InstanceRef
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
[DataMember(Name = "instanceType")]
|
||||
public string InstanceType { get; set; }
|
||||
[DataMember(Name = "attempt")]
|
||||
public int Attempt { get; set; }
|
||||
}
|
||||
|
||||
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
||||
{
|
||||
Trace.Entering();
|
||||
ArgUtil.NotNull(_session, nameof(_session));
|
||||
ArgUtil.NotNull(_settings, nameof(_settings));
|
||||
bool encounteringError = false;
|
||||
int continuousError = 0;
|
||||
string errorMessage = string.Empty;
|
||||
Stopwatch heartbeat = new Stopwatch();
|
||||
heartbeat.Restart();
|
||||
while (true)
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
string message = null;
|
||||
try
|
||||
{
|
||||
message = await _brokerServer.GetMessageAsync(_session, _settings, null/*_lastMessageId*/, token);
|
||||
_term.WriteLine($"{DateTime.UtcNow:u}: {message}");
|
||||
if (!string.IsNullOrEmpty(message))
|
||||
{
|
||||
var messageRef = StringUtil.ConvertFromJson<MessageRef>(message);
|
||||
var client = new HttpClient();
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", messageRef.Token);
|
||||
var response = await client.GetAsync(messageRef.Url, token);
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = default(string);
|
||||
try
|
||||
{
|
||||
content = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
var error = $"HTTP {(int)response.StatusCode} {Enum.GetName(typeof(HttpStatusCode), response.StatusCode)}";
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
error = $"{error}: {content}";
|
||||
}
|
||||
throw new Exception(error);
|
||||
}
|
||||
|
||||
var fullMessage = await response.Content.ReadAsStringAsync();
|
||||
return StringUtil.ConvertFromJson<TaskAgentMessage>(fullMessage);
|
||||
}
|
||||
|
||||
if (encounteringError) //print the message once only if there was an error
|
||||
{
|
||||
_term.WriteLine($"{DateTime.UtcNow:u}: Runner reconnected.");
|
||||
encounteringError = false;
|
||||
continuousError = 0;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
Trace.Info("Get next message has been cancelled.");
|
||||
throw;
|
||||
}
|
||||
catch (TaskAgentAccessTokenExpiredException)
|
||||
{
|
||||
Trace.Info("Runner OAuth token has been revoked. Unable to pull message.");
|
||||
_accessTokenRevoked = true;
|
||||
throw;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Trace.Error("Catch exception during get next message.");
|
||||
Trace.Error(ex);
|
||||
|
||||
// don't retry if SkipSessionRecover = true, DT service will delete agent session to stop agent from taking more jobs.
|
||||
if (ex is TaskAgentSessionExpiredException && !_settings.SkipSessionRecover && await CreateSessionAsync(token))
|
||||
{
|
||||
Trace.Info($"{nameof(TaskAgentSessionExpiredException)} received, recovered by recreate session.");
|
||||
}
|
||||
else if (!IsGetNextMessageExceptionRetriable(ex))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
continuousError++;
|
||||
//retry after a random backoff to avoid service throttling
|
||||
//in case of there is a service error happened and all agents get kicked off of the long poll and all agent try to reconnect back at the same time.
|
||||
if (continuousError <= 5)
|
||||
{
|
||||
// random backoff [15, 30]
|
||||
_getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30), _getNextMessageRetryInterval);
|
||||
}
|
||||
else
|
||||
{
|
||||
// more aggressive backoff [30, 60]
|
||||
_getNextMessageRetryInterval = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(60), _getNextMessageRetryInterval);
|
||||
}
|
||||
|
||||
if (!encounteringError)
|
||||
{
|
||||
//print error only on the first consecutive error
|
||||
_term.WriteError($"{DateTime.UtcNow:u}: Runner connect error: {ex.Message}. Retrying until reconnected.");
|
||||
encounteringError = true;
|
||||
}
|
||||
|
||||
// re-create VssConnection before next retry
|
||||
await _runnerServer.RefreshConnectionAsync(RunnerConnectionType.MessageQueue, TimeSpan.FromSeconds(60));
|
||||
|
||||
Trace.Info("Sleeping for {0} seconds before retrying.", _getNextMessageRetryInterval.TotalSeconds);
|
||||
await HostContext.Delay(_getNextMessageRetryInterval, token);
|
||||
}
|
||||
}
|
||||
|
||||
// if (message == null)
|
||||
// {
|
||||
// if (heartbeat.Elapsed > TimeSpan.FromMinutes(30))
|
||||
// {
|
||||
// Trace.Info($"No message retrieved from session '{_session.SessionId}' within last 30 minutes.");
|
||||
// heartbeat.Restart();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Trace.Verbose($"No message retrieved from session '{_session.SessionId}'.");
|
||||
// }
|
||||
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// Trace.Info($"Message '{message.MessageId}' received from session '{_session.SessionId}'.");
|
||||
// return message;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public async Task<TaskAgentMessage> GetNextMessageAsync(CancellationToken token)
|
||||
{
|
||||
Trace.Entering();
|
||||
@@ -281,6 +487,7 @@ namespace GitHub.Runner.Listener
|
||||
return message;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public async Task DeleteMessageAsync(TaskAgentMessage message)
|
||||
{
|
||||
|
||||
@@ -95,15 +95,7 @@ namespace GitHub.Runner.Listener
|
||||
var unknownCommandlines = command.Validate();
|
||||
if (unknownCommandlines.Count > 0)
|
||||
{
|
||||
string commandName = command.GetCommandName();
|
||||
if (string.IsNullOrEmpty(commandName))
|
||||
{
|
||||
terminal.WriteError($"This command does not recognize the command-line input arguments: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||
}
|
||||
else
|
||||
{
|
||||
terminal.WriteError($"Unrecognized command-line input arguments for command {commandName}: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||
}
|
||||
terminal.WriteError($"Unrecognized command-line input arguments: '{string.Join(", ", unknownCommandlines)}'. For usage refer to: .\\config.cmd --help or ./config.sh --help");
|
||||
}
|
||||
|
||||
// Defer to the Runner class to execute the command.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -13,6 +13,10 @@ using GitHub.Runner.Sdk;
|
||||
using System.Linq;
|
||||
using GitHub.Runner.Listener.Check;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
|
||||
namespace GitHub.Runner.Listener
|
||||
{
|
||||
@@ -449,7 +453,37 @@ namespace GitHub.Runner.Listener
|
||||
{
|
||||
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);
|
||||
jobDispatcher.Run(jobMessage, runOnce);
|
||||
jobDispatcher.Run(Guid.Empty, jobMessage, runOnce);
|
||||
if (runOnce)
|
||||
{
|
||||
Trace.Info("One time used runner received job message.");
|
||||
runOnceJobReceived = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Broker flow
|
||||
else if (string.Equals(message.MessageType, JobRequestMessageTypes.RunnerJobRequest, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
if (autoUpdateInProgress || runOnceJobReceived)
|
||||
{
|
||||
skipMessageDeletion = true;
|
||||
Trace.Info($"Skip message deletion for job request message '{message.MessageId}'.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var messageRef = StringUtil.ConvertFromJson<MessageRef>(message.Body);
|
||||
|
||||
// Create connection
|
||||
var credMgr = HostContext.GetService<ICredentialManager>();
|
||||
var creds = credMgr.LoadCredentials();
|
||||
|
||||
// todo: add retries
|
||||
var runServer = HostContext.CreateService<IRunServer>();
|
||||
await runServer.ConnectAsync(new Uri(settings.ServerUrl), creds);
|
||||
var jobMessage = await runServer.GetJobMessageAsync(messageRef.ScopeId, messageRef.HostId, messageRef.PlanType, messageRef.PlanGroup, messageRef.PlanId, messageRef.InstanceRefs);
|
||||
|
||||
// todo: Trace.Info($"Received job message of length {message.Body.Length} from service, with hash '{IOUtil.GetSha256Hash(message.Body)}'");
|
||||
jobDispatcher.Run(messageRef.HostId, jobMessage, runOnce);
|
||||
if (runOnce)
|
||||
{
|
||||
Trace.Info("One time used runner received job message.");
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace GitHub.Runner.Sdk
|
||||
|
||||
public static VssConnection CreateConnection(Uri serverUri, VssCredentials credentials, IEnumerable<DelegatingHandler> additionalDelegatingHandler = null, TimeSpan? timeout = null)
|
||||
{
|
||||
// System.Console.WriteLine("VssUtil.CreateConnection");
|
||||
VssClientHttpRequestSettings settings = VssClientHttpRequestSettings.Default.Clone();
|
||||
|
||||
int maxRetryRequest;
|
||||
|
||||
@@ -817,6 +817,7 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
// Something else bad happened, let's go to our retry logic
|
||||
response.EnsureSuccessStatusCode();
|
||||
throw new Exception("Unexpected response code: " + response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.ObjectTemplating;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
@@ -10,6 +9,7 @@ using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
|
||||
@@ -171,16 +171,8 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
// Load the inputs.
|
||||
ExecutionContext.Debug("Loading inputs");
|
||||
Dictionary<string, string> inputs;
|
||||
if (ExecutionContext.Global.Variables.GetBoolean(Constants.Runner.Features.UseContainerPathForTemplate) ?? false)
|
||||
{
|
||||
inputs = EvaluateStepInputs(stepHost);
|
||||
}
|
||||
else
|
||||
{
|
||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||
inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
||||
}
|
||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, ExecutionContext.ExpressionValues, ExecutionContext.ExpressionFunctions);
|
||||
|
||||
var userInputs = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (KeyValuePair<string, string> input in inputs)
|
||||
@@ -307,15 +299,6 @@ namespace GitHub.Runner.Worker
|
||||
return didFullyEvaluate;
|
||||
}
|
||||
|
||||
private Dictionary<String, String> EvaluateStepInputs(IStepHost stepHost)
|
||||
{
|
||||
DictionaryContextData expressionValues = ExecutionContext.GetExpressionValues(stepHost);
|
||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||
var inputs = templateEvaluator.EvaluateStepInputs(Action.Inputs, expressionValues, ExecutionContext.ExpressionFunctions);
|
||||
|
||||
return inputs;
|
||||
}
|
||||
|
||||
private string GenerateDisplayName(ActionStep action, DictionaryContextData contextData, IExecutionContext context, out bool didFullyEvaluate)
|
||||
{
|
||||
ArgUtil.NotNull(context, nameof(context));
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
|
||||
namespace GitHub.Runner.Worker.Container
|
||||
{
|
||||
public class ContainerInfo
|
||||
{
|
||||
private IDictionary<string, string> _userMountVolumes;
|
||||
private List<MountVolume> _mountVolumes;
|
||||
private IDictionary<string, string> _userPortMappings;
|
||||
private List<PortMapping> _portMappings;
|
||||
@@ -68,7 +68,8 @@ namespace GitHub.Runner.Worker.Container
|
||||
{
|
||||
foreach (var volume in container.Volumes)
|
||||
{
|
||||
MountVolumes.Add(new MountVolume(volume, isUserProvided: true));
|
||||
UserMountVolumes[volume] = volume;
|
||||
MountVolumes.Add(new MountVolume(volume));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,20 +104,19 @@ namespace GitHub.Runner.Worker.Container
|
||||
return _environmentVariables;
|
||||
}
|
||||
}
|
||||
public ReadOnlyCollection<MountVolume> UserMountVolumes
|
||||
|
||||
public IDictionary<string, string> UserMountVolumes
|
||||
{
|
||||
get
|
||||
{
|
||||
return MountVolumes.Where(v => !string.IsNullOrEmpty(v.UserProvidedValue)).ToList().AsReadOnly();
|
||||
}
|
||||
}
|
||||
public ReadOnlyCollection<MountVolume> SystemMountVolumes
|
||||
{
|
||||
get
|
||||
{
|
||||
return MountVolumes.Where(v => string.IsNullOrEmpty(v.UserProvidedValue)).ToList().AsReadOnly();
|
||||
if (_userMountVolumes == null)
|
||||
{
|
||||
_userMountVolumes = new Dictionary<string, string>();
|
||||
}
|
||||
return _userMountVolumes;
|
||||
}
|
||||
}
|
||||
|
||||
public List<MountVolume> MountVolumes
|
||||
{
|
||||
get
|
||||
@@ -260,27 +260,18 @@ namespace GitHub.Runner.Worker.Container
|
||||
|
||||
public class MountVolume
|
||||
{
|
||||
public string UserProvidedValue { get; set; }
|
||||
public MountVolume(string sourceVolumePath, string targetVolumePath, bool readOnly = false)
|
||||
{
|
||||
this.SourceVolumePath = sourceVolumePath;
|
||||
this.TargetVolumePath = targetVolumePath;
|
||||
this.ReadOnly = readOnly;
|
||||
}
|
||||
|
||||
public MountVolume(string fromString)
|
||||
{
|
||||
ParseVolumeString(fromString);
|
||||
}
|
||||
|
||||
public MountVolume(string fromString, bool isUserProvided)
|
||||
{
|
||||
ParseVolumeString(fromString);
|
||||
if (isUserProvided)
|
||||
{
|
||||
UserProvidedValue = fromString;
|
||||
}
|
||||
}
|
||||
|
||||
private void ParseVolumeString(string volume)
|
||||
{
|
||||
var volumeSplit = volume.Split(":");
|
||||
|
||||
@@ -192,12 +192,13 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
Trace.Info($"User provided port: {port.Value}");
|
||||
}
|
||||
foreach (var mount in container.UserMountVolumes)
|
||||
foreach (var volume in container.UserMountVolumes)
|
||||
{
|
||||
Trace.Info($"User provided volume: {mount.UserProvidedValue}");
|
||||
Trace.Info($"User provided volume: {volume.Value}");
|
||||
var mount = new MountVolume(volume.Value);
|
||||
if (string.Equals(mount.SourceVolumePath, "/", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
executionContext.Warning($"Volume mount {mount.UserProvidedValue} is going to mount '/' into the container which may cause file ownership change in the entire file system and cause Actions Runner to lose permission to access the disk.");
|
||||
executionContext.Warning($"Volume mount {volume.Value} is going to mount '/' into the container which may cause file ownership change in the entire file system and cause Actions Runner to lose permission to access the disk.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
using GitHub.DistributedTask.Expressions2;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
@@ -15,7 +20,7 @@ using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using GitHub.Services.WebApi;
|
||||
using Newtonsoft.Json;
|
||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||
@@ -110,6 +115,7 @@ namespace GitHub.Runner.Worker
|
||||
void UpdateGlobalStepsContext();
|
||||
|
||||
void WriteWebhookPayload();
|
||||
|
||||
}
|
||||
|
||||
public sealed class ExecutionContext : RunnerService, IExecutionContext
|
||||
@@ -1193,66 +1199,6 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
return new TemplateTraceWriter(context);
|
||||
}
|
||||
|
||||
public static DictionaryContextData GetExpressionValues(this IExecutionContext context, IStepHost stepHost)
|
||||
{
|
||||
if (stepHost is ContainerStepHost)
|
||||
{
|
||||
|
||||
var expressionValues = context.ExpressionValues.Clone() as DictionaryContextData;
|
||||
context.UpdatePathsInExpressionValues("github", expressionValues, stepHost);
|
||||
context.UpdatePathsInExpressionValues("runner", expressionValues, stepHost);
|
||||
return expressionValues;
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.ExpressionValues.Clone() as DictionaryContextData;
|
||||
}
|
||||
}
|
||||
|
||||
private static void UpdatePathsInExpressionValues(this IExecutionContext context, string contextName, DictionaryContextData expressionValues, IStepHost stepHost)
|
||||
{
|
||||
var dict = expressionValues[contextName].AssertDictionary($"expected context {contextName} to be a dictionary");
|
||||
context.ResolvePathsInExpressionValuesDictionary(dict, stepHost);
|
||||
expressionValues[contextName] = dict;
|
||||
}
|
||||
|
||||
private static void ResolvePathsInExpressionValuesDictionary(this IExecutionContext context, DictionaryContextData dict, IStepHost stepHost)
|
||||
{
|
||||
foreach (var key in dict.Keys.ToList())
|
||||
{
|
||||
if (dict[key] is StringContextData)
|
||||
{
|
||||
var value = dict[key].ToString();
|
||||
if (!string.IsNullOrEmpty(value))
|
||||
{
|
||||
dict[key] = new StringContextData(stepHost.ResolvePathForStepHost(value));
|
||||
}
|
||||
}
|
||||
else if (dict[key] is DictionaryContextData)
|
||||
{
|
||||
var innerDict = dict[key].AssertDictionary("expected dictionary");
|
||||
context.ResolvePathsInExpressionValuesDictionary(innerDict, stepHost);
|
||||
var updatedDict = new DictionaryContextData();
|
||||
foreach (var k in innerDict.Keys.ToList())
|
||||
{
|
||||
updatedDict[k] = innerDict[k];
|
||||
}
|
||||
dict[key] = updatedDict;
|
||||
}
|
||||
else if (dict[key] is CaseSensitiveDictionaryContextData)
|
||||
{
|
||||
var innerDict = dict[key].AssertDictionary("expected dictionary");
|
||||
context.ResolvePathsInExpressionValuesDictionary(innerDict, stepHost);
|
||||
var updatedDict = new CaseSensitiveDictionaryContextData();
|
||||
foreach (var k in innerDict.Keys.ToList())
|
||||
{
|
||||
updatedDict[k] = innerDict[k];
|
||||
}
|
||||
dict[key] = updatedDict;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class TemplateTraceWriter : ObjectTemplating.ITraceWriter
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
void InitializeFiles(IExecutionContext context, ContainerInfo container);
|
||||
void ProcessFiles(IExecutionContext context, ContainerInfo container);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public sealed class FileCommandManager : RunnerService, IFileCommandManager
|
||||
@@ -57,7 +57,7 @@ namespace GitHub.Runner.Worker
|
||||
TryDeleteFile(newPath);
|
||||
File.Create(newPath).Dispose();
|
||||
|
||||
var pathToSet = container != null ? container.TranslateToContainerPath(newPath) : newPath;
|
||||
var pathToSet = container != null ? container.TranslateToContainerPath(newPath) : newPath;
|
||||
context.SetGitHubContext(fileCommand.ContextName, pathToSet);
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace GitHub.Runner.Worker
|
||||
{
|
||||
foreach (var fileCommand in _commandExtensions)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
fileCommand.ProcessCommand(context, Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix),container);
|
||||
}
|
||||
@@ -266,7 +266,7 @@ namespace GitHub.Runner.Worker
|
||||
|
||||
public sealed class CreateStepSummaryCommand : RunnerService, IFileCommandExtension
|
||||
{
|
||||
public const int AttachmentSizeLimit = 1024 * 1024;
|
||||
private const int _attachmentSizeLimit = 128 * 1024;
|
||||
|
||||
public string ContextName => "step_summary";
|
||||
public string FilePrefix => "step_summary_";
|
||||
@@ -296,9 +296,9 @@ namespace GitHub.Runner.Worker
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileSize > AttachmentSizeLimit)
|
||||
if (fileSize > _attachmentSizeLimit)
|
||||
{
|
||||
context.Error(String.Format(Constants.Runner.UnsupportedSummarySize, AttachmentSizeLimit / 1024, fileSize / 1024));
|
||||
context.Error(String.Format(Constants.Runner.UnsupportedSummarySize, _attachmentSizeLimit / 1024, fileSize / 1024));
|
||||
Trace.Info($"Step Summary file ({filePath}) is too large ({fileSize} bytes); skipping attachment upload");
|
||||
|
||||
return;
|
||||
|
||||
@@ -94,14 +94,6 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
workingDirectory = HostContext.GetDirectory(WellKnownDirectory.Work);
|
||||
}
|
||||
|
||||
#if OS_OSX
|
||||
if (string.Equals(Data.NodeVersion, "node12", StringComparison.OrdinalIgnoreCase) &&
|
||||
Constants.Runner.PlatformArchitecture.Equals(Constants.Architecture.Arm64))
|
||||
{
|
||||
ExecutionContext.Output($"The node12 is not supported on macOS ARM64 platform. Use node16 instead.");
|
||||
Data.NodeVersion = "node16";
|
||||
}
|
||||
#endif
|
||||
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext, Data.NodeVersion);
|
||||
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||
|
||||
|
||||
@@ -151,11 +151,6 @@ namespace GitHub.Runner.Worker.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
if (line.Contains("fatal: unsafe repository", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
_executionContext.StepTelemetry.ErrorMessages.Add(line);
|
||||
}
|
||||
|
||||
// Regular output
|
||||
_executionContext.Output(line);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Common.Util;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Services.WebApi;
|
||||
using Newtonsoft.Json;
|
||||
using GitHub.Runner.Common;
|
||||
using GitHub.Runner.Sdk;
|
||||
using System.Linq;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
|
||||
namespace GitHub.Runner.Worker.Handlers
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -132,7 +132,7 @@
|
||||
"continue-on-error": "boolean-steps-context",
|
||||
"working-directory": "string-steps-context",
|
||||
"shell": {
|
||||
"type": "string-steps-context",
|
||||
"type": "non-empty-string",
|
||||
"required": true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace GitHub.Services.Common
|
||||
|
||||
public override bool IsAuthenticationChallenge(IHttpResponse webResponse)
|
||||
{
|
||||
// System.Console.WriteLine($"FederatedCredential.IsAuthenticationChallenge");
|
||||
if (webResponse == null)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace GitHub.Services.Common
|
||||
IHttpResponse response,
|
||||
IssuedToken failedToken)
|
||||
{
|
||||
// System.Console.WriteLine("IssuedTokenCredential.CreateTokenProvider");
|
||||
if (response != null && !IsAuthenticationChallenge(response))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
@@ -99,12 +100,14 @@ namespace GitHub.Services.Common
|
||||
{
|
||||
throw new InvalidOperationException($"The {nameof(TokenStorageUrl)} property must have a value if the {nameof(Storage)} property is set on this instance of {GetType().Name}.");
|
||||
}
|
||||
// System.Console.WriteLine($"IssuedTokenCredential.CreateTokenProvider: TokenStorageUrl: {TokenStorageUrl}");
|
||||
InitialToken = Storage.RetrieveToken(TokenStorageUrl, CredentialType);
|
||||
}
|
||||
|
||||
IssuedTokenProvider provider = OnCreateTokenProvider(serverUrl, response);
|
||||
if (provider != null)
|
||||
{
|
||||
// System.Console.WriteLine($"IssuedTokenCredential.CreateTokenProvider: provider: {provider}");
|
||||
provider.TokenStorageUrl = TokenStorageUrl;
|
||||
}
|
||||
|
||||
@@ -123,6 +126,7 @@ namespace GitHub.Services.Common
|
||||
|
||||
internal virtual string GetAuthenticationChallenge(IHttpResponse webResponse)
|
||||
{
|
||||
// System.Console.WriteLine($"IssuedTokenCredential.GetAuthenticationChallenge");
|
||||
IEnumerable<String> values;
|
||||
if (!webResponse.Headers.TryGetValues(Internal.HttpHeaders.WwwAuthenticate, out values))
|
||||
{
|
||||
|
||||
@@ -108,6 +108,7 @@ namespace GitHub.Services.Common
|
||||
TaskScheduler scheduler,
|
||||
IVssCredentialPrompt credentialPrompt)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.ctor");
|
||||
this.PromptType = promptType;
|
||||
|
||||
if (promptType == CredentialPromptType.PromptIfNeeded && scheduler == null)
|
||||
@@ -150,6 +151,7 @@ namespace GitHub.Services.Common
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.get_PromptType");
|
||||
return m_promptType;
|
||||
}
|
||||
set
|
||||
@@ -170,6 +172,7 @@ namespace GitHub.Services.Common
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.get_Federated");
|
||||
return m_federatedCredential;
|
||||
}
|
||||
}
|
||||
@@ -184,6 +187,7 @@ namespace GitHub.Services.Common
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.get_Storage");
|
||||
return m_credentialStorage;
|
||||
}
|
||||
set
|
||||
@@ -203,6 +207,7 @@ namespace GitHub.Services.Common
|
||||
/// </summary>
|
||||
internal virtual bool TryGetValidAdalToken(IVssCredentialPrompt prompt)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.TryGetValidAdalToken");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,6 +223,7 @@ namespace GitHub.Services.Common
|
||||
IHttpResponse webResponse,
|
||||
IssuedToken failedToken)
|
||||
{
|
||||
// System.Console.WriteLine("VssCredential.CreateTokenProvider");
|
||||
ArgumentUtility.CheckForNull(serverUrl, "serverUrl");
|
||||
|
||||
IssuedTokenProvider tokenProvider = null;
|
||||
@@ -263,6 +269,7 @@ namespace GitHub.Services.Common
|
||||
Uri serverUrl,
|
||||
out IssuedTokenProvider provider)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.TryGetTokenProvider");
|
||||
ArgumentUtility.CheckForNull(serverUrl, "serverUrl");
|
||||
|
||||
lock (m_thisLock)
|
||||
@@ -272,11 +279,13 @@ namespace GitHub.Services.Common
|
||||
{
|
||||
if (m_federatedCredential != null)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.TryGetTokenProvider: Using federated credential");
|
||||
m_currentProvider = m_federatedCredential.CreateTokenProvider(serverUrl, null, null);
|
||||
}
|
||||
|
||||
if (m_currentProvider != null)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.TryGetTokenProvider: Issued token provider created");
|
||||
VssHttpEventSource.Log.IssuedTokenProviderCreated(VssTraceActivity.Current, m_currentProvider);
|
||||
}
|
||||
}
|
||||
@@ -294,6 +303,7 @@ namespace GitHub.Services.Common
|
||||
/// <returns>True if this is an token authentication redirect, false otherwise</returns>
|
||||
internal bool IsAuthenticationChallenge(IHttpResponse webResponse)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.IsAuthenticationChallenge");
|
||||
if (webResponse == null)
|
||||
{
|
||||
return false;
|
||||
@@ -313,6 +323,7 @@ namespace GitHub.Services.Common
|
||||
Uri serviceLocation,
|
||||
string identityProvider)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.SignOut");
|
||||
// Remove the token in the storage and the current token provider. Note that we don't
|
||||
// call InvalidateToken here because we want to remove the whole token not just its value
|
||||
if ((m_currentProvider != null) && (m_currentProvider.CurrentToken != null))
|
||||
@@ -349,6 +360,7 @@ namespace GitHub.Services.Common
|
||||
string token,
|
||||
IDictionary<string, string> attributes)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.WriteAuthorizationToken");
|
||||
int i = 0;
|
||||
for (int j = 0; j < token.Length; i++, j += 128)
|
||||
{
|
||||
@@ -360,6 +372,7 @@ namespace GitHub.Services.Common
|
||||
|
||||
protected static string ReadAuthorizationToken(IDictionary<string, string> attributes)
|
||||
{
|
||||
// System.Console.WriteLine($"VssCredentials.ReadAuthorizationToken");
|
||||
string authTokenCountValue;
|
||||
if (attributes.TryGetValue("AuthTokenSegmentCount", out authTokenCountValue))
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace GitHub.Services.Common.ClientStorage
|
||||
private readonly string m_filePath;
|
||||
private readonly VssFileStorageReader m_reader;
|
||||
private readonly IVssClientStorageWriter m_writer;
|
||||
|
||||
private const char c_defaultPathSeparator = '\\';
|
||||
private const bool c_defaultIgnoreCaseInPaths = false;
|
||||
|
||||
@@ -191,7 +192,7 @@ namespace GitHub.Services.Common.ClientStorage
|
||||
// Windows Impersonation is being used.
|
||||
|
||||
// Check to see if we can find the user's local application data directory.
|
||||
string subDir = Path.Combine("GitHub", "ActionsService");
|
||||
string subDir = "GitHub\\ActionsService";
|
||||
string path = Environment.GetEnvironmentVariable("localappdata");
|
||||
SafeGetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
if (string.IsNullOrEmpty(path))
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace GitHub.Services.Common
|
||||
VssHttpRequestSettings settings,
|
||||
HttpMessageHandler innerHandler)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.ctor");
|
||||
this.Credentials = credentials;
|
||||
this.Settings = settings;
|
||||
this.ExpectContinue = settings.ExpectContinue;
|
||||
@@ -122,6 +123,7 @@ namespace GitHub.Services.Common
|
||||
HttpRequestMessage request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.SendAsync");
|
||||
VssTraceActivity traceActivity = VssTraceActivity.Current;
|
||||
|
||||
var traceInfo = VssHttpMessageHandlerTraceInfo.GetTraceInfo(request);
|
||||
@@ -130,6 +132,7 @@ namespace GitHub.Services.Common
|
||||
if (!m_appliedClientCertificatesToTransportHandler &&
|
||||
request.RequestUri.Scheme == "https")
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.SendAsync: !appliedClientCertificatesToTransportHandler");
|
||||
HttpClientHandler httpClientHandler = m_transportHandler as HttpClientHandler;
|
||||
if (httpClientHandler != null &&
|
||||
this.Settings.ClientCertificateManager != null &&
|
||||
@@ -144,6 +147,7 @@ namespace GitHub.Services.Common
|
||||
if (!m_appliedServerCertificateValidationCallbackToTransportHandler &&
|
||||
request.RequestUri.Scheme == "https")
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.SendAsync: !appliedServerCertificateValidationCallbackToTransportHandler");
|
||||
HttpClientHandler httpClientHandler = m_transportHandler as HttpClientHandler;
|
||||
if (httpClientHandler != null &&
|
||||
this.Settings.ServerCertificateValidationCallback != null)
|
||||
@@ -165,6 +169,7 @@ namespace GitHub.Services.Common
|
||||
IssuedTokenProvider provider;
|
||||
if (this.Credentials.TryGetTokenProvider(request.RequestUri, out provider))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.SendAsync: Got token provider from credentials");
|
||||
token = provider.CurrentToken;
|
||||
}
|
||||
|
||||
@@ -225,6 +230,7 @@ namespace GitHub.Services.Common
|
||||
|
||||
traceInfo?.TraceResponseContentTime();
|
||||
|
||||
// System.Console.WriteLine($"VssHttpMessageHandler.SendAsync: Creating response wrapper");
|
||||
responseWrapper = new HttpResponseMessageWrapper(response);
|
||||
|
||||
if (!this.Credentials.IsAuthenticationChallenge(responseWrapper))
|
||||
@@ -232,6 +238,7 @@ namespace GitHub.Services.Common
|
||||
// Validate the token after it has been successfully authenticated with the server.
|
||||
if (provider != null)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.SendAsync: Validating token");
|
||||
provider.ValidateToken(token, responseWrapper);
|
||||
}
|
||||
|
||||
@@ -243,6 +250,7 @@ namespace GitHub.Services.Common
|
||||
}
|
||||
else
|
||||
{
|
||||
// System.Console.WriteLine($"VssHttpMessageHandler.SendAsync: Auth challenge. Response status code {response.StatusCode}; headers {response.Headers}");
|
||||
// In the case of a Windows token, only apply it to the web proxy if it
|
||||
// returned a 407 Proxy Authentication Required. If we didn't get this
|
||||
// status code back, then the proxy (if there is one) is clearly working fine,
|
||||
@@ -288,6 +296,7 @@ namespace GitHub.Services.Common
|
||||
}
|
||||
|
||||
// Now invoke the provider and await the result
|
||||
// System.Console.WriteLine($"VssHttpMessageHandler.SendAsync: Calling GetTokenAsync");
|
||||
token = await provider.GetTokenAsync(token, tokenSource.Token).ConfigureAwait(false);
|
||||
|
||||
// I always see 0 here, but the method above could take more time so keep for now
|
||||
@@ -432,6 +441,7 @@ namespace GitHub.Services.Common
|
||||
activity != VssTraceActivity.Empty &&
|
||||
!request.Headers.Contains(HttpHeaders.TfsSessionHeader))
|
||||
{
|
||||
// System.Console.WriteLine($"VssHttpMessageHandler.ApplyHeaders: Activity ID {activity.Id}");
|
||||
request.Headers.Add(HttpHeaders.TfsSessionHeader, activity.Id.ToString("D"));
|
||||
}
|
||||
|
||||
@@ -452,13 +462,16 @@ namespace GitHub.Services.Common
|
||||
ICredentials credentialsToken = token as ICredentials;
|
||||
if (credentialsToken != null)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Credentials token != null");
|
||||
if (applyICredentialsToWebProxy)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Apply credentials to web proxy");
|
||||
HttpClientHandler httpClientHandler = m_transportHandler as HttpClientHandler;
|
||||
|
||||
if (httpClientHandler != null &&
|
||||
httpClientHandler.Proxy != null)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Setting proxy crednetials");
|
||||
httpClientHandler.Proxy.Credentials = credentialsToken;
|
||||
}
|
||||
}
|
||||
@@ -467,6 +480,7 @@ namespace GitHub.Services.Common
|
||||
}
|
||||
else
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpMessageHandler.ApplyToken: Applying credentials to request");
|
||||
token.ApplyTo(new HttpRequestMessageWrapper(request));
|
||||
}
|
||||
}
|
||||
@@ -479,7 +493,8 @@ namespace GitHub.Services.Common
|
||||
HttpClientHandler httpClientHandler = handler as HttpClientHandler;
|
||||
if (httpClientHandler != null)
|
||||
{
|
||||
httpClientHandler.AllowAutoRedirect = settings.AllowAutoRedirect;
|
||||
// System.Console.WriteLine($"VssHttpMessageHandler.ApplySettings: Default credentials = {defaultCredentials} AllowAutoRedirect = {settings.AllowAutoRedirect}");
|
||||
httpClientHandler.AllowAutoRedirect = true; //settings.AllowAutoRedirect;
|
||||
httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
|
||||
//Setting httpClientHandler.UseDefaultCredentials to false in .Net Core, clears httpClientHandler.Credentials if
|
||||
//credentials is already set to defaultcredentials. Therefore httpClientHandler.Credentials must be
|
||||
@@ -550,6 +565,7 @@ namespace GitHub.Services.Common
|
||||
Uri uri,
|
||||
String authType)
|
||||
{
|
||||
// System.Console.WriteLine($"CredentialWrapper.GetCredential: InnerCredentials = {InnerCredentials}");
|
||||
return InnerCredentials != null ? InnerCredentials.GetCredential(uri, authType) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ using System.Net.Http.Headers;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
using GitHub.Services.Common;
|
||||
using GitHub.Services.WebApi;
|
||||
|
||||
@@ -378,6 +379,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
/// <param name="requestId"></param>
|
||||
/// <param name="lockToken"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="targetHostId"></param>
|
||||
/// <param name="userState"></param>
|
||||
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
@@ -386,6 +388,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
long requestId,
|
||||
Guid lockToken,
|
||||
TaskAgentJobRequest request,
|
||||
Guid targetHostId,
|
||||
object userState = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -396,6 +399,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
|
||||
List<KeyValuePair<string, string>> queryParams = new List<KeyValuePair<string, string>>();
|
||||
queryParams.Add("lockToken", lockToken.ToString());
|
||||
queryParams.Add("targetHostId", targetHostId.ToString());
|
||||
|
||||
return SendAsync<TaskAgentJobRequest>(
|
||||
httpMethod,
|
||||
@@ -703,6 +707,47 @@ namespace GitHub.DistributedTask.WebApi
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [Preview API]
|
||||
/// </summary>
|
||||
/// <param name="scopeId"></param>
|
||||
/// <param name="planType"></param>
|
||||
/// <param name="planGroup"></param>
|
||||
/// <param name="planId"></param>
|
||||
/// <param name="instanceRefsJson"></param>
|
||||
/// <param name="userState"></param>
|
||||
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public virtual Task<Pipelines.AgentJobRequestMessage> GetJobMessageAsync(
|
||||
Guid scopeId,
|
||||
Guid hostId,
|
||||
string planType,
|
||||
string planGroup,
|
||||
Guid planId,
|
||||
string instanceRefsJson,
|
||||
object userState = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
HttpMethod httpMethod = new HttpMethod("GET");
|
||||
Guid locationId = new Guid("25adab70-1379-4186-be8e-b643061ebe3a");
|
||||
|
||||
List<KeyValuePair<string, string>> queryParams = new List<KeyValuePair<string, string>>();
|
||||
queryParams.Add("scopeId", scopeId.ToString());
|
||||
queryParams.Add("hostId", hostId.ToString());
|
||||
queryParams.Add("planType", planType);
|
||||
queryParams.Add("planGroup", planGroup);
|
||||
queryParams.Add("planId", planId.ToString());
|
||||
queryParams.Add("instanceRefsJson", instanceRefsJson);
|
||||
|
||||
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
||||
httpMethod,
|
||||
locationId,
|
||||
version: new ApiResourceVersion(6.0, 1),
|
||||
queryParameters: queryParams,
|
||||
userState: userState,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [Preview API]
|
||||
/// </summary>
|
||||
@@ -717,6 +762,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
object userState = null,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
// System.Console.WriteLine("TaskAgentHttpClientBase.CreateAgentSessionAsync");
|
||||
HttpMethod httpMethod = new HttpMethod("POST");
|
||||
Guid locationId = new Guid("134e239e-2df3-4794-a6f6-24f1f19ec8dc");
|
||||
object routeValues = new { poolId = poolId };
|
||||
|
||||
@@ -5,5 +5,6 @@ namespace GitHub.DistributedTask.WebApi
|
||||
public static class JobRequestMessageTypes
|
||||
{
|
||||
public const String PipelineAgentJobRequest = "PipelineAgentJobRequest";
|
||||
public const String RunnerJobRequest = "RunnerJobRequest";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
Guid lockToken,
|
||||
DateTime finishTime,
|
||||
TaskResult result,
|
||||
Guid targetHostId,
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
@@ -74,7 +75,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
Result = result,
|
||||
};
|
||||
|
||||
return UpdateAgentRequestAsync(poolId, requestId, lockToken, request, userState, cancellationToken);
|
||||
return UpdateAgentRequestAsync(poolId, requestId, lockToken, request, targetHostId, userState, cancellationToken);
|
||||
}
|
||||
|
||||
public Task<List<TaskAgent>> GetAgentsAsync(
|
||||
@@ -152,6 +153,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
CancellationToken cancellationToken = default(CancellationToken),
|
||||
Func<HttpResponseMessage, CancellationToken, Task<T>> processResponse = null)
|
||||
{
|
||||
// System.Console.WriteLine("TaskAgentHttpClient.SendAsync 1");
|
||||
return SendAsync<T>(method, null, locationId, routeValues, version, content, queryParameters, userState, cancellationToken, processResponse);
|
||||
}
|
||||
|
||||
@@ -170,6 +172,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||
using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, additionalHeaders, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
// System.Console.WriteLine("TaskAgentHttpClient.SendAsync 2");
|
||||
return await SendAsync<T>(requestMessage, userState, cancellationToken, processResponse).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@@ -180,6 +183,7 @@ namespace GitHub.DistributedTask.WebApi
|
||||
CancellationToken cancellationToken = default(CancellationToken),
|
||||
Func<HttpResponseMessage, CancellationToken, Task<T>> processResponse = null)
|
||||
{
|
||||
// System.Console.WriteLine("TaskAgentHttpClient.SendAsync 3");
|
||||
if (processResponse == null)
|
||||
{
|
||||
processResponse = ReadContentAsAsync<T>;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603</NoWarn>
|
||||
<Version>$(Version)</Version>
|
||||
|
||||
@@ -801,6 +801,7 @@ namespace GitHub.Services.WebApi.Location
|
||||
|
||||
private async Task<ConnectionData> GetConnectionDataAsync(ConnectOptions connectOptions, int lastChangeId, CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine("ServerDataProvider.GetConnectionDataAsync");
|
||||
int timeoutRetries = 1;
|
||||
|
||||
while (true)
|
||||
|
||||
@@ -75,6 +75,7 @@ namespace GitHub.Services.OAuth
|
||||
|
||||
internal override void ApplyTo(IHttpRequest request)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthAccessToken.ApplyTo: Bearer {m_value}");
|
||||
request.Headers.SetValue(Common.Internal.HttpHeaders.Authorization, $"Bearer {m_value}");
|
||||
}
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ namespace GitHub.Services.OAuth
|
||||
Uri serverUrl,
|
||||
IHttpResponse response)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthAccessTokenCredential.OnCreateTokenProvider");
|
||||
return new VssOAuthAccessTokenProvider(this, serverUrl, null);
|
||||
}
|
||||
|
||||
@@ -71,6 +72,7 @@ namespace GitHub.Services.OAuth
|
||||
Uri signInUrl)
|
||||
: base(credential, serverUrl, signInUrl)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthAccessTokenProvider.ctor");
|
||||
}
|
||||
|
||||
public override Boolean GetTokenIsInteractive
|
||||
|
||||
@@ -103,17 +103,23 @@ namespace GitHub.Services.OAuth
|
||||
/// <returns>True if the web response indicates an authorization challenge; otherwise, false</returns>
|
||||
public override Boolean IsAuthenticationChallenge(IHttpResponse webResponse)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge");
|
||||
if (webResponse == null)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: webResponse is null");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (webResponse.StatusCode == HttpStatusCode.Found ||
|
||||
webResponse.StatusCode == HttpStatusCode.Unauthorized)
|
||||
{
|
||||
return webResponse.Headers.GetValues(Common.Internal.HttpHeaders.WwwAuthenticate).Any(x => x.IndexOf("Bearer", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
// System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: found or unauthorized");
|
||||
var result = webResponse.Headers.GetValues(Common.Internal.HttpHeaders.WwwAuthenticate).Any(x => x.IndexOf("Bearer", StringComparison.OrdinalIgnoreCase) >= 0);
|
||||
// System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
// System.Console.WriteLine($"VssOAuthCredential.IsAuthenticationChallenge: false");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,6 +127,7 @@ namespace GitHub.Services.OAuth
|
||||
Uri serverUrl,
|
||||
IHttpResponse response)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthCredential.OnCreateTokenProvider");
|
||||
return new VssOAuthTokenProvider(this, serverUrl);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace GitHub.Services.OAuth
|
||||
VssOAuthTokenParameters tokenParameters = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// todo: qqq
|
||||
VssTraceActivity traceActivity = VssTraceActivity.Current;
|
||||
using (HttpClient client = new HttpClient(CreateMessageHandler(this.AuthorizationUrl)))
|
||||
{
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace GitHub.Services.OAuth
|
||||
VssOAuthTokenParameters tokenParameters)
|
||||
: base(credential, serverUrl, authorizationUrl)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.ctor");
|
||||
m_grant = grant;
|
||||
m_tokenParameters = tokenParameters;
|
||||
m_clientCredential = clientCrential;
|
||||
@@ -59,6 +60,7 @@ namespace GitHub.Services.OAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.get_Grant");
|
||||
return m_grant;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +72,7 @@ namespace GitHub.Services.OAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.get_ClientCredential");
|
||||
return m_clientCredential;
|
||||
}
|
||||
}
|
||||
@@ -81,6 +84,7 @@ namespace GitHub.Services.OAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.get_TokenParameters");
|
||||
return m_tokenParameters;
|
||||
}
|
||||
}
|
||||
@@ -92,6 +96,7 @@ namespace GitHub.Services.OAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.get_GetTokenIsInteractive");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -100,6 +105,7 @@ namespace GitHub.Services.OAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.get_AuthenticationParameter");
|
||||
if (this.ClientCredential == null)
|
||||
{
|
||||
return null;
|
||||
@@ -115,12 +121,14 @@ namespace GitHub.Services.OAuth
|
||||
{
|
||||
get
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.get_AuthenticationScheme");
|
||||
return "Bearer";
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<string> ValidateCredentialAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.ValidateCredentialAsync: Calling VssOAuthTokenHttpClient.GetTokenAsync");
|
||||
var tokenHttpClient = new VssOAuthTokenHttpClient(this.SignInUrl);
|
||||
var tokenResponse = await tokenHttpClient.GetTokenAsync(this.Grant, this.ClientCredential, this.TokenParameters, cancellationToken);
|
||||
|
||||
@@ -139,6 +147,7 @@ namespace GitHub.Services.OAuth
|
||||
IssuedToken failedToken,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.OnGetTokenAsync");
|
||||
if (this.SignInUrl == null ||
|
||||
this.Grant == null ||
|
||||
this.ClientCredential == null)
|
||||
@@ -151,6 +160,7 @@ namespace GitHub.Services.OAuth
|
||||
try
|
||||
{
|
||||
var tokenHttpClient = new VssOAuthTokenHttpClient(this.SignInUrl);
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.OnGetTokenAsync: Calling VssOAuthTokenHttpClient.GetTokenAsync; sign-in url {this.SignInUrl.AbsoluteUri}");
|
||||
var tokenResponse = await tokenHttpClient.GetTokenAsync(this.Grant, this.ClientCredential, this.TokenParameters, cancellationToken).ConfigureAwait(false);
|
||||
if (!String.IsNullOrEmpty(tokenResponse.AccessToken))
|
||||
{
|
||||
@@ -197,6 +207,7 @@ namespace GitHub.Services.OAuth
|
||||
|
||||
protected virtual IssuedToken CreateIssuedToken(VssOAuthTokenResponse tokenResponse)
|
||||
{
|
||||
// System.Console.WriteLine($"VssOAuthTokenProvider.CreateIssuedToken");
|
||||
if (tokenResponse.ExpiresIn > 0)
|
||||
{
|
||||
return new VssOAuthAccessToken(tokenResponse.AccessToken, DateTime.UtcNow.AddSeconds(tokenResponse.ExpiresIn));
|
||||
|
||||
@@ -100,6 +100,7 @@ namespace GitHub.Services.WebApi
|
||||
IDictionary<String, String> parameters,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssConnection.ConnectAsync");
|
||||
CheckForDisposed();
|
||||
// Set the connectMode on the credential's FederatedPrompt
|
||||
if (Credentials.Federated != null && Credentials.Federated.Prompt != null)
|
||||
|
||||
@@ -390,6 +390,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 1");
|
||||
return SendAsync<T>(method, null, locationId, routeValues, version, content, queryParameters, userState, cancellationToken);
|
||||
}
|
||||
|
||||
@@ -404,6 +405,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 2");
|
||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||
using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, additionalHeaders, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
@@ -422,6 +424,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 3");
|
||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||
using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, additionalHeaders, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
@@ -455,6 +458,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 4");
|
||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||
using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
@@ -473,6 +477,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 5");
|
||||
using (VssTraceActivity.GetOrCreate().EnterCorrelationScope())
|
||||
using (HttpRequestMessage requestMessage = await CreateRequestMessageAsync(method, locationId, routeValues, version, content, queryParameters, userState, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
@@ -501,6 +506,7 @@ namespace GitHub.Services.WebApi
|
||||
CancellationToken cancellationToken = default(CancellationToken),
|
||||
String mediaType = c_jsonMediaType)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 1");
|
||||
return CreateRequestMessageAsync(method, null, locationId, routeValues, version, content, queryParameters, userState, cancellationToken, mediaType);
|
||||
}
|
||||
|
||||
@@ -526,6 +532,7 @@ namespace GitHub.Services.WebApi
|
||||
CancellationToken cancellationToken = default(CancellationToken),
|
||||
String mediaType = c_jsonMediaType)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 2");
|
||||
// Lookup the location
|
||||
ApiResourceLocation location = await GetResourceLocationAsync(locationId, userState, cancellationToken).ConfigureAwait(false);
|
||||
if (location == null)
|
||||
@@ -555,6 +562,7 @@ namespace GitHub.Services.WebApi
|
||||
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
||||
String mediaType = c_jsonMediaType)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 3");
|
||||
return CreateRequestMessage(method, null, location, routeValues, version, content, queryParameters, mediaType);
|
||||
}
|
||||
|
||||
@@ -578,6 +586,7 @@ namespace GitHub.Services.WebApi
|
||||
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
||||
String mediaType = c_jsonMediaType)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.CreateRequestMessageAsync 4");
|
||||
CheckForDisposed();
|
||||
// Negotiate the request version to send
|
||||
ApiResourceVersion requestVersion = NegotiateRequestVersion(location, version);
|
||||
@@ -749,12 +758,14 @@ namespace GitHub.Services.WebApi
|
||||
//from deadlocking...
|
||||
using (HttpResponseMessage response = await this.SendAsync(message, userState, cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 6");
|
||||
return await ReadContentAsAsync<T>(response, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
protected async Task<T> ReadContentAsAsync<T>(HttpResponseMessage response, CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine($"VssHttpClientBase.ReadContentAsAsync {response.Headers}");
|
||||
CheckForDisposed();
|
||||
Boolean isJson = IsJsonResponse(response);
|
||||
bool mismatchContentType = false;
|
||||
@@ -766,17 +777,20 @@ namespace GitHub.Services.WebApi
|
||||
!typeof(Byte[]).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()) &&
|
||||
!typeof(JObject).GetTypeInfo().IsAssignableFrom(typeof(T).GetTypeInfo()))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.ReadContentAsAsync: isJson 1");
|
||||
// expect it to come back wrapped, if it isn't it is a bug!
|
||||
var wrapper = await ReadJsonContentAsync<VssJsonCollectionWrapper<T>>(response, cancellationToken).ConfigureAwait(false);
|
||||
return wrapper.Value;
|
||||
}
|
||||
else if (isJson)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.ReadContentAsAsync: isJson 2");
|
||||
return await ReadJsonContentAsync<T>(response, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch (JsonReaderException)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.ReadContentAsAsync: mismatchContentType");
|
||||
// We thought the content was JSON but failed to parse.
|
||||
// In this case, do nothing and utilize the HandleUnknownContentType call below
|
||||
mismatchContentType = true;
|
||||
@@ -802,6 +816,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 7");
|
||||
// the default in httpClient for HttpCompletionOption is ResponseContentRead so that is what we do here
|
||||
return this.SendAsync(
|
||||
message,
|
||||
@@ -816,6 +831,7 @@ namespace GitHub.Services.WebApi
|
||||
Object userState = null,
|
||||
CancellationToken cancellationToken = default(CancellationToken))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.SendAsync 8");
|
||||
CheckForDisposed();
|
||||
if (message.Headers.UserAgent != null)
|
||||
{
|
||||
@@ -851,6 +867,7 @@ namespace GitHub.Services.WebApi
|
||||
//ConfigureAwait(false) enables the continuation to be run outside
|
||||
//any captured SyncronizationContext (such as ASP.NET's) which keeps things
|
||||
//from deadlocking...
|
||||
// System.Console.WriteLine($"VssHttpClientBase.SendAsync 8: Calling Client.SendAsync {message}");
|
||||
HttpResponseMessage response = await Client.SendAsync(message, completionOption, cancellationToken).ConfigureAwait(false);
|
||||
|
||||
// Inject delay or failure for testing
|
||||
@@ -868,6 +885,7 @@ namespace GitHub.Services.WebApi
|
||||
[Obsolete("Use VssHttpClientBase.HandleResponseAsync instead")]
|
||||
protected virtual void HandleResponse(HttpResponseMessage response)
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.HandleResponse 1");
|
||||
|
||||
}
|
||||
|
||||
@@ -875,6 +893,7 @@ namespace GitHub.Services.WebApi
|
||||
HttpResponseMessage response,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
// System.Console.WriteLine($"VssHttpClientBase.HandleResponse 2 status code {response.StatusCode} headers {response.Headers}");
|
||||
response.Trace();
|
||||
VssHttpEventSource.Log.HttpRequestStop(VssTraceActivity.Current, response);
|
||||
|
||||
@@ -886,6 +905,7 @@ namespace GitHub.Services.WebApi
|
||||
}
|
||||
else if (ShouldThrowError(response))
|
||||
{
|
||||
// System.Console.WriteLine("VssHttpClientBase.HandleResponse: Should throw error");
|
||||
Exception exToThrow = null;
|
||||
if (IsJsonResponse(response))
|
||||
{
|
||||
@@ -909,6 +929,7 @@ namespace GitHub.Services.WebApi
|
||||
{
|
||||
message = response.ReasonPhrase;
|
||||
}
|
||||
// System.Console.WriteLine($"VssHttpClientBase.HandleResponse: Exception message {message}");
|
||||
exToThrow = new VssServiceResponseException(response.StatusCode, message, exToThrow);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ namespace GitHub.Runner.Common.Tests
|
||||
"linux-x64",
|
||||
"linux-arm",
|
||||
"linux-arm64",
|
||||
"osx-x64",
|
||||
"osx-arm64"
|
||||
"osx-x64"
|
||||
};
|
||||
|
||||
Assert.True(BuildConstants.Source.CommitHash.Length == 40, $"CommitHash should be SHA-1 hash {BuildConstants.Source.CommitHash}");
|
||||
|
||||
@@ -708,85 +708,33 @@ namespace GitHub.Runner.Common.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("configure", "once")]
|
||||
[InlineData("remove", "disableupdate")]
|
||||
[InlineData("remove", "ephemeral")]
|
||||
[InlineData("remove", "once")]
|
||||
[InlineData("remove", "replace")]
|
||||
[InlineData("remove", "runasservice")]
|
||||
[InlineData("remove", "unattended")]
|
||||
[InlineData("run", "disableupdate")]
|
||||
[InlineData("run", "ephemeral")]
|
||||
[InlineData("run", "replace")]
|
||||
[InlineData("run", "runasservice")]
|
||||
[InlineData("run", "unattended")]
|
||||
[InlineData("warmup", "disableupdate")]
|
||||
[InlineData("warmup", "ephemeral")]
|
||||
[InlineData("warmup", "once")]
|
||||
[InlineData("warmup", "replace")]
|
||||
[InlineData("warmup", "runasservice")]
|
||||
[InlineData("warmup", "unattended")]
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateInvalidFlagCommandCombination(string validCommand, string flag)
|
||||
public void ValidateFlags()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
||||
var command = new CommandSettings(hc, args: new string[] { "--badflag" });
|
||||
|
||||
// Assert.
|
||||
Assert.Contains(flag, command.Validate());
|
||||
Assert.Contains("badflag", command.Validate());
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("remove", "auth", "bar arg value")]
|
||||
[InlineData("remove", "labels", "bar arg value")]
|
||||
[InlineData("remove", "monitorsocketaddress", "bar arg value")]
|
||||
[InlineData("remove", "name", "bar arg value")]
|
||||
[InlineData("remove", "runnergroup", "bar arg value")]
|
||||
[InlineData("remove", "url", "bar arg value")]
|
||||
[InlineData("remove", "username", "bar arg value")]
|
||||
[InlineData("remove", "windowslogonaccount", "bar arg value")]
|
||||
[InlineData("remove", "windowslogonpassword", "bar arg value")]
|
||||
[InlineData("remove", "work", "bar arg value")]
|
||||
[InlineData("run", "auth", "bad arg value")]
|
||||
[InlineData("run", "labels", "bad arg value")]
|
||||
[InlineData("run", "monitorsocketaddress", "bad arg value")]
|
||||
[InlineData("run", "name", "bad arg value")]
|
||||
[InlineData("run", "pat", "bad arg value")]
|
||||
[InlineData("run", "runnergroup", "bad arg value")]
|
||||
[InlineData("run", "token", "bad arg value")]
|
||||
[InlineData("run", "url", "bad arg value")]
|
||||
[InlineData("run", "username", "bad arg value")]
|
||||
[InlineData("run", "windowslogonaccount", "bad arg value")]
|
||||
[InlineData("run", "windowslogonpassword", "bad arg value")]
|
||||
[InlineData("run", "work", "bad arg value")]
|
||||
[InlineData("warmup", "auth", "bad arg value")]
|
||||
[InlineData("warmup", "labels", "bad arg value")]
|
||||
[InlineData("warmup", "monitorsocketaddress", "bad arg value")]
|
||||
[InlineData("warmup", "name", "bad arg value")]
|
||||
[InlineData("warmup", "pat", "bad arg value")]
|
||||
[InlineData("warmup", "runnergroup", "bad arg value")]
|
||||
[InlineData("warmup", "token", "bad arg value")]
|
||||
[InlineData("warmup", "url", "bad arg value")]
|
||||
[InlineData("warmup", "username", "bad arg value")]
|
||||
[InlineData("warmup", "windowslogonaccount", "bad arg value")]
|
||||
[InlineData("warmup", "windowslogonpassword", "bad arg value")]
|
||||
[InlineData("warmup", "work", "bad arg value")]
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateInvalidArgCommandCombination(string validCommand, string arg, string argValue)
|
||||
public void ValidateArgs()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
||||
var command = new CommandSettings(hc, args: new string[] { "--badargname", "bad arg value" });
|
||||
|
||||
// Assert.
|
||||
Assert.Contains(arg, command.Validate());
|
||||
Assert.Contains("badargname", command.Validate());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -810,73 +758,6 @@ namespace GitHub.Runner.Common.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("configure", "help")]
|
||||
[InlineData("configure", "version")]
|
||||
[InlineData("configure", "commit")]
|
||||
[InlineData("configure", "check")]
|
||||
[InlineData("configure", "disableupdate")]
|
||||
[InlineData("configure", "ephemeral")]
|
||||
[InlineData("configure", "replace")]
|
||||
[InlineData("configure", "runasservice")]
|
||||
[InlineData("configure", "unattended")]
|
||||
[InlineData("remove", "help")]
|
||||
[InlineData("remove", "version")]
|
||||
[InlineData("remove", "commit")]
|
||||
[InlineData("remove", "check")]
|
||||
[InlineData("run", "help")]
|
||||
[InlineData("run", "version")]
|
||||
[InlineData("run", "commit")]
|
||||
[InlineData("run", "check")]
|
||||
[InlineData("run", "once")]
|
||||
[InlineData("warmup", "help")]
|
||||
[InlineData("warmup", "version")]
|
||||
[InlineData("warmup", "commit")]
|
||||
[InlineData("warmup", "check")]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateGoodFlagCommandCombination(string validCommand, string flag)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{flag}" });
|
||||
|
||||
// Assert.
|
||||
Assert.True(command.Validate().Count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("configure", "auth", "good arg value")]
|
||||
[InlineData("configure", "labels", "good arg value")]
|
||||
[InlineData("configure", "monitorsocketaddress", "good arg value")]
|
||||
[InlineData("configure", "name", "good arg value")]
|
||||
[InlineData("configure", "pat", "good arg value")]
|
||||
[InlineData("configure", "runnergroup", "good arg value")]
|
||||
[InlineData("configure", "token", "good arg value")]
|
||||
[InlineData("configure", "url", "good arg value")]
|
||||
[InlineData("configure", "username", "good arg value")]
|
||||
[InlineData("configure", "windowslogonaccount", "good arg value")]
|
||||
[InlineData("configure", "windowslogonpassword", "good arg value")]
|
||||
[InlineData("configure", "work", "good arg value")]
|
||||
[InlineData("remove", "token", "good arg value")]
|
||||
[InlineData("remove", "pat", "good arg value")]
|
||||
[InlineData("run", "startuptype", "good arg value")]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", nameof(CommandSettings))]
|
||||
public void ValidateGoodArgCommandCombination(string validCommand, string arg, string argValue)
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
// Arrange.
|
||||
var command = new CommandSettings(hc, args: new string[] { validCommand, $"--{arg}", argValue });
|
||||
|
||||
// Assert.
|
||||
Assert.True(command.Validate().Count == 0);
|
||||
}
|
||||
}
|
||||
|
||||
private TestHostContext CreateTestContext([CallerMemberName] string testName = "")
|
||||
{
|
||||
TestHostContext hc = new TestHostContext(this, testName);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#if !(OS_OSX && ARM64)
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -51,9 +50,9 @@ namespace GitHub.Runner.Common.Tests.Listener
|
||||
var response = await client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "https://github.com/actions/runner/releases/latest"));
|
||||
if (response.StatusCode == System.Net.HttpStatusCode.Redirect)
|
||||
{
|
||||
var redirectUrl = response.Headers.Location.ToString();
|
||||
var redirect = await response.Content.ReadAsStringAsync();
|
||||
Regex regex = new Regex(@"/runner/releases/tag/v(?<version>\d+\.\d+\.\d+)");
|
||||
var match = regex.Match(redirectUrl);
|
||||
var match = regex.Match(redirect);
|
||||
if (match.Success)
|
||||
{
|
||||
latestVersion = match.Groups["version"].Value;
|
||||
@@ -64,10 +63,6 @@ namespace GitHub.Runner.Common.Tests.Listener
|
||||
_packageUrl = $"https://github.com/actions/runner/releases/download/v{latestVersion}/actions-runner-{BuildConstants.RunnerPackage.PackageName}-{latestVersion}.zip";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("The latest runner version could not be determined so a download URL could not be generated for it. Please check the location header of the redirect response of 'https://github.com/actions/runner/releases/latest'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,4 +791,3 @@ namespace GitHub.Runner.Common.Tests.Listener
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -166,9 +166,9 @@ namespace GitHub.Runner.Common.Tests
|
||||
string binDir = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/bin");
|
||||
|
||||
#if OS_WINDOWS
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node12\bin\node");
|
||||
#else
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node12/bin/node");
|
||||
#endif
|
||||
string hashFilesScript = Path.Combine(binDir, "hashFiles");
|
||||
var hashResult = string.Empty;
|
||||
@@ -228,9 +228,9 @@ namespace GitHub.Runner.Common.Tests
|
||||
string binDir = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/bin");
|
||||
|
||||
#if OS_WINDOWS
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node12\bin\node");
|
||||
#else
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node12/bin/node");
|
||||
#endif
|
||||
string hashFilesScript = Path.Combine(binDir, "hashFiles");
|
||||
var hashResult = string.Empty;
|
||||
|
||||
@@ -27,9 +27,9 @@ namespace GitHub.Runner.Common.Tests
|
||||
try
|
||||
{
|
||||
#if OS_WINDOWS
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node16\bin\node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"..\_layout\externals\node12\bin\node");
|
||||
#else
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node16/bin/node");
|
||||
string node = Path.Combine(TestUtil.GetSrcPath(), @"../_layout/externals/node12/bin/node");
|
||||
hc.EnqueueInstance<IProcessInvoker>(new ProcessInvokerWrapper());
|
||||
#endif
|
||||
var startInfo = new ProcessStartInfo(node, "-e \"setTimeout(function(){{}}, 15 * 1000);\"");
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
using (var hostContext = Setup(featureFlagState: "false"))
|
||||
{
|
||||
var stepSummaryFile = Path.Combine(_rootDirectory, "feature-off");
|
||||
|
||||
|
||||
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
||||
_jobExecutionContext.Complete();
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
using (var hostContext = Setup())
|
||||
{
|
||||
var stepSummaryFile = Path.Combine(_rootDirectory, "empty-file");
|
||||
File.WriteAllBytes(stepSummaryFile, new byte[CreateStepSummaryCommand.AttachmentSizeLimit + 1]);
|
||||
File.WriteAllBytes(stepSummaryFile, new byte[128 * 1024 + 1]);
|
||||
|
||||
_createStepCommand.ProcessCommand(_executionContext.Object, stepSummaryFile, null);
|
||||
_jobExecutionContext.Complete();
|
||||
|
||||
@@ -6,8 +6,6 @@ using System.Threading;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using GitHub.DistributedTask.WebApi;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
||||
@@ -726,149 +724,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
|
||||
return hc;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void GetExpressionValues_ContainerStepHost()
|
||||
{
|
||||
using (TestHostContext hc = CreateTestContext())
|
||||
{
|
||||
const string source = "/home/username/Projects/work/runner/_layout";
|
||||
var containerInfo = new ContainerInfo();
|
||||
containerInfo.ContainerId = "test";
|
||||
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_work", "/__w");
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_temp", "/__t");
|
||||
containerInfo.AddPathTranslateMapping($"{source}/externals", "/__e");
|
||||
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_work/_temp/_github_home", "/github/home");
|
||||
containerInfo.AddPathTranslateMapping($"{source}/_work/_temp/_github_workflow", "/github/workflow");
|
||||
|
||||
foreach (var v in new List<string>() {
|
||||
$"{source}/_work",
|
||||
$"{source}/externals",
|
||||
$"{source}/_work/_temp",
|
||||
$"{source}/_work/_actions",
|
||||
$"{source}/_work/_tool",
|
||||
})
|
||||
{
|
||||
containerInfo.MountVolumes.Add(new MountVolume(v, containerInfo.TranslateToContainerPath(v)));
|
||||
};
|
||||
|
||||
var stepHost = new ContainerStepHost();
|
||||
stepHost.Container = containerInfo;
|
||||
|
||||
var ec = new Runner.Worker.ExecutionContext();
|
||||
ec.Initialize(hc);
|
||||
|
||||
var inputGithubContext = new GitHubContext();
|
||||
var inputeRunnerContext = new RunnerContext();
|
||||
|
||||
// string context data
|
||||
inputGithubContext["action_path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_actions/owner/composite/main");
|
||||
inputGithubContext["action"] = new StringContextData("__owner_composite");
|
||||
inputGithubContext["api_url"] = new StringContextData("https://api.github.com/custom/path");
|
||||
inputGithubContext["env"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_runner_file_commands/set_env_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
inputGithubContext["path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_runner_file_commands/add_path_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
inputGithubContext["event_path"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp/_github_workflow/event.json");
|
||||
inputGithubContext["repository"] = new StringContextData("owner/repo-name");
|
||||
inputGithubContext["run_id"] = new StringContextData("2033211332");
|
||||
inputGithubContext["workflow"] = new StringContextData("Name of Workflow");
|
||||
inputGithubContext["workspace"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/step-order/step-order");
|
||||
inputeRunnerContext["temp"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_temp");
|
||||
inputeRunnerContext["tool_cache"] = new StringContextData("/home/username/Projects/work/runner/_layout/_work/_tool");
|
||||
|
||||
// dictionary context data
|
||||
var githubEvent = new DictionaryContextData();
|
||||
githubEvent["inputs"] = null;
|
||||
githubEvent["ref"] = new StringContextData("refs/heads/main");
|
||||
githubEvent["repository"] = new DictionaryContextData();
|
||||
githubEvent["sender"] = new DictionaryContextData();
|
||||
githubEvent["workflow"] = new StringContextData(".github/workflows/composite_step_host_translate.yaml");
|
||||
|
||||
inputGithubContext["event"] = githubEvent;
|
||||
|
||||
ec.ExpressionValues["github"] = inputGithubContext;
|
||||
ec.ExpressionValues["runner"] = inputeRunnerContext;
|
||||
|
||||
var ecExpect = new Runner.Worker.ExecutionContext();
|
||||
ecExpect.Initialize(hc);
|
||||
|
||||
var expectedGithubEvent = new DictionaryContextData();
|
||||
expectedGithubEvent["inputs"] = null;
|
||||
expectedGithubEvent["ref"] = new StringContextData("refs/heads/main");
|
||||
expectedGithubEvent["repository"] = new DictionaryContextData();
|
||||
expectedGithubEvent["sender"] = new DictionaryContextData();
|
||||
expectedGithubEvent["workflow"] = new StringContextData(".github/workflows/composite_step_host_translate.yaml");
|
||||
var expectedGithubContext = new GitHubContext();
|
||||
var expectedRunnerContext = new RunnerContext();
|
||||
expectedGithubContext["action_path"] = new StringContextData("/__w/_actions/owner/composite/main");
|
||||
expectedGithubContext["action"] = new StringContextData("__owner_composite");
|
||||
expectedGithubContext["api_url"] = new StringContextData("https://api.github.com/custom/path");
|
||||
expectedGithubContext["env"] = new StringContextData("/__w/_temp/_runner_file_commands/set_env_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
expectedGithubContext["path"] = new StringContextData("/__w/_temp/_runner_file_commands/add_path_265698aa-7f38-40f5-9316-5c01a3153672");
|
||||
expectedGithubContext["event_path"] = new StringContextData("/github/workflow/event.json");
|
||||
expectedGithubContext["repository"] = new StringContextData("owner/repo-name");
|
||||
expectedGithubContext["run_id"] = new StringContextData("2033211332");
|
||||
expectedGithubContext["workflow"] = new StringContextData("Name of Workflow");
|
||||
expectedGithubContext["workspace"] = new StringContextData("/__w/step-order/step-order");
|
||||
expectedGithubContext["event"] = expectedGithubEvent;
|
||||
expectedRunnerContext["temp"] = new StringContextData("/__w/_temp");
|
||||
expectedRunnerContext["tool_cache"] = new StringContextData("/__w/_tool");
|
||||
|
||||
ecExpect.ExpressionValues["github"] = expectedGithubContext;
|
||||
ecExpect.ExpressionValues["runner"] = expectedRunnerContext;
|
||||
|
||||
var translatedExpressionValues = ec.GetExpressionValues(stepHost);
|
||||
|
||||
foreach (var contextName in new string[] { "github", "runner" })
|
||||
{
|
||||
var dict = translatedExpressionValues[contextName].AssertDictionary($"expected context github to be a dictionary");
|
||||
var expectedExpressionValues = ecExpect.ExpressionValues[contextName].AssertDictionary("expect dict");
|
||||
foreach (var key in dict.Keys.ToList())
|
||||
{
|
||||
if (dict[key] is StringContextData)
|
||||
{
|
||||
var expect = dict[key].AssertString("expect string");
|
||||
var outcome = expectedExpressionValues[key].AssertString("expect string");
|
||||
Assert.Equal(expect.Value, outcome.Value);
|
||||
}
|
||||
else if (dict[key] is DictionaryContextData || dict[key] is CaseSensitiveDictionaryContextData)
|
||||
{
|
||||
var expectDict = dict[key].AssertDictionary("expect dict");
|
||||
var actualDict = expectedExpressionValues[key].AssertDictionary("expect dict");
|
||||
Assert.True(ExpressionValuesAssertEqual(expectDict, actualDict));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ExpressionValuesAssertEqual(DictionaryContextData expect, DictionaryContextData actual)
|
||||
{
|
||||
foreach (var key in expect.Keys.ToList())
|
||||
{
|
||||
if (expect[key] is StringContextData)
|
||||
{
|
||||
var expectValue = expect[key].AssertString("expect string");
|
||||
var actualValue = actual[key].AssertString("expect string");
|
||||
if (expectValue.Equals(actualValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (expect[key] is DictionaryContextData || expect[key] is CaseSensitiveDictionaryContextData)
|
||||
{
|
||||
var expectDict = expect[key].AssertDictionary("expect dict");
|
||||
var actualDict = actual[key].AssertDictionary("expect dict");
|
||||
if (!ExpressionValuesAssertEqual(expectDict, actualDict))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.CompilerServices;
|
||||
using GitHub.Runner.Sdk;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
@@ -937,19 +937,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
public void CaptureTelemetryForGitUnsafeRepository()
|
||||
{
|
||||
using (Setup())
|
||||
using (_outputManager)
|
||||
{
|
||||
Process("fatal: unsafe repository ('/github/workspace' is owned by someone else)");
|
||||
Assert.Contains("fatal: unsafe repository ('/github/workspace' is owned by someone else)", _executionContext.Object.StepTelemetry.ErrorMessages);
|
||||
}
|
||||
}
|
||||
|
||||
private TestHostContext Setup(
|
||||
[CallerMemberName] string name = "",
|
||||
IssueMatchersConfig matchers = null,
|
||||
@@ -975,8 +962,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Variables = _variables,
|
||||
WriteDebug = true,
|
||||
});
|
||||
_executionContext.Setup(x => x.StepTelemetry)
|
||||
.Returns(new DTWebApi.ActionsStepTelemetry());
|
||||
_executionContext.Setup(x => x.GetMatchers())
|
||||
.Returns(matchers?.Matchers ?? new List<IssueMatcherConfig>());
|
||||
_executionContext.Setup(x => x.Add(It.IsAny<OnMatcherChanged>()))
|
||||
|
||||
@@ -7,9 +7,6 @@ using Xunit;
|
||||
using GitHub.Runner.Worker;
|
||||
using GitHub.Runner.Worker.Handlers;
|
||||
using GitHub.Runner.Worker.Container;
|
||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||
using System.Linq;
|
||||
using GitHub.DistributedTask.Pipelines;
|
||||
|
||||
namespace GitHub.Runner.Common.Tests.Worker
|
||||
{
|
||||
@@ -32,7 +29,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
return hc;
|
||||
}
|
||||
|
||||
#if OS_LINUX
|
||||
[Fact]
|
||||
[Trait("Level", "L0")]
|
||||
[Trait("Category", "Worker")]
|
||||
@@ -109,6 +105,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
||||
Assert.Equal("node16", nodeVersion);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64;osx-arm64</RuntimeIdentifiers>
|
||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||
<NoWarn>NU1701;NU1603;NU1603;xUnit2013;</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
26
src/dev.sh
26
src/dev.sh
@@ -2,7 +2,7 @@
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# ./dev.sh build/layout/test/package [Debug/Release]
|
||||
# ./dev.sh build/layout/test/package [Debug/Release] [linux-x64|linux-x86|linux-arm64|linux-arm|osx-x64|win-x64|win-x86] [use-broker]
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
@@ -11,6 +11,7 @@ set -e
|
||||
DEV_CMD=$1
|
||||
DEV_CONFIG=$2
|
||||
DEV_TARGET_RUNTIME=$3
|
||||
DEV_USE_BROKER=$4
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
||||
@@ -22,7 +23,7 @@ DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
||||
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
||||
PACKAGE_TRIMS_DIR="$SCRIPT_DIR/../_package_trims"
|
||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||
DOTNETSDK_VERSION="6.0.300"
|
||||
DOTNETSDK_VERSION="6.0.100"
|
||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||
RUNNER_VERSION=$(cat runnerversion)
|
||||
|
||||
@@ -54,12 +55,6 @@ elif [[ "$CURRENT_PLATFORM" == 'linux' ]]; then
|
||||
fi
|
||||
elif [[ "$CURRENT_PLATFORM" == 'darwin' ]]; then
|
||||
RUNTIME_ID='osx-x64'
|
||||
if command -v uname > /dev/null; then
|
||||
CPU_NAME=$(uname -m)
|
||||
case $CPU_NAME in
|
||||
arm64) RUNTIME_ID="osx-arm64";;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$DEV_TARGET_RUNTIME" ]]; then
|
||||
@@ -69,7 +64,7 @@ fi
|
||||
# Make sure current platform support publish the dotnet runtime
|
||||
# Windows can publish win-x86/x64
|
||||
# Linux can publish linux-x64/arm/arm64
|
||||
# OSX can publish osx-x64/arm64
|
||||
# OSX can publish osx-x64
|
||||
if [[ "$CURRENT_PLATFORM" == 'windows' ]]; then
|
||||
if [[ ("$RUNTIME_ID" != 'win-x86') && ("$RUNTIME_ID" != 'win-x64') ]]; then
|
||||
echo "Failed: Can't build $RUNTIME_ID package $CURRENT_PLATFORM" >&2
|
||||
@@ -81,12 +76,19 @@ elif [[ "$CURRENT_PLATFORM" == 'linux' ]]; then
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "$CURRENT_PLATFORM" == 'darwin' ]]; then
|
||||
if [[ ("$RUNTIME_ID" != 'osx-x64') && ("$RUNTIME_ID" != 'osx-arm64') ]]; then
|
||||
if [[ ("$RUNTIME_ID" != 'osx-x64') ]]; then
|
||||
echo "Failed: Can't build $RUNTIME_ID package $CURRENT_PLATFORM" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$DEV_USE_BROKER" ]; then
|
||||
USE_BROKER='-p:USE_BROKER="true"'
|
||||
else
|
||||
USE_BROKER=''
|
||||
fi
|
||||
|
||||
|
||||
function failed()
|
||||
{
|
||||
local error=${1:-Undefined error}
|
||||
@@ -120,13 +122,13 @@ function heading()
|
||||
function build ()
|
||||
{
|
||||
heading "Building ..."
|
||||
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
||||
dotnet msbuild -t:Build -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" $USE_BROKER ./dir.proj || failed build
|
||||
}
|
||||
|
||||
function layout ()
|
||||
{
|
||||
heading "Create layout ..."
|
||||
dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" ./dir.proj || failed build
|
||||
dotnet msbuild -t:layout -p:PackageRuntime="${RUNTIME_ID}" -p:BUILDCONFIG="${BUILD_CONFIG}" -p:RunnerVersion="${RUNNER_VERSION}" $USE_BROKER ./dir.proj || failed build
|
||||
|
||||
#change execution flag to allow running with sudo
|
||||
if [[ ("$CURRENT_PLATFORM" == "linux") || ("$CURRENT_PLATFORM" == "darwin") ]]; then
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
<Target Name="Test" DependsOnTargets="GenerateConstant">
|
||||
<Exec Command="dotnet build Test/Test.csproj -c $(BUILDCONFIG) /p:PackageRuntime=$(PackageRuntime)" ConsoleToMSBuild="true" />
|
||||
<Exec Command="dotnet test Test/Test.csproj -c $(BUILDCONFIG) --no-build --logger:trx" ConsoleToMSBuild="true" />
|
||||
<Exec Command="dotnet test Test/Test.csproj --no-build --logger:trx" ConsoleToMSBuild="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="Layout" DependsOnTargets="Clean;Build">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "6.0.300"
|
||||
"version": "6.0.100"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.292.0
|
||||
2.289.2
|
||||
|
||||
Reference in New Issue
Block a user