mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
25 Commits
v2.299.1
...
users/jww3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3e42889af | ||
|
|
f3961c4895 | ||
|
|
cb89be7aac | ||
|
|
b70f97f183 | ||
|
|
14096a7ee4 | ||
|
|
4eb9adc958 | ||
|
|
efc0a92cc7 | ||
|
|
87ababb858 | ||
|
|
3902257e9d | ||
|
|
7036627d47 | ||
|
|
2eeb90a944 | ||
|
|
369a4eccad | ||
|
|
088981a372 | ||
|
|
852a80fcbd | ||
|
|
63640e91fa | ||
|
|
9122fe7e10 | ||
|
|
6b8452170a | ||
|
|
cc49e65356 | ||
|
|
1632e4a343 | ||
|
|
b465102e7f | ||
|
|
98c857b927 | ||
|
|
dda53af485 | ||
|
|
c0bc4c02f8 | ||
|
|
c6630ce285 | ||
|
|
40ed7f8a40 |
65
.github/workflows/publish-image.yml
vendored
Normal file
65
.github/workflows/publish-image.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: Publish Runner Image
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
runnerVersion:
|
||||||
|
type: string
|
||||||
|
description: Version of the runner being installed
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Compute image version
|
||||||
|
id: image
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const inputRunnerVersion = "${{ github.event.inputs.runnerVersion }}"
|
||||||
|
if (inputRunnerVersion) {
|
||||||
|
console.log(`Using input runner version ${inputRunnerVersion}`)
|
||||||
|
core.setOutput('version', inputRunnerVersion);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const runnerVersion = fs.readFileSync('${{ github.workspace }}/src/runnerversion', 'utf8').replace(/\n$/g, '')
|
||||||
|
console.log(`Using runner version ${runnerVersion}`)
|
||||||
|
core.setOutput('version', runnerVersion);
|
||||||
|
|
||||||
|
- name: Setup Docker buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
id: build-and-push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: ./images
|
||||||
|
tags: |
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.image.outputs.version }}
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||||
|
build-args: |
|
||||||
|
RUNNER_VERSION=${{ steps.image.outputs.version }}
|
||||||
|
push: true
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.source=${{github.server_url}}/${{github.repository}}
|
||||||
|
org.opencontainers.image.description=https://github.com/actions/runner/releases/tag/v${{ steps.image.outputs.version }}
|
||||||
|
org.opencontainers.image.licenses=MIT
|
||||||
49
.github/workflows/release.yml
vendored
49
.github/workflows/release.yml
vendored
@@ -660,3 +660,52 @@ jobs:
|
|||||||
asset_path: ${{ github.workspace }}/linux-arm64-trimmedpackages.json
|
asset_path: ${{ github.workspace }}/linux-arm64-trimmedpackages.json
|
||||||
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
asset_name: actions-runner-linux-arm64-${{ steps.releaseNote.outputs.version }}-trimmedpackages.json
|
||||||
asset_content_type: application/octet-stream
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
publish-image:
|
||||||
|
needs: release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: ${{ github.repository_owner }}/actions-runner
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Compute image version
|
||||||
|
id: image
|
||||||
|
uses: actions/github-script@v6
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const fs = require('fs');
|
||||||
|
const runnerVersion = fs.readFileSync('${{ github.workspace }}/releaseVersion', 'utf8').replace(/\n$/g, '')
|
||||||
|
console.log(`Using runner version ${runnerVersion}`)
|
||||||
|
core.setOutput('version', runnerVersion);
|
||||||
|
|
||||||
|
- name: Setup Docker buildx
|
||||||
|
uses: docker/setup-buildx-action@v2
|
||||||
|
|
||||||
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
id: build-and-push
|
||||||
|
uses: docker/build-push-action@v3
|
||||||
|
with:
|
||||||
|
context: ./images
|
||||||
|
tags: |
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.image.outputs.version }}
|
||||||
|
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest
|
||||||
|
build-args: |
|
||||||
|
RUNNER_VERSION=${{ steps.image.outputs.version }}
|
||||||
|
push: true
|
||||||
|
labels: |
|
||||||
|
org.opencontainers.image.source=${{github.server_url}}/${{github.repository}}
|
||||||
|
org.opencontainers.image.description=https://github.com/actions/runner/releases/tag/v${{ steps.image.outputs.version }}
|
||||||
|
org.opencontainers.image.licenses=MIT
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ Runner releases:
|
|||||||
|
|
||||||
## Contribute
|
## Contribute
|
||||||
|
|
||||||
We accept contributions in the form of issues and pull requests. [Read more here](docs/contribute.md) before contributing.
|
We accept contributions in the form of issues and pull requests. The runner typically requires changes across the entire system and we aim for issues in the runner to be entirely self contained and fixable here. Therefore, we will primarily handle bug issues opened in this repo and we kindly request you to create all feature and enhancement requests on the [GitHub Feedback](https://github.com/community/community/discussions/categories/actions-and-packages) page. [Read more about our guidelines here](docs/contribute.md) before contributing.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Contributions
|
# Contributions
|
||||||
|
|
||||||
We welcome contributions in the form of issues and pull requests. We view the contributions and the process as the same for github and external contributors.
|
We welcome contributions in the form of issues and pull requests. We view the contributions and the process as the same for github and external contributors.Please note the runner typically requires changes across the entire system and we aim for issues in the runner to be entirely self contained and fixable here. Therefore, we will primarily handle bug issues opened in this repo and we kindly request you to create all feature and enhancement requests on the [GitHub Feedback](https://github.com/community/community/discussions/categories/actions-and-packages) page.
|
||||||
|
|
||||||
> IMPORTANT: Building your own runner is critical for the dev inner loop process when contributing changes. However, only runners built and distributed by GitHub (releases) are supported in production. Be aware that workflows and orchestrations run service side with the runner being a remote process to run steps. For that reason, the service can pull the runner forward so customizations can be lost.
|
> IMPORTANT: Building your own runner is critical for the dev inner loop process when contributing changes. However, only runners built and distributed by GitHub (releases) are supported in production. Be aware that workflows and orchestrations run service side with the runner being a remote process to run steps. For that reason, the service can pull the runner forward so customizations can be lost.
|
||||||
|
|
||||||
|
|||||||
24
images/Dockerfile
Normal file
24
images/Dockerfile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0 as build
|
||||||
|
|
||||||
|
ARG RUNNER_VERSION
|
||||||
|
ARG RUNNER_ARCH="x64"
|
||||||
|
ARG RUNNER_CONTAINER_HOOKS_VERSION=0.1.3
|
||||||
|
|
||||||
|
RUN apt update -y && apt install curl unzip -y
|
||||||
|
|
||||||
|
WORKDIR /actions-runner
|
||||||
|
RUN curl -f -L -o runner.tar.gz https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-${RUNNER_ARCH}-${RUNNER_VERSION}.tar.gz \
|
||||||
|
&& tar xzf ./runner.tar.gz \
|
||||||
|
&& rm runner.tar.gz
|
||||||
|
|
||||||
|
RUN curl -f -L -o runner-container-hooks.zip https://github.com/actions/runner-container-hooks/releases/download/v${RUNNER_CONTAINER_HOOKS_VERSION}/actions-runner-hooks-k8s-${RUNNER_CONTAINER_HOOKS_VERSION}.zip \
|
||||||
|
&& unzip ./runner-container-hooks.zip -d ./k8s \
|
||||||
|
&& rm runner-container-hooks.zip
|
||||||
|
|
||||||
|
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0
|
||||||
|
|
||||||
|
ENV RUNNER_ALLOW_RUNASROOT=1
|
||||||
|
ENV RUNNER_MANUALLY_TRAP_SIG=1
|
||||||
|
|
||||||
|
WORKDIR /actions-runner
|
||||||
|
COPY --from=build /actions-runner .
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
- Displays the error logs in dedicated sub-sections of the Initialize containers section (#2182)
|
- Displays the error logs in dedicated sub-sections of the Initialize containers section (#2182)
|
||||||
- Add generateServiceConfig option for configure command (#2226)
|
- Add generateServiceConfig option for configure command (#2226)
|
||||||
- Setting debug using GitHub Action variables (#2234)
|
- Setting debug using GitHub Action variables (#2234)
|
||||||
- run.sh installs SIGINT and SIGTERM traps to gracefully stop runner (#2233, 2240)
|
- run.sh installs SIGINT and SIGTERM traps to gracefully stop runner (#2233, #2240)
|
||||||
|
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.299.1
|
<Update to ./src/runnerversion when creating release>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ set -e
|
|||||||
|
|
||||||
flags_found=false
|
flags_found=false
|
||||||
|
|
||||||
while getopts 's:g:n:r:u:l:d' opt; do
|
while getopts 's:g:n:r:u:l:df' opt; do
|
||||||
flags_found=true
|
flags_found=true
|
||||||
|
|
||||||
case $opt in
|
case $opt in
|
||||||
@@ -35,6 +35,9 @@ while getopts 's:g:n:r:u:l:d' opt; do
|
|||||||
l)
|
l)
|
||||||
labels=$OPTARG
|
labels=$OPTARG
|
||||||
;;
|
;;
|
||||||
|
f)
|
||||||
|
replace='true'
|
||||||
|
;;
|
||||||
d)
|
d)
|
||||||
disableupdate='true'
|
disableupdate='true'
|
||||||
;;
|
;;
|
||||||
@@ -53,7 +56,8 @@ Usage:
|
|||||||
-r optional name of the runner group to add the runner to, defaults to the Default group
|
-r optional name of the runner group to add the runner to, defaults to the Default group
|
||||||
-u optional user svc will run as, defaults to current
|
-u optional user svc will run as, defaults to current
|
||||||
-l optional list of labels (split by comma) applied on the runner
|
-l optional list of labels (split by comma) applied on the runner
|
||||||
-d optional allow runner to remain on the current version for one month after the release of a newer version"
|
-d optional allow runner to remain on the current version for one month after the release of a newer version
|
||||||
|
-f optional replace any existing runner with the same name"
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
@@ -174,7 +178,7 @@ fi
|
|||||||
echo
|
echo
|
||||||
echo "Configuring ${runner_name} @ $runner_url"
|
echo "Configuring ${runner_name} @ $runner_url"
|
||||||
echo "./config.sh --unattended --url $runner_url --token *** --name $runner_name ${labels:+--labels $labels} ${runner_group:+--runnergroup \"$runner_group\"} ${disableupdate:+--disableupdate}"
|
echo "./config.sh --unattended --url $runner_url --token *** --name $runner_name ${labels:+--labels $labels} ${runner_group:+--runnergroup \"$runner_group\"} ${disableupdate:+--disableupdate}"
|
||||||
sudo -E -u ${svc_user} ./config.sh --unattended --url $runner_url --token $RUNNER_TOKEN --name $runner_name ${labels:+--labels $labels} ${runner_group:+--runnergroup "$runner_group"} ${disableupdate:+--disableupdate}
|
sudo -E -u ${svc_user} ./config.sh --unattended --url $runner_url --token $RUNNER_TOKEN ${replace:+--replace} --name $runner_name ${labels:+--labels $labels} ${runner_group:+--runnergroup "$runner_group"} ${disableupdate:+--disableupdate}
|
||||||
|
|
||||||
#---------------------------------------
|
#---------------------------------------
|
||||||
# Configuring as a service
|
# Configuring as a service
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ set -e
|
|||||||
#
|
#
|
||||||
# Usage:
|
# Usage:
|
||||||
# export RUNNER_CFG_PAT=<yourPAT>
|
# export RUNNER_CFG_PAT=<yourPAT>
|
||||||
# ./delete.sh scope name
|
# ./delete.sh <scope> [<name>]
|
||||||
#
|
#
|
||||||
# scope required repo (:owner/:repo) or org (:organization)
|
# scope required repo (:owner/:repo) or org (:organization)
|
||||||
# name optional defaults to hostname. name to delete
|
# name optional defaults to hostname. name to delete
|
||||||
@@ -26,17 +26,17 @@ set -e
|
|||||||
runner_scope=${1}
|
runner_scope=${1}
|
||||||
runner_name=${2}
|
runner_name=${2}
|
||||||
|
|
||||||
echo "Deleting runner ${runner_name} @ ${runner_scope}"
|
function fatal()
|
||||||
|
|
||||||
function fatal()
|
|
||||||
{
|
{
|
||||||
echo "error: $1" >&2
|
echo "error: $1" >&2
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -z "${runner_scope}" ]; then fatal "supply scope as argument 1"; fi
|
if [ -z "${runner_scope}" ]; then fatal "supply scope as argument 1"; fi
|
||||||
if [ -z "${runner_name}" ]; then fatal "supply name as argument 2"; fi
|
|
||||||
if [ -z "${RUNNER_CFG_PAT}" ]; then fatal "RUNNER_CFG_PAT must be set before calling"; fi
|
if [ -z "${RUNNER_CFG_PAT}" ]; then fatal "RUNNER_CFG_PAT must be set before calling"; fi
|
||||||
|
if [ -z "${runner_name}" ]; then runner_name=`hostname`; fi
|
||||||
|
|
||||||
|
echo "Deleting runner ${runner_name} @ ${runner_scope}"
|
||||||
|
|
||||||
which curl || fatal "curl required. Please install in PATH with apt-get, brew, etc"
|
which curl || fatal "curl required. Please install in PATH with apt-get, brew, etc"
|
||||||
which jq || fatal "jq required. Please install in PATH with apt-get, brew, etc"
|
which jq || fatal "jq required. Please install in PATH with apt-get, brew, etc"
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ runWithManualTrap() {
|
|||||||
trap - INT TERM
|
trap - INT TERM
|
||||||
# wait for last parts to be logged
|
# wait for last parts to be logged
|
||||||
wait $PID
|
wait $PID
|
||||||
exit 0
|
exit $returnCode
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
||||||
public static readonly string UnsupportedStopCommandTokenDisabled = "You cannot use a endToken that is an empty string, the string 'pause-logging', or another workflow command. For more information see: https://docs.github.com/actions/learn-github-actions/workflow-commands-for-github-actions#example-stopping-and-starting-workflow-commands or opt into insecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS` environment variable to `true`.";
|
public static readonly string UnsupportedStopCommandTokenDisabled = "You cannot use a endToken that is an empty string, the string 'pause-logging', or another workflow command. For more information see: https://docs.github.com/actions/learn-github-actions/workflow-commands-for-github-actions#example-stopping-and-starting-workflow-commands or opt into insecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_STOPCOMMAND_TOKENS` environment variable to `true`.";
|
||||||
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
public static readonly string UnsupportedSummarySize = "$GITHUB_STEP_SUMMARY upload aborted, supports content up to a size of {0}k, got {1}k. For more information see: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-markdown-summary";
|
||||||
public static readonly string Node12DetectedAfterEndOfLife = "Node.js 12 actions are deprecated. For more information see: https://github.blog/changelog/2022-09-22-github-actions-all-actions-will-begin-running-on-node16-instead-of-node12/. Please update the following actions to use Node.js 16: {0}";
|
public static 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 class RunnerEvent
|
public static class RunnerEvent
|
||||||
@@ -245,6 +245,7 @@ namespace GitHub.Runner.Common
|
|||||||
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
// Set this env var to "node12" to downgrade the node version for internal functions (e.g hashfiles). This does NOT affect the version of node actions.
|
||||||
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
public static readonly string ForcedInternalNodeVersion = "ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION";
|
||||||
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
public static readonly string ForcedActionsNodeVersion = "ACTIONS_RUNNER_FORCE_ACTIONS_NODE_VERSION";
|
||||||
|
public static readonly string PrintLogToStdout = "ACTIONS_RUNNER_PRINT_LOG_TO_STDOUT";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class System
|
public static class System
|
||||||
|
|||||||
@@ -94,6 +94,13 @@ namespace GitHub.Runner.Common
|
|||||||
this.SecretMasker.AddValueEncoder(ValueEncoders.PowerShellPreAmpersandEscape);
|
this.SecretMasker.AddValueEncoder(ValueEncoders.PowerShellPreAmpersandEscape);
|
||||||
this.SecretMasker.AddValueEncoder(ValueEncoders.PowerShellPostAmpersandEscape);
|
this.SecretMasker.AddValueEncoder(ValueEncoders.PowerShellPostAmpersandEscape);
|
||||||
|
|
||||||
|
// Create StdoutTraceListener if ENV is set
|
||||||
|
StdoutTraceListener stdoutTraceListener = null;
|
||||||
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable(Constants.Variables.Agent.PrintLogToStdout)))
|
||||||
|
{
|
||||||
|
stdoutTraceListener = new StdoutTraceListener(hostType);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the trace manager.
|
// Create the trace manager.
|
||||||
if (string.IsNullOrEmpty(logFile))
|
if (string.IsNullOrEmpty(logFile))
|
||||||
{
|
{
|
||||||
@@ -113,11 +120,11 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
// this should give us _diag folder under runner root directory
|
// this should give us _diag folder under runner root directory
|
||||||
string diagLogDirectory = Path.Combine(new DirectoryInfo(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)).Parent.FullName, Constants.Path.DiagDirectory);
|
string diagLogDirectory = Path.Combine(new DirectoryInfo(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location)).Parent.FullName, Constants.Path.DiagDirectory);
|
||||||
_traceManager = new TraceManager(new HostTraceListener(diagLogDirectory, hostType, logPageSize, logRetentionDays), this.SecretMasker);
|
_traceManager = new TraceManager(new HostTraceListener(diagLogDirectory, hostType, logPageSize, logRetentionDays), stdoutTraceListener, this.SecretMasker);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_traceManager = new TraceManager(new HostTraceListener(logFile), this.SecretMasker);
|
_traceManager = new TraceManager(new HostTraceListener(logFile), stdoutTraceListener, this.SecretMasker);
|
||||||
}
|
}
|
||||||
|
|
||||||
_trace = GetTrace(nameof(HostContext));
|
_trace = GetTrace(nameof(HostContext));
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Give at most 60s for each request.
|
// Give at most 60s for each request.
|
||||||
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60)))
|
using (var timeoutTokenSource = new CancellationTokenSource(TimeSpan.FromSeconds(60)))
|
||||||
{
|
{
|
||||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, timeoutTokenSource.Token);
|
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber, timeoutTokenSource.Token);
|
||||||
@@ -600,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}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace GitHub.Runner.Common
|
|||||||
Task<TaskAgentSession> CreateAgentSessionAsync(Int32 poolId, TaskAgentSession session, CancellationToken cancellationToken);
|
Task<TaskAgentSession> CreateAgentSessionAsync(Int32 poolId, TaskAgentSession session, CancellationToken cancellationToken);
|
||||||
Task DeleteAgentMessageAsync(Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken);
|
Task DeleteAgentMessageAsync(Int32 poolId, Int64 messageId, Guid sessionId, CancellationToken cancellationToken);
|
||||||
Task DeleteAgentSessionAsync(Int32 poolId, Guid sessionId, CancellationToken cancellationToken);
|
Task DeleteAgentSessionAsync(Int32 poolId, Guid sessionId, CancellationToken cancellationToken);
|
||||||
Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, CancellationToken cancellationToken);
|
Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, string runnerVersion, CancellationToken cancellationToken);
|
||||||
|
|
||||||
// job request
|
// job request
|
||||||
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
Task<TaskAgentJobRequest> GetAgentRequestAsync(int poolId, long requestId, CancellationToken cancellationToken);
|
||||||
@@ -272,10 +272,10 @@ namespace GitHub.Runner.Common
|
|||||||
return _messageTaskAgentClient.DeleteAgentSessionAsync(poolId, sessionId, cancellationToken: cancellationToken);
|
return _messageTaskAgentClient.DeleteAgentSessionAsync(poolId, sessionId, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, CancellationToken cancellationToken)
|
public Task<TaskAgentMessage> GetAgentMessageAsync(Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, string runnerVersion, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection(RunnerConnectionType.MessageQueue);
|
CheckConnection(RunnerConnectionType.MessageQueue);
|
||||||
return _messageTaskAgentClient.GetMessageAsync(poolId, sessionId, lastMessageId, status, cancellationToken: cancellationToken);
|
return _messageTaskAgentClient.GetMessageAsync(poolId, sessionId, lastMessageId, status, runnerVersion, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------
|
//-----------------------------------------------------------------
|
||||||
|
|||||||
90
src/Runner.Common/StdoutTraceListener.cs
Normal file
90
src/Runner.Common/StdoutTraceListener.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using GitHub.Runner.Sdk;
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace GitHub.Runner.Common
|
||||||
|
{
|
||||||
|
public sealed class StdoutTraceListener : ConsoleTraceListener
|
||||||
|
{
|
||||||
|
private readonly string _hostType;
|
||||||
|
|
||||||
|
public StdoutTraceListener(string hostType)
|
||||||
|
{
|
||||||
|
this._hostType = hostType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied and modified slightly from .Net Core source code. Modification was required to make it compile.
|
||||||
|
// There must be some TraceFilter extension class that is missing in this source code.
|
||||||
|
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
|
||||||
|
{
|
||||||
|
if (Filter != null && !Filter.ShouldTrace(eventCache, source, eventType, id, message, null, null, null))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteHeader(source, eventType, id);
|
||||||
|
WriteLine(message);
|
||||||
|
WriteFooter(eventCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool IsEnabled(TraceOptions opts)
|
||||||
|
{
|
||||||
|
return (opts & TraceOutputOptions) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Altered from the original .Net Core implementation.
|
||||||
|
private void WriteHeader(string source, TraceEventType eventType, int id)
|
||||||
|
{
|
||||||
|
string type = null;
|
||||||
|
switch (eventType)
|
||||||
|
{
|
||||||
|
case TraceEventType.Critical:
|
||||||
|
type = "CRIT";
|
||||||
|
break;
|
||||||
|
case TraceEventType.Error:
|
||||||
|
type = "ERR ";
|
||||||
|
break;
|
||||||
|
case TraceEventType.Warning:
|
||||||
|
type = "WARN";
|
||||||
|
break;
|
||||||
|
case TraceEventType.Information:
|
||||||
|
type = "INFO";
|
||||||
|
break;
|
||||||
|
case TraceEventType.Verbose:
|
||||||
|
type = "VERB";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type = eventType.ToString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(StringUtil.Format("[{0} {1:u} {2} {3}] ", _hostType.ToUpperInvariant(), DateTime.UtcNow, type, source));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied and modified slightly from .Net Core source code to make it compile. The original code
|
||||||
|
// accesses a private indentLevel field. In this code it has been modified to use the getter/setter.
|
||||||
|
private void WriteFooter(TraceEventCache eventCache)
|
||||||
|
{
|
||||||
|
if (eventCache == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
IndentLevel++;
|
||||||
|
if (IsEnabled(TraceOptions.ProcessId))
|
||||||
|
WriteLine("ProcessId=" + eventCache.ProcessId);
|
||||||
|
|
||||||
|
if (IsEnabled(TraceOptions.ThreadId))
|
||||||
|
WriteLine("ThreadId=" + eventCache.ThreadId);
|
||||||
|
|
||||||
|
if (IsEnabled(TraceOptions.DateTime))
|
||||||
|
WriteLine("DateTime=" + eventCache.DateTime.ToString("o", CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
|
if (IsEnabled(TraceOptions.Timestamp))
|
||||||
|
WriteLine("Timestamp=" + eventCache.Timestamp);
|
||||||
|
|
||||||
|
IndentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ namespace GitHub.Runner.Common
|
|||||||
string ReadSecret();
|
string ReadSecret();
|
||||||
void Write(string message, ConsoleColor? colorCode = null);
|
void Write(string message, ConsoleColor? colorCode = null);
|
||||||
void WriteLine();
|
void WriteLine();
|
||||||
void WriteLine(string line, ConsoleColor? colorCode = null);
|
void WriteLine(string line, ConsoleColor? colorCode = null, bool skipTracing = false);
|
||||||
void WriteError(Exception ex);
|
void WriteError(Exception ex);
|
||||||
void WriteError(string line);
|
void WriteError(string line);
|
||||||
void WriteSection(string message);
|
void WriteSection(string message);
|
||||||
@@ -116,9 +116,12 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
// Do not add a format string overload. Terminal messages are user facing and therefore
|
// Do not add a format string overload. Terminal messages are user facing and therefore
|
||||||
// should be localized. Use the Loc method in the StringUtil class.
|
// should be localized. Use the Loc method in the StringUtil class.
|
||||||
public void WriteLine(string line, ConsoleColor? colorCode = null)
|
public void WriteLine(string line, ConsoleColor? colorCode = null, bool skipTracing = false)
|
||||||
{
|
{
|
||||||
Trace.Info($"WRITE LINE: {line}");
|
if (!skipTracing)
|
||||||
|
{
|
||||||
|
Trace.Info($"WRITE LINE: {line}");
|
||||||
|
}
|
||||||
if (!Silent)
|
if (!Silent)
|
||||||
{
|
{
|
||||||
if (colorCode != null)
|
if (colorCode != null)
|
||||||
|
|||||||
@@ -16,21 +16,23 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, Tracing> _sources = new(StringComparer.OrdinalIgnoreCase);
|
private readonly ConcurrentDictionary<string, Tracing> _sources = new(StringComparer.OrdinalIgnoreCase);
|
||||||
private readonly HostTraceListener _hostTraceListener;
|
private readonly HostTraceListener _hostTraceListener;
|
||||||
|
private readonly StdoutTraceListener _stdoutTraceListener;
|
||||||
private TraceSetting _traceSetting;
|
private TraceSetting _traceSetting;
|
||||||
private ISecretMasker _secretMasker;
|
private ISecretMasker _secretMasker;
|
||||||
|
|
||||||
public TraceManager(HostTraceListener traceListener, ISecretMasker secretMasker)
|
public TraceManager(HostTraceListener traceListener, StdoutTraceListener stdoutTraceListener, ISecretMasker secretMasker)
|
||||||
: this(traceListener, new TraceSetting(), secretMasker)
|
: this(traceListener, stdoutTraceListener, new TraceSetting(), secretMasker)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public TraceManager(HostTraceListener traceListener, TraceSetting traceSetting, ISecretMasker secretMasker)
|
public TraceManager(HostTraceListener traceListener, StdoutTraceListener stdoutTraceListener, TraceSetting traceSetting, ISecretMasker secretMasker)
|
||||||
{
|
{
|
||||||
// Validate and store params.
|
// Validate and store params.
|
||||||
ArgUtil.NotNull(traceListener, nameof(traceListener));
|
ArgUtil.NotNull(traceListener, nameof(traceListener));
|
||||||
ArgUtil.NotNull(traceSetting, nameof(traceSetting));
|
ArgUtil.NotNull(traceSetting, nameof(traceSetting));
|
||||||
ArgUtil.NotNull(secretMasker, nameof(secretMasker));
|
ArgUtil.NotNull(secretMasker, nameof(secretMasker));
|
||||||
_hostTraceListener = traceListener;
|
_hostTraceListener = traceListener;
|
||||||
|
_stdoutTraceListener = stdoutTraceListener;
|
||||||
_traceSetting = traceSetting;
|
_traceSetting = traceSetting;
|
||||||
_secretMasker = secretMasker;
|
_secretMasker = secretMasker;
|
||||||
|
|
||||||
@@ -81,7 +83,7 @@ namespace GitHub.Runner.Common
|
|||||||
Level = sourceTraceLevel.ToSourceLevels()
|
Level = sourceTraceLevel.ToSourceLevels()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return new Tracing(name, _secretMasker, sourceSwitch, _hostTraceListener);
|
return new Tracing(name, _secretMasker, sourceSwitch, _hostTraceListener, _stdoutTraceListener);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace GitHub.Runner.Common
|
|||||||
private ISecretMasker _secretMasker;
|
private ISecretMasker _secretMasker;
|
||||||
private TraceSource _traceSource;
|
private TraceSource _traceSource;
|
||||||
|
|
||||||
public Tracing(string name, ISecretMasker secretMasker, SourceSwitch sourceSwitch, HostTraceListener traceListener)
|
public Tracing(string name, ISecretMasker secretMasker, SourceSwitch sourceSwitch, HostTraceListener traceListener, StdoutTraceListener stdoutTraceListener = null)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(secretMasker, nameof(secretMasker));
|
ArgUtil.NotNull(secretMasker, nameof(secretMasker));
|
||||||
_secretMasker = secretMasker;
|
_secretMasker = secretMasker;
|
||||||
@@ -27,6 +27,10 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
_traceSource.Listeners.Add(traceListener);
|
_traceSource.Listeners.Add(traceListener);
|
||||||
|
if (stdoutTraceListener != null)
|
||||||
|
{
|
||||||
|
_traceSource.Listeners.Add(stdoutTraceListener);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Info(string message)
|
public void Info(string message)
|
||||||
|
|||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -400,6 +400,7 @@ namespace GitHub.Runner.Listener
|
|||||||
Task<int> workerProcessTask = null;
|
Task<int> workerProcessTask = null;
|
||||||
object _outputLock = new();
|
object _outputLock = new();
|
||||||
List<string> workerOutput = new();
|
List<string> workerOutput = new();
|
||||||
|
bool printToStdout = StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable(Constants.Variables.Agent.PrintLogToStdout));
|
||||||
using (var processChannel = HostContext.CreateService<IProcessChannel>())
|
using (var processChannel = HostContext.CreateService<IProcessChannel>())
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
{
|
{
|
||||||
@@ -421,7 +422,15 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
lock (_outputLock)
|
lock (_outputLock)
|
||||||
{
|
{
|
||||||
workerOutput.Add(stdout.Data);
|
if (!stdout.Data.StartsWith("[WORKER"))
|
||||||
|
{
|
||||||
|
workerOutput.Add(stdout.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (printToStdout)
|
||||||
|
{
|
||||||
|
term.WriteLine(stdout.Data, skipTracing: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -503,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
|
||||||
{
|
{
|
||||||
@@ -611,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));
|
||||||
|
|
||||||
@@ -658,7 +667,7 @@ namespace GitHub.Runner.Listener
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
Busy = false;
|
Busy = false;
|
||||||
|
|
||||||
if (JobStatus != null)
|
if (JobStatus != null)
|
||||||
{
|
{
|
||||||
JobStatus(this, new JobStatusEventArgs(TaskAgentStatus.Online));
|
JobStatus(this, new JobStatusEventArgs(TaskAgentStatus.Online));
|
||||||
@@ -1005,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);
|
||||||
|
|||||||
@@ -211,6 +211,7 @@ namespace GitHub.Runner.Listener
|
|||||||
_session.SessionId,
|
_session.SessionId,
|
||||||
_lastMessageId,
|
_lastMessageId,
|
||||||
runnerStatus,
|
runnerStatus,
|
||||||
|
BuildConstants.RunnerPackage.Version,
|
||||||
_getMessagesTokenSource.Token);
|
_getMessagesTokenSource.Token);
|
||||||
|
|
||||||
// Decrypt the message body if the session is using encryption
|
// Decrypt the message body if the session is using encryption
|
||||||
|
|||||||
@@ -430,12 +430,22 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
message = await getNextMessage; //get next message
|
message = await getNextMessage; //get next message
|
||||||
HostContext.WritePerfCounter($"MessageReceived_{message.MessageType}");
|
HostContext.WritePerfCounter($"MessageReceived_{message.MessageType}");
|
||||||
if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(message.MessageType, RunnerRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
if (autoUpdateInProgress == false)
|
if (autoUpdateInProgress == false)
|
||||||
{
|
{
|
||||||
autoUpdateInProgress = true;
|
autoUpdateInProgress = true;
|
||||||
var runnerUpdateMessage = JsonUtility.FromString<AgentRefreshMessage>(message.Body);
|
AgentRefreshMessage runnerUpdateMessage = null;
|
||||||
|
if (string.Equals(message.MessageType, AgentRefreshMessage.MessageType, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
runnerUpdateMessage = JsonUtility.FromString<AgentRefreshMessage>(message.Body);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var brokerRunnerUpdateMessage = JsonUtility.FromString<RunnerRefreshMessage>(message.Body);
|
||||||
|
runnerUpdateMessage = new AgentRefreshMessage(brokerRunnerUpdateMessage.RunnerId, brokerRunnerUpdateMessage.TargetVersion, TimeSpan.FromSeconds(brokerRunnerUpdateMessage.TimeoutInSeconds));
|
||||||
|
}
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
// Can mock the update for testing
|
// Can mock the update for testing
|
||||||
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_IS_MOCK_UPDATE")))
|
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_IS_MOCK_UPDATE")))
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -90,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);
|
||||||
|
|
||||||
@@ -124,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;
|
||||||
|
|
||||||
@@ -133,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;
|
||||||
@@ -147,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; }
|
||||||
@@ -159,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>();
|
||||||
|
|
||||||
@@ -184,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
|
||||||
{
|
{
|
||||||
@@ -319,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;
|
||||||
@@ -344,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)
|
||||||
@@ -365,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;
|
||||||
}
|
}
|
||||||
@@ -411,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.
|
||||||
@@ -425,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;
|
||||||
@@ -545,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)
|
||||||
@@ -975,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.
|
||||||
@@ -1085,7 +1123,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
if (contextData != null &&
|
if (contextData != null &&
|
||||||
contextData.TryGetValue(PipelineTemplateConstants.Vars, out var varsPipelineContextData) &&
|
contextData.TryGetValue(PipelineTemplateConstants.Vars, out var varsPipelineContextData) &&
|
||||||
varsPipelineContextData != null &&
|
varsPipelineContextData != null &&
|
||||||
varsPipelineContextData is DictionaryContextData varsContextData)
|
varsPipelineContextData is DictionaryContextData varsContextData)
|
||||||
{
|
{
|
||||||
// Set debug variables only when StepDebug/RunnerDebug variables are not present.
|
// Set debug variables only when StepDebug/RunnerDebug variables are not present.
|
||||||
@@ -1158,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().
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace GitHub.Runner.Worker
|
|||||||
"action_repository",
|
"action_repository",
|
||||||
"action",
|
"action",
|
||||||
"actor",
|
"actor",
|
||||||
|
"actor_id",
|
||||||
"api_url",
|
"api_url",
|
||||||
"base_ref",
|
"base_ref",
|
||||||
"env",
|
"env",
|
||||||
@@ -27,8 +28,10 @@ namespace GitHub.Runner.Worker
|
|||||||
"ref_protected",
|
"ref_protected",
|
||||||
"ref_type",
|
"ref_type",
|
||||||
"ref",
|
"ref",
|
||||||
"repository_owner",
|
|
||||||
"repository",
|
"repository",
|
||||||
|
"repository_id",
|
||||||
|
"repository_owner",
|
||||||
|
"repository_owner_id",
|
||||||
"retention_days",
|
"retention_days",
|
||||||
"run_attempt",
|
"run_attempt",
|
||||||
"run_id",
|
"run_id",
|
||||||
@@ -39,7 +42,9 @@ namespace GitHub.Runner.Worker
|
|||||||
"step_summary",
|
"step_summary",
|
||||||
"triggering_actor",
|
"triggering_actor",
|
||||||
"workflow",
|
"workflow",
|
||||||
"workspace",
|
"workflow_ref",
|
||||||
|
"workflow_sha",
|
||||||
|
"workspace"
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyValuePair<string, string>> GetRuntimeEnvironmentVariables()
|
public IEnumerable<KeyValuePair<string, string>> GetRuntimeEnvironmentVariables()
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
// Set action_status to the success of the current composite action
|
// Set action_status to the success of the current composite action
|
||||||
var actionResult = ExecutionContext.Result?.ToActionResult() ?? ActionResult.Success;
|
var actionResult = ExecutionContext.Result?.ToActionResult() ?? ActionResult.Success;
|
||||||
step.ExecutionContext.SetGitHubContext("action_status", actionResult.ToString());
|
step.ExecutionContext.SetGitHubContext("action_status", actionResult.ToString().ToLowerInvariant());
|
||||||
|
|
||||||
// Initialize env context
|
// Initialize env context
|
||||||
Trace.Info("Initialize Env context for embedded step");
|
Trace.Info("Initialize Env context for embedded step");
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -325,10 +325,10 @@ namespace GitHub.Runner.Worker
|
|||||||
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}");
|
||||||
}
|
}
|
||||||
@@ -336,7 +336,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(message.JobDisplayName))
|
if (!string.IsNullOrWhiteSpace(message.JobDisplayName))
|
||||||
{
|
{
|
||||||
context.Output($"Complete job name: {message.JobDisplayName}");
|
context.Output($"Complete job name: {message.JobDisplayName}");
|
||||||
}
|
}
|
||||||
@@ -660,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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -450,6 +450,8 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
/// <param name="poolId"></param>
|
/// <param name="poolId"></param>
|
||||||
/// <param name="sessionId"></param>
|
/// <param name="sessionId"></param>
|
||||||
/// <param name="lastMessageId"></param>
|
/// <param name="lastMessageId"></param>
|
||||||
|
/// <param name="status"></param>
|
||||||
|
/// <param name="runnerVersion"></param>
|
||||||
/// <param name="userState"></param>
|
/// <param name="userState"></param>
|
||||||
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
/// <param name="cancellationToken">The cancellation token to cancel operation.</param>
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
@@ -458,6 +460,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
Guid sessionId,
|
Guid sessionId,
|
||||||
long? lastMessageId = null,
|
long? lastMessageId = null,
|
||||||
TaskAgentStatus? status = null,
|
TaskAgentStatus? status = null,
|
||||||
|
string runnerVersion = null,
|
||||||
object userState = null,
|
object userState = null,
|
||||||
CancellationToken cancellationToken = default)
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
@@ -475,12 +478,16 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
{
|
{
|
||||||
queryParams.Add("status", status.Value.ToString());
|
queryParams.Add("status", status.Value.ToString());
|
||||||
}
|
}
|
||||||
|
if (runnerVersion != null)
|
||||||
|
{
|
||||||
|
queryParams.Add("runnerVersion", runnerVersion);
|
||||||
|
}
|
||||||
|
|
||||||
return SendAsync<TaskAgentMessage>(
|
return SendAsync<TaskAgentMessage>(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
locationId,
|
locationId,
|
||||||
routeValues: routeValues,
|
routeValues: routeValues,
|
||||||
version: new ApiResourceVersion(5.1, 1),
|
version: new ApiResourceVersion(6.0, 1),
|
||||||
queryParameters: queryParams,
|
queryParameters: queryParams,
|
||||||
userState: userState,
|
userState: userState,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
src/Sdk/DTWebApi/WebApi/RunnerRefreshMessage.cs
Normal file
49
src/Sdk/DTWebApi/WebApi/RunnerRefreshMessage.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using Newtonsoft.Json;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
|
||||||
|
namespace GitHub.DistributedTask.WebApi
|
||||||
|
{
|
||||||
|
[DataContract]
|
||||||
|
public sealed class RunnerRefreshMessage
|
||||||
|
{
|
||||||
|
public static readonly String MessageType = "RunnerRefresh";
|
||||||
|
|
||||||
|
[JsonConstructor]
|
||||||
|
internal RunnerRefreshMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RunnerRefreshMessage(
|
||||||
|
Int32 runnerId,
|
||||||
|
String targetVersion,
|
||||||
|
int? timeoutInSeconds = null)
|
||||||
|
{
|
||||||
|
this.RunnerId = runnerId;
|
||||||
|
this.TimeoutInSeconds = timeoutInSeconds ?? TimeSpan.FromMinutes(60).Seconds;
|
||||||
|
this.TargetVersion = targetVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember]
|
||||||
|
public Int32 RunnerId
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember]
|
||||||
|
public int TimeoutInSeconds
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DataMember]
|
||||||
|
public String TargetVersion
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
private set;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Setup(x => x.GetAgentMessageAsync(
|
.Setup(x => x.GetAgentMessageAsync(
|
||||||
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<CancellationToken>()))
|
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Returns(async (Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, CancellationToken cancellationToken) =>
|
.Returns(async (Int32 poolId, Guid sessionId, Int64? lastMessageId, TaskAgentStatus status, string runnerVersion, CancellationToken cancellationToken) =>
|
||||||
{
|
{
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
return messages.Dequeue();
|
return messages.Dequeue();
|
||||||
@@ -208,7 +208,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
//Assert
|
//Assert
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.GetAgentMessageAsync(
|
.Verify(x => x.GetAgentMessageAsync(
|
||||||
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<CancellationToken>()), Times.Exactly(arMessages.Length));
|
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Exactly(arMessages.Length));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Setup(x => x.GetAgentMessageAsync(
|
.Setup(x => x.GetAgentMessageAsync(
|
||||||
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<CancellationToken>()))
|
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<string>(), It.IsAny<CancellationToken>()))
|
||||||
.Throws(new TaskAgentAccessTokenExpiredException("test"));
|
.Throws(new TaskAgentAccessTokenExpiredException("test"));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -311,7 +311,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
//Assert
|
//Assert
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.GetAgentMessageAsync(
|
.Verify(x => x.GetAgentMessageAsync(
|
||||||
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<CancellationToken>()), Times.Once);
|
_settings.PoolId, expectedSession.SessionId, It.IsAny<long?>(), TaskAgentStatus.Online, It.IsAny<string>(), It.IsAny<CancellationToken>()), Times.Once);
|
||||||
|
|
||||||
_runnerServer
|
_runnerServer
|
||||||
.Verify(x => x.DeleteAgentSessionAsync(
|
.Verify(x => x.DeleteAgentSessionAsync(
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
_secretMasker = new SecretMasker();
|
_secretMasker = new SecretMasker();
|
||||||
_secretMasker.AddValueEncoder(ValueEncoders.JsonStringEscape);
|
_secretMasker.AddValueEncoder(ValueEncoders.JsonStringEscape);
|
||||||
_secretMasker.AddValueEncoder(ValueEncoders.UriDataEscape);
|
_secretMasker.AddValueEncoder(ValueEncoders.UriDataEscape);
|
||||||
_traceManager = new TraceManager(traceListener, _secretMasker);
|
_traceManager = new TraceManager(traceListener, null, _secretMasker);
|
||||||
_trace = GetTrace(nameof(TestHostContext));
|
_trace = GetTrace(nameof(TestHostContext));
|
||||||
|
|
||||||
// inject a terminal in silent mode so all console output
|
// inject a terminal in silent mode so all console output
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user