mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
11 Commits
v2.301.0
...
users/jww3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3e42889af | ||
|
|
f3961c4895 | ||
|
|
cb89be7aac | ||
|
|
b70f97f183 | ||
|
|
14096a7ee4 | ||
|
|
4eb9adc958 | ||
|
|
efc0a92cc7 | ||
|
|
87ababb858 | ||
|
|
3902257e9d | ||
|
|
7036627d47 | ||
|
|
2eeb90a944 |
@@ -6,9 +6,6 @@
|
|||||||
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
|
"ghcr.io/devcontainers/features/docker-in-docker:1": {},
|
||||||
"ghcr.io/devcontainers/features/dotnet": {
|
"ghcr.io/devcontainers/features/dotnet": {
|
||||||
"version": "6.0.300"
|
"version": "6.0.300"
|
||||||
},
|
|
||||||
"ghcr.io/devcontainers/features/node:1": {
|
|
||||||
"version": "16"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"customizations": {
|
"customizations": {
|
||||||
|
|||||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,5 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: 🛑 Request a feature in the runner application
|
|
||||||
url: https://github.com/orgs/community/discussions/categories/actions-and-packages
|
|
||||||
about: If you have feature requests for GitHub Actions, please use the Actions and Packages section on the Github Product Feedback page.
|
|
||||||
- name: ✅ Support for GitHub Actions
|
- name: ✅ Support for GitHub Actions
|
||||||
url: https://github.community/c/code-to-cloud/52
|
url: https://github.community/c/code-to-cloud/52
|
||||||
about: If you have questions about GitHub Actions or need support writing workflows, please ask in the GitHub Community Support forum.
|
about: If you have questions about GitHub Actions or need support writing workflows, please ask in the GitHub Community Support forum.
|
||||||
|
|||||||
32
.github/ISSUE_TEMPLATE/enhancement_request.md
vendored
Normal file
32
.github/ISSUE_TEMPLATE/enhancement_request.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
---
|
||||||
|
name: 🛑 Request a feature in the runner application
|
||||||
|
about: If you have feature requests for GitHub Actions, please use the "feedback and suggestions for GitHub Actions" link below.
|
||||||
|
title: ''
|
||||||
|
labels: enhancement
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
👋 You're opening a request for an enhancement in the GitHub Actions **runner application**.
|
||||||
|
|
||||||
|
🛑 Please stop if you're not certain that the feature you want is in the runner application - if you have a suggestion for improving GitHub Actions, please see the [GitHub Actions Feedback](https://github.com/github/feedback/discussions/categories/actions-and-packages-feedback) discussion forum which is actively monitored. Using the forum ensures that we route your problem to the correct team. 😃
|
||||||
|
|
||||||
|
Some additional useful links:
|
||||||
|
* If you have found a security issue [please submit it here](https://hackerone.com/github)
|
||||||
|
* If you have questions or issues with the service, writing workflows or actions, then please [visit the GitHub Community Forum's Actions Board](https://github.community/t5/GitHub-Actions/bd-p/actions)
|
||||||
|
* If you are having an issue or have a question about GitHub Actions then please [contact customer support](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-github-actions#contacting-support)
|
||||||
|
|
||||||
|
If you have a feature request that is relevant to this repository, the runner, then please include the information below:
|
||||||
|
-->
|
||||||
|
|
||||||
|
**Describe the enhancement**
|
||||||
|
A clear and concise description of what the features or enhancement you need.
|
||||||
|
|
||||||
|
**Code Snippet**
|
||||||
|
If applicable, add a code snippet.
|
||||||
|
|
||||||
|
**Additional information**
|
||||||
|
Add any other context about the feature here.
|
||||||
|
|
||||||
|
NOTE: if the feature request has been agreed upon then the assignee will create an ADR. See docs/adrs/README.md
|
||||||
@@ -35,7 +35,7 @@ All the configs below can be found in `.vscode/launch.json`.
|
|||||||
If you launch `Run` or `Run [build]`, it starts a process called `Runner.Listener`.
|
If you launch `Run` or `Run [build]`, it starts a process called `Runner.Listener`.
|
||||||
This process will receive any job queued on this repository if the job runs on matching labels (e.g `runs-on: self-hosted`).
|
This process will receive any job queued on this repository if the job runs on matching labels (e.g `runs-on: self-hosted`).
|
||||||
Once a job is received, a `Runner.Listener` starts a new process of `Runner.Worker`.
|
Once a job is received, a `Runner.Listener` starts a new process of `Runner.Worker`.
|
||||||
Since this is a different process, you can't use the same debugger session debug it.
|
Since this is a diferent process, you can't use the same debugger session debug it.
|
||||||
Instead, a parallel debugging session has to be started, using a different launch config.
|
Instead, a parallel debugging session has to be started, using a different launch config.
|
||||||
Luckily, VS Code supports multiple parallel debugging sessions.
|
Luckily, VS Code supports multiple parallel debugging sessions.
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:6.0 as build
|
|||||||
|
|
||||||
ARG RUNNER_VERSION
|
ARG RUNNER_VERSION
|
||||||
ARG RUNNER_ARCH="x64"
|
ARG RUNNER_ARCH="x64"
|
||||||
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.2.0
|
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.1.3
|
||||||
|
|
||||||
RUN apt update -y && apt install curl unzip -y
|
RUN apt update -y && apt install curl unzip -y
|
||||||
|
|
||||||
@@ -19,7 +19,6 @@ FROM mcr.microsoft.com/dotnet/runtime-deps:6.0
|
|||||||
|
|
||||||
ENV RUNNER_ALLOW_RUNASROOT=1
|
ENV RUNNER_ALLOW_RUNASROOT=1
|
||||||
ENV RUNNER_MANUALLY_TRAP_SIG=1
|
ENV RUNNER_MANUALLY_TRAP_SIG=1
|
||||||
ENV ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT=1
|
|
||||||
|
|
||||||
WORKDIR /actions-runner
|
WORKDIR /actions-runner
|
||||||
COPY --from=build /actions-runner .
|
COPY --from=build /actions-runner .
|
||||||
|
|||||||
@@ -1,24 +1,18 @@
|
|||||||
## Features
|
## Features
|
||||||
- Log GitHub RequestId for better traceability (#2332)
|
- Displays the error logs in dedicated sub-sections of the Initialize containers section (#2182)
|
||||||
- Dual upload summary to Actions and Result service (#2334)
|
- Add generateServiceConfig option for configure command (#2226)
|
||||||
- Allow providing extra User-Agent for better correlation (#2370)
|
- Setting debug using GitHub Action variables (#2234)
|
||||||
- Show more information in the runner log (#2377)
|
- run.sh installs SIGINT and SIGTERM traps to gracefully stop runner (#2233, #2240)
|
||||||
- New option to remove local config files (#2367)
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
- Split by regex (#2333)
|
- Use Global.Variables instead of JobContext and include action path/ref in the message. (#2214)
|
||||||
- Treat jitconfig as secret (#2335)
|
|
||||||
- Add Header/Footer to multi-line message in StdoutTraceListener (#2336)
|
|
||||||
- Update Node dependencies (#2381)
|
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
- Make runner image print diag log to STDOUT (#2331)
|
- Allow '--disableupdate' in create-latest-svc.sh (#2201)
|
||||||
- Update Node.js to 16.16.0 (#2371)
|
- Fix markup for support link (#2114)
|
||||||
- Add a disclaimer for which runner version is available to a given tenant (#2362)
|
- Add runner devcontainer (#2187)
|
||||||
|
- Setup linter for Runner (#2211, #2213, #2216)
|
||||||
_Note: Actions Runner follows a progressive release policy, so the latest release might not be available to your enterprise, organization, or repository yet.
|
|
||||||
To confirm which version of the Actions Runner you should expect, please view the download instructions for your enterprise, organization, or repository.
|
|
||||||
See https://docs.github.com/en/enterprise-cloud@latest/actions/hosting-your-own-runners/adding-self-hosted-runners_
|
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.301.0
|
<Update to ./src/runnerversion when creating release>
|
||||||
|
|||||||
2
src/Misc/contentHash/externals/linux-arm
vendored
2
src/Misc/contentHash/externals/linux-arm
vendored
@@ -1 +1 @@
|
|||||||
3807dcbf947e840c33535fb466b096d76bf09e5c0254af8fc8cbbb24c6388222
|
6ed30a2c1ee403a610d63e82bb230b9ba846a9c25cec9e4ea8672fb6ed4e1a51
|
||||||
2
src/Misc/contentHash/externals/linux-arm64
vendored
2
src/Misc/contentHash/externals/linux-arm64
vendored
@@ -1 +1 @@
|
|||||||
ee01eee80cd8a460a4b9780ee13fdd20f25c59e754b4ccd99df55fbba2a85634
|
711c30c51ec52c9b7a9a2eb399d6ab2ab5ee1dc72de11879f2f36f919f163d78
|
||||||
2
src/Misc/contentHash/externals/linux-x64
vendored
2
src/Misc/contentHash/externals/linux-x64
vendored
@@ -1 +1 @@
|
|||||||
a9fb9c14e24e79aec97d4da197dd7bfc6364297d6fce573afb2df48cc9a931f8
|
a49479ca4b4988a06c097e8d22c51fd08a11c13f40807366236213d0e008cf6a
|
||||||
2
src/Misc/contentHash/externals/osx-arm64
vendored
2
src/Misc/contentHash/externals/osx-arm64
vendored
@@ -1 +1 @@
|
|||||||
a4e0e8fc62eba0967a39c7d693dcd0aeb8b2bed0765f9c38df80d42884f65341
|
cc4708962a80325de0baa5ae8484e0cb9ae976ac6a4178c1c0d448b8c52bd7f7
|
||||||
2
src/Misc/contentHash/externals/osx-x64
vendored
2
src/Misc/contentHash/externals/osx-x64
vendored
@@ -1 +1 @@
|
|||||||
17ac17fbe785b3d6fa2868d8d17185ebfe0c90b4b0ddf6b67eac70e42bcd989b
|
8e97df75230b843462a9b4c578ccec604ee4b4a1066120c85b04374317fa372b
|
||||||
2
src/Misc/contentHash/externals/win-arm64
vendored
2
src/Misc/contentHash/externals/win-arm64
vendored
@@ -1 +1 @@
|
|||||||
89f24657a550f1e818b0e9975e5b80edcf4dd22b7d4bccbb9e48e37f45d30fb1
|
e5dace2d41cc0682d096dcce4970079ad48ec7107e46195970eecfdb3df2acef
|
||||||
|
|||||||
2
src/Misc/contentHash/externals/win-x64
vendored
2
src/Misc/contentHash/externals/win-x64
vendored
@@ -1 +1 @@
|
|||||||
24fd131b5dce33ef16038b771407bc0507da8682a72fb3b7780607235f76db0b
|
f75a671e5a188c76680739689aa75331a2c09d483dce9c80023518c48fd67a18
|
||||||
43
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
43
src/Misc/expressionFunc/hashFiles/package-lock.json
generated
@@ -14,7 +14,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^12.7.12",
|
"@types/node": "^12.7.12",
|
||||||
"@typescript-eslint/parser": "^5.15.0",
|
"@typescript-eslint/parser": "^5.15.0",
|
||||||
"@vercel/ncc": "^0.36.0",
|
"@zeit/ncc": "^0.20.5",
|
||||||
"eslint": "^8.11.0",
|
"eslint": "^8.11.0",
|
||||||
"eslint-plugin-github": "^4.3.5",
|
"eslint-plugin-github": "^4.3.5",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
@@ -346,10 +346,11 @@
|
|||||||
"url": "https://opencollective.com/typescript-eslint"
|
"url": "https://opencollective.com/typescript-eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vercel/ncc": {
|
"node_modules/@zeit/ncc": {
|
||||||
"version": "0.36.0",
|
"version": "0.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.20.5.tgz",
|
||||||
"integrity": "sha512-/ZTUJ/ZkRt694k7KJNimgmHjtQcRuVwsST2Z6XfYveQIuBbHR+EqkTc1jfgPkQmMyk/vtpxo3nVxe8CNuau86A==",
|
"integrity": "sha512-XU6uzwvv95DqxciQx+aOLhbyBx/13ky+RK1y88Age9Du3BlA4mMPCy13BGjayOrrumOzlq1XV3SD/BWiZENXlw==",
|
||||||
|
"deprecated": "@zeit/ncc is no longer maintained. Please use @vercel/ncc instead.",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"ncc": "dist/ncc/cli.js"
|
"ncc": "dist/ncc/cli.js"
|
||||||
@@ -1721,9 +1722,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
@@ -1823,9 +1824,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimatch": {
|
"node_modules/minimatch": {
|
||||||
"version": "3.1.2",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
},
|
},
|
||||||
@@ -2746,10 +2747,10 @@
|
|||||||
"eslint-visitor-keys": "^3.0.0"
|
"eslint-visitor-keys": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@vercel/ncc": {
|
"@zeit/ncc": {
|
||||||
"version": "0.36.0",
|
"version": "0.20.5",
|
||||||
"resolved": "https://registry.npmjs.org/@vercel/ncc/-/ncc-0.36.0.tgz",
|
"resolved": "https://registry.npmjs.org/@zeit/ncc/-/ncc-0.20.5.tgz",
|
||||||
"integrity": "sha512-/ZTUJ/ZkRt694k7KJNimgmHjtQcRuVwsST2Z6XfYveQIuBbHR+EqkTc1jfgPkQmMyk/vtpxo3nVxe8CNuau86A==",
|
"integrity": "sha512-XU6uzwvv95DqxciQx+aOLhbyBx/13ky+RK1y88Age9Du3BlA4mMPCy13BGjayOrrumOzlq1XV3SD/BWiZENXlw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"acorn": {
|
"acorn": {
|
||||||
@@ -3755,9 +3756,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
||||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
@@ -3839,9 +3840,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimatch": {
|
"minimatch": {
|
||||||
"version": "3.1.2",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^12.7.12",
|
"@types/node": "^12.7.12",
|
||||||
"@typescript-eslint/parser": "^5.15.0",
|
"@typescript-eslint/parser": "^5.15.0",
|
||||||
"@vercel/ncc": "^0.36.0",
|
"@zeit/ncc": "^0.20.5",
|
||||||
"eslint": "^8.11.0",
|
"eslint": "^8.11.0",
|
||||||
"eslint-plugin-github": "^4.3.5",
|
"eslint-plugin-github": "^4.3.5",
|
||||||
"prettier": "^1.19.1",
|
"prettier": "^1.19.1",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ PRECACHE=$2
|
|||||||
NODE_URL=https://nodejs.org/dist
|
NODE_URL=https://nodejs.org/dist
|
||||||
UNOFFICIAL_NODE_URL=https://unofficial-builds.nodejs.org/download/release
|
UNOFFICIAL_NODE_URL=https://unofficial-builds.nodejs.org/download/release
|
||||||
NODE12_VERSION="12.22.7"
|
NODE12_VERSION="12.22.7"
|
||||||
NODE16_VERSION="16.16.0"
|
NODE16_VERSION="16.13.0"
|
||||||
|
|
||||||
get_abs_path() {
|
get_abs_path() {
|
||||||
# exploits the fact that pwd will print abs path when no args
|
# exploits the fact that pwd will print abs path when no args
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -90,6 +90,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static class Args
|
public static class Args
|
||||||
{
|
{
|
||||||
public static readonly string Auth = "auth";
|
public static readonly string Auth = "auth";
|
||||||
|
public static readonly string JitConfig = "jitconfig";
|
||||||
public static readonly string Labels = "labels";
|
public static readonly string Labels = "labels";
|
||||||
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
||||||
public static readonly string Name = "name";
|
public static readonly string Name = "name";
|
||||||
@@ -104,13 +105,11 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string Token = "token";
|
public static readonly string Token = "token";
|
||||||
public static readonly string PAT = "pat";
|
public static readonly string PAT = "pat";
|
||||||
public static readonly string WindowsLogonPassword = "windowslogonpassword";
|
public static readonly string WindowsLogonPassword = "windowslogonpassword";
|
||||||
public static readonly string JitConfig = "jitconfig";
|
|
||||||
public static string[] Secrets => new[]
|
public static string[] Secrets => new[]
|
||||||
{
|
{
|
||||||
PAT,
|
PAT,
|
||||||
Token,
|
Token,
|
||||||
WindowsLogonPassword,
|
WindowsLogonPassword,
|
||||||
JitConfig,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +130,6 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string Ephemeral = "ephemeral";
|
public static readonly string Ephemeral = "ephemeral";
|
||||||
public static readonly string GenerateServiceConfig = "generateServiceConfig";
|
public static readonly string GenerateServiceConfig = "generateServiceConfig";
|
||||||
public static readonly string Help = "help";
|
public static readonly string Help = "help";
|
||||||
public static readonly string Local = "local";
|
|
||||||
public static readonly string Replace = "replace";
|
public static readonly string Replace = "replace";
|
||||||
public static readonly string DisableUpdate = "disableupdate";
|
public static readonly string DisableUpdate = "disableupdate";
|
||||||
public static readonly string Once = "once"; // Keep this around since customers still relies on it
|
public static readonly string Once = "once"; // Keep this around since customers still relies on it
|
||||||
@@ -159,16 +157,13 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||||
public static readonly Guid TelemetryRecordId = new Guid("11111111-1111-1111-1111-111111111111");
|
|
||||||
public static readonly string WorkerCrash = "WORKER_CRASH";
|
public static readonly string WorkerCrash = "WORKER_CRASH";
|
||||||
public static readonly string LowDiskSpace = "LOW_DISK_SPACE";
|
public static readonly string LowDiskSpace = "LOW_DISK_SPACE";
|
||||||
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
||||||
public static readonly string ResultsUploadFailure = "RESULTS_UPLOAD_FAILURE";
|
|
||||||
public static readonly string UnsupportedCommandMessage = "The `{0}` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/";
|
public static readonly string UnsupportedCommandMessage = "The `{0}` command is deprecated and will be disabled soon. Please upgrade to using Environment Files. For more information see: https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/";
|
||||||
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
||||||
public static readonly string UnsupportedStopCommandTokenDisabled = "You cannot use a endToken that is an empty string, the string 'pause-logging', or another workflow command. For more information see: https://docs.github.com/actions/learn-github-actions/workflow-commands-for-github-actions#example-stopping-and-starting-workflow-commands or opt into insecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS` environment variable to `true`.";
|
public static readonly string UnsupportedStopCommandTokenDisabled = "You cannot use a endToken that is an empty string, the string 'pause-logging', or another workflow command. For more information see: https://docs.github.com/actions/learn-github-actions/workflow-commands-for-github-actions#example-stopping-and-starting-workflow-commands or opt into insecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS` environment variable to `true`.";
|
||||||
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
||||||
public static readonly string SummaryUploadError = "$GITHUB_STEP_SUMMARY upload aborted, an error occurred when uploading the summary. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
|
||||||
public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: {0}. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.";
|
public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. Please update the following actions to use Node.js 16: {0}. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/.";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -226,20 +226,6 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
_userAgents.Add(new ProductInfoHeaderValue("CommitSHA", BuildConstants.Source.CommitHash));
|
_userAgents.Add(new ProductInfoHeaderValue("CommitSHA", BuildConstants.Source.CommitHash));
|
||||||
|
|
||||||
var extraUserAgent = Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_EXTRA_USER_AGENT");
|
|
||||||
if (!string.IsNullOrEmpty(extraUserAgent))
|
|
||||||
{
|
|
||||||
var extraUserAgentSplit = extraUserAgent.Split('/', StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
if (extraUserAgentSplit.Length != 2)
|
|
||||||
{
|
|
||||||
_trace.Error($"GITHUB_ACTIONS_RUNNER_EXTRA_USER_AGENT is not in the format of 'name/version'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
var extraUserAgentHeader = new ProductInfoHeaderValue(extraUserAgentSplit[0], extraUserAgentSplit[1]);
|
|
||||||
_trace.Info($"Adding extra user agent '{extraUserAgentHeader}' to all HTTP requests.");
|
|
||||||
_userAgents.Add(extraUserAgentHeader);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetDirectory(WellKnownDirectory directory)
|
public string GetDirectory(WellKnownDirectory directory)
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ using GitHub.Runner.Sdk;
|
|||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using GitHub.Services.WebApi.Utilities.Internal;
|
using GitHub.Services.WebApi.Utilities.Internal;
|
||||||
using GitHub.Services.Results.Client;
|
|
||||||
using GitHub.Services.OAuth;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
@@ -24,13 +22,11 @@ namespace GitHub.Runner.Common
|
|||||||
Task ConnectAsync(VssConnection jobConnection);
|
Task ConnectAsync(VssConnection jobConnection);
|
||||||
|
|
||||||
void InitializeWebsocketClient(ServiceEndpoint serviceEndpoint);
|
void InitializeWebsocketClient(ServiceEndpoint serviceEndpoint);
|
||||||
void InitializeResultsClient(Uri uri, string token);
|
|
||||||
|
|
||||||
// logging and console
|
// logging and console
|
||||||
Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken);
|
Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken);
|
||||||
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long? startLine, CancellationToken cancellationToken);
|
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long? startLine, CancellationToken cancellationToken);
|
||||||
Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken);
|
Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken);
|
||||||
Task CreateStepSymmaryAsync(string planId, string jobId, string stepId, string file, CancellationToken cancellationToken);
|
|
||||||
Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken);
|
Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken);
|
||||||
Task<Timeline> CreateTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
Task<Timeline> CreateTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
||||||
Task<List<TimelineRecord>> UpdateTimelineRecordsAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, IEnumerable<TimelineRecord> records, CancellationToken cancellationToken);
|
Task<List<TimelineRecord>> UpdateTimelineRecordsAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, IEnumerable<TimelineRecord> records, CancellationToken cancellationToken);
|
||||||
@@ -44,7 +40,6 @@ namespace GitHub.Runner.Common
|
|||||||
private bool _hasConnection;
|
private bool _hasConnection;
|
||||||
private VssConnection _connection;
|
private VssConnection _connection;
|
||||||
private TaskHttpClient _taskClient;
|
private TaskHttpClient _taskClient;
|
||||||
private ResultsHttpClient _resultsClient;
|
|
||||||
private ClientWebSocket _websocketClient;
|
private ClientWebSocket _websocketClient;
|
||||||
|
|
||||||
private ServiceEndpoint _serviceEndpoint;
|
private ServiceEndpoint _serviceEndpoint;
|
||||||
@@ -148,12 +143,6 @@ namespace GitHub.Runner.Common
|
|||||||
InitializeWebsocketClient(TimeSpan.Zero);
|
InitializeWebsocketClient(TimeSpan.Zero);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void InitializeResultsClient(Uri uri, string token)
|
|
||||||
{
|
|
||||||
var httpMessageHandler = HostContext.CreateHttpClientHandler();
|
|
||||||
this._resultsClient = new ResultsHttpClient(uri, httpMessageHandler, token, disposeHandler: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask DisposeAsync()
|
public ValueTask DisposeAsync()
|
||||||
{
|
{
|
||||||
CloseWebSocket(WebSocketCloseStatus.NormalClosure, CancellationToken.None);
|
CloseWebSocket(WebSocketCloseStatus.NormalClosure, CancellationToken.None);
|
||||||
@@ -316,16 +305,6 @@ namespace GitHub.Runner.Common
|
|||||||
return _taskClient.CreateAttachmentAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, type, name, uploadStream, cancellationToken: cancellationToken);
|
return _taskClient.CreateAttachmentAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, type, name, uploadStream, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task CreateStepSymmaryAsync(string planId, string jobId, string stepId, string file, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (_resultsClient != null)
|
|
||||||
{
|
|
||||||
return _resultsClient.UploadStepSummaryAsync(planId, jobId, stepId, file, cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
throw new InvalidOperationException("Results client is not initialized.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken)
|
public Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ namespace GitHub.Runner.Common
|
|||||||
void Start(Pipelines.AgentJobRequestMessage jobRequest);
|
void Start(Pipelines.AgentJobRequestMessage jobRequest);
|
||||||
void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber = null);
|
void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber = null);
|
||||||
void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource);
|
void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource);
|
||||||
void QueueSummaryUpload(Guid stepRecordId, string name, string path, bool deleteSource);
|
|
||||||
void QueueTimelineRecordUpdate(Guid timelineId, TimelineRecord timelineRecord);
|
void QueueTimelineRecordUpdate(Guid timelineId, TimelineRecord timelineRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@ namespace GitHub.Runner.Common
|
|||||||
private static readonly TimeSpan _delayForWebConsoleLineDequeue = TimeSpan.FromMilliseconds(500);
|
private static readonly TimeSpan _delayForWebConsoleLineDequeue = TimeSpan.FromMilliseconds(500);
|
||||||
private static readonly TimeSpan _delayForTimelineUpdateDequeue = TimeSpan.FromMilliseconds(500);
|
private static readonly TimeSpan _delayForTimelineUpdateDequeue = TimeSpan.FromMilliseconds(500);
|
||||||
private static readonly TimeSpan _delayForFileUploadDequeue = TimeSpan.FromMilliseconds(1000);
|
private static readonly TimeSpan _delayForFileUploadDequeue = TimeSpan.FromMilliseconds(1000);
|
||||||
private static readonly TimeSpan _delayForSummaryUploadDequeue = TimeSpan.FromMilliseconds(1000);
|
|
||||||
|
|
||||||
// Job message information
|
// Job message information
|
||||||
private Guid _scopeIdentifier;
|
private Guid _scopeIdentifier;
|
||||||
@@ -46,8 +44,6 @@ namespace GitHub.Runner.Common
|
|||||||
// queue for file upload (log file or attachment)
|
// queue for file upload (log file or attachment)
|
||||||
private readonly ConcurrentQueue<UploadFileInfo> _fileUploadQueue = new();
|
private readonly ConcurrentQueue<UploadFileInfo> _fileUploadQueue = new();
|
||||||
|
|
||||||
private readonly ConcurrentQueue<SummaryUploadFileInfo> _summaryFileUploadQueue = new();
|
|
||||||
|
|
||||||
// queue for timeline or timeline record update (one queue per timeline)
|
// queue for timeline or timeline record update (one queue per timeline)
|
||||||
private readonly ConcurrentDictionary<Guid, ConcurrentQueue<TimelineRecord>> _timelineUpdateQueue = new();
|
private readonly ConcurrentDictionary<Guid, ConcurrentQueue<TimelineRecord>> _timelineUpdateQueue = new();
|
||||||
|
|
||||||
@@ -60,7 +56,6 @@ namespace GitHub.Runner.Common
|
|||||||
// Task for each queue's dequeue process
|
// Task for each queue's dequeue process
|
||||||
private Task _webConsoleLineDequeueTask;
|
private Task _webConsoleLineDequeueTask;
|
||||||
private Task _fileUploadDequeueTask;
|
private Task _fileUploadDequeueTask;
|
||||||
private Task _summaryUploadDequeueTask;
|
|
||||||
private Task _timelineUpdateDequeueTask;
|
private Task _timelineUpdateDequeueTask;
|
||||||
|
|
||||||
// common
|
// common
|
||||||
@@ -98,20 +93,6 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
_jobServer.InitializeWebsocketClient(serviceEndPoint);
|
_jobServer.InitializeWebsocketClient(serviceEndPoint);
|
||||||
|
|
||||||
// This code is usually wrapped by an instance of IExecutionContext which isn't available here.
|
|
||||||
jobRequest.Variables.TryGetValue("system.github.results_endpoint", out VariableValue resultsEndpointVariable);
|
|
||||||
var resultsReceiverEndpoint = resultsEndpointVariable?.Value;
|
|
||||||
|
|
||||||
if (serviceEndPoint?.Authorization != null &&
|
|
||||||
serviceEndPoint.Authorization.Parameters.TryGetValue("AccessToken", out var accessToken) &&
|
|
||||||
!string.IsNullOrEmpty(accessToken) &&
|
|
||||||
!string.IsNullOrEmpty(resultsReceiverEndpoint))
|
|
||||||
{
|
|
||||||
Trace.Info("Initializing results client");
|
|
||||||
_jobServer.InitializeResultsClient(new Uri(resultsReceiverEndpoint), accessToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (_queueInProcess)
|
if (_queueInProcess)
|
||||||
{
|
{
|
||||||
Trace.Info("No-opt, all queue process tasks are running.");
|
Trace.Info("No-opt, all queue process tasks are running.");
|
||||||
@@ -139,13 +120,10 @@ namespace GitHub.Runner.Common
|
|||||||
Trace.Info("Start process file upload queue.");
|
Trace.Info("Start process file upload queue.");
|
||||||
_fileUploadDequeueTask = ProcessFilesUploadQueueAsync();
|
_fileUploadDequeueTask = ProcessFilesUploadQueueAsync();
|
||||||
|
|
||||||
Trace.Info("Start results file upload queue.");
|
|
||||||
_summaryUploadDequeueTask = ProcessSummaryUploadQueueAsync();
|
|
||||||
|
|
||||||
Trace.Info("Start process timeline update queue.");
|
Trace.Info("Start process timeline update queue.");
|
||||||
_timelineUpdateDequeueTask = ProcessTimelinesUpdateQueueAsync();
|
_timelineUpdateDequeueTask = ProcessTimelinesUpdateQueueAsync();
|
||||||
|
|
||||||
_allDequeueTasks = new Task[] { _webConsoleLineDequeueTask, _fileUploadDequeueTask, _timelineUpdateDequeueTask, _summaryUploadDequeueTask };
|
_allDequeueTasks = new Task[] { _webConsoleLineDequeueTask, _fileUploadDequeueTask, _timelineUpdateDequeueTask };
|
||||||
_queueInProcess = true;
|
_queueInProcess = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,10 +154,6 @@ namespace GitHub.Runner.Common
|
|||||||
await ProcessFilesUploadQueueAsync(runOnce: true);
|
await ProcessFilesUploadQueueAsync(runOnce: true);
|
||||||
Trace.Info("File upload queue drained.");
|
Trace.Info("File upload queue drained.");
|
||||||
|
|
||||||
Trace.Verbose("Draining results summary upload queue.");
|
|
||||||
await ProcessSummaryUploadQueueAsync(runOnce: true);
|
|
||||||
Trace.Info("Results summary upload queue drained.");
|
|
||||||
|
|
||||||
// ProcessTimelinesUpdateQueueAsync() will throw exception during shutdown
|
// ProcessTimelinesUpdateQueueAsync() will throw exception during shutdown
|
||||||
// if there is any timeline records that failed to update contains output variabls.
|
// if there is any timeline records that failed to update contains output variabls.
|
||||||
Trace.Verbose("Draining timeline update queue.");
|
Trace.Verbose("Draining timeline update queue.");
|
||||||
@@ -230,23 +204,6 @@ namespace GitHub.Runner.Common
|
|||||||
_fileUploadQueue.Enqueue(newFile);
|
_fileUploadQueue.Enqueue(newFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueSummaryUpload(Guid stepRecordId, string name, string path, bool deleteSource)
|
|
||||||
{
|
|
||||||
// all parameter not null, file path exist.
|
|
||||||
var newFile = new SummaryUploadFileInfo()
|
|
||||||
{
|
|
||||||
Name = name,
|
|
||||||
Path = path,
|
|
||||||
PlanId = _planId.ToString(),
|
|
||||||
JobId = _jobTimelineRecordId.ToString(),
|
|
||||||
StepId = stepRecordId.ToString(),
|
|
||||||
DeleteSource = deleteSource
|
|
||||||
};
|
|
||||||
|
|
||||||
Trace.Verbose("Enqueue results file upload queue: file '{0}' attach to job {1} step {2}", newFile.Path, _jobTimelineRecordId, stepRecordId);
|
|
||||||
_summaryFileUploadQueue.Enqueue(newFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QueueTimelineRecordUpdate(Guid timelineId, TimelineRecord timelineRecord)
|
public void QueueTimelineRecordUpdate(Guid timelineId, TimelineRecord timelineRecord)
|
||||||
{
|
{
|
||||||
ArgUtil.NotEmpty(timelineId, nameof(timelineId));
|
ArgUtil.NotEmpty(timelineId, nameof(timelineId));
|
||||||
@@ -437,73 +394,6 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ProcessSummaryUploadQueueAsync(bool runOnce = false)
|
|
||||||
{
|
|
||||||
Trace.Info("Starting results-based upload queue...");
|
|
||||||
|
|
||||||
while (!_jobCompletionSource.Task.IsCompleted || runOnce)
|
|
||||||
{
|
|
||||||
List<SummaryUploadFileInfo> filesToUpload = new();
|
|
||||||
SummaryUploadFileInfo dequeueFile;
|
|
||||||
while (_summaryFileUploadQueue.TryDequeue(out dequeueFile))
|
|
||||||
{
|
|
||||||
filesToUpload.Add(dequeueFile);
|
|
||||||
// process at most 10 file upload.
|
|
||||||
if (!runOnce && filesToUpload.Count > 10)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (filesToUpload.Count > 0)
|
|
||||||
{
|
|
||||||
if (runOnce)
|
|
||||||
{
|
|
||||||
Trace.Info($"Uploading {filesToUpload.Count} summary files in one shot through results service.");
|
|
||||||
}
|
|
||||||
|
|
||||||
int errorCount = 0;
|
|
||||||
foreach (var file in filesToUpload)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await UploadSummaryFile(file);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
var issue = new Issue() { Type = IssueType.Warning, Message = $"Caught exception during summary file upload to results. {ex.Message}" };
|
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.ResultsUploadFailure;
|
|
||||||
|
|
||||||
var telemetryRecord = new TimelineRecord()
|
|
||||||
{
|
|
||||||
Id = Constants.Runner.TelemetryRecordId,
|
|
||||||
};
|
|
||||||
telemetryRecord.Issues.Add(issue);
|
|
||||||
QueueTimelineRecordUpdate(_jobTimelineId, telemetryRecord);
|
|
||||||
|
|
||||||
Trace.Info("Catch exception during summary file upload to results, keep going since the process is best effort.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
errorCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Trace.Info("Tried to upload {0} summary files to results, success rate: {1}/{0}.", filesToUpload.Count, filesToUpload.Count - errorCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (runOnce)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await Task.Delay(_delayForSummaryUploadDequeue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessTimelinesUpdateQueueAsync(bool runOnce = false)
|
private async Task ProcessTimelinesUpdateQueueAsync(bool runOnce = false)
|
||||||
{
|
{
|
||||||
while (!_jobCompletionSource.Task.IsCompleted || runOnce)
|
while (!_jobCompletionSource.Task.IsCompleted || runOnce)
|
||||||
@@ -710,8 +600,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
foreach (var issue in record.Issues)
|
foreach (var issue in record.Issues)
|
||||||
{
|
{
|
||||||
String source;
|
string source = issue["sourcepath"];
|
||||||
issue.Data.TryGetValue("sourcepath", out source);
|
|
||||||
Trace.Verbose($" Issue: c={issue.Category}, t={issue.Type}, s={source ?? string.Empty}, m={issue.Message}");
|
Trace.Verbose($" Issue: c={issue.Category}, t={issue.Type}, s={source ?? string.Empty}, m={issue.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -775,35 +664,6 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UploadSummaryFile(SummaryUploadFileInfo file)
|
|
||||||
{
|
|
||||||
bool uploadSucceed = false;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Upload the step summary
|
|
||||||
Trace.Info($"Starting to upload summary file to results service {file.Name}, {file.Path}");
|
|
||||||
var cancellationTokenSource = new CancellationTokenSource();
|
|
||||||
await _jobServer.CreateStepSymmaryAsync(file.PlanId, file.JobId, file.StepId, file.Path, cancellationTokenSource.Token);
|
|
||||||
|
|
||||||
uploadSucceed = true;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (uploadSucceed && file.DeleteSource)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(file.Path);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Info("Catch exception during delete success results uploaded summary file.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class PendingTimelineRecord
|
internal class PendingTimelineRecord
|
||||||
@@ -822,17 +682,6 @@ namespace GitHub.Runner.Common
|
|||||||
public bool DeleteSource { get; set; }
|
public bool DeleteSource { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class SummaryUploadFileInfo
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public string Path { get; set; }
|
|
||||||
public string PlanId { get; set; }
|
|
||||||
public string JobId { get; set; }
|
|
||||||
public string StepId { get; set; }
|
|
||||||
public bool DeleteSource { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
internal class ConsoleLineInfo
|
internal class ConsoleLineInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
using GitHub.Runner.Sdk;
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
{
|
{
|
||||||
@@ -24,16 +24,9 @@ namespace GitHub.Runner.Common
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(message))
|
WriteHeader(source, eventType, id);
|
||||||
{
|
WriteLine(message);
|
||||||
var messageLines = message.Split(Environment.NewLine);
|
WriteFooter(eventCache);
|
||||||
foreach (var messageLine in messageLines)
|
|
||||||
{
|
|
||||||
WriteHeader(source, eventType, id);
|
|
||||||
WriteLine(messageLine);
|
|
||||||
WriteFooter(eventCache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool IsEnabled(TraceOptions opts)
|
internal bool IsEnabled(TraceOptions opts)
|
||||||
@@ -93,4 +86,5 @@ namespace GitHub.Runner.Common
|
|||||||
IndentLevel--;
|
IndentLevel--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ namespace GitHub.Runner.Listener
|
|||||||
new string[]
|
new string[]
|
||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Args.Token,
|
Constants.Runner.CommandLine.Args.Token,
|
||||||
Constants.Runner.CommandLine.Args.PAT,
|
Constants.Runner.CommandLine.Args.PAT
|
||||||
Constants.Runner.CommandLine.Flags.Local
|
|
||||||
},
|
},
|
||||||
// Valid run flags and args
|
// Valid run flags and args
|
||||||
[Constants.Runner.CommandLine.Commands.Run] =
|
[Constants.Runner.CommandLine.Commands.Run] =
|
||||||
@@ -87,7 +86,6 @@ namespace GitHub.Runner.Listener
|
|||||||
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
||||||
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
||||||
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
||||||
public bool RemoveLocalConfig => TestFlag(Constants.Runner.CommandLine.Flags.Local);
|
|
||||||
|
|
||||||
// Keep this around since customers still relies on it
|
// Keep this around since customers still relies on it
|
||||||
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
|
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
|
||||||
|
|||||||
@@ -1,3 +1,10 @@
|
|||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Common;
|
||||||
|
using GitHub.Runner.Common.Util;
|
||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
using GitHub.Services.Common.Internal;
|
||||||
|
using GitHub.Services.OAuth;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -7,13 +14,6 @@ using System.Runtime.InteropServices;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using GitHub.Services.Common;
|
|
||||||
using GitHub.Services.Common.Internal;
|
|
||||||
using GitHub.Services.OAuth;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Configuration
|
namespace GitHub.Runner.Listener.Configuration
|
||||||
{
|
{
|
||||||
@@ -636,7 +636,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
while (retryCount < 3)
|
while(retryCount < 3)
|
||||||
{
|
{
|
||||||
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
using (var httpClient = new HttpClient(httpClientHandler))
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
@@ -646,29 +646,28 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
||||||
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
||||||
|
|
||||||
var responseStatus = System.Net.HttpStatusCode.OK;
|
var responseStatus = System.Net.HttpStatusCode.OK;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
||||||
responseStatus = response.StatusCode;
|
responseStatus = response.StatusCode;
|
||||||
var githubRequestId = GetGitHubRequestId(response.Headers);
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if (response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}' ({githubRequestId})");
|
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}' (Request Id: {githubRequestId})");
|
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
var errorResponse = await response.Content.ReadAsStringAsync();
|
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||||
_term.WriteError(errorResponse);
|
_term.WriteError(errorResponse);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (retryCount < 2 && responseStatus != System.Net.HttpStatusCode.NotFound)
|
catch(Exception ex) when (retryCount < 2 && responseStatus != System.Net.HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
retryCount++;
|
retryCount++;
|
||||||
Trace.Error($"Failed to get JIT runner token -- Atempt: {retryCount}");
|
Trace.Error($"Failed to get JIT runner token -- Atempt: {retryCount}");
|
||||||
@@ -715,23 +714,22 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
{
|
{
|
||||||
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(StringUtil.ConvertToJson(bodyObject), null, "application/json"));
|
||||||
responseStatus = response.StatusCode;
|
responseStatus = response.StatusCode;
|
||||||
var githubRequestId = GetGitHubRequestId(response.Headers);
|
|
||||||
|
|
||||||
if (response.IsSuccessStatusCode)
|
if(response.IsSuccessStatusCode)
|
||||||
{
|
{
|
||||||
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}' ({githubRequestId})");
|
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
var jsonResponse = await response.Content.ReadAsStringAsync();
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
return StringUtil.ConvertFromJson<GitHubAuthResult>(jsonResponse);
|
return StringUtil.ConvertFromJson<GitHubAuthResult>(jsonResponse);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}' (Request Id: {githubRequestId})");
|
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
var errorResponse = await response.Content.ReadAsStringAsync();
|
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||||
_term.WriteError(errorResponse);
|
_term.WriteError(errorResponse);
|
||||||
response.EnsureSuccessStatusCode();
|
response.EnsureSuccessStatusCode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex) when (retryCount < 2 && responseStatus != System.Net.HttpStatusCode.NotFound)
|
catch(Exception ex) when (retryCount < 2 && responseStatus != System.Net.HttpStatusCode.NotFound)
|
||||||
{
|
{
|
||||||
retryCount++;
|
retryCount++;
|
||||||
Trace.Error($"Failed to get tenant credentials -- Atempt: {retryCount}");
|
Trace.Error($"Failed to get tenant credentials -- Atempt: {retryCount}");
|
||||||
@@ -744,14 +742,5 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetGitHubRequestId(HttpResponseHeaders headers)
|
|
||||||
{
|
|
||||||
if (headers.TryGetValues("x-github-request-id", out var headerValues))
|
|
||||||
{
|
|
||||||
return headerValues.FirstOrDefault();
|
|
||||||
}
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace GitHub.Runner.Listener
|
|||||||
// This implementation of IJobDispatcher is not thread safe.
|
// This implementation of IJobDispatcher is not thread safe.
|
||||||
// It is based on the fact that the current design of the runner is a dequeue
|
// It is based on the fact that the current design of the runner is a dequeue
|
||||||
// and processes one message from the message queue at a time.
|
// and processes one message from the message queue at a time.
|
||||||
// In addition, it only executes one job every time,
|
// In addition, it only executes one job every time,
|
||||||
// and the server will not send another job while this one is still running.
|
// and the server will not send another job while this one is still running.
|
||||||
public sealed class JobDispatcher : RunnerService, IJobDispatcher
|
public sealed class JobDispatcher : RunnerService, IJobDispatcher
|
||||||
{
|
{
|
||||||
@@ -426,7 +426,7 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
workerOutput.Add(stdout.Data);
|
workerOutput.Add(stdout.Data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (printToStdout)
|
if (printToStdout)
|
||||||
{
|
{
|
||||||
term.WriteLine(stdout.Data, skipTracing: true);
|
term.WriteLine(stdout.Data, skipTracing: true);
|
||||||
@@ -512,7 +512,7 @@ namespace GitHub.Runner.Listener
|
|||||||
var accessToken = systemConnection?.Authorization?.Parameters["AccessToken"];
|
var accessToken = systemConnection?.Authorization?.Parameters["AccessToken"];
|
||||||
notification.JobStarted(message.JobId, accessToken, systemConnection.Url);
|
notification.JobStarted(message.JobId, accessToken, systemConnection.Url);
|
||||||
|
|
||||||
HostContext.WritePerfCounter($"SentJobToWorker_{requestId.ToString()}");
|
HostContext.WritePerfCounter($"SentJobToWorker_{requestId}");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -620,7 +620,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait worker to exit
|
// wait worker to exit
|
||||||
// if worker doesn't exit within timeout, then kill worker.
|
// if worker doesn't exit within timeout, then kill worker.
|
||||||
completedTask = await Task.WhenAny(workerProcessTask, Task.Delay(-1, workerCancelTimeoutKillToken));
|
completedTask = await Task.WhenAny(workerProcessTask, Task.Delay(-1, workerCancelTimeoutKillToken));
|
||||||
|
|
||||||
@@ -1014,7 +1014,7 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = errorMessage };
|
var unhandledExceptionIssue = new Issue() { Type = IssueType.Error, Message = errorMessage };
|
||||||
unhandledExceptionIssue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
|
unhandledExceptionIssue[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.WorkerCrash;
|
||||||
jobRecord.ErrorCount++;
|
jobRecord.ErrorCount++;
|
||||||
jobRecord.Issues.Add(unhandledExceptionIssue);
|
jobRecord.Issues.Add(unhandledExceptionIssue);
|
||||||
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, new TimelineRecord[] { jobRecord }, CancellationToken.None);
|
await jobServer.UpdateTimelineRecordsAsync(message.Plan.ScopeIdentifier, message.Plan.PlanType, message.Plan.PlanId, message.Timeline.Id, new TimelineRecord[] { jobRecord }, CancellationToken.None);
|
||||||
|
|||||||
@@ -135,12 +135,6 @@ namespace GitHub.Runner.Listener
|
|||||||
// remove config files, remove service, and exit
|
// remove config files, remove service, and exit
|
||||||
if (command.Remove)
|
if (command.Remove)
|
||||||
{
|
{
|
||||||
// only remove local config files and exit
|
|
||||||
if(command.RemoveLocalConfig)
|
|
||||||
{
|
|
||||||
configManager.DeleteLocalRunnerConfig();
|
|
||||||
return Constants.Runner.ReturnCode.Success;
|
|
||||||
}
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await configManager.UnconfigureAsync(command);
|
await configManager.UnconfigureAsync(command);
|
||||||
@@ -653,7 +647,6 @@ Config Options:
|
|||||||
--name string Name of the runner to configure (default {Environment.MachineName ?? "myrunner"})
|
--name string Name of the runner to configure (default {Environment.MachineName ?? "myrunner"})
|
||||||
--runnergroup string Name of the runner group to add this runner to (defaults to the default runner group)
|
--runnergroup string Name of the runner group to add this runner to (defaults to the default runner group)
|
||||||
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
||||||
--local Removes the runner config files from your local machine. Used as an option to the remove command
|
|
||||||
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
||||||
--replace Replace any existing runner with the same name (default false)
|
--replace Replace any existing runner with the same name (default false)
|
||||||
--pat GitHub personal access token with repo scope. Used for checking network connectivity when executing `.{separator}run.{ext} --check`
|
--pat GitHub personal access token with repo scope. Used for checking network connectivity when executing `.{separator}run.{ext} --check`
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ using System.Threading;
|
|||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Sdk
|
namespace GitHub.Runner.Sdk
|
||||||
{
|
{
|
||||||
@@ -265,17 +264,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
{
|
{
|
||||||
foreach (KeyValuePair<string, string> kvp in environment)
|
foreach (KeyValuePair<string, string> kvp in environment)
|
||||||
{
|
{
|
||||||
#if OS_WINDOWS
|
|
||||||
string tempKey = String.IsNullOrWhiteSpace(kvp.Key) ? kvp.Key : Regex.Split(kvp.Key, @"\p{C}")[0];
|
|
||||||
string tempValue = String.IsNullOrWhiteSpace(kvp.Value) ? kvp.Value : Regex.Split(kvp.Value, @"\p{C}")[0];
|
|
||||||
if(!String.IsNullOrWhiteSpace(tempKey))
|
|
||||||
{
|
|
||||||
_proc.StartInfo.Environment[tempKey] = tempValue;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
_proc.StartInfo.Environment[kvp.Key] = kvp.Value;
|
_proc.StartInfo.Environment[kvp.Key] = kvp.Value;
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -270,12 +270,9 @@ namespace GitHub.Runner.Worker
|
|||||||
if (string.Equals(blocked, envName, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(blocked, envName, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
// Log Telemetry and let user know they shouldn't do this
|
// Log Telemetry and let user know they shouldn't do this
|
||||||
var issue = new Issue()
|
var message = $"Can't update {blocked} environment variable using ::set-env:: command.";
|
||||||
{
|
var metadata = new IssueMetadata(Constants.Runner.InternalTelemetryIssueDataKey, $"{Constants.Runner.UnsupportedCommand}_{envName}");
|
||||||
Type = IssueType.Error,
|
var issue = context.CreateIssue(IssueType.Error, message, metadata, true);
|
||||||
Message = $"Can't update {blocked} environment variable using ::set-env:: command."
|
|
||||||
};
|
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = $"{Constants.Runner.UnsupportedCommand}_{envName}";
|
|
||||||
context.AddIssue(issue);
|
context.AddIssue(issue);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -309,12 +306,9 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
if (context.Global.Variables.GetBoolean("DistributedTask.DeprecateStepOutputCommands") ?? false)
|
if (context.Global.Variables.GetBoolean("DistributedTask.DeprecateStepOutputCommands") ?? false)
|
||||||
{
|
{
|
||||||
var issue = new Issue()
|
var message = string.Format(Constants.Runner.UnsupportedCommandMessage, this.Command);
|
||||||
{
|
var metadata = new IssueMetadata(Constants.Runner.InternalTelemetryIssueDataKey, Constants.Runner.UnsupportedCommand);
|
||||||
Type = IssueType.Warning,
|
var issue = context.CreateIssue(IssueType.Warning, message, metadata, true);
|
||||||
Message = String.Format(Constants.Runner.UnsupportedCommandMessage, this.Command)
|
|
||||||
};
|
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.UnsupportedCommand;
|
|
||||||
context.AddIssue(issue);
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,12 +338,9 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
if (context.Global.Variables.GetBoolean("DistributedTask.DeprecateStepOutputCommands") ?? false)
|
if (context.Global.Variables.GetBoolean("DistributedTask.DeprecateStepOutputCommands") ?? false)
|
||||||
{
|
{
|
||||||
var issue = new Issue()
|
var message = string.Format(Constants.Runner.UnsupportedCommandMessage, this.Command);
|
||||||
{
|
var metadata = new IssueMetadata(Constants.Runner.InternalTelemetryIssueDataKey, Constants.Runner.UnsupportedCommand);
|
||||||
Type = IssueType.Warning,
|
var issue = context.CreateIssue(IssueType.Warning, message, metadata, true);
|
||||||
Message = String.Format(Constants.Runner.UnsupportedCommandMessage, this.Command)
|
|
||||||
};
|
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.UnsupportedCommand;
|
|
||||||
context.AddIssue(issue);
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,16 +609,11 @@ namespace GitHub.Runner.Worker
|
|||||||
context.Debug("Enhanced Annotations not enabled on the server. The 'title', 'end_line', and 'end_column' fields are unsupported.");
|
context.Debug("Enhanced Annotations not enabled on the server. The 'title', 'end_line', and 'end_column' fields are unsupported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Issue issue = new()
|
var issueCategory = "General";
|
||||||
{
|
|
||||||
Category = "General",
|
|
||||||
Type = this.Type,
|
|
||||||
Message = command.Data
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(file))
|
if (!string.IsNullOrEmpty(file))
|
||||||
{
|
{
|
||||||
issue.Category = "Code";
|
issueCategory = "Code";
|
||||||
|
|
||||||
if (container != null)
|
if (container != null)
|
||||||
{
|
{
|
||||||
@@ -658,14 +644,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var property in command.Properties)
|
string keyToExclude = Constants.Runner.InternalTelemetryIssueDataKey;
|
||||||
{
|
var filteredDictionaryEntries = command.Properties
|
||||||
if (!string.Equals(property.Key, Constants.Runner.InternalTelemetryIssueDataKey, StringComparison.OrdinalIgnoreCase))
|
.Where(kvp => !string.Equals(kvp.Key, keyToExclude, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
.ToList();
|
||||||
issue.Data[property.Key] = property.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var metadata = new IssueMetadata(issueCategory, false, null, filteredDictionaryEntries);
|
||||||
|
var issue = context.CreateIssue(this.Type, command.Data, metadata, true);
|
||||||
context.AddIssue(issue);
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression; // required for OS_WINDOWS
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
|||||||
@@ -33,14 +33,8 @@ namespace GitHub.Runner.Worker
|
|||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable(Constants.Hooks.ContainerHooksPath)))
|
_dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
{
|
_containerHookManager = HostContext.GetService<IContainerHookManager>();
|
||||||
_dockerManager = HostContext.GetService<IDockerCommandManager>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_containerHookManager = HostContext.GetService<IContainerHookManager>();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ using System.IO.Compression;
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
@@ -32,7 +31,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
private static string DateTimeFormat = "yyyyMMdd-HHmmss";
|
private static string DateTimeFormat = "yyyyMMdd-HHmmss";
|
||||||
public void UploadDiagnosticLogs(IExecutionContext executionContext,
|
public void UploadDiagnosticLogs(IExecutionContext executionContext,
|
||||||
IExecutionContext parentContext,
|
IExecutionContext parentContext,
|
||||||
Pipelines.AgentJobRequestMessage message,
|
Pipelines.AgentJobRequestMessage message,
|
||||||
DateTime jobStartTimeUtc)
|
DateTime jobStartTimeUtc)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ using GitHub.Runner.Common.Util;
|
|||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
using ObjectTemplating = GitHub.DistributedTask.ObjectTemplating;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
@@ -80,7 +81,6 @@ namespace GitHub.Runner.Worker
|
|||||||
// logging
|
// logging
|
||||||
long Write(string tag, string message);
|
long Write(string tag, string message);
|
||||||
void QueueAttachFile(string type, string name, string filePath);
|
void QueueAttachFile(string type, string name, string filePath);
|
||||||
void QueueSummaryFile(string name, string filePath, Guid stepRecordId);
|
|
||||||
|
|
||||||
// timeline record update methods
|
// timeline record update methods
|
||||||
void Start(string currentOperation = null);
|
void Start(string currentOperation = null);
|
||||||
@@ -91,7 +91,8 @@ namespace GitHub.Runner.Worker
|
|||||||
void SetGitHubContext(string name, string value);
|
void SetGitHubContext(string name, string value);
|
||||||
void SetOutput(string name, string value, out string reference);
|
void SetOutput(string name, string value, out string reference);
|
||||||
void SetTimeout(TimeSpan? timeout);
|
void SetTimeout(TimeSpan? timeout);
|
||||||
void AddIssue(Issue issue, string message = null);
|
IReadOnlyIssue CreateIssue(IssueType issueType, string rawMessage, IssueMetadata metadata, bool writeToLog);
|
||||||
|
void AddIssue(IReadOnlyIssue issue);
|
||||||
void Progress(int percentage, string currentOperation = null);
|
void Progress(int percentage, string currentOperation = null);
|
||||||
void UpdateDetailTimelineRecord(TimelineRecord record);
|
void UpdateDetailTimelineRecord(TimelineRecord record);
|
||||||
|
|
||||||
@@ -125,8 +126,10 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
private readonly TimelineRecord _record = new();
|
private readonly TimelineRecord _record = new();
|
||||||
private readonly Dictionary<Guid, TimelineRecord> _detailRecords = new();
|
private readonly Dictionary<Guid, TimelineRecord> _detailRecords = new();
|
||||||
|
private readonly List<IReadOnlyIssue> _embeddedIssueCollector;
|
||||||
private readonly object _loggerLock = new();
|
private readonly object _loggerLock = new();
|
||||||
private readonly object _matchersLock = new();
|
private readonly object _matchersLock = new();
|
||||||
|
private readonly ExecutionContext _parentExecutionContext;
|
||||||
|
|
||||||
private event OnMatcherChanged _onMatcherChanged;
|
private event OnMatcherChanged _onMatcherChanged;
|
||||||
|
|
||||||
@@ -134,7 +137,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
private IPagingLogger _logger;
|
private IPagingLogger _logger;
|
||||||
private IJobServerQueue _jobServerQueue;
|
private IJobServerQueue _jobServerQueue;
|
||||||
private ExecutionContext _parentExecutionContext;
|
|
||||||
|
|
||||||
private Guid _mainTimelineId;
|
private Guid _mainTimelineId;
|
||||||
private Guid _detailTimelineId;
|
private Guid _detailTimelineId;
|
||||||
@@ -148,6 +150,29 @@ namespace GitHub.Runner.Worker
|
|||||||
private long _totalThrottlingDelayInMilliseconds = 0;
|
private long _totalThrottlingDelayInMilliseconds = 0;
|
||||||
private bool _stepTelemetryPublished = false;
|
private bool _stepTelemetryPublished = false;
|
||||||
|
|
||||||
|
public ExecutionContext()
|
||||||
|
: this(null, false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExecutionContext(ExecutionContext parent, bool embedded)
|
||||||
|
{
|
||||||
|
if (embedded)
|
||||||
|
{
|
||||||
|
ArgUtil.NotNull(parent, nameof(parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
_parentExecutionContext = parent;
|
||||||
|
this.IsEmbedded = embedded;
|
||||||
|
this.StepTelemetry = new ActionsStepTelemetry
|
||||||
|
{
|
||||||
|
IsEmbedded = embedded
|
||||||
|
};
|
||||||
|
|
||||||
|
//Embedded Execution Contexts pseudo-inherit their parent's embeddedIssueCollector.
|
||||||
|
_embeddedIssueCollector = embedded ? parent._embeddedIssueCollector : new();
|
||||||
|
}
|
||||||
|
|
||||||
public Guid Id => _record.Id;
|
public Guid Id => _record.Id;
|
||||||
public Guid EmbeddedId { get; private set; }
|
public Guid EmbeddedId { get; private set; }
|
||||||
public string ScopeName { get; private set; }
|
public string ScopeName { get; private set; }
|
||||||
@@ -160,7 +185,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public Dictionary<string, VariableValue> JobOutputs { get; private set; }
|
public Dictionary<string, VariableValue> JobOutputs { get; private set; }
|
||||||
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment { get; private set; }
|
public ActionsEnvironmentReference ActionsEnvironment { get; private set; }
|
||||||
public ActionsStepTelemetry StepTelemetry { get; } = new ActionsStepTelemetry();
|
public ActionsStepTelemetry StepTelemetry { get; private init; }
|
||||||
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
||||||
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
||||||
|
|
||||||
@@ -185,7 +210,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// An embedded execution context shares the same record ID, record name, and logger
|
// An embedded execution context shares the same record ID, record name, and logger
|
||||||
// as its enclosing execution context.
|
// as its enclosing execution context.
|
||||||
public bool IsEmbedded { get; private set; }
|
public bool IsEmbedded { get; private init; }
|
||||||
|
|
||||||
public TaskResult? Result
|
public TaskResult? Result
|
||||||
{
|
{
|
||||||
@@ -320,7 +345,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
var child = new ExecutionContext();
|
var child = new ExecutionContext(this, isEmbedded);
|
||||||
child.Initialize(HostContext);
|
child.Initialize(HostContext);
|
||||||
child.Global = Global;
|
child.Global = Global;
|
||||||
child.ScopeName = scopeName;
|
child.ScopeName = scopeName;
|
||||||
@@ -345,7 +370,6 @@ namespace GitHub.Runner.Worker
|
|||||||
child.ExpressionFunctions.Add(item);
|
child.ExpressionFunctions.Add(item);
|
||||||
}
|
}
|
||||||
child._cancellationTokenSource = cancellationTokenSource ?? new CancellationTokenSource();
|
child._cancellationTokenSource = cancellationTokenSource ?? new CancellationTokenSource();
|
||||||
child._parentExecutionContext = this;
|
|
||||||
child.EchoOnActionCommand = EchoOnActionCommand;
|
child.EchoOnActionCommand = EchoOnActionCommand;
|
||||||
|
|
||||||
if (recordOrder != null)
|
if (recordOrder != null)
|
||||||
@@ -366,11 +390,9 @@ namespace GitHub.Runner.Worker
|
|||||||
child._logger.Setup(_mainTimelineId, recordId);
|
child._logger.Setup(_mainTimelineId, recordId);
|
||||||
}
|
}
|
||||||
|
|
||||||
child.IsEmbedded = isEmbedded;
|
|
||||||
child.StepTelemetry.StepId = recordId;
|
child.StepTelemetry.StepId = recordId;
|
||||||
child.StepTelemetry.Stage = stage.ToString();
|
child.StepTelemetry.Stage = stage.ToString();
|
||||||
child.StepTelemetry.IsEmbedded = isEmbedded;
|
child.StepTelemetry.StepContextName = child.GetFullyQualifiedContextName();
|
||||||
child.StepTelemetry.StepContextName = child.GetFullyQualifiedContextName(); ;
|
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
@@ -412,13 +434,24 @@ namespace GitHub.Runner.Worker
|
|||||||
this.Warning($"The job has experienced {TimeSpan.FromMilliseconds(_totalThrottlingDelayInMilliseconds).TotalSeconds} seconds total delay caused by server throttling.");
|
this.Warning($"The job has experienced {TimeSpan.FromMilliseconds(_totalThrottlingDelayInMilliseconds).TotalSeconds} seconds total delay caused by server throttling.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DateTime now = DateTime.UtcNow;
|
||||||
_record.CurrentOperation = currentOperation ?? _record.CurrentOperation;
|
_record.CurrentOperation = currentOperation ?? _record.CurrentOperation;
|
||||||
_record.ResultCode = resultCode ?? _record.ResultCode;
|
_record.ResultCode = resultCode ?? _record.ResultCode;
|
||||||
_record.FinishTime = DateTime.UtcNow;
|
_record.FinishTime = now;
|
||||||
_record.PercentComplete = 100;
|
_record.PercentComplete = 100;
|
||||||
_record.Result = _record.Result ?? TaskResult.Succeeded;
|
_record.Result = _record.Result ?? TaskResult.Succeeded;
|
||||||
_record.State = TimelineRecordState.Completed;
|
_record.State = TimelineRecordState.Completed;
|
||||||
|
|
||||||
|
// Before our main timeline's final QueueTimelineRecordUpdate,
|
||||||
|
// inject any issues collected by embedded ExecutionContexts.
|
||||||
|
if (!this.IsEmbedded)
|
||||||
|
{
|
||||||
|
foreach (var issue in _embeddedIssueCollector)
|
||||||
|
{
|
||||||
|
AddIssue(issue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);
|
_jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);
|
||||||
|
|
||||||
// complete all detail timeline records.
|
// complete all detail timeline records.
|
||||||
@@ -426,7 +459,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
foreach (var record in _detailRecords)
|
foreach (var record in _detailRecords)
|
||||||
{
|
{
|
||||||
record.Value.FinishTime = record.Value.FinishTime ?? DateTime.UtcNow;
|
record.Value.FinishTime = record.Value.FinishTime ?? now;
|
||||||
record.Value.PercentComplete = record.Value.PercentComplete ?? 100;
|
record.Value.PercentComplete = record.Value.PercentComplete ?? 100;
|
||||||
record.Value.Result = record.Value.Result ?? TaskResult.Succeeded;
|
record.Value.Result = record.Value.Result ?? TaskResult.Succeeded;
|
||||||
record.Value.State = TimelineRecordState.Completed;
|
record.Value.State = TimelineRecordState.Completed;
|
||||||
@@ -546,76 +579,89 @@ namespace GitHub.Runner.Worker
|
|||||||
_jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);
|
_jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is not thread safe, the caller need to take lock before calling issue()
|
// This is not thread safe, the caller needs to take lock before calling issue()
|
||||||
public void AddIssue(Issue issue, string logMessage = null)
|
public IReadOnlyIssue CreateIssue(IssueType issueType, string rawMessage, IssueMetadata metadata, bool writeToLog)
|
||||||
|
{
|
||||||
|
string refinedMessage = PrimitiveExtensions.TrimExcess(HostContext.SecretMasker.MaskSecrets(rawMessage), _maxIssueMessageLength);
|
||||||
|
|
||||||
|
var result = new Issue() {
|
||||||
|
Type = issueType,
|
||||||
|
Message = refinedMessage,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (metadata != null)
|
||||||
|
{
|
||||||
|
result.Category = metadata.Category;
|
||||||
|
result.IsInfrastructureIssue = metadata.IsInfrastructureIssue;
|
||||||
|
foreach (var kvp in metadata.Data)
|
||||||
|
{
|
||||||
|
result[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's important to keep track of the step number (key:stepNumber) and the line number (key:logFileLineNumber) of every issue that gets logged.
|
||||||
|
// Actions UI from the run summary page use both values to easily link to an exact locations in logs where annotations originate from.
|
||||||
|
if (_record.Order != null)
|
||||||
|
{
|
||||||
|
result["stepNumber"] = _record.Order.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
string wellKnownTag = null;
|
||||||
|
Int32? previousCountForIssueType = null;
|
||||||
|
switch (issueType)
|
||||||
|
{
|
||||||
|
case IssueType.Error:
|
||||||
|
wellKnownTag = WellKnownTags.Error;
|
||||||
|
previousCountForIssueType = _record.ErrorCount++;
|
||||||
|
break;
|
||||||
|
case IssueType.Warning:
|
||||||
|
wellKnownTag = WellKnownTags.Warning;
|
||||||
|
previousCountForIssueType = _record.WarningCount++;
|
||||||
|
break;
|
||||||
|
case IssueType.Notice:
|
||||||
|
wellKnownTag = WellKnownTags.Notice;
|
||||||
|
previousCountForIssueType = _record.NoticeCount++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(wellKnownTag))
|
||||||
|
{
|
||||||
|
if (writeToLog)
|
||||||
|
{
|
||||||
|
//Note that ::Write() has it's own secret masking logic
|
||||||
|
string logText = metadata?.LogMessageOverride ?? result.Message;
|
||||||
|
if (!string.IsNullOrEmpty(logText))
|
||||||
|
{
|
||||||
|
long logLineNumber = Write(wellKnownTag, logText);
|
||||||
|
result["logFileLineNumber"] = logLineNumber.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (previousCountForIssueType.GetValueOrDefault(0) < _maxIssueCount)
|
||||||
|
{
|
||||||
|
_record.Issues.Add(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This is not thread safe, the caller needs to take lock before calling issue()
|
||||||
|
public void AddIssue(IReadOnlyIssue issue)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(issue, nameof(issue));
|
ArgUtil.NotNull(issue, nameof(issue));
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(logMessage))
|
// Embedded ExecutionContexts (a.k.a. Composite actions) should never upload a timeline record to the server.
|
||||||
|
// Instead, we store processed issues on a shared (psuedo-inherited) list (belonging to the closest
|
||||||
|
// non-embedded ancestor ExecutionContext) so that they can be processed when that ancestor completes.
|
||||||
|
if (this.IsEmbedded)
|
||||||
{
|
{
|
||||||
logMessage = issue.Message;
|
_embeddedIssueCollector.Add(issue);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
issue.Message = HostContext.SecretMasker.MaskSecrets(issue.Message);
|
|
||||||
if (issue.Message.Length > _maxIssueMessageLength)
|
|
||||||
{
|
{
|
||||||
issue.Message = issue.Message[.._maxIssueMessageLength];
|
_jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tracking the line number (logFileLineNumber) and step number (stepNumber) for each issue that gets created
|
|
||||||
// Actions UI from the run summary page use both values to easily link to an exact locations in logs where annotations originate from
|
|
||||||
if (_record.Order != null)
|
|
||||||
{
|
|
||||||
issue.Data["stepNumber"] = _record.Order.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (issue.Type == IssueType.Error)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(logMessage))
|
|
||||||
{
|
|
||||||
long logLineNumber = Write(WellKnownTags.Error, logMessage);
|
|
||||||
issue.Data["logFileLineNumber"] = logLineNumber.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_record.ErrorCount < _maxIssueCount)
|
|
||||||
{
|
|
||||||
_record.Issues.Add(issue);
|
|
||||||
}
|
|
||||||
|
|
||||||
_record.ErrorCount++;
|
|
||||||
}
|
|
||||||
else if (issue.Type == IssueType.Warning)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(logMessage))
|
|
||||||
{
|
|
||||||
long logLineNumber = Write(WellKnownTags.Warning, logMessage);
|
|
||||||
issue.Data["logFileLineNumber"] = logLineNumber.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_record.WarningCount < _maxIssueCount)
|
|
||||||
{
|
|
||||||
_record.Issues.Add(issue);
|
|
||||||
}
|
|
||||||
|
|
||||||
_record.WarningCount++;
|
|
||||||
}
|
|
||||||
else if (issue.Type == IssueType.Notice)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(logMessage))
|
|
||||||
{
|
|
||||||
long logLineNumber = Write(WellKnownTags.Notice, logMessage);
|
|
||||||
issue.Data["logFileLineNumber"] = logLineNumber.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_record.NoticeCount < _maxIssueCount)
|
|
||||||
{
|
|
||||||
_record.Issues.Add(issue);
|
|
||||||
}
|
|
||||||
|
|
||||||
_record.NoticeCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_jobServerQueue.QueueTimelineRecordUpdate(_mainTimelineId, _record);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateDetailTimelineRecord(TimelineRecord record)
|
public void UpdateDetailTimelineRecord(TimelineRecord record)
|
||||||
@@ -847,19 +893,6 @@ namespace GitHub.Runner.Worker
|
|||||||
_jobServerQueue.QueueFileUpload(_mainTimelineId, _record.Id, type, name, filePath, deleteSource: false);
|
_jobServerQueue.QueueFileUpload(_mainTimelineId, _record.Id, type, name, filePath, deleteSource: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueSummaryFile(string name, string filePath, Guid stepRecordId)
|
|
||||||
{
|
|
||||||
ArgUtil.NotNullOrEmpty(name, nameof(name));
|
|
||||||
ArgUtil.NotNullOrEmpty(filePath, nameof(filePath));
|
|
||||||
|
|
||||||
if (!File.Exists(filePath))
|
|
||||||
{
|
|
||||||
throw new FileNotFoundException($"Can't upload (name:{name}) file: {filePath}. File does not exist.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_jobServerQueue.QueueSummaryUpload(stepRecordId, name, filePath, deleteSource: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add OnMatcherChanged
|
// Add OnMatcherChanged
|
||||||
public void Add(OnMatcherChanged handler)
|
public void Add(OnMatcherChanged handler)
|
||||||
{
|
{
|
||||||
@@ -989,16 +1022,7 @@ namespace GitHub.Runner.Worker
|
|||||||
if ((issue.Type == IssueType.Error || issue.Type == IssueType.Warning) &&
|
if ((issue.Type == IssueType.Error || issue.Type == IssueType.Warning) &&
|
||||||
!string.IsNullOrEmpty(issue.Message))
|
!string.IsNullOrEmpty(issue.Message))
|
||||||
{
|
{
|
||||||
string issueTelemetry;
|
string issueTelemetry = PrimitiveExtensions.TrimExcess(issue.Message, _maxIssueMessageLengthInTelemetry);
|
||||||
if (issue.Message.Length > _maxIssueMessageLengthInTelemetry)
|
|
||||||
{
|
|
||||||
issueTelemetry = $"{issue.Message[.._maxIssueMessageLengthInTelemetry]}";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
issueTelemetry = issue.Message;
|
|
||||||
}
|
|
||||||
|
|
||||||
StepTelemetry.ErrorMessages.Add(issueTelemetry);
|
StepTelemetry.ErrorMessages.Add(issueTelemetry);
|
||||||
|
|
||||||
// Only send over the first 3 issues to avoid sending too much data.
|
// Only send over the first 3 issues to avoid sending too much data.
|
||||||
@@ -1172,19 +1196,23 @@ namespace GitHub.Runner.Worker
|
|||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||||
public static void Error(this IExecutionContext context, string message)
|
public static void Error(this IExecutionContext context, string message)
|
||||||
{
|
{
|
||||||
context.AddIssue(new Issue() { Type = IssueType.Error, Message = message });
|
var issue = context.CreateIssue(IssueType.Error, message, null, true);
|
||||||
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||||
public static void InfrastructureError(this IExecutionContext context, string message)
|
public static void InfrastructureError(this IExecutionContext context, string message)
|
||||||
{
|
{
|
||||||
context.AddIssue(new Issue() { Type = IssueType.Error, Message = message, IsInfrastructureIssue = true });
|
var metadata = new IssueMetadata(null, true, null, Enumerable.Empty<KeyValuePair<string, string>>());
|
||||||
|
var issue = context.CreateIssue(IssueType.Error, message, metadata, true);
|
||||||
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||||
public static void Warning(this IExecutionContext context, string message)
|
public static void Warning(this IExecutionContext context, string message)
|
||||||
{
|
{
|
||||||
context.AddIssue(new Issue() { Type = IssueType.Warning, Message = message });
|
var issue = context.CreateIssue(IssueType.Warning, message, null, true);
|
||||||
|
context.AddIssue(issue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||||
|
|||||||
@@ -204,23 +204,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachmentName = !context.IsEmbedded
|
var attachmentName = !context.IsEmbedded
|
||||||
? context.Id.ToString()
|
? context.Id.ToString()
|
||||||
: context.EmbeddedId.ToString();
|
: context.EmbeddedId.ToString();
|
||||||
|
|
||||||
Trace.Info($"Queueing file ({filePath}) for attachment upload ({attachmentName})");
|
Trace.Info($"Queueing file ({filePath}) for attachment upload ({attachmentName})");
|
||||||
// Attachments must be added to the parent context (job), not the current context (step)
|
// Attachments must be added to the parent context (job), not the current context (step)
|
||||||
context.Root.QueueAttachFile(ChecksAttachmentType.StepSummary, attachmentName, scrubbedFilePath);
|
context.Root.QueueAttachFile(ChecksAttachmentType.StepSummary, attachmentName, scrubbedFilePath);
|
||||||
|
|
||||||
// Dual upload the same files to Results Service
|
|
||||||
context.Global.Variables.TryGetValue("system.github.results_endpoint", out string resultsReceiverEndpoint);
|
|
||||||
if (resultsReceiverEndpoint != null)
|
|
||||||
{
|
|
||||||
Trace.Info($"Queueing results file ({filePath}) for attachment upload ({attachmentName})");
|
|
||||||
var stepId = context.Id;
|
|
||||||
// Attachments must be added to the parent context (job), not the current context (step)
|
|
||||||
context.Root.QueueSummaryFile(attachmentName, scrubbedFilePath, stepId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -294,7 +294,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Evaluation error
|
// Evaluation error
|
||||||
Trace.Info("Caught exception from expression for embedded step.env");
|
Trace.Info("Caught exception from expression for embedded step.env");
|
||||||
step.ExecutionContext.Error(ex);
|
step.ExecutionContext.Error(ex);
|
||||||
step.ExecutionContext.Complete(TaskResult.Failed);
|
SetStepConclusion(step, TaskResult.Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register Callback
|
// Register Callback
|
||||||
|
|||||||
@@ -38,17 +38,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Update the env dictionary.
|
// Update the env dictionary.
|
||||||
AddInputsToEnvironment();
|
AddInputsToEnvironment();
|
||||||
|
|
||||||
IDockerCommandManager dockerManager = null;
|
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
IContainerHookManager containerHookManager = null;
|
var containerHookManager = HostContext.GetService<IContainerHookManager>();
|
||||||
if (FeatureManager.IsContainerHooksEnabled(ExecutionContext.Global.Variables))
|
|
||||||
{
|
|
||||||
containerHookManager = HostContext.GetService<IContainerHookManager>();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
dockerManager = HostContext.GetService<IDockerCommandManager>();
|
|
||||||
}
|
|
||||||
|
|
||||||
string dockerFile = null;
|
string dockerFile = null;
|
||||||
|
|
||||||
// container image haven't built/pull
|
// container image haven't built/pull
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using System.Globalization;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
@@ -97,7 +98,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
var matchers = _matchers;
|
var matchers = _matchers;
|
||||||
|
|
||||||
// Strip color codes
|
// Strip color codes
|
||||||
var stripped = line.Contains(_colorCodePrefix) ? _colorCodeRegex.Replace(line, string.Empty) : line;
|
var refinedLine = line.Contains(_colorCodePrefix) ? _colorCodeRegex.Replace(line, string.Empty) : line;
|
||||||
|
|
||||||
foreach (var matcher in matchers)
|
foreach (var matcher in matchers)
|
||||||
{
|
{
|
||||||
@@ -107,8 +108,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Match
|
// Match
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
match = matcher.Match(stripped);
|
match = matcher.Match(refinedLine);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (RegexMatchTimeoutException ex)
|
catch (RegexMatchTimeoutException ex)
|
||||||
@@ -116,7 +116,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
if (attempt < _maxAttempts)
|
if (attempt < _maxAttempts)
|
||||||
{
|
{
|
||||||
// Debug
|
// Debug
|
||||||
_executionContext.Debug($"Timeout processing issue matcher '{matcher.Owner}' against line '{stripped}'. Exception: {ex.ToString()}");
|
_executionContext.Debug($"Timeout processing issue matcher '{matcher.Owner}' against line '{refinedLine}'. Exception: {ex}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -139,12 +139,10 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
// Convert to issue
|
// Convert to issue
|
||||||
var issue = ConvertToIssue(match);
|
var issue = ConvertToIssue(match);
|
||||||
|
|
||||||
if (issue != null)
|
if (issue != null)
|
||||||
{
|
{
|
||||||
// Log issue
|
// Log issue
|
||||||
_executionContext.AddIssue(issue, stripped);
|
_executionContext.AddIssue(issue);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,7 +194,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private DTWebApi.Issue ConvertToIssue(IssueMatch match)
|
private DTWebApi.IReadOnlyIssue ConvertToIssue(IssueMatch match)
|
||||||
{
|
{
|
||||||
// Validate the message
|
// Validate the message
|
||||||
if (string.IsNullOrWhiteSpace(match.Message))
|
if (string.IsNullOrWhiteSpace(match.Message))
|
||||||
@@ -225,18 +223,14 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var issue = new DTWebApi.Issue
|
var issueData = new Dictionary<string, string>();
|
||||||
{
|
|
||||||
Message = match.Message,
|
|
||||||
Type = issueType,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Line
|
// Line
|
||||||
if (!string.IsNullOrEmpty(match.Line))
|
if (!string.IsNullOrEmpty(match.Line))
|
||||||
{
|
{
|
||||||
if (int.TryParse(match.Line, NumberStyles.None, CultureInfo.InvariantCulture, out var line))
|
if (int.TryParse(match.Line, NumberStyles.None, CultureInfo.InvariantCulture, out var line))
|
||||||
{
|
{
|
||||||
issue.Data["line"] = line.ToString(CultureInfo.InvariantCulture);
|
issueData["line"] = line.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -249,7 +243,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
if (int.TryParse(match.Column, NumberStyles.None, CultureInfo.InvariantCulture, out var column))
|
if (int.TryParse(match.Column, NumberStyles.None, CultureInfo.InvariantCulture, out var column))
|
||||||
{
|
{
|
||||||
issue.Data["col"] = column.ToString(CultureInfo.InvariantCulture);
|
issueData["col"] = column.ToString(CultureInfo.InvariantCulture);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -260,7 +254,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Code
|
// Code
|
||||||
if (!string.IsNullOrWhiteSpace(match.Code))
|
if (!string.IsNullOrWhiteSpace(match.Code))
|
||||||
{
|
{
|
||||||
issue.Data["code"] = match.Code.Trim();
|
issueData["code"] = match.Code.Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
// File
|
// File
|
||||||
@@ -312,7 +306,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
var relativePath = file.Substring(repositoryPath.Length).TrimStart(Path.DirectorySeparatorChar);
|
var relativePath = file.Substring(repositoryPath.Length).TrimStart(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
// Prefer `/` on all platforms
|
// Prefer `/` on all platforms
|
||||||
issue.Data["file"] = relativePath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
issueData["file"] = relativePath.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -327,9 +321,11 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_executionContext.Debug($"Dropping file value '{match.File}' and fromPath value '{match.FromPath}'. Exception during validation: {ex.ToString()}");
|
_executionContext.Debug($"Dropping file value '{match.File}' and fromPath value '{match.FromPath}'. Exception during validation: {ex}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var metadata = new IssueMetadata(null, false, match.SourceText, issueData);
|
||||||
|
var issue = _executionContext.CreateIssue(issueType, match.Message, metadata, true);
|
||||||
return issue;
|
return issue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,31 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
public delegate void OnMatcherChanged(object sender, MatcherChangedEventArgs e);
|
public delegate void OnMatcherChanged(object sender, MatcherChangedEventArgs e);
|
||||||
|
|
||||||
|
|
||||||
|
public sealed class IssueMetadata
|
||||||
|
{
|
||||||
|
public IssueMetadata(string key, string value)
|
||||||
|
: this(null, false, null, new []{ KeyValuePair.Create(key, value) })
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IssueMetadata(string category, bool infrastructureIssue, string logMessageOverride, IEnumerable<KeyValuePair<string, string>> data)
|
||||||
|
{
|
||||||
|
this.Category = category;
|
||||||
|
this.IsInfrastructureIssue = infrastructureIssue;
|
||||||
|
this.LogMessageOverride = logMessageOverride;
|
||||||
|
|
||||||
|
// Close-over the incoming IEnumerable to force immediate evaluation.
|
||||||
|
var empty = Enumerable.Empty<KeyValuePair<string, string>>();
|
||||||
|
this.Data = new Dictionary<string, string>(data ?? empty, StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly string Category;
|
||||||
|
public readonly bool IsInfrastructureIssue;
|
||||||
|
public readonly string LogMessageOverride;
|
||||||
|
public readonly IEnumerable<KeyValuePair<string, string>> Data;
|
||||||
|
}
|
||||||
|
|
||||||
public sealed class MatcherChangedEventArgs : EventArgs
|
public sealed class MatcherChangedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
public MatcherChangedEventArgs(IssueMatcherConfig config)
|
public MatcherChangedEventArgs(IssueMatcherConfig config)
|
||||||
@@ -69,7 +94,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (regexMatch.Success)
|
if (regexMatch.Success)
|
||||||
{
|
{
|
||||||
return new IssueMatch(null, pattern, regexMatch.Groups, DefaultSeverity);
|
return new IssueMatch(line, null, pattern, regexMatch.Groups, DefaultSeverity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -110,13 +135,13 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return
|
// Return
|
||||||
return new IssueMatch(runningMatch, pattern, regexMatch.Groups, DefaultSeverity);
|
return new IssueMatch(line, runningMatch, pattern, regexMatch.Groups, DefaultSeverity);
|
||||||
}
|
}
|
||||||
// Not the last pattern
|
// Not the last pattern
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Store the match
|
// Store the match
|
||||||
_state[i] = new IssueMatch(runningMatch, pattern, regexMatch.Groups);
|
_state[i] = new IssueMatch(line, runningMatch, pattern, regexMatch.Groups);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Not matched
|
// Not matched
|
||||||
@@ -184,8 +209,9 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public sealed class IssueMatch
|
public sealed class IssueMatch
|
||||||
{
|
{
|
||||||
public IssueMatch(IssueMatch runningMatch, IssuePattern pattern, GroupCollection groups, string defaultSeverity = null)
|
public IssueMatch(string sourceText, IssueMatch runningMatch, IssuePattern pattern, GroupCollection groups, string defaultSeverity = null)
|
||||||
{
|
{
|
||||||
|
SourceText = sourceText;
|
||||||
File = runningMatch?.File ?? GetValue(groups, pattern.File);
|
File = runningMatch?.File ?? GetValue(groups, pattern.File);
|
||||||
Line = runningMatch?.Line ?? GetValue(groups, pattern.Line);
|
Line = runningMatch?.Line ?? GetValue(groups, pattern.Line);
|
||||||
Column = runningMatch?.Column ?? GetValue(groups, pattern.Column);
|
Column = runningMatch?.Column ?? GetValue(groups, pattern.Column);
|
||||||
@@ -200,6 +226,8 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string SourceText { get; }
|
||||||
|
|
||||||
public string File { get; }
|
public string File { get; }
|
||||||
|
|
||||||
public string Line { get; }
|
public string Line { get; }
|
||||||
@@ -455,7 +483,7 @@ namespace GitHub.Runner.Worker
|
|||||||
if (Loop && Message == null)
|
if (Loop && Message == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException($"The {_loopPropertyName} pattern must set '{_messagePropertyName}'");
|
throw new ArgumentException($"The {_loopPropertyName} pattern must set '{_messagePropertyName}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
var regex = new Regex(Pattern ?? string.Empty, RegexOptions);
|
var regex = new Regex(Pattern ?? string.Empty, RegexOptions);
|
||||||
var groupCount = regex.GetGroupNumbers().Length;
|
var groupCount = regex.GetGroupNumbers().Length;
|
||||||
|
|||||||
@@ -321,28 +321,25 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (message.Variables.TryGetValue("system.workflowFileFullPath", out VariableValue workflowFileFullPath))
|
if (message.Variables.TryGetValue("system.workflowFileFullPath", out VariableValue workflowFileFullPath))
|
||||||
{
|
{
|
||||||
var usesLogText = $"Uses: {workflowFileFullPath.Value}";
|
context.Output($"Uses: {workflowFileFullPath.Value}");
|
||||||
var reference = GetWorkflowReference(message.Variables);
|
|
||||||
context.Output(usesLogText + reference);
|
|
||||||
|
|
||||||
if (message.ContextData.TryGetValue("inputs", out var pipelineContextData))
|
if (message.ContextData.TryGetValue("inputs", out var pipelineContextData))
|
||||||
{
|
{
|
||||||
var inputs = pipelineContextData.AssertDictionary("inputs");
|
var inputs = pipelineContextData.AssertDictionary("inputs");
|
||||||
if (inputs.Any())
|
if (inputs.Any())
|
||||||
{
|
{
|
||||||
context.Output($"##[group] Inputs");
|
context.Output($"##[group] Inputs");
|
||||||
foreach (var input in inputs)
|
foreach (var input in inputs)
|
||||||
{
|
{
|
||||||
context.Output($" {input.Key}: {input.Value}");
|
context.Output($" {input.Key}: {input.Value}");
|
||||||
}
|
}
|
||||||
context.Output("##[endgroup]");
|
context.Output("##[endgroup]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(message.JobDisplayName))
|
if (!string.IsNullOrWhiteSpace(message.JobDisplayName))
|
||||||
{
|
{
|
||||||
context.Output($"Complete job name: {message.JobDisplayName}");
|
context.Output($"Complete job name: {message.JobDisplayName}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var intraActionStates = new Dictionary<Guid, Dictionary<string, string>>();
|
var intraActionStates = new Dictionary<Guid, Dictionary<string, string>>();
|
||||||
@@ -455,24 +452,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetWorkflowReference(IDictionary<string, VariableValue> variables)
|
|
||||||
{
|
|
||||||
var reference = "";
|
|
||||||
if (variables.TryGetValue("system.workflowFileSha", out VariableValue workflowFileSha))
|
|
||||||
{
|
|
||||||
if (variables.TryGetValue("system.workflowFileRef", out VariableValue workflowFileRef)
|
|
||||||
&& !string.IsNullOrEmpty(workflowFileRef.Value))
|
|
||||||
{
|
|
||||||
reference += $"@{workflowFileRef.Value} ({workflowFileSha.Value})";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
reference += $"@{workflowFileSha.Value}";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return reference;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc)
|
public void FinalizeJob(IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, DateTime jobStartTimeUtc)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
@@ -681,8 +660,9 @@ namespace GitHub.Runner.Worker
|
|||||||
var freeSpaceInMB = driveInfo.AvailableFreeSpace / 1024 / 1024;
|
var freeSpaceInMB = driveInfo.AvailableFreeSpace / 1024 / 1024;
|
||||||
if (freeSpaceInMB < lowDiskSpaceThreshold)
|
if (freeSpaceInMB < lowDiskSpaceThreshold)
|
||||||
{
|
{
|
||||||
var issue = new Issue() { Type = IssueType.Warning, Message = $"You are running out of disk space. The runner will stop working when the machine runs out of disk space. Free space left: {freeSpaceInMB} MB" };
|
var message = $"You are running out of disk space. The runner will stop working when the machine runs out of disk space. Free space left: {freeSpaceInMB} MB";
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = Constants.Runner.LowDiskSpace;
|
var metadata = new IssueMetadata(Constants.Runner.InternalTelemetryIssueDataKey, Constants.Runner.LowDiskSpace);
|
||||||
|
var issue = context.CreateIssue(IssueType.Warning, message, metadata, true);
|
||||||
context.AddIssue(issue);
|
context.AddIssue(issue);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,8 @@ namespace GitHub.Runner.Worker
|
|||||||
default:
|
default:
|
||||||
throw new ArgumentException(HostContext.RunnerShutdownReason.ToString(), nameof(HostContext.RunnerShutdownReason));
|
throw new ArgumentException(HostContext.RunnerShutdownReason.ToString(), nameof(HostContext.RunnerShutdownReason));
|
||||||
}
|
}
|
||||||
jobContext.AddIssue(new Issue() { Type = IssueType.Error, Message = errorMessage });
|
var issue = jobContext.CreateIssue(IssueType.Error, errorMessage, null, true);
|
||||||
|
jobContext.AddIssue(issue);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Validate directory permissions.
|
// Validate directory permissions.
|
||||||
|
|||||||
@@ -27,6 +27,18 @@ namespace GitHub.Services.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string TrimExcess(string text, int maxLength)
|
||||||
|
{
|
||||||
|
string result = text;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(result) && result.Length > maxLength)
|
||||||
|
{
|
||||||
|
result = result.Substring(0, maxLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static string ToBase64StringNoPaddingFromString(string utf8String)
|
public static string ToBase64StringNoPaddingFromString(string utf8String)
|
||||||
{
|
{
|
||||||
return ToBase64StringNoPadding(Encoding.UTF8.GetBytes(utf8String));
|
return ToBase64StringNoPadding(Encoding.UTF8.GetBytes(utf8String));
|
||||||
@@ -46,7 +58,7 @@ namespace GitHub.Services.Common
|
|||||||
|
|
||||||
//These methods convert To and From base64 strings without padding
|
//These methods convert To and From base64 strings without padding
|
||||||
//for JWT scenarios
|
//for JWT scenarios
|
||||||
//code taken from the JWS spec here:
|
//code taken from the JWS spec here:
|
||||||
//http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-08#appendix-C
|
//http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-08#appendix-C
|
||||||
public static String ToBase64StringNoPadding(this byte[] bytes)
|
public static String ToBase64StringNoPadding(this byte[] bytes)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,30 +1,38 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.WebApi
|
namespace GitHub.DistributedTask.WebApi
|
||||||
{
|
{
|
||||||
|
public interface IReadOnlyIssue
|
||||||
|
{
|
||||||
|
IssueType Type { get; }
|
||||||
|
string Category { get; }
|
||||||
|
string Message { get; }
|
||||||
|
bool? IsInfrastructureIssue { get; }
|
||||||
|
string this[string key] { get; }
|
||||||
|
}
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
public class Issue
|
public class Issue : IReadOnlyIssue
|
||||||
{
|
{
|
||||||
|
|
||||||
public Issue()
|
public Issue()
|
||||||
|
: this(null)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private Issue(Issue issueToBeCloned)
|
private Issue(Issue original)
|
||||||
{
|
{
|
||||||
this.Type = issueToBeCloned.Type;
|
this.EnsureInitialized();
|
||||||
this.Category = issueToBeCloned.Category;
|
if (original != null)
|
||||||
this.Message = issueToBeCloned.Message;
|
|
||||||
this.IsInfrastructureIssue = issueToBeCloned.IsInfrastructureIssue;
|
|
||||||
|
|
||||||
if (issueToBeCloned.m_data != null)
|
|
||||||
{
|
{
|
||||||
foreach (var item in issueToBeCloned.m_data)
|
this.Type = original.Type;
|
||||||
{
|
this.Category = original.Category;
|
||||||
this.Data.Add(item);
|
this.Message = original.Message;
|
||||||
}
|
this.IsInfrastructureIssue = original.IsInfrastructureIssue;
|
||||||
|
m_data.AddRange(original.m_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,14 +44,14 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(Order = 2)]
|
[DataMember(Order = 2)]
|
||||||
public String Category
|
public string Category
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(Order = 3)]
|
[DataMember(Order = 3)]
|
||||||
public String Message
|
public string Message
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
@@ -56,15 +64,16 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDictionary<String, String> Data
|
public string this[string key]
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_data == null)
|
m_data.TryGetValue(key, out string result);
|
||||||
{
|
return result;
|
||||||
m_data = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
|
}
|
||||||
}
|
set
|
||||||
return m_data;
|
{
|
||||||
|
m_data[key] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +86,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
private void OnDeserialized(StreamingContext context)
|
private void OnDeserialized(StreamingContext context)
|
||||||
{
|
{
|
||||||
SerializationHelper.Copy(ref m_serializedData, ref m_data, StringComparer.OrdinalIgnoreCase, true);
|
SerializationHelper.Copy(ref m_serializedData, ref m_data, StringComparer.OrdinalIgnoreCase, true);
|
||||||
|
this.EnsureInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
[OnSerializing]
|
[OnSerializing]
|
||||||
@@ -91,9 +101,21 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
m_serializedData = null;
|
m_serializedData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(Name = "Data", EmitDefaultValue = false, Order = 4)]
|
/// <summary>
|
||||||
private IDictionary<String, String> m_serializedData;
|
/// DataContractSerializer bypasses all constructor logic and inline initialization!
|
||||||
|
/// This method takes the place of a workhorse constructor for baseline initialization.
|
||||||
|
/// The expectation is for this logic to be accessible to constructors and also to the OnDeserialized helper.
|
||||||
|
/// </summary>
|
||||||
|
private void EnsureInitialized()
|
||||||
|
{
|
||||||
|
//Note that ?? is a short-circuiting operator.
|
||||||
|
m_data = m_data ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember(Name = "Data", EmitDefaultValue = false, Order = 4)]
|
||||||
|
private IDictionary<string, string> m_serializedData;
|
||||||
|
|
||||||
|
private IDictionary<string, string> m_data;
|
||||||
|
|
||||||
private IDictionary<String, String> m_data;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.Type = type;
|
this.Type = type;
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[DataMember]
|
[DataMember]
|
||||||
public String Type
|
public String Type
|
||||||
|
|||||||
@@ -10,69 +10,76 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
public sealed class TimelineRecord
|
public sealed class TimelineRecord
|
||||||
{
|
{
|
||||||
public TimelineRecord()
|
public TimelineRecord()
|
||||||
|
: this(null)
|
||||||
{
|
{
|
||||||
this.Attempt = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private TimelineRecord(TimelineRecord recordToBeCloned)
|
private TimelineRecord(TimelineRecord recordToBeCloned)
|
||||||
{
|
{
|
||||||
this.Attempt = recordToBeCloned.Attempt;
|
this.EnsureInitialized();
|
||||||
this.ChangeId = recordToBeCloned.ChangeId;
|
if (recordToBeCloned != null)
|
||||||
this.CurrentOperation = recordToBeCloned.CurrentOperation;
|
|
||||||
this.FinishTime = recordToBeCloned.FinishTime;
|
|
||||||
this.Id = recordToBeCloned.Id;
|
|
||||||
this.Identifier = recordToBeCloned.Identifier;
|
|
||||||
this.LastModified = recordToBeCloned.LastModified;
|
|
||||||
this.Location = recordToBeCloned.Location;
|
|
||||||
this.Name = recordToBeCloned.Name;
|
|
||||||
this.Order = recordToBeCloned.Order;
|
|
||||||
this.ParentId = recordToBeCloned.ParentId;
|
|
||||||
this.PercentComplete = recordToBeCloned.PercentComplete;
|
|
||||||
this.RecordType = recordToBeCloned.RecordType;
|
|
||||||
this.Result = recordToBeCloned.Result;
|
|
||||||
this.ResultCode = recordToBeCloned.ResultCode;
|
|
||||||
this.StartTime = recordToBeCloned.StartTime;
|
|
||||||
this.State = recordToBeCloned.State;
|
|
||||||
this.TimelineId = recordToBeCloned.TimelineId;
|
|
||||||
this.WorkerName = recordToBeCloned.WorkerName;
|
|
||||||
this.RefName = recordToBeCloned.RefName;
|
|
||||||
this.ErrorCount = recordToBeCloned.ErrorCount;
|
|
||||||
this.WarningCount = recordToBeCloned.WarningCount;
|
|
||||||
this.NoticeCount = recordToBeCloned.NoticeCount;
|
|
||||||
this.AgentPlatform = recordToBeCloned.AgentPlatform;
|
|
||||||
|
|
||||||
if (recordToBeCloned.Log != null)
|
|
||||||
{
|
{
|
||||||
this.Log = new TaskLogReference
|
this.Attempt = recordToBeCloned.Attempt;
|
||||||
|
this.ChangeId = recordToBeCloned.ChangeId;
|
||||||
|
this.CurrentOperation = recordToBeCloned.CurrentOperation;
|
||||||
|
this.FinishTime = recordToBeCloned.FinishTime;
|
||||||
|
this.Id = recordToBeCloned.Id;
|
||||||
|
this.Identifier = recordToBeCloned.Identifier;
|
||||||
|
this.LastModified = recordToBeCloned.LastModified;
|
||||||
|
this.Location = recordToBeCloned.Location;
|
||||||
|
this.Name = recordToBeCloned.Name;
|
||||||
|
this.Order = recordToBeCloned.Order;
|
||||||
|
this.ParentId = recordToBeCloned.ParentId;
|
||||||
|
this.PercentComplete = recordToBeCloned.PercentComplete;
|
||||||
|
this.RecordType = recordToBeCloned.RecordType;
|
||||||
|
this.Result = recordToBeCloned.Result;
|
||||||
|
this.ResultCode = recordToBeCloned.ResultCode;
|
||||||
|
this.StartTime = recordToBeCloned.StartTime;
|
||||||
|
this.State = recordToBeCloned.State;
|
||||||
|
this.TimelineId = recordToBeCloned.TimelineId;
|
||||||
|
this.WorkerName = recordToBeCloned.WorkerName;
|
||||||
|
this.RefName = recordToBeCloned.RefName;
|
||||||
|
this.ErrorCount = recordToBeCloned.ErrorCount;
|
||||||
|
this.WarningCount = recordToBeCloned.WarningCount;
|
||||||
|
this.NoticeCount = recordToBeCloned.NoticeCount;
|
||||||
|
this.AgentPlatform = recordToBeCloned.AgentPlatform;
|
||||||
|
|
||||||
|
if (recordToBeCloned.Log != null)
|
||||||
{
|
{
|
||||||
Id = recordToBeCloned.Log.Id,
|
this.Log = new TaskLogReference
|
||||||
Location = recordToBeCloned.Log.Location,
|
{
|
||||||
};
|
Id = recordToBeCloned.Log.Id,
|
||||||
}
|
Location = recordToBeCloned.Log.Location,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (recordToBeCloned.Details != null)
|
if (recordToBeCloned.Details != null)
|
||||||
{
|
|
||||||
this.Details = new TimelineReference
|
|
||||||
{
|
{
|
||||||
ChangeId = recordToBeCloned.Details.ChangeId,
|
this.Details = new TimelineReference
|
||||||
Id = recordToBeCloned.Details.Id,
|
{
|
||||||
Location = recordToBeCloned.Details.Location,
|
ChangeId = recordToBeCloned.Details.ChangeId,
|
||||||
};
|
Id = recordToBeCloned.Details.Id,
|
||||||
}
|
Location = recordToBeCloned.Details.Location,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (recordToBeCloned.m_issues?.Count> 0)
|
if (recordToBeCloned.m_issues?.Count > 0)
|
||||||
{
|
{
|
||||||
this.Issues.AddRange(recordToBeCloned.Issues.Select(i => i.Clone()));
|
m_issues.AddRange(recordToBeCloned.m_issues.Select(i => i.Clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recordToBeCloned.m_previousAttempts?.Count > 0)
|
if (recordToBeCloned.m_previousAttempts?.Count > 0)
|
||||||
{
|
{
|
||||||
this.PreviousAttempts.AddRange(recordToBeCloned.PreviousAttempts);
|
m_previousAttempts.AddRange(recordToBeCloned.m_previousAttempts);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recordToBeCloned.m_variables?.Count > 0)
|
if (recordToBeCloned.m_variables?.Count > 0)
|
||||||
{
|
{
|
||||||
this.m_variables = recordToBeCloned.Variables.ToDictionary(k => k.Key, v => v.Value.Clone());
|
// Don't pave over the case-insensitive Dictionary we initialized above.
|
||||||
|
foreach (var kvp in recordToBeCloned.m_variables) {
|
||||||
|
m_variables[kvp.Key] = kvp.Value.Clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,10 +241,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_issues == null)
|
|
||||||
{
|
|
||||||
m_issues = new List<Issue>();
|
|
||||||
}
|
|
||||||
return m_issues;
|
return m_issues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,22 +277,14 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_previousAttempts == null)
|
|
||||||
{
|
|
||||||
m_previousAttempts = new List<TimelineAttempt>();
|
|
||||||
}
|
|
||||||
return m_previousAttempts;
|
return m_previousAttempts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDictionary<String, VariableValue> Variables
|
public IDictionary<string, VariableValue> Variables
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (m_variables == null)
|
|
||||||
{
|
|
||||||
m_variables = new Dictionary<String, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
return m_variables;
|
return m_variables;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -299,11 +294,32 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
return new TimelineRecord(this);
|
return new TimelineRecord(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[OnDeserialized]
|
||||||
|
private void OnDeserialized(StreamingContext context)
|
||||||
|
{
|
||||||
|
this.EnsureInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// DataContractSerializer bypasses all constructor logic and inline initialization!
|
||||||
|
/// This method takes the place of a workhorse constructor for baseline initialization.
|
||||||
|
/// The expectation is for this logic to be accessible to constructors and also to the OnDeserialized helper.
|
||||||
|
/// </summary>
|
||||||
|
private void EnsureInitialized()
|
||||||
|
{
|
||||||
|
//Note that ?? is a short-circuiting operator.
|
||||||
|
m_issues = m_issues ?? new List<Issue>();
|
||||||
|
m_variables = m_variables ?? new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
m_previousAttempts = m_previousAttempts ?? new List<TimelineAttempt>();
|
||||||
|
this.Attempt = Math.Max(this.Attempt, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[DataMember(Name = "Issues", EmitDefaultValue = false, Order = 60)]
|
[DataMember(Name = "Issues", EmitDefaultValue = false, Order = 60)]
|
||||||
private List<Issue> m_issues;
|
private List<Issue> m_issues;
|
||||||
|
|
||||||
[DataMember(Name = "Variables", EmitDefaultValue = false, Order = 80)]
|
[DataMember(Name = "Variables", EmitDefaultValue = false, Order = 80)]
|
||||||
private Dictionary<String, VariableValue> m_variables;
|
private Dictionary<string, VariableValue> m_variables;
|
||||||
|
|
||||||
[DataMember(Name = "PreviousAttempts", EmitDefaultValue = false, Order = 120)]
|
[DataMember(Name = "PreviousAttempts", EmitDefaultValue = false, Order = 120)]
|
||||||
private List<TimelineAttempt> m_previousAttempts;
|
private List<TimelineAttempt> m_previousAttempts;
|
||||||
|
|||||||
@@ -1,60 +0,0 @@
|
|||||||
using System.Runtime.Serialization;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Serialization;
|
|
||||||
|
|
||||||
namespace GitHub.Services.Results.Contracts
|
|
||||||
{
|
|
||||||
[DataContract]
|
|
||||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
|
||||||
public class GetSignedStepSummaryURLRequest
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string WorkflowJobRunBackendId;
|
|
||||||
[DataMember]
|
|
||||||
public string WorkflowRunBackendId;
|
|
||||||
[DataMember]
|
|
||||||
public string StepBackendId;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
|
||||||
public class GetSignedStepSummaryURLResponse
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string SummaryUrl;
|
|
||||||
[DataMember]
|
|
||||||
public long SoftSizeLimit;
|
|
||||||
[DataMember]
|
|
||||||
public string BlobStorageType;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
|
||||||
public class StepSummaryMetadataCreate
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string StepBackendId;
|
|
||||||
[DataMember]
|
|
||||||
public string WorkflowRunBackendId;
|
|
||||||
[DataMember]
|
|
||||||
public string WorkflowJobRunBackendId;
|
|
||||||
[DataMember]
|
|
||||||
public long Size;
|
|
||||||
[DataMember]
|
|
||||||
public string UploadedAt;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
[JsonObject(NamingStrategyType = typeof(SnakeCaseNamingStrategy))]
|
|
||||||
public class CreateStepSummaryMetadataResponse
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public bool Ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class BlobStorageTypes
|
|
||||||
{
|
|
||||||
public static readonly string AzureBlobStorage = "BLOB_STORAGE_TYPE_AZURE";
|
|
||||||
public static readonly string Unspecified = "BLOB_STORAGE_TYPE_UNSPECIFIED";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.Http.Headers;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using GitHub.Services.Results.Contracts;
|
|
||||||
using System.Net.Http.Formatting;
|
|
||||||
using Sdk.WebApi.WebApi;
|
|
||||||
|
|
||||||
namespace GitHub.Services.Results.Client
|
|
||||||
{
|
|
||||||
public class ResultsHttpClient : RawHttpClientBase
|
|
||||||
{
|
|
||||||
public ResultsHttpClient(
|
|
||||||
Uri baseUrl,
|
|
||||||
HttpMessageHandler pipeline,
|
|
||||||
string token,
|
|
||||||
bool disposeHandler)
|
|
||||||
: base(baseUrl, pipeline, disposeHandler)
|
|
||||||
{
|
|
||||||
m_token = token;
|
|
||||||
m_resultsServiceUrl = baseUrl;
|
|
||||||
m_formatter = new JsonMediaTypeFormatter();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<GetSignedStepSummaryURLResponse> GetStepSummaryUploadUrlAsync(string planId, string jobId, string stepId, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var request = new GetSignedStepSummaryURLRequest()
|
|
||||||
{
|
|
||||||
WorkflowJobRunBackendId= jobId,
|
|
||||||
WorkflowRunBackendId= planId,
|
|
||||||
StepBackendId= stepId
|
|
||||||
};
|
|
||||||
|
|
||||||
var stepSummaryUploadRequest = new Uri(m_resultsServiceUrl, "twirp/results.services.receiver.Receiver/GetStepSummarySignedBlobURL");
|
|
||||||
|
|
||||||
using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, stepSummaryUploadRequest))
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", m_token);
|
|
||||||
requestMessage.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
|
||||||
|
|
||||||
using (HttpContent content = new ObjectContent<GetSignedStepSummaryURLRequest>(request, m_formatter))
|
|
||||||
{
|
|
||||||
requestMessage.Content = content;
|
|
||||||
using (var response = await SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, cancellationToken: cancellationToken))
|
|
||||||
{
|
|
||||||
return await ReadJsonContentAsync<GetSignedStepSummaryURLResponse>(response, cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task StepSummaryUploadCompleteAsync(string planId, string jobId, string stepId, long size, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var timestamp = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK");
|
|
||||||
var request = new StepSummaryMetadataCreate()
|
|
||||||
{
|
|
||||||
WorkflowJobRunBackendId= jobId,
|
|
||||||
WorkflowRunBackendId= planId,
|
|
||||||
StepBackendId = stepId,
|
|
||||||
Size = size,
|
|
||||||
UploadedAt = timestamp
|
|
||||||
};
|
|
||||||
|
|
||||||
var stepSummaryUploadCompleteRequest = new Uri(m_resultsServiceUrl, "twirp/results.services.receiver.Receiver/CreateStepSummaryMetadata");
|
|
||||||
|
|
||||||
using (HttpRequestMessage requestMessage = new HttpRequestMessage(HttpMethod.Post, stepSummaryUploadCompleteRequest))
|
|
||||||
{
|
|
||||||
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", m_token);
|
|
||||||
requestMessage.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse("application/json"));
|
|
||||||
|
|
||||||
using (HttpContent content = new ObjectContent<StepSummaryMetadataCreate>(request, m_formatter))
|
|
||||||
{
|
|
||||||
requestMessage.Content = content;
|
|
||||||
using (var response = await SendAsync(requestMessage, HttpCompletionOption.ResponseContentRead, cancellationToken: cancellationToken))
|
|
||||||
{
|
|
||||||
var jsonResponse = await ReadJsonContentAsync<CreateStepSummaryMetadataResponse>(response, cancellationToken);
|
|
||||||
if (!jsonResponse.Ok)
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to mark step summary upload as complete, status code: {response.StatusCode}, ok: {jsonResponse.Ok}, size: {size}, timestamp: {timestamp}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<HttpResponseMessage> UploadFileAsync(string url, string blobStorageType, FileStream file, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// Upload the file to the url
|
|
||||||
var request = new HttpRequestMessage(HttpMethod.Put, url)
|
|
||||||
{
|
|
||||||
Content = new StreamContent(file)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (blobStorageType == BlobStorageTypes.AzureBlobStorage)
|
|
||||||
{
|
|
||||||
request.Content.Headers.Add("x-ms-blob-type", "BlockBlob");
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var response = await SendAsync(request, HttpCompletionOption.ResponseHeadersRead, userState: null, cancellationToken))
|
|
||||||
{
|
|
||||||
if (!response.IsSuccessStatusCode)
|
|
||||||
{
|
|
||||||
throw new Exception($"Failed to upload file, status code: {response.StatusCode}, reason: {response.ReasonPhrase}");
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle file upload for step summary
|
|
||||||
public async Task UploadStepSummaryAsync(string planId, string jobId, string stepId, string file, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// Get the upload url
|
|
||||||
var uploadUrlResponse = await GetStepSummaryUploadUrlAsync(planId, jobId, stepId, cancellationToken);
|
|
||||||
if (uploadUrlResponse == null)
|
|
||||||
{
|
|
||||||
throw new Exception("Failed to get step summary upload url");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do we want to throw an exception here or should we just be uploading/truncating the data
|
|
||||||
var fileSize = new FileInfo(file).Length;
|
|
||||||
if (fileSize > uploadUrlResponse.SoftSizeLimit)
|
|
||||||
{
|
|
||||||
throw new Exception($"File size is larger than the upload url allows, file size: {fileSize}, upload url size: {uploadUrlResponse.SoftSizeLimit}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload the file
|
|
||||||
using (var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, true))
|
|
||||||
{
|
|
||||||
var response = await UploadFileAsync(uploadUrlResponse.SummaryUrl, uploadUrlResponse.BlobStorageType, fileStream, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send step summary upload complete message
|
|
||||||
await StepSummaryUploadCompleteAsync(planId, jobId, stepId, fileSize, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private MediaTypeFormatter m_formatter;
|
|
||||||
private Uri m_resultsServiceUrl;
|
|
||||||
private string m_token;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -824,7 +824,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
[InlineData("remove", "version")]
|
[InlineData("remove", "version")]
|
||||||
[InlineData("remove", "commit")]
|
[InlineData("remove", "commit")]
|
||||||
[InlineData("remove", "check")]
|
[InlineData("remove", "check")]
|
||||||
[InlineData("remove", "local")]
|
|
||||||
[InlineData("run", "help")]
|
[InlineData("run", "help")]
|
||||||
[InlineData("run", "version")]
|
[InlineData("run", "version")]
|
||||||
[InlineData("run", "commit")]
|
[InlineData("run", "commit")]
|
||||||
|
|||||||
@@ -502,34 +502,5 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
_messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), Times.Once());
|
_messageListener.Verify(x => x.DeleteMessageAsync(It.IsAny<TaskAgentMessage>()), Times.Once());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Runner")]
|
|
||||||
public async void TestRemoveLocalRunnerConfig()
|
|
||||||
{
|
|
||||||
using (var hc = new TestHostContext(this))
|
|
||||||
{
|
|
||||||
hc.SetSingleton<IConfigurationManager>(_configurationManager.Object);
|
|
||||||
hc.SetSingleton<IConfigurationStore>(_configStore.Object);
|
|
||||||
hc.SetSingleton<IPromptManager>(_promptManager.Object);
|
|
||||||
|
|
||||||
var command = new CommandSettings(hc, new[] { "remove", "--local" });
|
|
||||||
|
|
||||||
_configStore.Setup(x => x.IsConfigured())
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
_configStore.Setup(x => x.HasCredentials())
|
|
||||||
.Returns(true);
|
|
||||||
|
|
||||||
|
|
||||||
var runner = new Runner.Listener.Runner();
|
|
||||||
runner.Initialize(hc);
|
|
||||||
await runner.ExecuteCommand(command);
|
|
||||||
|
|
||||||
// verify that we delete the local runner config with the correct remove parameter
|
|
||||||
_configurationManager.Verify(x => x.DeleteLocalRunnerConfig(), Times.Once());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -128,144 +128,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#if OS_WINDOWS
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public async Task SetTestEnvWithNullInKey()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = new(this))
|
|
||||||
{
|
|
||||||
Tracing trace = hc.GetTrace();
|
|
||||||
|
|
||||||
Int32 exitCode = -1;
|
|
||||||
var processInvoker = new ProcessInvokerWrapper();
|
|
||||||
processInvoker.Initialize(hc);
|
|
||||||
var stdout = new List<string>();
|
|
||||||
var stderr = new List<string>();
|
|
||||||
processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stdout.Add(e.Data);
|
|
||||||
};
|
|
||||||
processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stderr.Add(e.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
exitCode = await processInvoker.ExecuteAsync("", "cmd.exe", "/c \"echo %TEST%\"", new Dictionary<string, string>() { { "TEST\0second", "first" } }, CancellationToken.None);
|
|
||||||
|
|
||||||
|
|
||||||
trace.Info("Exit Code: {0}", exitCode);
|
|
||||||
Assert.Equal(0, exitCode);
|
|
||||||
Assert.Equal("first", stdout.First(x => !string.IsNullOrWhiteSpace(x)));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public async Task SetTestEnvWithTabInKey()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = new(this))
|
|
||||||
{
|
|
||||||
Tracing trace = hc.GetTrace();
|
|
||||||
|
|
||||||
Int32 exitCode = -1;
|
|
||||||
var processInvoker = new ProcessInvokerWrapper();
|
|
||||||
processInvoker.Initialize(hc);
|
|
||||||
var stdout = new List<string>();
|
|
||||||
var stderr = new List<string>();
|
|
||||||
processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stdout.Add(e.Data);
|
|
||||||
};
|
|
||||||
processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stderr.Add(e.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
exitCode = await processInvoker.ExecuteAsync("", "cmd.exe", "/c \"echo %TEST%\"", new Dictionary<string, string>() { { "TEST\u0009second", "first" } }, CancellationToken.None);
|
|
||||||
|
|
||||||
trace.Info("Exit Code: {0}", exitCode);
|
|
||||||
Assert.Equal(0, exitCode);
|
|
||||||
Assert.Equal("first", stdout.First(x => !string.IsNullOrWhiteSpace(x)));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public async Task SetTestEnvWithNullInValue()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = new(this))
|
|
||||||
{
|
|
||||||
Tracing trace = hc.GetTrace();
|
|
||||||
|
|
||||||
Int32 exitCode = -1;
|
|
||||||
var processInvoker = new ProcessInvokerWrapper();
|
|
||||||
processInvoker.Initialize(hc);
|
|
||||||
var stdout = new List<string>();
|
|
||||||
var stderr = new List<string>();
|
|
||||||
processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stdout.Add(e.Data);
|
|
||||||
};
|
|
||||||
processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stderr.Add(e.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
exitCode = await processInvoker.ExecuteAsync("", "cmd.exe", "/c \"echo %TEST%\"", new Dictionary<string, string>() { { "TEST", "first\0second" } }, CancellationToken.None);
|
|
||||||
|
|
||||||
trace.Info("Exit Code: {0}", exitCode);
|
|
||||||
Assert.Equal(0, exitCode);
|
|
||||||
Assert.Equal("first", stdout.First(x => !string.IsNullOrWhiteSpace(x)));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public async Task SetTestEnvWithTabInValue()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = new(this))
|
|
||||||
{
|
|
||||||
Tracing trace = hc.GetTrace();
|
|
||||||
|
|
||||||
Int32 exitCode = -1;
|
|
||||||
var processInvoker = new ProcessInvokerWrapper();
|
|
||||||
processInvoker.Initialize(hc);
|
|
||||||
var stdout = new List<string>();
|
|
||||||
var stderr = new List<string>();
|
|
||||||
processInvoker.OutputDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stdout.Add(e.Data);
|
|
||||||
};
|
|
||||||
processInvoker.ErrorDataReceived += (object sender, ProcessDataReceivedEventArgs e) =>
|
|
||||||
{
|
|
||||||
trace.Info(e.Data);
|
|
||||||
stderr.Add(e.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
exitCode = await processInvoker.ExecuteAsync("", "cmd.exe", "/c \"echo %TEST%\"", new Dictionary<string, string>() { { "TEST", "first\u0009second" } }, CancellationToken.None);
|
|
||||||
|
|
||||||
trace.Info("Exit Code: {0}", exitCode);
|
|
||||||
Assert.Equal(0, exitCode);
|
|
||||||
Assert.Equal("first", stdout.First(x => !string.IsNullOrWhiteSpace(x)));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Common")]
|
[Trait("Category", "Common")]
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
using Xunit;
|
using Xunit;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
using GitHub.DistributedTask.WebApi;
|
||||||
|
using GitHub.Runner.Worker;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests
|
namespace GitHub.Runner.Common.Tests
|
||||||
{
|
{
|
||||||
@@ -41,5 +43,26 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Assert.True(Directory.Exists(testDataDir));
|
Assert.True(Directory.Exists(testDataDir));
|
||||||
return testDataDir;
|
return testDataDir;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyIssue CreateTestIssue(IssueType type, string message, IssueMetadata metadata, bool writeToLog)
|
||||||
|
{
|
||||||
|
var result = new Issue()
|
||||||
|
{
|
||||||
|
Type = type,
|
||||||
|
Message = message,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (metadata != null)
|
||||||
|
{
|
||||||
|
result.Category = metadata.Category;
|
||||||
|
result.IsInfrastructureIssue = metadata.IsInfrastructureIssue;
|
||||||
|
foreach (var kvp in metadata.Data)
|
||||||
|
{
|
||||||
|
result[kvp.Key] = kvp.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,10 +32,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
hc.GetTrace().Info($"{tag} {line}");
|
hc.GetTrace().Info($"{tag} {line}");
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>()))
|
_ec.Setup(x => x.AddIssue(It.IsAny<IReadOnlyIssue>()))
|
||||||
.Callback((Issue issue, string message) =>
|
.Callback((IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
hc.GetTrace().Info($"{issue.Type} {issue.Message} {message ?? string.Empty}");
|
hc.GetTrace().Info($"{issue.Type} {issue.Message}");
|
||||||
});
|
});
|
||||||
|
|
||||||
_commandManager.EnablePluginInternalCommand();
|
_commandManager.EnablePluginInternalCommand();
|
||||||
@@ -59,10 +59,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
hc.GetTrace().Info($"{tag} {line}");
|
hc.GetTrace().Info($"{tag} {line}");
|
||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>()))
|
_ec.Setup(x => x.AddIssue(It.IsAny<IReadOnlyIssue>()))
|
||||||
.Callback((Issue issue, string message) =>
|
.Callback((IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
hc.GetTrace().Info($"{issue.Type} {issue.Message} {message ?? string.Empty}");
|
hc.GetTrace().Info($"{issue.Type} {issue.Message}");
|
||||||
});
|
});
|
||||||
|
|
||||||
_commandManager.EnablePluginInternalCommand();
|
_commandManager.EnablePluginInternalCommand();
|
||||||
@@ -92,10 +92,12 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
return 1;
|
return 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>()))
|
_ec.Setup(x => x.CreateIssue(It.IsAny<IssueType>(), It.IsAny<string>(), It.IsAny<IssueMetadata>(), It.IsAny<bool>()))
|
||||||
.Callback((Issue issue, string message) =>
|
.Returns(TestUtil.CreateTestIssue);
|
||||||
|
_ec.Setup(x => x.AddIssue(It.IsAny<IReadOnlyIssue>()))
|
||||||
|
.Callback((IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
hc.GetTrace().Info($"{issue.Type} {issue.Message} {message ?? string.Empty}");
|
hc.GetTrace().Info($"{issue.Type} {issue.Message}");
|
||||||
});
|
});
|
||||||
|
|
||||||
_ec.Object.Global.EnvironmentVariables = new Dictionary<string, string>();
|
_ec.Object.Global.EnvironmentVariables = new Dictionary<string, string>();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@@ -14,6 +13,11 @@ using GitHub.DistributedTask.WebApi;
|
|||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
|
using System.IO.Compression;
|
||||||
|
#endif
|
||||||
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Moq.Protected;
|
using Moq.Protected;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
@@ -2147,7 +2151,9 @@ runs:
|
|||||||
_ec.Object.Global.FileTable = new List<String>();
|
_ec.Object.Global.FileTable = new List<String>();
|
||||||
_ec.Object.Global.Plan = new TaskOrchestrationPlanReference();
|
_ec.Object.Global.Plan = new TaskOrchestrationPlanReference();
|
||||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
|
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
_ec.Setup(x => x.CreateIssue(It.IsAny<IssueType>(), It.IsAny<string>(), It.IsAny<IssueMetadata>(), It.IsAny<bool>()))
|
||||||
|
.Returns(TestUtil.CreateTestIssue);
|
||||||
|
_ec.Setup(x => x.AddIssue(It.IsAny<IReadOnlyIssue>())).Callback((IReadOnlyIssue issue) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message}"); });
|
||||||
_ec.Setup(x => x.GetGitHubContext("workspace")).Returns(Path.Combine(_workFolder, "actions", "actions"));
|
_ec.Setup(x => x.GetGitHubContext("workspace")).Returns(Path.Combine(_workFolder, "actions", "actions"));
|
||||||
|
|
||||||
_dockerManager = new Mock<IDockerCommandManager>();
|
_dockerManager = new Mock<IDockerCommandManager>();
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ using GitHub.DistributedTask.Pipelines.ContextData;
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Expressions;
|
using GitHub.Runner.Worker.Expressions;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using Moq;
|
using Moq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -670,7 +670,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
Teardown();
|
Teardown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
@@ -715,7 +715,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
//Assert
|
//Assert
|
||||||
var err = Assert.Throws<ArgumentException>(() => actionManifest.Load(_ec.Object, action_path));
|
var err = Assert.Throws<ArgumentException>(() => actionManifest.Load(_ec.Object, action_path));
|
||||||
Assert.Contains($"Fail to load {action_path}", err.Message);
|
Assert.Contains($"Fail to load {action_path}", err.Message);
|
||||||
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Missing 'using' value. 'using' requires 'composite', 'docker', 'node12' or 'node16'.")), It.IsAny<string>()), Times.Once);
|
_ec.Verify(x => x.AddIssue(It.Is<IReadOnlyIssue>(s => s.Message.Contains("Missing 'using' value. 'using' requires 'composite', 'docker', 'node12' or 'node16'."))), Times.Once);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -860,7 +860,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
_ec.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
||||||
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
_ec.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
||||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"{tag}{message}"); });
|
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"{tag}{message}"); });
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
|
||||||
|
_ec.Setup(x => x.CreateIssue(It.IsAny<IssueType>(), It.IsAny<string>(), It.IsAny<IssueMetadata>(), It.IsAny<bool>()))
|
||||||
|
.Returns(TestUtil.CreateTestIssue);
|
||||||
|
_ec.Setup(x => x.AddIssue(It.IsAny<IReadOnlyIssue>())).Callback((IReadOnlyIssue issue) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message}"); });
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Teardown()
|
private void Teardown()
|
||||||
|
|||||||
@@ -3,20 +3,15 @@ using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
|
||||||
using System.IO.Compression;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
@@ -330,7 +325,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Assert.Equal("invalid1", finialInputs["invalid1"]);
|
Assert.Equal("invalid1", finialInputs["invalid1"]);
|
||||||
Assert.Equal("invalid2", finialInputs["invalid2"]);
|
Assert.Equal("invalid2", finialInputs["invalid2"]);
|
||||||
|
|
||||||
_ec.Verify(x => x.AddIssue(It.Is<Issue>(s => s.Message.Contains("Unexpected input(s) 'invalid1', 'invalid2'")), It.IsAny<string>()), Times.Once);
|
_ec.Verify(x => x.AddIssue(It.Is<IReadOnlyIssue>(s => s.Message.Contains("Unexpected input(s) 'invalid1', 'invalid2'"))), Times.Once);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -449,7 +444,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
_ec.Setup(x => x.CancellationToken).Returns(_ecTokenSource.Token);
|
||||||
_ec.Object.Global.Variables = new Variables(_hc, new Dictionary<string, VariableValue>());
|
_ec.Object.Global.Variables = new Variables(_hc, new Dictionary<string, VariableValue>());
|
||||||
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
|
_ec.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>())).Callback((string tag, string message) => { _hc.GetTrace().Info($"[{tag}]{message}"); });
|
||||||
_ec.Setup(x => x.AddIssue(It.IsAny<Issue>(), It.IsAny<string>())).Callback((Issue issue, string message) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message ?? message}"); });
|
_ec.Setup(x => x.CreateIssue(It.IsAny<IssueType>(), It.IsAny<string>(), It.IsAny<IssueMetadata>(), It.IsAny<bool>()))
|
||||||
|
.Returns(TestUtil.CreateTestIssue);
|
||||||
|
_ec.Setup(x => x.AddIssue(It.IsAny<IReadOnlyIssue>())).Callback((IReadOnlyIssue issue) => { _hc.GetTrace().Info($"[{issue.Type}]{issue.Message}"); });
|
||||||
|
|
||||||
_hc.SetSingleton<IActionManager>(_actionManager.Object);
|
_hc.SetSingleton<IActionManager>(_actionManager.Object);
|
||||||
_hc.SetSingleton<IHandlerFactory>(_handlerFactory.Object);
|
_hc.SetSingleton<IHandlerFactory>(_handlerFactory.Object);
|
||||||
|
|||||||
@@ -99,46 +99,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void InitializeWithCorrectManager()
|
|
||||||
{
|
|
||||||
containers.Add(new ContainerInfo() { ContainerImage = "ubuntu:16.04" });
|
|
||||||
_hc = new TestHostContext(this, "Test");
|
|
||||||
_ec = new Mock<IExecutionContext>();
|
|
||||||
serverQueue = new Mock<IJobServerQueue>();
|
|
||||||
pagingLogger = new Mock<IPagingLogger>();
|
|
||||||
|
|
||||||
containerOperationProvider = new ContainerOperationProvider();
|
|
||||||
|
|
||||||
_hc.SetSingleton<IJobServerQueue>(serverQueue.Object);
|
|
||||||
_hc.SetSingleton<IPagingLogger>(pagingLogger.Object);
|
|
||||||
|
|
||||||
|
|
||||||
_ec.Setup(x => x.Global).Returns(new GlobalContext());
|
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable(Constants.Hooks.ContainerHooksPath, "/tmp/k8s/index.js");
|
|
||||||
_dockerManager = new Mock<IDockerCommandManager>();
|
|
||||||
_dockerManager.Setup(x => x.Initialize(_hc)).Throws(new Exception("Docker manager's Initialize should not be called"));
|
|
||||||
|
|
||||||
_containerHookManager = new Mock<IContainerHookManager>();
|
|
||||||
_hc.SetSingleton<IDockerCommandManager>(_dockerManager.Object);
|
|
||||||
_hc.SetSingleton<IContainerHookManager>(_containerHookManager.Object);
|
|
||||||
|
|
||||||
containerOperationProvider.Initialize(_hc);
|
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable(Constants.Hooks.ContainerHooksPath, null);
|
|
||||||
_containerHookManager = new Mock<IContainerHookManager>();
|
|
||||||
_containerHookManager.Setup(x => x.Initialize(_hc)).Throws(new Exception("Container hook manager's Initialize should not be called"));
|
|
||||||
|
|
||||||
_dockerManager = new Mock<IDockerCommandManager>();
|
|
||||||
_hc.SetSingleton<IDockerCommandManager>(_dockerManager.Object);
|
|
||||||
_hc.SetSingleton<IContainerHookManager>(_containerHookManager.Object);
|
|
||||||
|
|
||||||
containerOperationProvider.Initialize(_hc);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Setup([CallerMemberName] string testName = "")
|
private void Setup([CallerMemberName] string testName = "")
|
||||||
{
|
{
|
||||||
containers.Add(new ContainerInfo() { ContainerImage = "ubuntu:16.04" });
|
containers.Add(new ContainerInfo() { ContainerImage = "ubuntu:16.04" });
|
||||||
@@ -151,6 +111,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_containerHookManager = new Mock<IContainerHookManager>();
|
_containerHookManager = new Mock<IContainerHookManager>();
|
||||||
containerOperationProvider = new ContainerOperationProvider();
|
containerOperationProvider = new ContainerOperationProvider();
|
||||||
|
|
||||||
|
_hc.SetSingleton<IDockerCommandManager>(_dockerManager.Object);
|
||||||
_hc.SetSingleton<IJobServerQueue>(serverQueue.Object);
|
_hc.SetSingleton<IJobServerQueue>(serverQueue.Object);
|
||||||
_hc.SetSingleton<IPagingLogger>(pagingLogger.Object);
|
_hc.SetSingleton<IPagingLogger>(pagingLogger.Object);
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Xunit;
|
|||||||
using DTWebApi = GitHub.DistributedTask.WebApi;
|
using DTWebApi = GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
using GitHub.Services.Common;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
{
|
{
|
||||||
@@ -19,7 +20,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
private Mock<IExecutionContext> _executionContext;
|
private Mock<IExecutionContext> _executionContext;
|
||||||
private Mock<IJobServerQueue> _jobServerQueue;
|
private Mock<IJobServerQueue> _jobServerQueue;
|
||||||
private ExecutionContext _jobExecutionContext;
|
private ExecutionContext _jobExecutionContext;
|
||||||
private List<Tuple<DTWebApi.Issue, string>> _issues;
|
private List<DTWebApi.IReadOnlyIssue> _issues;
|
||||||
private Variables _variables;
|
private Variables _variables;
|
||||||
private string _rootDirectory;
|
private string _rootDirectory;
|
||||||
private CreateStepSummaryCommand _createStepCommand;
|
private CreateStepSummaryCommand _createStepCommand;
|
||||||
@@ -186,7 +187,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
var hostContext = new TestHostContext(this, name);
|
var hostContext = new TestHostContext(this, name);
|
||||||
|
|
||||||
_issues = new List<Tuple<DTWebApi.Issue, string>>();
|
_issues = new List<DTWebApi.IReadOnlyIssue>();
|
||||||
|
|
||||||
// Setup a job request
|
// Setup a job request
|
||||||
TaskOrchestrationPlanReference plan = new();
|
TaskOrchestrationPlanReference plan = new();
|
||||||
@@ -247,13 +248,14 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
WriteDebug = true,
|
WriteDebug = true,
|
||||||
Variables = _variables,
|
Variables = _variables,
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.Issue>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.IReadOnlyIssue>()))
|
||||||
.Callback((DTWebApi.Issue issue, string logMessage) =>
|
.Callback((DTWebApi.IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
_issues.Add(new Tuple<DTWebApi.Issue, string>(issue, logMessage));
|
_issues.Add(issue);
|
||||||
var message = !string.IsNullOrEmpty(logMessage) ? logMessage : issue.Message;
|
_trace.Info($"Issue '{issue.Type}': {issue.Message}");
|
||||||
_trace.Info($"Issue '{issue.Type}': {message}");
|
|
||||||
});
|
});
|
||||||
|
_executionContext.Setup(x => x.CreateIssue(It.IsAny<IssueType>(), It.IsAny<string>(), It.IsAny<IssueMetadata>(), It.IsAny<bool>()))
|
||||||
|
.Returns(TestUtil.CreateTestIssue);
|
||||||
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Callback((string tag, string message) =>
|
.Callback((string tag, string message) =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -52,36 +52,36 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
// Act.
|
// Act.
|
||||||
ec.InitializeJob(jobRequest, CancellationToken.None);
|
ec.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
|
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
|
|
||||||
ec.Complete();
|
ec.Complete();
|
||||||
|
|
||||||
@@ -190,9 +190,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
bigMessage += "a";
|
bigMessage += "a";
|
||||||
}
|
}
|
||||||
|
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = bigMessage });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, bigMessage, null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = bigMessage });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, bigMessage, null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Notice, Message = bigMessage });
|
ec.AddIssue(ec.CreateIssue(IssueType.Notice, bigMessage, null, true));
|
||||||
|
|
||||||
ec.Complete();
|
ec.Complete();
|
||||||
|
|
||||||
@@ -242,13 +242,13 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var embeddedStep = ec.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, ActionRunStage.Main, isEmbedded: true);
|
var embeddedStep = ec.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, ActionRunStage.Main, isEmbedded: true);
|
||||||
embeddedStep.Start();
|
embeddedStep.Start();
|
||||||
|
|
||||||
embeddedStep.AddIssue(new Issue() { Type = IssueType.Error, Message = "error annotation that should have step and line number information" });
|
embeddedStep.AddIssue(embeddedStep.CreateIssue(IssueType.Error, "error annotation that should have step and line number information", null, true));
|
||||||
embeddedStep.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning annotation that should have step and line number information" });
|
embeddedStep.AddIssue(embeddedStep.CreateIssue(IssueType.Warning, "warning annotation that should have step and line number information", null, true));
|
||||||
embeddedStep.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice annotation that should have step and line number information" });
|
embeddedStep.AddIssue(embeddedStep.CreateIssue(IssueType.Notice, "notice annotation that should have step and line number information", null, true));
|
||||||
|
|
||||||
jobServerQueue.Verify(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.Is<TimelineRecord>(t => t.Issues.Where(i => i.Data.ContainsKey("stepNumber") && i.Data.ContainsKey("logFileLineNumber") && i.Type == IssueType.Error).Count() == 1)), Times.AtLeastOnce);
|
jobServerQueue.Verify(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.Is<TimelineRecord>(t => t.Issues.Where(i => i["stepNumber"] != null && i["logFileLineNumber"] != null && i.Type == IssueType.Error).Count() == 1)), Times.AtLeastOnce);
|
||||||
jobServerQueue.Verify(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.Is<TimelineRecord>(t => t.Issues.Where(i => i.Data.ContainsKey("stepNumber") && i.Data.ContainsKey("logFileLineNumber") && i.Type == IssueType.Warning).Count() == 1)), Times.AtLeastOnce);
|
jobServerQueue.Verify(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.Is<TimelineRecord>(t => t.Issues.Where(i => i["stepNumber"] != null && i["logFileLineNumber"] != null && i.Type == IssueType.Warning).Count() == 1)), Times.AtLeastOnce);
|
||||||
jobServerQueue.Verify(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.Is<TimelineRecord>(t => t.Issues.Where(i => i.Data.ContainsKey("stepNumber") && i.Data.ContainsKey("logFileLineNumber") && i.Type == IssueType.Notice).Count() == 1)), Times.AtLeastOnce);
|
jobServerQueue.Verify(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.Is<TimelineRecord>(t => t.Issues.Where(i => i["stepNumber"] != null && i["logFileLineNumber"] != null && i.Type == IssueType.Notice).Count() == 1)), Times.AtLeastOnce);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -626,12 +626,12 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
ec.StepTelemetry.StepId = Guid.NewGuid();
|
ec.StepTelemetry.StepId = Guid.NewGuid();
|
||||||
ec.StepTelemetry.Stage = "main";
|
ec.StepTelemetry.Stage = "main";
|
||||||
|
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Notice, "notice", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
ec.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice" });
|
ec.AddIssue(ec.CreateIssue(IssueType.Notice, "notice", null, true));
|
||||||
|
|
||||||
ec.Complete();
|
ec.Complete();
|
||||||
|
|
||||||
@@ -692,9 +692,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
embeddedStep.StepTelemetry.Action = "actions/checkout";
|
||||||
embeddedStep.StepTelemetry.Ref = "v2";
|
embeddedStep.StepTelemetry.Ref = "v2";
|
||||||
|
|
||||||
embeddedStep.AddIssue(new Issue() { Type = IssueType.Error, Message = "error" });
|
embeddedStep.AddIssue(ec.CreateIssue(IssueType.Error, "error", null, true));
|
||||||
embeddedStep.AddIssue(new Issue() { Type = IssueType.Warning, Message = "warning" });
|
embeddedStep.AddIssue(ec.CreateIssue(IssueType.Warning, "warning", null, true));
|
||||||
embeddedStep.AddIssue(new Issue() { Type = IssueType.Notice, Message = "notice" });
|
embeddedStep.AddIssue(ec.CreateIssue(IssueType.Notice, "notice", null, true));
|
||||||
|
|
||||||
embeddedStep.PublishStepTelemetry();
|
embeddedStep.PublishStepTelemetry();
|
||||||
|
|
||||||
@@ -870,7 +870,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
inputVarsContext["VARIABLE_2"] = new StringContextData("value2");
|
inputVarsContext["VARIABLE_2"] = new StringContextData("value2");
|
||||||
jobRequest.ContextData["vars"] = inputVarsContext;
|
jobRequest.ContextData["vars"] = inputVarsContext;
|
||||||
|
|
||||||
// Arrange: Setup the paging logger.
|
// Arrange: Setup the paging logger.
|
||||||
var pagingLogger1 = new Mock<IPagingLogger>();
|
var pagingLogger1 = new Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
hc.EnqueueInstance(pagingLogger1.Object);
|
hc.EnqueueInstance(pagingLogger1.Object);
|
||||||
@@ -884,7 +884,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var expected = new DictionaryContextData();
|
var expected = new DictionaryContextData();
|
||||||
expected["VARIABLE_1"] = new StringContextData("value1");
|
expected["VARIABLE_1"] = new StringContextData("value1");
|
||||||
expected["VARIABLE_2"] = new StringContextData("value1");
|
expected["VARIABLE_2"] = new StringContextData("value1");
|
||||||
|
|
||||||
Assert.True(ExpressionValuesAssertEqual(expected, jobContext.ExpressionValues["vars"] as DictionaryContextData));
|
Assert.True(ExpressionValuesAssertEqual(expected, jobContext.ExpressionValues["vars"] as DictionaryContextData));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -915,7 +915,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
inputVarsContext[Constants.Variables.Actions.RunnerDebug] = new StringContextData("true");
|
inputVarsContext[Constants.Variables.Actions.RunnerDebug] = new StringContextData("true");
|
||||||
jobRequest.ContextData["vars"] = inputVarsContext;
|
jobRequest.ContextData["vars"] = inputVarsContext;
|
||||||
|
|
||||||
// Arrange: Setup the paging logger.
|
// Arrange: Setup the paging logger.
|
||||||
var pagingLogger1 = new Mock<IPagingLogger>();
|
var pagingLogger1 = new Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
hc.EnqueueInstance(pagingLogger1.Object);
|
hc.EnqueueInstance(pagingLogger1.Object);
|
||||||
@@ -926,7 +926,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
|
|
||||||
Assert.Equal("true", jobContext.Global.Variables.Get(Constants.Variables.Actions.StepDebug));
|
Assert.Equal("true", jobContext.Global.Variables.Get(Constants.Variables.Actions.StepDebug));
|
||||||
Assert.Equal("true", jobContext.Global.Variables.Get(Constants.Variables.Actions.RunnerDebug));
|
Assert.Equal("true", jobContext.Global.Variables.Get(Constants.Variables.Actions.RunnerDebug));
|
||||||
}
|
}
|
||||||
@@ -961,7 +961,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
jobRequest.Variables[Constants.Variables.Actions.StepDebug] = "false";
|
jobRequest.Variables[Constants.Variables.Actions.StepDebug] = "false";
|
||||||
jobRequest.Variables[Constants.Variables.Actions.RunnerDebug] = "false";
|
jobRequest.Variables[Constants.Variables.Actions.RunnerDebug] = "false";
|
||||||
|
|
||||||
// Arrange: Setup the paging logger.
|
// Arrange: Setup the paging logger.
|
||||||
var pagingLogger1 = new Mock<IPagingLogger>();
|
var pagingLogger1 = new Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
hc.EnqueueInstance(pagingLogger1.Object);
|
hc.EnqueueInstance(pagingLogger1.Object);
|
||||||
@@ -972,7 +972,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
|
|
||||||
Assert.Equal("false", jobContext.Global.Variables.Get(Constants.Variables.Actions.StepDebug));
|
Assert.Equal("false", jobContext.Global.Variables.Get(Constants.Variables.Actions.StepDebug));
|
||||||
Assert.Equal("false", jobContext.Global.Variables.Get(Constants.Variables.Actions.RunnerDebug));
|
Assert.Equal("false", jobContext.Global.Variables.Get(Constants.Variables.Actions.RunnerDebug));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using GitHub.Runner.Sdk;
|
|||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
using GitHub.Runner.Worker.Handlers;
|
using GitHub.Runner.Worker.Handlers;
|
||||||
|
using GitHub.Services.Common;
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using DTWebApi = GitHub.DistributedTask.WebApi;
|
using DTWebApi = GitHub.DistributedTask.WebApi;
|
||||||
@@ -21,7 +22,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
private Mock<IActionCommandManager> _commandManager;
|
private Mock<IActionCommandManager> _commandManager;
|
||||||
private Variables _variables;
|
private Variables _variables;
|
||||||
private OnMatcherChanged _onMatcherChanged;
|
private OnMatcherChanged _onMatcherChanged;
|
||||||
private List<Tuple<DTWebApi.Issue, string>> _issues;
|
private List<DTWebApi.IReadOnlyIssue> _issues;
|
||||||
private List<string> _messages;
|
private List<string> _messages;
|
||||||
private List<string> _commands;
|
private List<string> _commands;
|
||||||
private OutputManager _outputManager;
|
private OutputManager _outputManager;
|
||||||
@@ -82,10 +83,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("ERROR: message 4");
|
Process("ERROR: message 4");
|
||||||
Process("NOT GOOD: message 5");
|
Process("NOT GOOD: message 5");
|
||||||
Assert.Equal(4, _issues.Count);
|
Assert.Equal(4, _issues.Count);
|
||||||
Assert.Equal("message 1", _issues[0].Item1.Message);
|
Assert.Equal("message 1", _issues[0].Message);
|
||||||
Assert.Equal("message 2", _issues[1].Item1.Message);
|
Assert.Equal("message 2", _issues[1].Message);
|
||||||
Assert.Equal("message 3", _issues[2].Item1.Message);
|
Assert.Equal("message 3", _issues[2].Message);
|
||||||
Assert.Equal("message 5", _issues[3].Item1.Message);
|
Assert.Equal("message 5", _issues[3].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(1, _messages.Count);
|
Assert.Equal(1, _messages.Count);
|
||||||
Assert.Equal("ERROR: message 4", _messages[0]);
|
Assert.Equal("ERROR: message 4", _messages[0]);
|
||||||
@@ -148,11 +149,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("ERROR: message 4");
|
Process("ERROR: message 4");
|
||||||
Process("NOT GOOD: message 5");
|
Process("NOT GOOD: message 5");
|
||||||
Assert.Equal(5, _issues.Count);
|
Assert.Equal(5, _issues.Count);
|
||||||
Assert.Equal("message 1", _issues[0].Item1.Message);
|
Assert.Equal("message 1", _issues[0].Message);
|
||||||
Assert.Equal("message 2", _issues[1].Item1.Message);
|
Assert.Equal("message 2", _issues[1].Message);
|
||||||
Assert.Equal("message 3", _issues[2].Item1.Message);
|
Assert.Equal("message 3", _issues[2].Message);
|
||||||
Assert.Equal("message 4", _issues[3].Item1.Message);
|
Assert.Equal("message 4", _issues[3].Message);
|
||||||
Assert.Equal("message 5", _issues[4].Item1.Message);
|
Assert.Equal("message 5", _issues[4].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(0, _messages.Count);
|
Assert.Equal(0, _messages.Count);
|
||||||
}
|
}
|
||||||
@@ -188,10 +189,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("BAD: real bad");
|
Process("BAD: real bad");
|
||||||
Process(": not working");
|
Process(": not working");
|
||||||
Assert.Equal(2, _issues.Count);
|
Assert.Equal(2, _issues.Count);
|
||||||
Assert.Equal("real bad", _issues[0].Item1.Message);
|
Assert.Equal("real bad", _issues[0].Message);
|
||||||
Assert.Equal("BAD", _issues[0].Item1.Data["code"]);
|
Assert.Equal("BAD", _issues[0]["code"]);
|
||||||
Assert.Equal("not working", _issues[1].Item1.Message);
|
Assert.Equal("not working", _issues[1].Message);
|
||||||
Assert.False(_issues[1].Item1.Data.ContainsKey("code"));
|
Assert.Null(_issues[1]["code"]);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(0, _messages.Count);
|
Assert.Equal(0, _messages.Count);
|
||||||
}
|
}
|
||||||
@@ -238,11 +239,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("Error: real bad");
|
Process("Error: real bad");
|
||||||
Process("regular message 2");
|
Process("regular message 2");
|
||||||
Assert.Equal(5, _issues.Count);
|
Assert.Equal(5, _issues.Count);
|
||||||
Assert.Equal("it broke", _issues[0].Item1.Message);
|
Assert.Equal("it broke", _issues[0].Message);
|
||||||
Assert.Equal("oh no", _issues[1].Item1.Message);
|
Assert.Equal("oh no", _issues[1].Message);
|
||||||
Assert.Equal("not good", _issues[2].Item1.Message);
|
Assert.Equal("not good", _issues[2].Message);
|
||||||
Assert.Equal("it broke again", _issues[3].Item1.Message);
|
Assert.Equal("it broke again", _issues[3].Message);
|
||||||
Assert.Equal("real bad", _issues[4].Item1.Message);
|
Assert.Equal("real bad", _issues[4].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(4, _messages.Count);
|
Assert.Equal(4, _messages.Count);
|
||||||
Assert.Equal("Start: hello", _messages[0]);
|
Assert.Equal("Start: hello", _messages[0]);
|
||||||
@@ -293,8 +294,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("ERROR: it is broken");
|
Process("ERROR: it is broken");
|
||||||
Process("NOT GOOD: that did not work");
|
Process("NOT GOOD: that did not work");
|
||||||
Assert.Equal(2, _issues.Count);
|
Assert.Equal(2, _issues.Count);
|
||||||
Assert.Equal("it is broken", _issues[0].Item1.Message);
|
Assert.Equal("it is broken", _issues[0].Message);
|
||||||
Assert.Equal("that did not work", _issues[1].Item1.Message);
|
Assert.Equal("that did not work", _issues[1].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(0, _messages.Count);
|
Assert.Equal(0, _messages.Count);
|
||||||
}
|
}
|
||||||
@@ -332,15 +333,15 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("(12,thirty-four): it is broken");
|
Process("(12,thirty-four): it is broken");
|
||||||
Process("(twelve,34): not working");
|
Process("(twelve,34): not working");
|
||||||
Assert.Equal(3, _issues.Count);
|
Assert.Equal(3, _issues.Count);
|
||||||
Assert.Equal("real bad", _issues[0].Item1.Message);
|
Assert.Equal("real bad", _issues[0].Message);
|
||||||
Assert.Equal("12", _issues[0].Item1.Data["line"]);
|
Assert.Equal("12", _issues[0]["line"]);
|
||||||
Assert.Equal("34", _issues[0].Item1.Data["col"]);
|
Assert.Equal("34", _issues[0]["col"]);
|
||||||
Assert.Equal("it is broken", _issues[1].Item1.Message);
|
Assert.Equal("it is broken", _issues[1].Message);
|
||||||
Assert.Equal("12", _issues[1].Item1.Data["line"]);
|
Assert.Equal("12", _issues[1]["line"]);
|
||||||
Assert.False(_issues[1].Item1.Data.ContainsKey("col"));
|
Assert.Null(_issues[1]["col"]);
|
||||||
Assert.Equal("not working", _issues[2].Item1.Message);
|
Assert.Equal("not working", _issues[2].Message);
|
||||||
Assert.False(_issues[2].Item1.Data.ContainsKey("line"));
|
Assert.Null(_issues[2]["line"]);
|
||||||
Assert.Equal("34", _issues[2].Item1.Data["col"]);
|
Assert.Equal("34", _issues[2]["col"]);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(2, _messages.Count);
|
Assert.Equal(2, _messages.Count);
|
||||||
Assert.Equal("##[debug]Unable to parse column number 'thirty-four'", _messages[0]);
|
Assert.Equal("##[debug]Unable to parse column number 'thirty-four'", _messages[0]);
|
||||||
@@ -373,8 +374,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("this line is a command too ##[some-command]even though it contains ERROR: not working again");
|
Process("this line is a command too ##[some-command]even though it contains ERROR: not working again");
|
||||||
Process("##[not-command]this line is an ERROR: it is broken again");
|
Process("##[not-command]this line is an ERROR: it is broken again");
|
||||||
Assert.Equal(2, _issues.Count);
|
Assert.Equal(2, _issues.Count);
|
||||||
Assert.Equal("it is broken", _issues[0].Item1.Message);
|
Assert.Equal("it is broken", _issues[0].Message);
|
||||||
Assert.Equal("it is broken again", _issues[1].Item1.Message);
|
Assert.Equal("it is broken again", _issues[1].Message);
|
||||||
Assert.Equal(2, _commands.Count);
|
Assert.Equal(2, _commands.Count);
|
||||||
Assert.Equal("##[some-command]this line is a command even though it contains ERROR: not working", _commands[0]);
|
Assert.Equal("##[some-command]this line is a command even though it contains ERROR: not working", _commands[0]);
|
||||||
Assert.Equal("this line is a command too ##[some-command]even though it contains ERROR: not working again", _commands[1]);
|
Assert.Equal("this line is a command too ##[some-command]even though it contains ERROR: not working again", _commands[1]);
|
||||||
@@ -404,8 +405,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
});
|
});
|
||||||
Process("the error: \033[31mred, \033[1;31mbright red, \033[mreset");
|
Process("the error: \033[31mred, \033[1;31mbright red, \033[mreset");
|
||||||
Assert.Equal(1, _issues.Count);
|
Assert.Equal(1, _issues.Count);
|
||||||
Assert.Equal("red, bright red, reset", _issues[0].Item1.Message);
|
Assert.Equal("red, bright red, reset", _issues[0].Message);
|
||||||
Assert.Equal("the error: red, bright red, reset", _issues[0].Item2);
|
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(0, _messages.Count);
|
Assert.Equal(0, _messages.Count);
|
||||||
}
|
}
|
||||||
@@ -455,9 +455,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("ERROR: message 3");
|
Process("ERROR: message 3");
|
||||||
Process("NOT GOOD: message 4");
|
Process("NOT GOOD: message 4");
|
||||||
Assert.Equal(3, _issues.Count);
|
Assert.Equal(3, _issues.Count);
|
||||||
Assert.Equal("message 1", _issues[0].Item1.Message);
|
Assert.Equal("message 1", _issues[0].Message);
|
||||||
Assert.Equal("message 2", _issues[1].Item1.Message);
|
Assert.Equal("message 2", _issues[1].Message);
|
||||||
Assert.Equal("message 4", _issues[2].Item1.Message);
|
Assert.Equal("message 4", _issues[2].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(1, _messages.Count);
|
Assert.Equal(1, _messages.Count);
|
||||||
Assert.Equal("ERROR: message 3", _messages[0]);
|
Assert.Equal("ERROR: message 3", _messages[0]);
|
||||||
@@ -517,8 +517,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("Matches both line 1: hello again");
|
Process("Matches both line 1: hello again");
|
||||||
Process("oh no, another error");
|
Process("oh no, another error");
|
||||||
Assert.Equal(2, _issues.Count);
|
Assert.Equal(2, _issues.Count);
|
||||||
Assert.Equal("it broke", _issues[0].Item1.Message);
|
Assert.Equal("it broke", _issues[0].Message);
|
||||||
Assert.Equal("oh no, another error", _issues[1].Item1.Message);
|
Assert.Equal("oh no, another error", _issues[1].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(4, _messages.Count);
|
Assert.Equal(4, _messages.Count);
|
||||||
Assert.Equal("Matches both line 1: hello", _messages[0]);
|
Assert.Equal("Matches both line 1: hello", _messages[0]);
|
||||||
@@ -573,14 +573,14 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process(": not working");
|
Process(": not working");
|
||||||
Process("ERROR! uh oh");
|
Process("ERROR! uh oh");
|
||||||
Assert.Equal(4, _issues.Count);
|
Assert.Equal(4, _issues.Count);
|
||||||
Assert.Equal("real bad", _issues[0].Item1.Message);
|
Assert.Equal("real bad", _issues[0].Message);
|
||||||
Assert.Equal(DTWebApi.IssueType.Error, _issues[0].Item1.Type);
|
Assert.Equal(DTWebApi.IssueType.Error, _issues[0].Type);
|
||||||
Assert.Equal("not great", _issues[1].Item1.Message);
|
Assert.Equal("not great", _issues[1].Message);
|
||||||
Assert.Equal(DTWebApi.IssueType.Warning, _issues[1].Item1.Type);
|
Assert.Equal(DTWebApi.IssueType.Warning, _issues[1].Type);
|
||||||
Assert.Equal("not working", _issues[2].Item1.Message);
|
Assert.Equal("not working", _issues[2].Message);
|
||||||
Assert.Equal(DTWebApi.IssueType.Error, _issues[2].Item1.Type);
|
Assert.Equal(DTWebApi.IssueType.Error, _issues[2].Type);
|
||||||
Assert.Equal("uh oh", _issues[3].Item1.Message);
|
Assert.Equal("uh oh", _issues[3].Message);
|
||||||
Assert.Equal(DTWebApi.IssueType.Error, _issues[3].Item1.Type);
|
Assert.Equal(DTWebApi.IssueType.Error, _issues[3].Type);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(2, _messages.Count);
|
Assert.Equal(2, _messages.Count);
|
||||||
Assert.StartsWith("##[debug]Skipped", _messages[0]);
|
Assert.StartsWith("##[debug]Skipped", _messages[0]);
|
||||||
@@ -633,9 +633,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Process("jane.doe@contoso.com");
|
Process("jane.doe@contoso.com");
|
||||||
Process("ERR: this error");
|
Process("ERR: this error");
|
||||||
Assert.Equal(3, _issues.Count);
|
Assert.Equal(3, _issues.Count);
|
||||||
Assert.Equal("john.doe@contoso.com", _issues[0].Item1.Message);
|
Assert.Equal("john.doe@contoso.com", _issues[0].Message);
|
||||||
Assert.Contains("Removing issue matcher 'email'", _issues[1].Item1.Message);
|
Assert.Contains("Removing issue matcher 'email'", _issues[1].Message);
|
||||||
Assert.Equal("this error", _issues[2].Item1.Message);
|
Assert.Equal("this error", _issues[2].Message);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(2, _messages.Where(x => x.StartsWith("##[debug]Timeout processing issue matcher")).Count());
|
Assert.Equal(2, _messages.Where(x => x.StartsWith("##[debug]Timeout processing issue matcher")).Count());
|
||||||
Assert.Equal(1, _messages.Where(x => x.Equals("t@t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.c%20")).Count());
|
Assert.Equal(1, _messages.Where(x => x.Equals("t@t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.t.c%20")).Count());
|
||||||
@@ -725,32 +725,32 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal(9, _issues.Count);
|
Assert.Equal(9, _issues.Count);
|
||||||
|
|
||||||
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
Assert.Equal("some error 1", _issues[0].Message);
|
||||||
Assert.False(_issues[0].Item1.Data.ContainsKey("file"));
|
Assert.Null(_issues[0]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 2", _issues[1].Item1.Message);
|
Assert.Equal("some error 2", _issues[1].Message);
|
||||||
Assert.Equal(file_workflowRepository.Substring(workflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[1].Item1.Data["file"]);
|
Assert.Equal(file_workflowRepository.Substring(workflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[1]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 3", _issues[2].Item1.Message);
|
Assert.Equal("some error 3", _issues[2].Message);
|
||||||
Assert.Equal(file_workflowRepository.Substring(workflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[2].Item1.Data["file"]);
|
Assert.Equal(file_workflowRepository.Substring(workflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[2]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 4", _issues[3].Item1.Message);
|
Assert.Equal("some error 4", _issues[3].Message);
|
||||||
Assert.Equal(file_workflowRepository_nestedDirectory.Substring(workflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[3].Item1.Data["file"]);
|
Assert.Equal(file_workflowRepository_nestedDirectory.Substring(workflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[3]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 5", _issues[4].Item1.Message);
|
Assert.Equal("some error 5", _issues[4].Message);
|
||||||
Assert.False(_issues[4].Item1.Data.ContainsKey("file"));
|
Assert.Null(_issues[4]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 6", _issues[5].Item1.Message);
|
Assert.Equal("some error 6", _issues[5].Message);
|
||||||
Assert.False(_issues[5].Item1.Data.ContainsKey("file"));
|
Assert.Null(_issues[5]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 7", _issues[6].Item1.Message);
|
Assert.Equal("some error 7", _issues[6].Message);
|
||||||
Assert.False(_issues[6].Item1.Data.ContainsKey("file"));
|
Assert.Null(_issues[6]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 8", _issues[7].Item1.Message);
|
Assert.Equal("some error 8", _issues[7].Message);
|
||||||
Assert.Equal(file_nestedWorkflowRepository.Substring(nestedWorkflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[7].Item1.Data["file"]);
|
Assert.Equal(file_nestedWorkflowRepository.Substring(nestedWorkflowRepository.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[7]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 9", _issues[8].Item1.Message);
|
Assert.Equal("some error 9", _issues[8].Message);
|
||||||
Assert.Equal(file_workflowRepositoryUsingSsh.Substring(workflowRepositoryUsingSsh.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[8].Item1.Data["file"]);
|
Assert.Equal(file_workflowRepositoryUsingSsh.Substring(workflowRepositoryUsingSsh.Length + 1).Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar), _issues[8]["file"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Environment.SetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE", "");
|
Environment.SetEnvironmentVariable("RUNNER_TEST_GET_REPOSITORY_PATH_FAILSAFE", "");
|
||||||
@@ -810,11 +810,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal(2, _issues.Count);
|
Assert.Equal(2, _issues.Count);
|
||||||
|
|
||||||
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
Assert.Equal("some error 1", _issues[0].Message);
|
||||||
Assert.Equal("some-file.txt", _issues[0].Item1.Data["file"]);
|
Assert.Equal("some-file.txt", _issues[0]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 2", _issues[1].Item1.Message);
|
Assert.Equal("some error 2", _issues[1].Message);
|
||||||
Assert.Equal("some-file.txt", _issues[1].Item1.Data["file"]);
|
Assert.Equal("some-file.txt", _issues[1]["file"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -871,11 +871,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
Assert.Equal(2, _issues.Count);
|
Assert.Equal(2, _issues.Count);
|
||||||
|
|
||||||
Assert.Equal("some error 1", _issues[0].Item1.Message);
|
Assert.Equal("some error 1", _issues[0].Message);
|
||||||
Assert.Equal("some-file.txt", _issues[0].Item1.Data["file"]);
|
Assert.Equal("some-file.txt", _issues[0]["file"]);
|
||||||
|
|
||||||
Assert.Equal("some error 2", _issues[1].Item1.Message);
|
Assert.Equal("some error 2", _issues[1].Message);
|
||||||
Assert.Equal("some-file.txt", _issues[1].Item1.Data["file"]);
|
Assert.Equal("some-file.txt", _issues[1]["file"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -929,8 +929,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
// Process
|
// Process
|
||||||
Process("some-directory/some-file.txt: some error [workflow-repo/some-project/some-project.proj]");
|
Process("some-directory/some-file.txt: some error [workflow-repo/some-project/some-project.proj]");
|
||||||
Assert.Equal(1, _issues.Count);
|
Assert.Equal(1, _issues.Count);
|
||||||
Assert.Equal("some error", _issues[0].Item1.Message);
|
Assert.Equal("some error", _issues[0].Message);
|
||||||
Assert.Equal("some-project/some-directory/some-file.txt", _issues[0].Item1.Data["file"]);
|
Assert.Equal("some-project/some-directory/some-file.txt", _issues[0]["file"]);
|
||||||
Assert.Equal(0, _commands.Count);
|
Assert.Equal(0, _commands.Count);
|
||||||
Assert.Equal(0, _messages.Count);
|
Assert.Equal(0, _messages.Count);
|
||||||
}
|
}
|
||||||
@@ -958,7 +958,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
matchers?.Validate();
|
matchers?.Validate();
|
||||||
|
|
||||||
_onMatcherChanged = null;
|
_onMatcherChanged = null;
|
||||||
_issues = new List<Tuple<DTWebApi.Issue, string>>();
|
_issues = new List<DTWebApi.IReadOnlyIssue>();
|
||||||
_messages = new List<string>();
|
_messages = new List<string>();
|
||||||
_commands = new List<string>();
|
_commands = new List<string>();
|
||||||
|
|
||||||
@@ -983,10 +983,12 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_onMatcherChanged = handler;
|
_onMatcherChanged = handler;
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.Issue>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.CreateIssue(It.IsAny<DTWebApi.IssueType>(), It.IsAny<string>(), It.IsAny<IssueMetadata>(), It.IsAny<bool>()))
|
||||||
.Callback((DTWebApi.Issue issue, string logMessage) =>
|
.Returns(TestUtil.CreateTestIssue);
|
||||||
|
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.IReadOnlyIssue>()))
|
||||||
|
.Callback((DTWebApi.IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
_issues.Add(new Tuple<DTWebApi.Issue, string>(issue, logMessage));
|
_issues.Add(issue);
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Callback((string tag, string message) =>
|
.Callback((string tag, string message) =>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
public sealed class SaveStateFileCommandL0
|
public sealed class SaveStateFileCommandL0
|
||||||
{
|
{
|
||||||
private Mock<IExecutionContext> _executionContext;
|
private Mock<IExecutionContext> _executionContext;
|
||||||
private List<Tuple<DTWebApi.Issue, string>> _issues;
|
private List<DTWebApi.IReadOnlyIssue> _issues;
|
||||||
private string _rootDirectory;
|
private string _rootDirectory;
|
||||||
private SaveStateFileCommand _saveStateFileCommand;
|
private SaveStateFileCommand _saveStateFileCommand;
|
||||||
private Dictionary<string, string> _intraActionState;
|
private Dictionary<string, string> _intraActionState;
|
||||||
@@ -390,7 +390,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
private TestHostContext Setup([CallerMemberName] string name = "")
|
private TestHostContext Setup([CallerMemberName] string name = "")
|
||||||
{
|
{
|
||||||
_issues = new List<Tuple<DTWebApi.Issue, string>>();
|
_issues = new List<DTWebApi.IReadOnlyIssue>();
|
||||||
_intraActionState = new Dictionary<string, string>();
|
_intraActionState = new Dictionary<string, string>();
|
||||||
|
|
||||||
var hostContext = new TestHostContext(this, name);
|
var hostContext = new TestHostContext(this, name);
|
||||||
@@ -413,12 +413,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
||||||
WriteDebug = true,
|
WriteDebug = true,
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.Issue>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.IReadOnlyIssue>()))
|
||||||
.Callback((DTWebApi.Issue issue, string logMessage) =>
|
.Callback((DTWebApi.IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
_issues.Add(new Tuple<DTWebApi.Issue, string>(issue, logMessage));
|
_issues.Add(issue);
|
||||||
var message = !string.IsNullOrEmpty(logMessage) ? logMessage : issue.Message;
|
_trace.Info($"Issue '{issue.Type}': {issue.Message}");
|
||||||
_trace.Info($"Issue '{issue.Type}': {message}");
|
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Callback((string tag, string message) =>
|
.Callback((string tag, string message) =>
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Worker.Handlers;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using DTWebApi = GitHub.DistributedTask.WebApi;
|
using DTWebApi = GitHub.DistributedTask.WebApi;
|
||||||
@@ -21,7 +15,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
public sealed class SetEnvFileCommandL0
|
public sealed class SetEnvFileCommandL0
|
||||||
{
|
{
|
||||||
private Mock<IExecutionContext> _executionContext;
|
private Mock<IExecutionContext> _executionContext;
|
||||||
private List<Tuple<DTWebApi.Issue, string>> _issues;
|
private List<DTWebApi.IReadOnlyIssue> _issues;
|
||||||
private string _rootDirectory;
|
private string _rootDirectory;
|
||||||
private SetEnvFileCommand _setEnvFileCommand;
|
private SetEnvFileCommand _setEnvFileCommand;
|
||||||
private ITraceWriter _trace;
|
private ITraceWriter _trace;
|
||||||
@@ -389,7 +383,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
private TestHostContext Setup([CallerMemberName] string name = "")
|
private TestHostContext Setup([CallerMemberName] string name = "")
|
||||||
{
|
{
|
||||||
_issues = new List<Tuple<DTWebApi.Issue, string>>();
|
_issues = new List<DTWebApi.IReadOnlyIssue>();
|
||||||
|
|
||||||
var hostContext = new TestHostContext(this, name);
|
var hostContext = new TestHostContext(this, name);
|
||||||
|
|
||||||
@@ -411,12 +405,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
||||||
WriteDebug = true,
|
WriteDebug = true,
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.Issue>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.IReadOnlyIssue>()))
|
||||||
.Callback((DTWebApi.Issue issue, string logMessage) =>
|
.Callback((DTWebApi.IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
_issues.Add(new Tuple<DTWebApi.Issue, string>(issue, logMessage));
|
_issues.Add(issue);
|
||||||
var message = !string.IsNullOrEmpty(logMessage) ? logMessage : issue.Message;
|
_trace.Info($"Issue '{issue.Type}': {issue.Message}");
|
||||||
_trace.Info($"Issue '{issue.Type}': {message}");
|
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Callback((string tag, string message) =>
|
.Callback((string tag, string message) =>
|
||||||
|
|||||||
@@ -1,17 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Runner.Worker;
|
using GitHub.Runner.Worker;
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Worker.Handlers;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using DTWebApi = GitHub.DistributedTask.WebApi;
|
using DTWebApi = GitHub.DistributedTask.WebApi;
|
||||||
@@ -21,7 +15,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
public sealed class SetOutputFileCommandL0
|
public sealed class SetOutputFileCommandL0
|
||||||
{
|
{
|
||||||
private Mock<IExecutionContext> _executionContext;
|
private Mock<IExecutionContext> _executionContext;
|
||||||
private List<Tuple<DTWebApi.Issue, string>> _issues;
|
private List<DTWebApi.IReadOnlyIssue> _issues;
|
||||||
private Dictionary<string, string> _outputs;
|
private Dictionary<string, string> _outputs;
|
||||||
private string _rootDirectory;
|
private string _rootDirectory;
|
||||||
private SetOutputFileCommand _setOutputFileCommand;
|
private SetOutputFileCommand _setOutputFileCommand;
|
||||||
@@ -390,7 +384,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
private TestHostContext Setup([CallerMemberName] string name = "")
|
private TestHostContext Setup([CallerMemberName] string name = "")
|
||||||
{
|
{
|
||||||
_issues = new List<Tuple<DTWebApi.Issue, string>>();
|
_issues = new List<DTWebApi.IReadOnlyIssue>();
|
||||||
_outputs = new Dictionary<string, string>();
|
_outputs = new Dictionary<string, string>();
|
||||||
|
|
||||||
var hostContext = new TestHostContext(this, name);
|
var hostContext = new TestHostContext(this, name);
|
||||||
@@ -413,12 +407,11 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
||||||
WriteDebug = true,
|
WriteDebug = true,
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.Issue>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.IReadOnlyIssue>()))
|
||||||
.Callback((DTWebApi.Issue issue, string logMessage) =>
|
.Callback((DTWebApi.IReadOnlyIssue issue) =>
|
||||||
{
|
{
|
||||||
_issues.Add(new Tuple<DTWebApi.Issue, string>(issue, logMessage));
|
_issues.Add(issue);
|
||||||
var message = !string.IsNullOrEmpty(logMessage) ? logMessage : issue.Message;
|
_trace.Info($"Issue '{issue.Type}': {issue.Message}");
|
||||||
_trace.Info($"Issue '{issue.Type}': {message}");
|
|
||||||
});
|
});
|
||||||
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
||||||
.Callback((string tag, string message) =>
|
.Callback((string tag, string message) =>
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.301.0
|
2.299.1
|
||||||
|
|||||||
Reference in New Issue
Block a user