mirror of
https://github.com/actions/runner.git
synced 2025-12-11 21:06:55 +00:00
Compare commits
11 Commits
users/tihu
...
features/n
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8cd472d17 | ||
|
|
23a693aa2c | ||
|
|
eb36db8ff9 | ||
|
|
85e1927754 | ||
|
|
b6dbf42746 | ||
|
|
67ba8a7d42 | ||
|
|
e4f9e6ae26 | ||
|
|
854d5e3bf3 | ||
|
|
57dec28f68 | ||
|
|
55a861f089 | ||
|
|
51b2031cbf |
@@ -5,7 +5,7 @@
|
|||||||
# GitHub Actions Runner
|
# GitHub Actions Runner
|
||||||
|
|
||||||
[](https://github.com/actions/runner/actions)
|
[](https://github.com/actions/runner/actions)
|
||||||
[](https://github.com/actions/runner/actions)
|
[](https://github.com/actions-canary/actions-runner-e2e/actions/workflows/runner_e2etest.yml)
|
||||||
|
|
||||||
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
||||||
|
|
||||||
|
|||||||
71
docs/adrs/1438-conditional-composite.md
Normal file
71
docs/adrs/1438-conditional-composite.md
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
# ADR 1438: Support Conditionals In Composite Actions
|
||||||
|
|
||||||
|
**Date**: 2021-10-13
|
||||||
|
|
||||||
|
**Status**: Accepted
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
We recently shipped composite actions, which allows you to reuse individual steps inside an action.
|
||||||
|
However, one of the [most requested features](https://github.com/actions/runner/issues/834) has been a way to support the `if` keyword.
|
||||||
|
|
||||||
|
### Goals
|
||||||
|
- We want to keep consistent with current behavior
|
||||||
|
- We want to support conditionals via the `if` keyword
|
||||||
|
- Our built in functions like `success` should be implementable without calling them, for example you can do `job.status == success` rather then `success()` currently.
|
||||||
|
|
||||||
|
### How does composite currently work?
|
||||||
|
|
||||||
|
Currently, we have limited conditional support in composite actions for `pre` and `post` steps.
|
||||||
|
These are based on the `job status`, and support keywords like `always()`, `failed()`, `success()` and `cancelled()`.
|
||||||
|
However, generic or main steps do **not** support conditionals.
|
||||||
|
|
||||||
|
By default, in a regular workflow, a step runs on the `success()` condition. Which looks at the **job** **status**, sees if it is successful and runs.
|
||||||
|
|
||||||
|
By default, in a composite action, main steps run until a single step fails in that composite action, then the composite action is halted early. It does **not** care about the job status.
|
||||||
|
Pre, and post steps in composite actions use the job status to determine if they should run.
|
||||||
|
|
||||||
|
### How do we go forward?
|
||||||
|
|
||||||
|
Well, if we think about what composite actions are currently doing when invoking main steps, they are checking if the current composite action is successful.
|
||||||
|
Lets formalize that concept into a "real" idea.
|
||||||
|
|
||||||
|
- We will add an `action_status` field to the github context to mimic the [job's context status](https://docs.github.com/en/actions/learn-github-actions/contexts#job-context).
|
||||||
|
- We have an existing concept that does this `action_path` which is only set for composite actions on the github context.
|
||||||
|
- In a composite action during a main step, the `success()` function will check if `action_status == success`, rather then `job_status == success`. Failure will work the same way.
|
||||||
|
- Pre and post steps in composite actions will not change, they will continue to check the job status.
|
||||||
|
|
||||||
|
|
||||||
|
### Nested Scenario
|
||||||
|
For nested composite actions, we will follow the existing behavior, you only care about your current composite action, not any parents.
|
||||||
|
For example, lets imagine a scenario with a simple nested composite action
|
||||||
|
|
||||||
|
```
|
||||||
|
- Job
|
||||||
|
- Regular Step
|
||||||
|
- Composite Action
|
||||||
|
- runs: exit 1
|
||||||
|
- if: always()
|
||||||
|
uses: A child composite action
|
||||||
|
- if: success()
|
||||||
|
runs: echo "this should print"
|
||||||
|
- runs: echo "this should also print"
|
||||||
|
- if: success()
|
||||||
|
runs: echo "this will not print as the current composite action has failed already"
|
||||||
|
|
||||||
|
```
|
||||||
|
The child composite actions steps should run in this example, the child composite action has not yet failed, so it should run all steps until a step fails. This is consistent with how a composite action currently works in production if the main job fails but a composite action is invoked with `if:always()` or `if: failure()`
|
||||||
|
|
||||||
|
### Other options explored
|
||||||
|
We could add the `current_step_status` to the job context rather then `__status` to the steps context, however this comes with two major downsides:
|
||||||
|
- We need to support the field for every type of step, because its non trivial to remove a field from the job context once it has been added (its readonly)
|
||||||
|
- For all actions besides composite it would only every be `success`
|
||||||
|
- Its weird to have a `current_step` value on the job context
|
||||||
|
- We also explored a `__status` on the steps context.
|
||||||
|
- The `__` is required to prevent us from colliding with a step with id: status
|
||||||
|
- This felt wrong because the naming was not smooth, and did not fit into current conventions.
|
||||||
|
|
||||||
|
### Consequences
|
||||||
|
- github context has a new field for the status of the current composite action.
|
||||||
|
- We support conditional's in composite actions
|
||||||
|
- We keep the existing behavior for all users, but allow them to expand that functionality.
|
||||||
74
job.yml
74
job.yml
@@ -1,74 +0,0 @@
|
|||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: Role
|
|
||||||
metadata:
|
|
||||||
name: pod-admin
|
|
||||||
namespace: default
|
|
||||||
rules:
|
|
||||||
- apiGroups: [""]
|
|
||||||
resources: ["pods", "pods/log", "pods/attach", "pods/exec"]
|
|
||||||
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
|
||||||
kind: RoleBinding
|
|
||||||
metadata:
|
|
||||||
name: default-pod-admin
|
|
||||||
namespace: default
|
|
||||||
roleRef:
|
|
||||||
apiGroup: rbac.authorization.k8s.io
|
|
||||||
kind: Role
|
|
||||||
name: pod-admin
|
|
||||||
subjects:
|
|
||||||
- kind: ServiceAccount
|
|
||||||
name: default
|
|
||||||
namespace: default
|
|
||||||
|
|
||||||
---
|
|
||||||
apiVersion: batch/v1
|
|
||||||
kind: Job
|
|
||||||
metadata:
|
|
||||||
namespace: default
|
|
||||||
name: actions-runners
|
|
||||||
spec:
|
|
||||||
template:
|
|
||||||
spec:
|
|
||||||
# hostNetwork: true
|
|
||||||
volumes:
|
|
||||||
- name: runner-working
|
|
||||||
emptyDir: {}
|
|
||||||
containers:
|
|
||||||
- name: k8srunner
|
|
||||||
image: huangtingluo/kube-runner:v0
|
|
||||||
imagePullPolicy: Always
|
|
||||||
volumeMounts:
|
|
||||||
- mountPath: /actions-runner/_work
|
|
||||||
name: runner-working
|
|
||||||
env:
|
|
||||||
- name: GITHUB_PAT
|
|
||||||
value: ghp_
|
|
||||||
- name: RUNNER_CONFIG_URL
|
|
||||||
value: https://github.com/bbq-beets/ting-test
|
|
||||||
- name: K8S_NODE_NAME
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
fieldPath: spec.nodeName
|
|
||||||
- name: K8S_POD_NAME
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
fieldPath: metadata.name
|
|
||||||
- name: K8S_POD_NAMESPACE
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
fieldPath: metadata.namespace
|
|
||||||
- name: K8S_POD_IP
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
fieldPath: status.podIP
|
|
||||||
- name: K8S_POD_SERVICE_ACCOUNT
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
fieldPath: spec.serviceAccountName
|
|
||||||
restartPolicy: Never
|
|
||||||
backoffLimit: 1
|
|
||||||
completions: 1
|
|
||||||
parallelism: 1
|
|
||||||
@@ -1,11 +1,20 @@
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
- Expose GITHUB_REF_* as environment variable (#1314)
|
||||||
|
- Add arch to runner context (#1372)
|
||||||
|
- Support Conditional Steps in Composite Actions (#1438)
|
||||||
|
- Log current runner version in terminal (#1441)
|
||||||
|
|
||||||
## Bugs
|
## Bugs
|
||||||
|
|
||||||
- Fixed an issue where ephemeral runners did not restart after upgrading (#1396)
|
- Makes the user keychains available to the service (#847)
|
||||||
|
- Use Actions Service health and api.github.com endpoints after connection failure on Actions Server and Hosted (#1385)
|
||||||
|
- Fix an issue where nested local composite actions did not correctly register post steps (#1433)
|
||||||
|
|
||||||
## Misc
|
## Misc
|
||||||
|
|
||||||
|
- Cleanup Older versions on MacOS now that we recreate node versions as needed (#1410)
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:3.1 AS Build
|
|
||||||
|
|
||||||
# ENV RUNNER_CONFIG_URL=""
|
|
||||||
# ENV GITHUB_PAT=""
|
|
||||||
# ENV RUNNER_NAME=""
|
|
||||||
# ENV RUNNER_GROUP=""
|
|
||||||
# ENV RUNNER_LABELS=""
|
|
||||||
# ENV GITHUB_RUNNER_SCOPE=""
|
|
||||||
# ENV GITHUB_SERVER_URL=""
|
|
||||||
# ENV GITHUB_API_URL=""
|
|
||||||
# ENV K8S_HOST_IP=""
|
|
||||||
|
|
||||||
RUN apt-get update --fix-missing \
|
|
||||||
&& apt-get install -y --no-install-recommends \
|
|
||||||
curl \
|
|
||||||
# jq \
|
|
||||||
# git \
|
|
||||||
apt-utils \
|
|
||||||
apt-transport-https \
|
|
||||||
unzip \
|
|
||||||
net-tools\
|
|
||||||
gnupg2\
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install kubectl
|
|
||||||
# RUN curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
|
|
||||||
# echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list && \
|
|
||||||
# apt-get update && apt-get -y install --no-install-recommends kubectl
|
|
||||||
|
|
||||||
# Install docker
|
|
||||||
# RUN curl -fsSL https://get.docker.com -o get-docker.sh
|
|
||||||
# RUN sh get-docker.sh
|
|
||||||
|
|
||||||
# Allow runner to run as root
|
|
||||||
# ENV RUNNER_ALLOW_RUNASROOT=1
|
|
||||||
|
|
||||||
# Directory for runner to operate in
|
|
||||||
RUN mkdir /actions-runner
|
|
||||||
RUN mkdir /actions-runner/src
|
|
||||||
WORKDIR /actions-runner/src
|
|
||||||
|
|
||||||
COPY ./ /actions-runner/src
|
|
||||||
|
|
||||||
RUN /actions-runner/src/dev.sh l
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1
|
|
||||||
|
|
||||||
ENV RUNNER_CONFIG_URL=""
|
|
||||||
ENV GITHUB_PAT=""
|
|
||||||
|
|
||||||
RUN apt-get update --fix-missing \
|
|
||||||
&& apt-get install -y --no-install-recommends \
|
|
||||||
curl \
|
|
||||||
# jq \
|
|
||||||
# git \
|
|
||||||
# apt-utils \
|
|
||||||
# apt-transport-https \
|
|
||||||
# unzip \
|
|
||||||
# net-tools\
|
|
||||||
gnupg2\
|
|
||||||
&& apt-get clean \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
# Install kubectl
|
|
||||||
RUN curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - && \
|
|
||||||
echo "deb https://apt.kubernetes.io/ kubernetes-xenial main" | tee -a /etc/apt/sources.list.d/kubernetes.list && \
|
|
||||||
apt-get update && apt-get -y install --no-install-recommends kubectl
|
|
||||||
|
|
||||||
|
|
||||||
# Allow runner to run as root
|
|
||||||
ENV RUNNER_ALLOW_RUNASROOT=1
|
|
||||||
|
|
||||||
# Directory for runner to operate in
|
|
||||||
RUN mkdir /actions-runner
|
|
||||||
WORKDIR /actions-runner
|
|
||||||
COPY --from=Build /actions-runner/_layout /actions-runner
|
|
||||||
ENTRYPOINT ["./entrypoint.sh"]
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": ["jest", "@typescript-eslint"],
|
|
||||||
"extends": ["plugin:github/es6"],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 9,
|
|
||||||
"sourceType": "module",
|
|
||||||
"project": "./tsconfig.json"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"eslint-comments/no-use": "off",
|
|
||||||
"import/no-namespace": "off",
|
|
||||||
"no-console": "off",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
|
||||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
|
||||||
"@typescript-eslint/no-require-imports": "error",
|
|
||||||
"@typescript-eslint/array-type": "error",
|
|
||||||
"@typescript-eslint/await-thenable": "error",
|
|
||||||
"@typescript-eslint/ban-ts-ignore": "error",
|
|
||||||
"camelcase": "off",
|
|
||||||
"@typescript-eslint/camelcase": "error",
|
|
||||||
"@typescript-eslint/class-name-casing": "error",
|
|
||||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
|
||||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
|
||||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
|
||||||
"@typescript-eslint/no-array-constructor": "error",
|
|
||||||
"@typescript-eslint/no-empty-interface": "error",
|
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
|
||||||
"@typescript-eslint/no-for-in-array": "error",
|
|
||||||
"@typescript-eslint/no-inferrable-types": "error",
|
|
||||||
"@typescript-eslint/no-misused-new": "error",
|
|
||||||
"@typescript-eslint/no-namespace": "error",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
||||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-useless-constructor": "error",
|
|
||||||
"@typescript-eslint/no-var-requires": "error",
|
|
||||||
"@typescript-eslint/prefer-for-of": "warn",
|
|
||||||
"@typescript-eslint/prefer-function-type": "warn",
|
|
||||||
"@typescript-eslint/prefer-includes": "error",
|
|
||||||
"@typescript-eslint/prefer-interface": "error",
|
|
||||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
|
||||||
"@typescript-eslint/promise-function-async": "error",
|
|
||||||
"@typescript-eslint/require-array-sort-compare": "error",
|
|
||||||
"@typescript-eslint/restrict-plus-operands": "error",
|
|
||||||
"semi": "off",
|
|
||||||
"@typescript-eslint/semi": ["error", "never"],
|
|
||||||
"@typescript-eslint/type-annotation-spacing": "error",
|
|
||||||
"@typescript-eslint/unbound-method": "error"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"node": true,
|
|
||||||
"es6": true,
|
|
||||||
"jest/globals": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"bracketSpacing": false,
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"parser": "typescript"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
To update kubeInnerHandler under `Misc/layoutbin` run `npm install && npm run all`
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "kubeInnerHandler",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "GitHub Actions",
|
|
||||||
"main": "lib/kubeInnerHandler.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "tsc",
|
|
||||||
"format": "prettier --write **/*.ts",
|
|
||||||
"format-check": "prettier --check **/*.ts",
|
|
||||||
"lint": "eslint src/**/*.ts",
|
|
||||||
"pack": "ncc build -o ../../layoutbin/kubeInnerHandler",
|
|
||||||
"all": "npm run build && npm run format && npm run lint && npm run pack"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/actions/runner.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"actions"
|
|
||||||
],
|
|
||||||
"author": "GitHub Actions",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/exec": "^1.1.0",
|
|
||||||
"@actions/core": "^1.6.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^12.7.12",
|
|
||||||
"@typescript-eslint/parser": "^2.8.0",
|
|
||||||
"@zeit/ncc": "^0.20.5",
|
|
||||||
"eslint": "^6.8.0",
|
|
||||||
"eslint-plugin-github": "^2.0.0",
|
|
||||||
"prettier": "^1.19.1",
|
|
||||||
"typescript": "^3.6.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
import * as exec from '@actions/exec'
|
|
||||||
import * as core from '@actions/core'
|
|
||||||
import * as events from 'events'
|
|
||||||
import * as readline from 'readline'
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
let input = ''
|
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: process.stdin
|
|
||||||
})
|
|
||||||
|
|
||||||
rl.on('line', line => {
|
|
||||||
core.debug(`Line from STDIN: ${line}`)
|
|
||||||
input = line
|
|
||||||
})
|
|
||||||
|
|
||||||
await events.once(rl, 'close')
|
|
||||||
|
|
||||||
core.debug(input)
|
|
||||||
|
|
||||||
const execInput = JSON.parse(input)
|
|
||||||
core.debug(JSON.stringify(execInput))
|
|
||||||
|
|
||||||
// podman exec -i --workdir /__w/canary/canary
|
|
||||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
|
||||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
|
||||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
|
||||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
|
||||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
|
||||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
|
||||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
|
||||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
|
||||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
|
||||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
|
||||||
|
|
||||||
const execArgs = []
|
|
||||||
const args = (<string>execInput.arguments).split(' ')
|
|
||||||
core.debug(JSON.stringify(args))
|
|
||||||
execArgs.push(...args)
|
|
||||||
|
|
||||||
core.debug(JSON.stringify(execArgs))
|
|
||||||
|
|
||||||
await exec.exec(execInput.fileName, execArgs, {
|
|
||||||
env: execInput.environmentVariables
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
|
||||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
|
||||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
|
||||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": ["jest", "@typescript-eslint"],
|
|
||||||
"extends": ["plugin:github/es6"],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 9,
|
|
||||||
"sourceType": "module",
|
|
||||||
"project": "./tsconfig.json"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"eslint-comments/no-use": "off",
|
|
||||||
"import/no-namespace": "off",
|
|
||||||
"no-console": "off",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
|
||||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
|
||||||
"@typescript-eslint/no-require-imports": "error",
|
|
||||||
"@typescript-eslint/array-type": "error",
|
|
||||||
"@typescript-eslint/await-thenable": "error",
|
|
||||||
"@typescript-eslint/ban-ts-ignore": "error",
|
|
||||||
"camelcase": "off",
|
|
||||||
"@typescript-eslint/camelcase": "error",
|
|
||||||
"@typescript-eslint/class-name-casing": "error",
|
|
||||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
|
||||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
|
||||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
|
||||||
"@typescript-eslint/no-array-constructor": "error",
|
|
||||||
"@typescript-eslint/no-empty-interface": "error",
|
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
|
||||||
"@typescript-eslint/no-for-in-array": "error",
|
|
||||||
"@typescript-eslint/no-inferrable-types": "error",
|
|
||||||
"@typescript-eslint/no-misused-new": "error",
|
|
||||||
"@typescript-eslint/no-namespace": "error",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
||||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-useless-constructor": "error",
|
|
||||||
"@typescript-eslint/no-var-requires": "error",
|
|
||||||
"@typescript-eslint/prefer-for-of": "warn",
|
|
||||||
"@typescript-eslint/prefer-function-type": "warn",
|
|
||||||
"@typescript-eslint/prefer-includes": "error",
|
|
||||||
"@typescript-eslint/prefer-interface": "error",
|
|
||||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
|
||||||
"@typescript-eslint/promise-function-async": "error",
|
|
||||||
"@typescript-eslint/require-array-sort-compare": "error",
|
|
||||||
"@typescript-eslint/restrict-plus-operands": "error",
|
|
||||||
"semi": "off",
|
|
||||||
"@typescript-eslint/semi": ["error", "never"],
|
|
||||||
"@typescript-eslint/type-annotation-spacing": "error",
|
|
||||||
"@typescript-eslint/unbound-method": "error"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"node": true,
|
|
||||||
"es6": true,
|
|
||||||
"jest/globals": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"bracketSpacing": false,
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"parser": "typescript"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
To update kubectlHandler under `Misc/layoutbin` run `npm install && npm run all`
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "kubectlHandler",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "GitHub Actions",
|
|
||||||
"main": "lib/kubectlHandler.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "tsc",
|
|
||||||
"format": "prettier --write **/*.ts",
|
|
||||||
"format-check": "prettier --check **/*.ts",
|
|
||||||
"lint": "eslint src/**/*.ts",
|
|
||||||
"pack": "ncc build -o ../../layoutbin/kubectlHandler",
|
|
||||||
"all": "npm run build && npm run format && npm run lint && npm run pack"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/actions/runner.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"actions"
|
|
||||||
],
|
|
||||||
"author": "GitHub Actions",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/exec": "^1.1.0",
|
|
||||||
"@actions/core": "^1.6.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^12.7.12",
|
|
||||||
"@typescript-eslint/parser": "^2.8.0",
|
|
||||||
"@zeit/ncc": "^0.20.5",
|
|
||||||
"eslint": "^6.8.0",
|
|
||||||
"eslint-plugin-github": "^2.0.0",
|
|
||||||
"prettier": "^1.19.1",
|
|
||||||
"typescript": "^3.6.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
import * as exec from '@actions/exec'
|
|
||||||
import * as core from '@actions/core'
|
|
||||||
import * as events from 'events'
|
|
||||||
import * as readline from 'readline'
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
let input = ''
|
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: process.stdin
|
|
||||||
})
|
|
||||||
|
|
||||||
rl.on('line', line => {
|
|
||||||
core.debug(`Line from STDIN: ${line}`)
|
|
||||||
input = line
|
|
||||||
})
|
|
||||||
|
|
||||||
await events.once(rl, 'close')
|
|
||||||
|
|
||||||
core.debug(input)
|
|
||||||
|
|
||||||
const inputJson = JSON.parse(input)
|
|
||||||
core.debug(JSON.stringify(inputJson))
|
|
||||||
|
|
||||||
const command = inputJson.command
|
|
||||||
if (command === 'Create') {
|
|
||||||
const creationInput = inputJson.creationInput
|
|
||||||
core.debug(JSON.stringify(creationInput))
|
|
||||||
const containers = creationInput.containers
|
|
||||||
const jobContainer = containers[0]
|
|
||||||
|
|
||||||
// const networkName = 'actions_podman_network'
|
|
||||||
// // podman network create {network} -> track and return `network` for ${{job.container.network}}
|
|
||||||
// await exec.exec('podman', ['network', 'create', networkName])
|
|
||||||
|
|
||||||
const containerImage = `${jobContainer.containerImage}`
|
|
||||||
// podman pull docker.io/library/{image}
|
|
||||||
// await exec.exec('podman', ['pull', containerImage])
|
|
||||||
|
|
||||||
// kubectl run e088c842be1f46b394212618408aaba0_node1016jessie_6196c9
|
|
||||||
// --image=node:10.16-jessie
|
|
||||||
// -- tail -f /dev/null
|
|
||||||
const runArgs = ['run', 'job-container']
|
|
||||||
// runArgs.push(`--workdir=${jobContainer.containerWorkDirectory}`)
|
|
||||||
// runArgs.push(`--network=${networkName}`)
|
|
||||||
|
|
||||||
// for (const mountVolume of jobContainer.mountVolumes) {
|
|
||||||
// runArgs.push(
|
|
||||||
// `-v=${mountVolume.sourceVolumePath}:${mountVolume.targetVolumePath}`
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
runArgs.push(`--image=${containerImage}`)
|
|
||||||
runArgs.push(`--`)
|
|
||||||
runArgs.push(`tail`)
|
|
||||||
runArgs.push(`-f`)
|
|
||||||
runArgs.push(`/dev/null`)
|
|
||||||
|
|
||||||
core.debug(JSON.stringify(runArgs))
|
|
||||||
|
|
||||||
// const containerId = await exec.getExecOutput('podman', [
|
|
||||||
// 'create',
|
|
||||||
// // `--workdir ${jobContainer.containerWorkDirectory}`,
|
|
||||||
// `--network=${networkName}`,
|
|
||||||
// // `-v=/Users/ting/Desktop/runner/_layout/_work:/__w`,
|
|
||||||
// `--entrypoint=${jobContainer.containerEntryPoint}`,
|
|
||||||
// `${containerImage}`,
|
|
||||||
// `${jobContainer.containerEntryPointArgs}`
|
|
||||||
// ])
|
|
||||||
|
|
||||||
await exec.exec('kubectl', runArgs)
|
|
||||||
|
|
||||||
// get PATH inside the container
|
|
||||||
|
|
||||||
const waitArgs = ['wait', '--for=condition=Ready', 'pod/job-container']
|
|
||||||
await exec.exec('kubectl', waitArgs)
|
|
||||||
|
|
||||||
// output containerId for ${{job.container.id}}
|
|
||||||
|
|
||||||
// copy over node.js
|
|
||||||
const cpNodeArgs = [
|
|
||||||
'cp',
|
|
||||||
'/actions-runner/externals/node12/bin',
|
|
||||||
'job-container:/__runner_util/'
|
|
||||||
]
|
|
||||||
await exec.exec('kubectl', cpNodeArgs)
|
|
||||||
|
|
||||||
// copy over innerhandler
|
|
||||||
const cpKubeInnerArgs = [
|
|
||||||
'cp',
|
|
||||||
'/actions-runner/bin/kubeInnerHandler',
|
|
||||||
'job-container:/__runner_util/kubeInnerHandler'
|
|
||||||
]
|
|
||||||
await exec.exec('kubectl', cpKubeInnerArgs)
|
|
||||||
|
|
||||||
// copy over _work
|
|
||||||
const cpWorkArgs = ['cp', '/actions-runner/_work', 'job-container:/__w/']
|
|
||||||
await exec.exec('kubectl', cpWorkArgs)
|
|
||||||
|
|
||||||
const creationOutput = {
|
|
||||||
JobContainerId: 'job-container',
|
|
||||||
Network: 'job-container'
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = JSON.stringify({CreationOutput: creationOutput})
|
|
||||||
core.debug(output)
|
|
||||||
|
|
||||||
process.stderr.write(
|
|
||||||
`___CONTAINER_ENGINE_HANDLER_OUTPUT___${output}___CONTAINER_ENGINE_HANDLER_OUTPUT___`
|
|
||||||
)
|
|
||||||
} else if (command === 'Remove') {
|
|
||||||
const removeInput = inputJson.removeInput
|
|
||||||
core.debug(JSON.stringify(removeInput))
|
|
||||||
// const jobContainerId = removeInput.jobContainerId
|
|
||||||
|
|
||||||
// await exec.exec('kubectl', ['delete', 'pod', jobContainerId, '--force'])
|
|
||||||
// await exec.exec('podman', ['network', 'rm', '-f', network])
|
|
||||||
} else if (command === 'Exec') {
|
|
||||||
const execInput = inputJson.execInput
|
|
||||||
core.debug(JSON.stringify(execInput))
|
|
||||||
|
|
||||||
// podman exec -i --workdir /__w/canary/canary
|
|
||||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
|
||||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
|
||||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
|
||||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
|
||||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
|
||||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
|
||||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
|
||||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
|
||||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
|
||||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
|
||||||
|
|
||||||
const cpTempArgs = [
|
|
||||||
'cp',
|
|
||||||
'/actions-runner/_work/_temp',
|
|
||||||
'job-container:/__w/'
|
|
||||||
]
|
|
||||||
await exec.exec('kubectl', cpTempArgs)
|
|
||||||
|
|
||||||
const execArgs = ['exec']
|
|
||||||
execArgs.push(execInput.jobContainer.containerId)
|
|
||||||
execArgs.push('-i')
|
|
||||||
execArgs.push('-t')
|
|
||||||
execArgs.push('--')
|
|
||||||
execArgs.push('/__runner_util/node')
|
|
||||||
execArgs.push('/__runner_util/kubeInnerHandler')
|
|
||||||
|
|
||||||
core.debug(JSON.stringify(execArgs))
|
|
||||||
|
|
||||||
await exec.exec('kubectl', execArgs, {
|
|
||||||
input: Buffer.from(JSON.stringify(execInput))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
|
||||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
|
||||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
|
||||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
{
|
|
||||||
"plugins": ["jest", "@typescript-eslint"],
|
|
||||||
"extends": ["plugin:github/es6"],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 9,
|
|
||||||
"sourceType": "module",
|
|
||||||
"project": "./tsconfig.json"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"eslint-comments/no-use": "off",
|
|
||||||
"import/no-namespace": "off",
|
|
||||||
"no-console": "off",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"@typescript-eslint/no-unused-vars": "error",
|
|
||||||
"@typescript-eslint/explicit-member-accessibility": ["error", {"accessibility": "no-public"}],
|
|
||||||
"@typescript-eslint/no-require-imports": "error",
|
|
||||||
"@typescript-eslint/array-type": "error",
|
|
||||||
"@typescript-eslint/await-thenable": "error",
|
|
||||||
"@typescript-eslint/ban-ts-ignore": "error",
|
|
||||||
"camelcase": "off",
|
|
||||||
"@typescript-eslint/camelcase": "error",
|
|
||||||
"@typescript-eslint/class-name-casing": "error",
|
|
||||||
"@typescript-eslint/explicit-function-return-type": ["error", {"allowExpressions": true}],
|
|
||||||
"@typescript-eslint/func-call-spacing": ["error", "never"],
|
|
||||||
"@typescript-eslint/generic-type-naming": ["error", "^[A-Z][A-Za-z]*$"],
|
|
||||||
"@typescript-eslint/no-array-constructor": "error",
|
|
||||||
"@typescript-eslint/no-empty-interface": "error",
|
|
||||||
"@typescript-eslint/no-explicit-any": "error",
|
|
||||||
"@typescript-eslint/no-extraneous-class": "error",
|
|
||||||
"@typescript-eslint/no-for-in-array": "error",
|
|
||||||
"@typescript-eslint/no-inferrable-types": "error",
|
|
||||||
"@typescript-eslint/no-misused-new": "error",
|
|
||||||
"@typescript-eslint/no-namespace": "error",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "warn",
|
|
||||||
"@typescript-eslint/no-object-literal-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
|
||||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
|
||||||
"@typescript-eslint/no-useless-constructor": "error",
|
|
||||||
"@typescript-eslint/no-var-requires": "error",
|
|
||||||
"@typescript-eslint/prefer-for-of": "warn",
|
|
||||||
"@typescript-eslint/prefer-function-type": "warn",
|
|
||||||
"@typescript-eslint/prefer-includes": "error",
|
|
||||||
"@typescript-eslint/prefer-interface": "error",
|
|
||||||
"@typescript-eslint/prefer-string-starts-ends-with": "error",
|
|
||||||
"@typescript-eslint/promise-function-async": "error",
|
|
||||||
"@typescript-eslint/require-array-sort-compare": "error",
|
|
||||||
"@typescript-eslint/restrict-plus-operands": "error",
|
|
||||||
"semi": "off",
|
|
||||||
"@typescript-eslint/semi": ["error", "never"],
|
|
||||||
"@typescript-eslint/type-annotation-spacing": "error",
|
|
||||||
"@typescript-eslint/unbound-method": "error"
|
|
||||||
},
|
|
||||||
"env": {
|
|
||||||
"node": true,
|
|
||||||
"es6": true,
|
|
||||||
"jest/globals": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
dist/
|
|
||||||
lib/
|
|
||||||
node_modules/
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"printWidth": 80,
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": false,
|
|
||||||
"singleQuote": true,
|
|
||||||
"trailingComma": "none",
|
|
||||||
"bracketSpacing": false,
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"parser": "typescript"
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
To update podmanHandler under `Misc/layoutbin` run `npm install && npm run all`
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "podmanHandler",
|
|
||||||
"version": "1.0.0",
|
|
||||||
"description": "GitHub Actions",
|
|
||||||
"main": "lib/podmanHandler.js",
|
|
||||||
"scripts": {
|
|
||||||
"build": "tsc",
|
|
||||||
"format": "prettier --write **/*.ts",
|
|
||||||
"format-check": "prettier --check **/*.ts",
|
|
||||||
"lint": "eslint src/**/*.ts",
|
|
||||||
"pack": "ncc build -o ../../layoutbin/podmanHandler",
|
|
||||||
"all": "npm run build && npm run format && npm run lint && npm run pack"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "git+https://github.com/actions/runner.git"
|
|
||||||
},
|
|
||||||
"keywords": [
|
|
||||||
"actions"
|
|
||||||
],
|
|
||||||
"author": "GitHub Actions",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"@actions/exec": "^1.1.0",
|
|
||||||
"@actions/core": "^1.6.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "^12.7.12",
|
|
||||||
"@typescript-eslint/parser": "^2.8.0",
|
|
||||||
"@zeit/ncc": "^0.20.5",
|
|
||||||
"eslint": "^6.8.0",
|
|
||||||
"eslint-plugin-github": "^2.0.0",
|
|
||||||
"prettier": "^1.19.1",
|
|
||||||
"typescript": "^3.6.4"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
import * as exec from '@actions/exec'
|
|
||||||
import * as core from '@actions/core'
|
|
||||||
import * as events from 'events'
|
|
||||||
import * as readline from 'readline'
|
|
||||||
|
|
||||||
async function run(): Promise<void> {
|
|
||||||
let input = ''
|
|
||||||
|
|
||||||
const rl = readline.createInterface({
|
|
||||||
input: process.stdin
|
|
||||||
})
|
|
||||||
|
|
||||||
rl.on('line', line => {
|
|
||||||
core.debug(`Line from STDIN: ${line}`)
|
|
||||||
input = line
|
|
||||||
})
|
|
||||||
|
|
||||||
await events.once(rl, 'close')
|
|
||||||
|
|
||||||
core.debug(input)
|
|
||||||
|
|
||||||
const inputJson = JSON.parse(input)
|
|
||||||
core.debug(JSON.stringify(inputJson))
|
|
||||||
|
|
||||||
const command = inputJson.command
|
|
||||||
if (command === 'Create') {
|
|
||||||
const creationInput = inputJson.creationInput
|
|
||||||
core.debug(JSON.stringify(creationInput))
|
|
||||||
const containers = creationInput.containers
|
|
||||||
const jobContainer = containers[0]
|
|
||||||
|
|
||||||
const networkName = 'actions_podman_network'
|
|
||||||
// podman network create {network} -> track and return `network` for ${{job.container.network}}
|
|
||||||
await exec.exec('podman', ['network', 'create', networkName])
|
|
||||||
|
|
||||||
const containerImage = `docker.io/library/${jobContainer.containerImage}`
|
|
||||||
// podman pull docker.io/library/{image}
|
|
||||||
await exec.exec('podman', ['pull', containerImage])
|
|
||||||
|
|
||||||
// podman create --name e088c842be1f46b394212618408aaba0_node1016jessie_6196c9
|
|
||||||
// --label fa4e14
|
|
||||||
// --workdir /__w/canary/canary
|
|
||||||
// --network github_network_f98a6e1e96e74d919d814c165641cba3
|
|
||||||
// -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true
|
|
||||||
// -v "/var/run/docker.sock":"/var/run/docker.sock"
|
|
||||||
// -v "/home/runner/work":"/__w"
|
|
||||||
// -v "/home/runner/runners/2.283.2/externals":"/__e":ro
|
|
||||||
// -v "/home/runner/work/_temp":"/__w/_temp"
|
|
||||||
// -v "/home/runner/work/_actions":"/__w/_actions"
|
|
||||||
// -v "/opt/hostedtoolcache":"/__t"
|
|
||||||
// -v "/home/runner/work/_temp/_github_home":"/github/home"
|
|
||||||
// -v "/home/runner/work/_temp/_github_workflow":"/github/workflow"
|
|
||||||
// --entrypoint "tail" node:10.16-jessie "-f" "/dev/null"
|
|
||||||
const creatArgs = ['create']
|
|
||||||
creatArgs.push(`--workdir=${jobContainer.containerWorkDirectory}`)
|
|
||||||
creatArgs.push(`--network=${networkName}`)
|
|
||||||
|
|
||||||
for (const mountVolume of jobContainer.mountVolumes) {
|
|
||||||
creatArgs.push(
|
|
||||||
`-v=${mountVolume.sourceVolumePath}:${mountVolume.targetVolumePath}`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
creatArgs.push(`--entrypoint=tail`)
|
|
||||||
creatArgs.push(containerImage)
|
|
||||||
creatArgs.push(`-f`)
|
|
||||||
creatArgs.push(`/dev/null`)
|
|
||||||
|
|
||||||
core.debug(JSON.stringify(creatArgs))
|
|
||||||
|
|
||||||
// const containerId = await exec.getExecOutput('podman', [
|
|
||||||
// 'create',
|
|
||||||
// // `--workdir ${jobContainer.containerWorkDirectory}`,
|
|
||||||
// `--network=${networkName}`,
|
|
||||||
// // `-v=/Users/ting/Desktop/runner/_layout/_work:/__w`,
|
|
||||||
// `--entrypoint=${jobContainer.containerEntryPoint}`,
|
|
||||||
// `${containerImage}`,
|
|
||||||
// `${jobContainer.containerEntryPointArgs}`
|
|
||||||
// ])
|
|
||||||
|
|
||||||
const containerId = await exec.getExecOutput('podman', creatArgs)
|
|
||||||
|
|
||||||
core.debug(JSON.stringify(containerId))
|
|
||||||
|
|
||||||
// podman start {containerId}
|
|
||||||
await exec.exec('podman', ['start', containerId.stdout.trim()])
|
|
||||||
|
|
||||||
// get PATH inside the container
|
|
||||||
|
|
||||||
// output containerId for ${{job.container.id}}
|
|
||||||
|
|
||||||
const creationOutput = {
|
|
||||||
JobContainerId: containerId.stdout.trim(),
|
|
||||||
Network: networkName
|
|
||||||
}
|
|
||||||
|
|
||||||
const output = JSON.stringify({CreationOutput: creationOutput})
|
|
||||||
core.debug(output)
|
|
||||||
|
|
||||||
process.stderr.write(
|
|
||||||
`___CONTAINER_ENGINE_HANDLER_OUTPUT___${output}___CONTAINER_ENGINE_HANDLER_OUTPUT___`
|
|
||||||
)
|
|
||||||
} else if (command === 'Remove') {
|
|
||||||
const removeInput = inputJson.removeInput
|
|
||||||
core.debug(JSON.stringify(removeInput))
|
|
||||||
const jobContainerId = removeInput.jobContainerId
|
|
||||||
const network = removeInput.network
|
|
||||||
|
|
||||||
await exec.exec('podman', ['rm', '-f', jobContainerId])
|
|
||||||
await exec.exec('podman', ['network', 'rm', '-f', network])
|
|
||||||
} else if (command === 'Exec') {
|
|
||||||
const execInput = inputJson.execInput
|
|
||||||
core.debug(JSON.stringify(execInput))
|
|
||||||
|
|
||||||
// podman exec -i --workdir /__w/canary/canary
|
|
||||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
|
||||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
|
||||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
|
||||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
|
||||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
|
||||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
|
||||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
|
||||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
|
||||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
|
||||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
|
||||||
|
|
||||||
const execArgs = ['exec']
|
|
||||||
execArgs.push('-i')
|
|
||||||
execArgs.push(`--workdir=${execInput.workingDirectory}`)
|
|
||||||
for (const envKey of execInput.environmentKeys) {
|
|
||||||
execArgs.push(`-e=${envKey}`)
|
|
||||||
}
|
|
||||||
execArgs.push(execInput.jobContainer.containerId)
|
|
||||||
execArgs.push(execInput.fileName)
|
|
||||||
|
|
||||||
const args = (<string>execInput.arguments).split(' ')
|
|
||||||
core.debug(JSON.stringify(args))
|
|
||||||
|
|
||||||
execArgs.push(...args)
|
|
||||||
|
|
||||||
core.debug(JSON.stringify(execArgs))
|
|
||||||
|
|
||||||
await exec.exec('podman', execArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
await exec.exec('podman', ['network', 'ls'])
|
|
||||||
await exec.exec('podman', ['ps', '-a'])
|
|
||||||
}
|
|
||||||
|
|
||||||
run()
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
|
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
|
||||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
|
||||||
"rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
|
||||||
"strict": true, /* Enable all strict type-checking options. */
|
|
||||||
"noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
|
||||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules", "**/*.test.ts"]
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,49 +0,0 @@
|
|||||||
// Job container creation
|
|
||||||
|
|
||||||
// podman network create {network} -> track and return `network` for ${{job.container.network}}
|
|
||||||
|
|
||||||
// podman pull docker.io/library/{image}
|
|
||||||
|
|
||||||
// podman create --name e088c842be1f46b394212618408aaba0_node1016jessie_6196c9
|
|
||||||
// --label fa4e14
|
|
||||||
// --workdir /__w/canary/canary
|
|
||||||
// --network github_network_f98a6e1e96e74d919d814c165641cba3
|
|
||||||
// -e "HOME=/github/home" -e GITHUB_ACTIONS=true -e CI=true
|
|
||||||
// -v "/var/run/docker.sock":"/var/run/docker.sock"
|
|
||||||
// -v "/home/runner/work":"/__w"
|
|
||||||
// -v "/home/runner/runners/2.283.2/externals":"/__e":ro
|
|
||||||
// -v "/home/runner/work/_temp":"/__w/_temp"
|
|
||||||
// -v "/home/runner/work/_actions":"/__w/_actions"
|
|
||||||
// -v "/opt/hostedtoolcache":"/__t"
|
|
||||||
// -v "/home/runner/work/_temp/_github_home":"/github/home"
|
|
||||||
// -v "/home/runner/work/_temp/_github_workflow":"/github/workflow"
|
|
||||||
// --entrypoint "tail" node:10.16-jessie "-f" "/dev/null"
|
|
||||||
|
|
||||||
// podman start {containerId}
|
|
||||||
|
|
||||||
// get PATH inside the container
|
|
||||||
|
|
||||||
// output containerId for ${{job.container.id}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Job container stop
|
|
||||||
|
|
||||||
// podman rm --force {containerId}
|
|
||||||
|
|
||||||
// podman network rm {network}
|
|
||||||
|
|
||||||
|
|
||||||
// Run step
|
|
||||||
|
|
||||||
// podman exec -i --workdir /__w/canary/canary
|
|
||||||
// -e GITHUB_JOB -e GITHUB_REF -e GITHUB_SHA -e GITHUB_REPOSITORY
|
|
||||||
// -e GITHUB_REPOSITORY_OWNER -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER
|
|
||||||
// -e GITHUB_RETENTION_DAYS -e GITHUB_RUN_ATTEMPT -e GITHUB_ACTOR
|
|
||||||
// -e GITHUB_WORKFLOW -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GITHUB_EVENT_NAME
|
|
||||||
// -e GITHUB_SERVER_URL -e GITHUB_API_URL -e GITHUB_GRAPHQL_URL
|
|
||||||
// -e GITHUB_WORKSPACE -e GITHUB_ACTION -e GITHUB_EVENT_PATH -e GITHUB_ACTION_REPOSITORY
|
|
||||||
// -e GITHUB_ACTION_REF -e GITHUB_PATH -e GITHUB_ENV -e RUNNER_DEBUG
|
|
||||||
// -e RUNNER_OS -e RUNNER_NAME -e RUNNER_TOOL_CACHE
|
|
||||||
// -e RUNNER_TEMP -e RUNNER_WORKSPACE
|
|
||||||
// eccdf520697a035599d6e8c8dc801f004fdd3797cdce88f590aba3669a88d9bc sh -e /__w/_temp/d3b30383-719c-4e76-a16f-8f85443352be.sh
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -161,59 +161,13 @@ if [[ "$currentplatform" == 'darwin' && restartinteractiverunner -eq 0 ]]; then
|
|||||||
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner path. Path: $path, pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner path. Path: $path, pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
|
runproc=$(ps x -o pgid,command | grep "run.sh" | grep -v grep | awk '{print $1}')
|
||||||
|
if [[ $? -eq 0 && -n "$runproc" ]]
|
||||||
|
then
|
||||||
|
date "+[%F %T-%4N] Running as ephemeral using run.sh, no need to recreate node folder" >> "$logfile" 2>&1
|
||||||
|
else
|
||||||
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup, root: $rootfolder" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup, root: $rootfolder" >> "$logfile" 2>&1
|
||||||
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
date "+[%F %T-%4N] DarwinRunnerUpgrade: Failed to find runner pgid. pgid: $procgroup, root: $rootfolder" >> "$telemetryfile" 2>&1
|
||||||
fi
|
|
||||||
|
|
||||||
if [ $attemptedtargetedfix -eq 0 ]
|
|
||||||
then
|
|
||||||
|
|
||||||
date "+[%F %T-%4N] DarwinRunnerUpgrade: Defaulting to old macOS service fix" >> "$logfile" 2>&1
|
|
||||||
date "+[%F %T-%4N] DarwinRunnerUpgrade: Defaulting to old macOS service fix" >> "$telemetryfile" 2>&1
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.280.3/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.280.3/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.280.3/node12/bin/node"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.280.2/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.280.2/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.280.2/node12/bin/node"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.280.1/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.280.1/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.280.1/node12/bin/node"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# GHES 3.2
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.279.0/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.279.0/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.279.0/node12/bin/node"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# GHES 3.1.2 or later
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.278.0/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.278.0/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.278.0/node12/bin/node"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# GHES 3.1.0
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.276.1/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.276.1/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.276.1/node12/bin/node"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# GHES 3.0
|
|
||||||
if [[ ! -e "$rootfolder/externals.2.273.5/node12/bin/node" ]]
|
|
||||||
then
|
|
||||||
mkdir -p "$rootfolder/externals.2.273.5/node12/bin"
|
|
||||||
cp "$rootfolder/externals/node12/bin/node" "$rootfolder/externals.2.273.5/node12/bin/node"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1,68 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
function fatal() {
|
|
||||||
echo "error: $1" >&2
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
|
|
||||||
[ -n "${GITHUB_PAT:-""}" ] || fatal "GITHUB_PAT variable must be set"
|
|
||||||
[ -n "${RUNNER_CONFIG_URL:-""}" ] || fatal "RUNNER_CONFIG_URL variable must be set"
|
|
||||||
# [ -n "${RUNNER_NAME:-""}" ] || fatal "RUNNER_NAME variable must be set"
|
|
||||||
|
|
||||||
# if [ -n "${RUNNER_NAME}" ]; then
|
|
||||||
# # Use container id to gen unique runner name if name not provide
|
|
||||||
# CONTAINER_ID=$(cat /proc/self/cgroup | head -n 1 | tr '/' '\n' | tail -1 | cut -c1-12)
|
|
||||||
# RUNNER_NAME="actions-runner-${CONTAINER_ID}"
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# if the scope has a slash, it's a repo runner
|
|
||||||
# orgs_or_repos="orgs"
|
|
||||||
# if [[ "$GITHUB_RUNNER_SCOPE" == *\/* ]]; then
|
|
||||||
# orgs_or_repos="repos"
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# RUNNER_REG_URL="${GITHUB_SERVER_URL:=https://github.com}/${GITHUB_RUNNER_SCOPE}"
|
|
||||||
|
|
||||||
# echo "Runner Name : ${RUNNER_NAME}"
|
|
||||||
echo "Registration URL : ${RUNNER_CONFIG_URL}"
|
|
||||||
# echo "GitHub API URL : ${GITHUB_API_URL:=https://api.github.com}"
|
|
||||||
# echo "Runner Labels : ${RUNNER_LABELS:=""}"
|
|
||||||
|
|
||||||
# TODO: if api url is not default, validate it ends in /api/v3
|
|
||||||
|
|
||||||
# RUNNER_LABELS_ARG=""
|
|
||||||
# if [ -n "${RUNNER_LABELS}" ]; then
|
|
||||||
# RUNNER_LABELS_ARG="--labels ${RUNNER_LABELS}"
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# RUNNER_GROUP_ARG=""
|
|
||||||
# if [ -n "${RUNNER_GROUP}" ]; then
|
|
||||||
# RUNNER_GROUP_ARG="--runnergroup ${RUNNER_GROUP}"
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# if [ -n "${K8S_HOST_IP}" ]; then
|
|
||||||
# export http_proxy=http://$K8S_HOST_IP:9090
|
|
||||||
# fi
|
|
||||||
|
|
||||||
# curl -v -s -X POST ${GITHUB_API_URL}/${orgs_or_repos}/${GITHUB_RUNNER_SCOPE}/actions/runners/registration-token -H "authorization: token $GITHUB_PAT" -H "accept: application/vnd.github.everest-preview+json"
|
|
||||||
|
|
||||||
# Generate registration token
|
|
||||||
# RUNNER_REG_TOKEN=$(curl -s -X POST ${GITHUB_API_URL}/${orgs_or_repos}/${GITHUB_RUNNER_SCOPE}/actions/runners/registration-token -H "authorization: token $GITHUB_PAT" -H "accept: application/vnd.github.everest-preview+json" | jq -r '.token')
|
|
||||||
|
|
||||||
# Create the runner and configure it
|
|
||||||
./config.sh --unattended --url $RUNNER_CONFIG_URL --pat $GITHUB_PAT --replace --ephemeral
|
|
||||||
|
|
||||||
# while (! docker version ); do
|
|
||||||
# # Docker takes a few seconds to initialize
|
|
||||||
# echo "Waiting for Docker to launch..."
|
|
||||||
# sleep 1
|
|
||||||
# done
|
|
||||||
|
|
||||||
# unset env
|
|
||||||
unset RUNNER_CONFIG_URL
|
|
||||||
unset GITHUB_PAT
|
|
||||||
|
|
||||||
# Run it
|
|
||||||
./run.sh
|
|
||||||
@@ -38,7 +38,8 @@ namespace GitHub.Runner.Common
|
|||||||
public async Task ConnectAsync(VssConnection jobConnection)
|
public async Task ConnectAsync(VssConnection jobConnection)
|
||||||
{
|
{
|
||||||
_connection = jobConnection;
|
_connection = jobConnection;
|
||||||
int attemptCount = 5;
|
int totalAttempts = 5;
|
||||||
|
int attemptCount = totalAttempts;
|
||||||
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
var configurationStore = HostContext.GetService<IConfigurationStore>();
|
||||||
var runnerSettings = configurationStore.GetSettings();
|
var runnerSettings = configurationStore.GetSettings();
|
||||||
|
|
||||||
@@ -56,18 +57,21 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
if (runnerSettings.IsHostedServer)
|
if (runnerSettings.IsHostedServer)
|
||||||
{
|
{
|
||||||
await CheckNetworkEndpointsAsync();
|
await CheckNetworkEndpointsAsync(attemptCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.Delay(100);
|
int attempt = totalAttempts - attemptCount;
|
||||||
|
TimeSpan backoff = BackoffTimerHelper.GetExponentialBackoff(attempt, TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(3.2), TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
await Task.Delay(backoff);
|
||||||
}
|
}
|
||||||
|
|
||||||
_taskClient = _connection.GetClient<TaskHttpClient>();
|
_taskClient = _connection.GetClient<TaskHttpClient>();
|
||||||
_hasConnection = true;
|
_hasConnection = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CheckNetworkEndpointsAsync()
|
private async Task CheckNetworkEndpointsAsync(int attemptsLeft)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -79,8 +83,8 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
actionsClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
actionsClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
|
||||||
// Call the _apis/health endpoint
|
// Call the _apis/health endpoint, and include how many attempts are left as a URL query for easy tracking
|
||||||
var response = await actionsClient.GetAsync(new Uri(baseUri, "_apis/health"));
|
var response = await actionsClient.GetAsync(new Uri(baseUri, $"_apis/health?_internalRunnerAttemptsLeft={attemptsLeft}"));
|
||||||
Trace.Info($"Actions health status code: {response.StatusCode}");
|
Trace.Info($"Actions health status code: {response.StatusCode}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,8 +104,8 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
gitHubClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
gitHubClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
|
||||||
// Call the api.github.com endpoint
|
// Call the api.github.com endpoint, and include how many attempts are left as a URL query for easy tracking
|
||||||
var response = await gitHubClient.GetAsync("https://api.github.com");
|
var response = await gitHubClient.GetAsync($"https://api.github.com?_internalRunnerAttemptsLeft={attemptsLeft}");
|
||||||
Trace.Info($"api.github.com status code: {response.StatusCode}");
|
Trace.Info($"api.github.com status code: {response.StatusCode}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ namespace GitHub.Runner.Listener
|
|||||||
validator: Validators.ServerUrlValidator);
|
validator: Validators.ServerUrlValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
public string GetWindowsLogonAccount(string defaultValue, string descriptionMsg)
|
public string GetWindowsLogonAccount(string defaultValue, string descriptionMsg)
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
@@ -251,6 +252,7 @@ namespace GitHub.Runner.Listener
|
|||||||
defaultValue: defaultValue,
|
defaultValue: defaultValue,
|
||||||
validator: Validators.NTAccountValidator);
|
validator: Validators.NTAccountValidator);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
public string GetWindowsLogonPassword(string accountName)
|
public string GetWindowsLogonPassword(string accountName)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return !string.IsNullOrEmpty(value);
|
return !string.IsNullOrEmpty(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
public static bool NTAccountValidator(string arg)
|
public static bool NTAccountValidator(string arg)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(arg) || String.IsNullOrEmpty(arg.TrimStart('.', '\\')))
|
if (string.IsNullOrEmpty(arg) || String.IsNullOrEmpty(arg.TrimStart('.', '\\')))
|
||||||
@@ -87,5 +88,6 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
private static void LoadAndSetEnv()
|
private static void LoadAndSetEnv()
|
||||||
{
|
{
|
||||||
var binDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
var binDir = Path.GetDirectoryName(AppContext.BaseDirectory);
|
||||||
var rootDir = new DirectoryInfo(binDir).Parent.FullName;
|
var rootDir = new DirectoryInfo(binDir).Parent.FullName;
|
||||||
string envFile = Path.Combine(rootDir, ".env");
|
string envFile = Path.Combine(rootDir, ".env");
|
||||||
if (File.Exists(envFile))
|
if (File.Exists(envFile))
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
||||||
|
|||||||
@@ -312,6 +312,8 @@ namespace GitHub.Runner.Listener
|
|||||||
}
|
}
|
||||||
|
|
||||||
HostContext.WritePerfCounter("SessionCreated");
|
HostContext.WritePerfCounter("SessionCreated");
|
||||||
|
|
||||||
|
_term.WriteLine($"Current runner version: '{BuildConstants.RunnerPackage.Version}'");
|
||||||
_term.WriteLine($"{DateTime.UtcNow:u}: Listening for Jobs");
|
_term.WriteLine($"{DateTime.UtcNow:u}: Listening for Jobs");
|
||||||
|
|
||||||
IJobDispatcher jobDispatcher = null;
|
IJobDispatcher jobDispatcher = null;
|
||||||
|
|||||||
@@ -75,11 +75,9 @@ namespace GitHub.Runner.Listener
|
|||||||
Trace.Info($"All running job has exited.");
|
Trace.Info($"All running job has exited.");
|
||||||
|
|
||||||
// We need to keep runner backup around for macOS until we fixed https://github.com/actions/runner/issues/743
|
// We need to keep runner backup around for macOS until we fixed https://github.com/actions/runner/issues/743
|
||||||
#if !OS_OSX
|
|
||||||
// delete runner backup
|
// delete runner backup
|
||||||
DeletePreviousVersionRunnerBackup(token);
|
DeletePreviousVersionRunnerBackup(token);
|
||||||
Trace.Info($"Delete old version runner backup.");
|
Trace.Info($"Delete old version runner backup.");
|
||||||
#endif
|
|
||||||
// generate update script from template
|
// generate update script from template
|
||||||
await UpdateRunnerUpdateStateAsync("Generate and execute update script.");
|
await UpdateRunnerUpdateStateAsync("Generate and execute update script.");
|
||||||
|
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace GitHub.Runner.PluginHost
|
|||||||
string assemblyFilename = assembly.Name + ".dll";
|
string assemblyFilename = assembly.Name + ".dll";
|
||||||
if (string.IsNullOrEmpty(executingAssemblyLocation))
|
if (string.IsNullOrEmpty(executingAssemblyLocation))
|
||||||
{
|
{
|
||||||
executingAssemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
executingAssemblyLocation = Path.GetDirectoryName(AppContext.BaseDirectory);
|
||||||
}
|
}
|
||||||
return context.LoadFromAssemblyPath(Path.Combine(executingAssemblyLocation, assemblyFilename));
|
return context.LoadFromAssemblyPath(Path.Combine(executingAssemblyLocation, assemblyFilename));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ namespace GitHub.Runner.Plugins.Artifact
|
|||||||
{
|
{
|
||||||
// We should never
|
// We should never
|
||||||
context.Error($"Error '{ex.Message}' when downloading file '{fileToDownload}'. (Downloader {downloaderId})");
|
context.Error($"Error '{ex.Message}' when downloading file '{fileToDownload}'. (Downloader {downloaderId})");
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -528,7 +528,7 @@ namespace GitHub.Runner.Plugins.Artifact
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
context.Output($"File error '{ex.Message}' when uploading file '{fileToUpload}'.");
|
context.Output($"File error '{ex.Message}' when uploading file '{fileToUpload}'.");
|
||||||
throw ex;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
||||||
|
|||||||
@@ -267,6 +267,19 @@ namespace GitHub.Runner.Worker
|
|||||||
_cachedEmbeddedPostSteps[parentStepId].Push(clonedAction);
|
_cachedEmbeddedPostSteps[parentStepId].Push(clonedAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if (depth > 0)
|
||||||
|
{
|
||||||
|
// if we're in a composite action and haven't loaded the local action yet
|
||||||
|
// we assume it has a post step
|
||||||
|
if (!_cachedEmbeddedPostSteps.ContainsKey(parentStepId))
|
||||||
|
{
|
||||||
|
// If we haven't done so already, add the parent to the post steps
|
||||||
|
_cachedEmbeddedPostSteps[parentStepId] = new Stack<Pipelines.ActionStep>();
|
||||||
|
}
|
||||||
|
// Clone action so we can modify the condition without affecting the original
|
||||||
|
var clonedAction = action.Clone() as Pipelines.ActionStep;
|
||||||
|
_cachedEmbeddedPostSteps[parentStepId].Push(clonedAction);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1034,7 +1047,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove once we remove the DistributedTask.EnableCompositeActions FF
|
|
||||||
foreach (var step in compositeAction.Steps)
|
foreach (var step in compositeAction.Steps)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && step.Reference.Type != Pipelines.ActionSourceType.Script)
|
if (string.IsNullOrEmpty(executionContext.Global.Variables.Get("DistributedTask.EnableCompositeActions")) && step.Reference.Type != Pipelines.ActionSourceType.Script)
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
_pathMappings.Add(new PathMapping(hostContext.GetDirectory(WellKnownDirectory.Externals), "/__e"));
|
_pathMappings.Add(new PathMapping(hostContext.GetDirectory(WellKnownDirectory.Externals), "/__e"));
|
||||||
if (this.IsJobContainer)
|
if (this.IsJobContainer)
|
||||||
{
|
{
|
||||||
// this.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock"));
|
this.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock"));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (container.Ports?.Count > 0)
|
if (container.Ports?.Count > 0)
|
||||||
|
|||||||
@@ -12,88 +12,9 @@ using GitHub.Runner.Sdk;
|
|||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
using GitHub.DistributedTask.Pipelines.ContextData;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
using GitHub.DistributedTask.Pipelines.ObjectTemplating;
|
||||||
using System.Threading.Channels;
|
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using System.Text;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
namespace GitHub.Runner.Worker
|
||||||
{
|
{
|
||||||
[DataContract]
|
|
||||||
public class ContainerEngineHandlerInput
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string Command { get; set; }
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public ContainersCreationInput CreationInput { get; set; }
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public JobContainerExecInput ExecInput { get; set; }
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public ContainersRemoveInput RemoveInput { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class ContainersCreationInput
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public List<ContainerInfo> Containers { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class JobContainerExecInput
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public ContainerInfo JobContainer { get; set; }
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string WorkingDirectory { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string FileName { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public string Arguments { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public List<string> EnvironmentKeys { get; set; }
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public Dictionary<string, string> EnvironmentVariables { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class ContainersRemoveInput
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string Network { get; set; }
|
|
||||||
[DataMember]
|
|
||||||
public string JobContainerId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class ContainersCreationOutput
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public string Network { get; set; }
|
|
||||||
[DataMember]
|
|
||||||
public string JobContainerId { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataContract]
|
|
||||||
public class ContainerEngineHandlerOutput
|
|
||||||
{
|
|
||||||
[DataMember]
|
|
||||||
public ContainersCreationOutput CreationOutput { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[ServiceLocator(Default = typeof(ContainerOperationProvider))]
|
[ServiceLocator(Default = typeof(ContainerOperationProvider))]
|
||||||
public interface IContainerOperationProvider : IRunnerService
|
public interface IContainerOperationProvider : IRunnerService
|
||||||
{
|
{
|
||||||
@@ -103,57 +24,25 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public class ContainerOperationProvider : RunnerService, IContainerOperationProvider
|
public class ContainerOperationProvider : RunnerService, IContainerOperationProvider
|
||||||
{
|
{
|
||||||
private IDockerCommandManager _dockerManager = null;
|
private IDockerCommandManager _dockerManager;
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
public override void Initialize(IHostContext hostContext)
|
||||||
{
|
{
|
||||||
base.Initialize(hostContext);
|
base.Initialize(hostContext);
|
||||||
// _dockerManager = HostContext.GetService<IDockerCommandManager>();
|
_dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
public async Task StartContainersAsync(IExecutionContext executionContext, object data)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
// if (!Constants.Runner.Platform.Equals(Constants.OSPlatform.Linux))
|
if (!Constants.Runner.Platform.Equals(Constants.OSPlatform.Linux))
|
||||||
// {
|
{
|
||||||
// throw new NotSupportedException("Container operations are only supported on Linux runners");
|
throw new NotSupportedException("Container operations are only supported on Linux runners");
|
||||||
// }
|
}
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
||||||
ArgUtil.NotNull(containers, nameof(containers));
|
ArgUtil.NotNull(containers, nameof(containers));
|
||||||
|
|
||||||
foreach (var container in containers)
|
|
||||||
{
|
|
||||||
if (container.IsJobContainer)
|
|
||||||
{
|
|
||||||
// Configure job container - Mount workspace and tools, set up environment, and start long running process
|
|
||||||
var githubContext = executionContext.ExpressionValues["github"] as GitHubContext;
|
|
||||||
ArgUtil.NotNull(githubContext, nameof(githubContext));
|
|
||||||
var workingDirectory = githubContext["workspace"] as StringContextData;
|
|
||||||
ArgUtil.NotNullOrEmpty(workingDirectory, nameof(workingDirectory));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Work), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Work))));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Temp), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Temp))));
|
|
||||||
// container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Actions), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Actions))));
|
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Tools), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Tools))));
|
|
||||||
|
|
||||||
var tempHomeDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_home");
|
|
||||||
Directory.CreateDirectory(tempHomeDirectory);
|
|
||||||
container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home"));
|
|
||||||
container.AddPathTranslateMapping(tempHomeDirectory, "/github/home");
|
|
||||||
container.ContainerEnvironmentVariables["HOME"] = container.TranslateToContainerPath(tempHomeDirectory);
|
|
||||||
|
|
||||||
var tempWorkflowDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), "_github_workflow");
|
|
||||||
Directory.CreateDirectory(tempWorkflowDirectory);
|
|
||||||
container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow"));
|
|
||||||
container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow");
|
|
||||||
|
|
||||||
container.ContainerWorkDirectory = container.TranslateToContainerPath(workingDirectory);
|
|
||||||
container.ContainerEntryPoint = "tail";
|
|
||||||
container.ContainerEntryPointArgs = "-f /dev/null";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var postJobStep = new JobExtensionRunner(runAsync: this.StopContainersAsync,
|
var postJobStep = new JobExtensionRunner(runAsync: this.StopContainersAsync,
|
||||||
condition: $"{PipelineTemplateConstants.Always}()",
|
condition: $"{PipelineTemplateConstants.Always}()",
|
||||||
displayName: "Stop containers",
|
displayName: "Stop containers",
|
||||||
@@ -162,71 +51,9 @@ namespace GitHub.Runner.Worker
|
|||||||
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
executionContext.Debug($"Register post job cleanup for stopping/deleting containers.");
|
||||||
executionContext.RegisterPostJobStep(postJobStep);
|
executionContext.RegisterPostJobStep(postJobStep);
|
||||||
|
|
||||||
var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "kubectlHandler", "index.js");
|
// Check whether we are inside a container.
|
||||||
if (File.Exists(podManHandler))
|
// Our container feature requires to map working directory from host to the container.
|
||||||
{
|
// If we are already inside a container, we will not able to find out the real working direcotry path on the host.
|
||||||
var podmanInput = new ContainerEngineHandlerInput()
|
|
||||||
{
|
|
||||||
Command = "Create",
|
|
||||||
CreationInput = new ContainersCreationInput()
|
|
||||||
{
|
|
||||||
Containers = containers
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ContainerEngineHandlerOutput podmanOutput = null;
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
|
||||||
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
|
|
||||||
|
|
||||||
processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
|
||||||
{
|
|
||||||
executionContext.Output(message.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
|
||||||
{
|
|
||||||
executionContext.Output(message.Data);
|
|
||||||
if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
executionContext.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute the process. Exit code 0 should always be returned.
|
|
||||||
// A non-zero exit code indicates infrastructural failure.
|
|
||||||
// Task failure should be communicated over STDOUT using ## commands.
|
|
||||||
await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Bin),
|
|
||||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
|
|
||||||
arguments: podManHandler,
|
|
||||||
environment: null,
|
|
||||||
requireExitCodeZero: false,
|
|
||||||
outputEncoding: Encoding.UTF8,
|
|
||||||
killProcessOnCancel: false,
|
|
||||||
redirectStandardIn: redirectStandardIn,
|
|
||||||
cancellationToken: executionContext.CancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (podmanOutput != null)
|
|
||||||
{
|
|
||||||
executionContext.JobContext.Container["network"] = new StringContextData(podmanOutput.CreationOutput.Network);
|
|
||||||
executionContext.JobContext.Container["id"] = new StringContextData(podmanOutput.CreationOutput.JobContainerId);
|
|
||||||
executionContext.Global.Container.ContainerId = podmanOutput.CreationOutput.JobContainerId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Check whether we are inside a container.
|
|
||||||
// Our container feature requires to map working directory from host to the container.
|
|
||||||
// If we are already inside a container, we will not able to find out the real working direcotry path on the host.
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
// service CExecSvc is Container Execution Agent.
|
// service CExecSvc is Container Execution Agent.
|
||||||
ServiceController[] scServices = ServiceController.GetServices();
|
ServiceController[] scServices = ServiceController.GetServices();
|
||||||
@@ -235,11 +62,11 @@ namespace GitHub.Runner.Worker
|
|||||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
var initProcessCgroup = File.ReadLines("/proc/1/cgroup");
|
||||||
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
if (initProcessCgroup.Any(x => x.IndexOf(":/docker/", StringComparison.OrdinalIgnoreCase) >= 0))
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
throw new NotSupportedException("Container feature is not supported when runner is already running inside container.");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
@@ -263,69 +90,68 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Check docker client/server version
|
// Check docker client/server version
|
||||||
executionContext.Output("##[group]Checking docker version");
|
executionContext.Output("##[group]Checking docker version");
|
||||||
DockerVersion dockerVersion = await _dockerManager.DockerVersion(executionContext);
|
DockerVersion dockerVersion = await _dockerManager.DockerVersion(executionContext);
|
||||||
executionContext.Output("##[endgroup]");
|
executionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
ArgUtil.NotNull(dockerVersion.ServerVersion, nameof(dockerVersion.ServerVersion));
|
ArgUtil.NotNull(dockerVersion.ServerVersion, nameof(dockerVersion.ServerVersion));
|
||||||
ArgUtil.NotNull(dockerVersion.ClientVersion, nameof(dockerVersion.ClientVersion));
|
ArgUtil.NotNull(dockerVersion.ClientVersion, nameof(dockerVersion.ClientVersion));
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
Version requiredDockerEngineAPIVersion = new Version(1, 30); // Docker-EE version 17.6
|
Version requiredDockerEngineAPIVersion = new Version(1, 30); // Docker-EE version 17.6
|
||||||
#else
|
#else
|
||||||
Version requiredDockerEngineAPIVersion = new Version(1, 35); // Docker-CE version 17.12
|
Version requiredDockerEngineAPIVersion = new Version(1, 35); // Docker-CE version 17.12
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (dockerVersion.ServerVersion < requiredDockerEngineAPIVersion)
|
if (dockerVersion.ServerVersion < requiredDockerEngineAPIVersion)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException($"Min required docker engine API server version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') server version is '{dockerVersion.ServerVersion}'");
|
throw new NotSupportedException($"Min required docker engine API server version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') server version is '{dockerVersion.ServerVersion}'");
|
||||||
}
|
|
||||||
if (dockerVersion.ClientVersion < requiredDockerEngineAPIVersion)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException($"Min required docker engine API client version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') client version is '{dockerVersion.ClientVersion}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up containers left by previous runs
|
|
||||||
executionContext.Output("##[group]Clean up resources from previous jobs");
|
|
||||||
var staleContainers = await _dockerManager.DockerPS(executionContext, $"--all --quiet --no-trunc --filter \"label={_dockerManager.DockerInstanceLabel}\"");
|
|
||||||
foreach (var staleContainer in staleContainers)
|
|
||||||
{
|
|
||||||
int containerRemoveExitCode = await _dockerManager.DockerRemove(executionContext, staleContainer);
|
|
||||||
if (containerRemoveExitCode != 0)
|
|
||||||
{
|
|
||||||
executionContext.Warning($"Delete stale containers failed, docker rm fail with exit code {containerRemoveExitCode} for container {staleContainer}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int networkPruneExitCode = await _dockerManager.DockerNetworkPrune(executionContext);
|
|
||||||
if (networkPruneExitCode != 0)
|
|
||||||
{
|
|
||||||
executionContext.Warning($"Delete stale container networks failed, docker network prune fail with exit code {networkPruneExitCode}");
|
|
||||||
}
|
|
||||||
executionContext.Output("##[endgroup]");
|
|
||||||
|
|
||||||
// Create local docker network for this job to avoid port conflict when multiple runners run on same machine.
|
|
||||||
// All containers within a job join the same network
|
|
||||||
executionContext.Output("##[group]Create local container network");
|
|
||||||
var containerNetwork = $"github_network_{Guid.NewGuid().ToString("N")}";
|
|
||||||
await CreateContainerNetworkAsync(executionContext, containerNetwork);
|
|
||||||
executionContext.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
|
||||||
executionContext.Output("##[endgroup]");
|
|
||||||
|
|
||||||
foreach (var container in containers)
|
|
||||||
{
|
|
||||||
container.ContainerNetwork = containerNetwork;
|
|
||||||
await StartContainerAsync(executionContext, container);
|
|
||||||
}
|
|
||||||
|
|
||||||
executionContext.Output("##[group]Waiting for all services to be ready");
|
|
||||||
foreach (var container in containers.Where(c => !c.IsJobContainer))
|
|
||||||
{
|
|
||||||
await ContainerHealthcheck(executionContext, container);
|
|
||||||
}
|
|
||||||
executionContext.Output("##[endgroup]");
|
|
||||||
}
|
}
|
||||||
|
if (dockerVersion.ClientVersion < requiredDockerEngineAPIVersion)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException($"Min required docker engine API client version is '{requiredDockerEngineAPIVersion}', your docker ('{_dockerManager.DockerPath}') client version is '{dockerVersion.ClientVersion}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up containers left by previous runs
|
||||||
|
executionContext.Output("##[group]Clean up resources from previous jobs");
|
||||||
|
var staleContainers = await _dockerManager.DockerPS(executionContext, $"--all --quiet --no-trunc --filter \"label={_dockerManager.DockerInstanceLabel}\"");
|
||||||
|
foreach (var staleContainer in staleContainers)
|
||||||
|
{
|
||||||
|
int containerRemoveExitCode = await _dockerManager.DockerRemove(executionContext, staleContainer);
|
||||||
|
if (containerRemoveExitCode != 0)
|
||||||
|
{
|
||||||
|
executionContext.Warning($"Delete stale containers failed, docker rm fail with exit code {containerRemoveExitCode} for container {staleContainer}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int networkPruneExitCode = await _dockerManager.DockerNetworkPrune(executionContext);
|
||||||
|
if (networkPruneExitCode != 0)
|
||||||
|
{
|
||||||
|
executionContext.Warning($"Delete stale container networks failed, docker network prune fail with exit code {networkPruneExitCode}");
|
||||||
|
}
|
||||||
|
executionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
|
// Create local docker network for this job to avoid port conflict when multiple runners run on same machine.
|
||||||
|
// All containers within a job join the same network
|
||||||
|
executionContext.Output("##[group]Create local container network");
|
||||||
|
var containerNetwork = $"github_network_{Guid.NewGuid().ToString("N")}";
|
||||||
|
await CreateContainerNetworkAsync(executionContext, containerNetwork);
|
||||||
|
executionContext.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
||||||
|
executionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
|
foreach (var container in containers)
|
||||||
|
{
|
||||||
|
container.ContainerNetwork = containerNetwork;
|
||||||
|
await StartContainerAsync(executionContext, container);
|
||||||
|
}
|
||||||
|
|
||||||
|
executionContext.Output("##[group]Waiting for all services to be ready");
|
||||||
|
foreach (var container in containers.Where(c => !c.IsJobContainer))
|
||||||
|
{
|
||||||
|
await ContainerHealthcheck(executionContext, container);
|
||||||
|
}
|
||||||
|
executionContext.Output("##[endgroup]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopContainersAsync(IExecutionContext executionContext, object data)
|
public async Task StopContainersAsync(IExecutionContext executionContext, object data)
|
||||||
@@ -336,69 +162,12 @@ namespace GitHub.Runner.Worker
|
|||||||
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
List<ContainerInfo> containers = data as List<ContainerInfo>;
|
||||||
ArgUtil.NotNull(containers, nameof(containers));
|
ArgUtil.NotNull(containers, nameof(containers));
|
||||||
|
|
||||||
var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "kubectlHandler", "index.js");
|
foreach (var container in containers)
|
||||||
if (File.Exists(podManHandler))
|
|
||||||
{
|
{
|
||||||
var podmanInput = new ContainerEngineHandlerInput()
|
await StopContainerAsync(executionContext, container);
|
||||||
{
|
|
||||||
Command = "Remove",
|
|
||||||
RemoveInput = new ContainersRemoveInput()
|
|
||||||
{
|
|
||||||
Network = executionContext.JobContext.Container["network"].ToString(),
|
|
||||||
JobContainerId = executionContext.JobContext.Container["id"].ToString()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ContainerEngineHandlerOutput podmanOutput = null;
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
|
||||||
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
|
|
||||||
|
|
||||||
processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
|
||||||
{
|
|
||||||
executionContext.Output(message.Data);
|
|
||||||
};
|
|
||||||
|
|
||||||
processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
|
||||||
{
|
|
||||||
executionContext.Output(message.Data);
|
|
||||||
if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
executionContext.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute the process. Exit code 0 should always be returned.
|
|
||||||
// A non-zero exit code indicates infrastructural failure.
|
|
||||||
// Task failure should be communicated over STDOUT using ## commands.
|
|
||||||
await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
|
||||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
|
|
||||||
arguments: podManHandler,
|
|
||||||
environment: null,
|
|
||||||
requireExitCodeZero: false,
|
|
||||||
outputEncoding: Encoding.UTF8,
|
|
||||||
killProcessOnCancel: false,
|
|
||||||
redirectStandardIn: redirectStandardIn,
|
|
||||||
cancellationToken: executionContext.CancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
foreach (var container in containers)
|
|
||||||
{
|
|
||||||
await StopContainerAsync(executionContext, container);
|
|
||||||
}
|
|
||||||
// Remove the container network
|
|
||||||
await RemoveContainerNetworkAsync(executionContext, containers.First().ContainerNetwork);
|
|
||||||
}
|
}
|
||||||
|
// Remove the container network
|
||||||
|
await RemoveContainerNetworkAsync(executionContext, containers.First().ContainerNetwork);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartContainerAsync(IExecutionContext executionContext, ContainerInfo container)
|
private async Task StartContainerAsync(IExecutionContext executionContext, ContainerInfo container)
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ namespace GitHub.Runner.Worker
|
|||||||
string ScopeName { get; }
|
string ScopeName { get; }
|
||||||
string SiblingScopeName { get; }
|
string SiblingScopeName { get; }
|
||||||
string ContextName { get; }
|
string ContextName { get; }
|
||||||
|
ActionRunStage Stage { get; }
|
||||||
Task ForceCompleted { get; }
|
Task ForceCompleted { get; }
|
||||||
TaskResult? Result { get; set; }
|
TaskResult? Result { get; set; }
|
||||||
TaskResult? Outcome { get; set; }
|
TaskResult? Outcome { get; set; }
|
||||||
@@ -62,7 +63,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Only job level ExecutionContext has PostJobSteps
|
// Only job level ExecutionContext has PostJobSteps
|
||||||
Stack<IStep> PostJobSteps { get; }
|
Stack<IStep> PostJobSteps { get; }
|
||||||
HashSet<Guid> EmbeddedStepsWithPostRegistered{ get; }
|
Dictionary<Guid, string> EmbeddedStepsWithPostRegistered { get; }
|
||||||
|
|
||||||
// Keep track of embedded steps states
|
// Keep track of embedded steps states
|
||||||
Dictionary<Guid, Dictionary<string, string>> EmbeddedIntraActionState { get; }
|
Dictionary<Guid, Dictionary<string, string>> EmbeddedIntraActionState { get; }
|
||||||
@@ -76,8 +77,8 @@ namespace GitHub.Runner.Worker
|
|||||||
// Initialize
|
// Initialize
|
||||||
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
|
void InitializeJob(Pipelines.AgentJobRequestMessage message, CancellationToken token);
|
||||||
void CancelToken();
|
void CancelToken();
|
||||||
IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null, Guid embeddedId = default(Guid), string siblingScopeName = null);
|
IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, ActionRunStage stage, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null, Guid embeddedId = default(Guid), string siblingScopeName = null);
|
||||||
IExecutionContext CreateEmbeddedChild(string scopeName, string contextName, Guid embeddedId, Dictionary<string, string> intraActionState = null, string siblingScopeName = null);
|
IExecutionContext CreateEmbeddedChild(string scopeName, string contextName, Guid embeddedId, ActionRunStage stage, Dictionary<string, string> intraActionState = null, string siblingScopeName = null);
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
long Write(string tag, string message);
|
long Write(string tag, string message);
|
||||||
@@ -144,6 +145,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public string ScopeName { get; private set; }
|
public string ScopeName { get; private set; }
|
||||||
public string SiblingScopeName { get; private set; }
|
public string SiblingScopeName { get; private set; }
|
||||||
public string ContextName { get; private set; }
|
public string ContextName { get; private set; }
|
||||||
|
public ActionRunStage Stage { get; private set; }
|
||||||
public Task ForceCompleted => _forceCompleted.Task;
|
public Task ForceCompleted => _forceCompleted.Task;
|
||||||
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
public CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
||||||
public Dictionary<string, string> IntraActionState { get; private set; }
|
public Dictionary<string, string> IntraActionState { get; private set; }
|
||||||
@@ -168,7 +170,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public HashSet<Guid> StepsWithPostRegistered { get; private set; }
|
public HashSet<Guid> StepsWithPostRegistered { get; private set; }
|
||||||
|
|
||||||
// Only job level ExecutionContext has EmbeddedStepsWithPostRegistered
|
// Only job level ExecutionContext has EmbeddedStepsWithPostRegistered
|
||||||
public HashSet<Guid> EmbeddedStepsWithPostRegistered { get; private set; }
|
public Dictionary<Guid, string> EmbeddedStepsWithPostRegistered { get; private set; }
|
||||||
|
|
||||||
public Dictionary<Guid, Dictionary<string, string>> EmbeddedIntraActionState { get; private set; }
|
public Dictionary<Guid, Dictionary<string, string>> EmbeddedIntraActionState { get; private set; }
|
||||||
|
|
||||||
@@ -265,12 +267,19 @@ namespace GitHub.Runner.Worker
|
|||||||
string siblingScopeName = null;
|
string siblingScopeName = null;
|
||||||
if (this.IsEmbedded)
|
if (this.IsEmbedded)
|
||||||
{
|
{
|
||||||
if (step is IActionRunner actionRunner && !Root.EmbeddedStepsWithPostRegistered.Add(actionRunner.Action.Id))
|
if (step is IActionRunner actionRunner)
|
||||||
{
|
{
|
||||||
Trace.Info($"'post' of '{actionRunner.DisplayName}' already push to child post step stack.");
|
if (Root.EmbeddedStepsWithPostRegistered.ContainsKey(actionRunner.Action.Id))
|
||||||
|
{
|
||||||
|
Trace.Info($"'post' of '{actionRunner.DisplayName}' already push to child post step stack.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Root.EmbeddedStepsWithPostRegistered[actionRunner.Action.Id] = actionRunner.Condition;
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
else if (step is IActionRunner actionRunner && !Root.StepsWithPostRegistered.Add(actionRunner.Action.Id))
|
else if (step is IActionRunner actionRunner && !Root.StepsWithPostRegistered.Add(actionRunner.Action.Id))
|
||||||
{
|
{
|
||||||
Trace.Info($"'post' of '{actionRunner.DisplayName}' already push to post step stack.");
|
Trace.Info($"'post' of '{actionRunner.DisplayName}' already push to post step stack.");
|
||||||
@@ -285,7 +294,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Root.PostJobSteps.Push(step);
|
Root.PostJobSteps.Push(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null, Guid embeddedId = default(Guid), string siblingScopeName = null)
|
public IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, ActionRunStage stage, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, bool isEmbedded = false, CancellationTokenSource cancellationTokenSource = null, Guid embeddedId = default(Guid), string siblingScopeName = null)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
@@ -294,6 +303,7 @@ namespace GitHub.Runner.Worker
|
|||||||
child.Global = Global;
|
child.Global = Global;
|
||||||
child.ScopeName = scopeName;
|
child.ScopeName = scopeName;
|
||||||
child.ContextName = contextName;
|
child.ContextName = contextName;
|
||||||
|
child.Stage = stage;
|
||||||
child.EmbeddedId = embeddedId;
|
child.EmbeddedId = embeddedId;
|
||||||
child.SiblingScopeName = siblingScopeName;
|
child.SiblingScopeName = siblingScopeName;
|
||||||
child.JobTelemetry = JobTelemetry;
|
child.JobTelemetry = JobTelemetry;
|
||||||
@@ -344,9 +354,9 @@ namespace GitHub.Runner.Worker
|
|||||||
/// An embedded execution context shares the same record ID, record name, logger,
|
/// An embedded execution context shares the same record ID, record name, logger,
|
||||||
/// and a linked cancellation token.
|
/// and a linked cancellation token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IExecutionContext CreateEmbeddedChild(string scopeName, string contextName, Guid embeddedId, Dictionary<string, string> intraActionState = null, string siblingScopeName = null)
|
public IExecutionContext CreateEmbeddedChild(string scopeName, string contextName, Guid embeddedId, ActionRunStage stage, Dictionary<string, string> intraActionState = null, string siblingScopeName = null)
|
||||||
{
|
{
|
||||||
return Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, contextName, logger: _logger, isEmbedded: true, cancellationTokenSource: CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token), intraActionState: intraActionState, embeddedId: embeddedId, siblingScopeName: siblingScopeName);
|
return Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, contextName, stage, logger: _logger, isEmbedded: true, cancellationTokenSource: CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token), intraActionState: intraActionState, embeddedId: embeddedId, siblingScopeName: siblingScopeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(string currentOperation = null)
|
public void Start(string currentOperation = null)
|
||||||
@@ -543,8 +553,8 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
_record.WarningCount++;
|
_record.WarningCount++;
|
||||||
}
|
}
|
||||||
else if (issue.Type == IssueType.Notice)
|
else if (issue.Type == IssueType.Notice)
|
||||||
{
|
{
|
||||||
|
|
||||||
// tracking line number for each issue in log file
|
// tracking line number for each issue in log file
|
||||||
@@ -716,10 +726,10 @@ namespace GitHub.Runner.Worker
|
|||||||
StepsWithPostRegistered = new HashSet<Guid>();
|
StepsWithPostRegistered = new HashSet<Guid>();
|
||||||
|
|
||||||
// EmbeddedStepsWithPostRegistered for job ExecutionContext
|
// EmbeddedStepsWithPostRegistered for job ExecutionContext
|
||||||
EmbeddedStepsWithPostRegistered = new HashSet<Guid>();
|
EmbeddedStepsWithPostRegistered = new Dictionary<Guid, string>();
|
||||||
|
|
||||||
// EmbeddedIntraActionState for job ExecutionContext
|
// EmbeddedIntraActionState for job ExecutionContext
|
||||||
EmbeddedIntraActionState = new Dictionary<Guid, Dictionary<string,string>>();
|
EmbeddedIntraActionState = new Dictionary<Guid, Dictionary<string, string>>();
|
||||||
|
|
||||||
// Job timeline record.
|
// Job timeline record.
|
||||||
InitializeTimelineRecord(
|
InitializeTimelineRecord(
|
||||||
@@ -937,7 +947,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
var newGuid = Guid.NewGuid();
|
var newGuid = Guid.NewGuid();
|
||||||
return CreateChild(newGuid, displayName, newGuid.ToString("N"), null, null, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count, siblingScopeName: siblingScopeName);
|
return CreateChild(newGuid, displayName, newGuid.ToString("N"), null, null, ActionRunStage.Post, intraActionState, _childTimelineRecordOrder - Root.PostJobSteps.Count, siblingScopeName: siblingScopeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -970,7 +980,7 @@ 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 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});
|
context.AddIssue(new Issue() { Type = IssueType.Error, Message = message, IsInfrastructureIssue = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
// Do not add a format string overload. See comment on ExecutionContext.Write().
|
||||||
|
|||||||
@@ -24,8 +24,19 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
||||||
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
|
||||||
return jobStatus == ActionResult.Failure;
|
// Decide based on 'action_status' for composite MAIN steps and 'job.status' for pre, post and job-level steps
|
||||||
|
var isCompositeMainStep = executionContext.IsEmbedded && executionContext.Stage == ActionRunStage.Main;
|
||||||
|
if (isCompositeMainStep)
|
||||||
|
{
|
||||||
|
ActionResult actionStatus = EnumUtil.TryParse<ActionResult>(executionContext.GetGitHubContext("action_status")) ?? ActionResult.Success;
|
||||||
|
return actionStatus == ActionResult.Failure;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
||||||
|
return jobStatus == ActionResult.Failure;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
context.Trace.Info($"Search root directory: '{githubWorkspace}'");
|
context.Trace.Info($"Search root directory: '{githubWorkspace}'");
|
||||||
context.Trace.Info($"Search pattern: '{string.Join(", ", patterns)}'");
|
context.Trace.Info($"Search pattern: '{string.Join(", ", patterns)}'");
|
||||||
|
|
||||||
string binDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
string binDir = Path.GetDirectoryName(AppContext.BaseDirectory);
|
||||||
string runnerRoot = new DirectoryInfo(binDir).Parent.FullName;
|
string runnerRoot = new DirectoryInfo(binDir).Parent.FullName;
|
||||||
|
|
||||||
string node = Path.Combine(runnerRoot, "externals", "node12", "bin", $"node{IOUtil.ExeExtension}");
|
string node = Path.Combine(runnerRoot, "externals", "node12", "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
|||||||
@@ -24,8 +24,19 @@ namespace GitHub.Runner.Worker.Expressions
|
|||||||
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
ArgUtil.NotNull(templateContext, nameof(templateContext));
|
||||||
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
var executionContext = templateContext.State[nameof(IExecutionContext)] as IExecutionContext;
|
||||||
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
ArgUtil.NotNull(executionContext, nameof(executionContext));
|
||||||
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
|
||||||
return jobStatus == ActionResult.Success;
|
// Decide based on 'action_status' for composite MAIN steps and 'job.status' for pre, post and job-level steps
|
||||||
|
var isCompositeMainStep = executionContext.IsEmbedded && executionContext.Stage == ActionRunStage.Main;
|
||||||
|
if (isCompositeMainStep)
|
||||||
|
{
|
||||||
|
ActionResult actionStatus = EnumUtil.TryParse<ActionResult>(executionContext.GetGitHubContext("action_status")) ?? ActionResult.Success;
|
||||||
|
return actionStatus == ActionResult.Success;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ActionResult jobStatus = executionContext.JobContext.Status ?? ActionResult.Success;
|
||||||
|
return jobStatus == ActionResult.Success;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,8 +50,9 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
// Only register post steps for steps that actually ran
|
// Only register post steps for steps that actually ran
|
||||||
foreach (var step in Data.PostSteps.ToList())
|
foreach (var step in Data.PostSteps.ToList())
|
||||||
{
|
{
|
||||||
if (ExecutionContext.Root.EmbeddedStepsWithPostRegistered.Contains(step.Id))
|
if (ExecutionContext.Root.EmbeddedStepsWithPostRegistered.ContainsKey(step.Id))
|
||||||
{
|
{
|
||||||
|
step.Condition = ExecutionContext.Root.EmbeddedStepsWithPostRegistered[step.Id];
|
||||||
steps.Add(step);
|
steps.Add(step);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -124,7 +125,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
ArgUtil.NotNull(step, step.DisplayName);
|
ArgUtil.NotNull(step, step.DisplayName);
|
||||||
var stepId = $"__{Guid.NewGuid()}";
|
var stepId = $"__{Guid.NewGuid()}";
|
||||||
step.ExecutionContext = ExecutionContext.CreateEmbeddedChild(childScopeName, stepId, Guid.NewGuid());
|
step.ExecutionContext = ExecutionContext.CreateEmbeddedChild(childScopeName, stepId, Guid.NewGuid(), stage);
|
||||||
embeddedSteps.Add(step);
|
embeddedSteps.Add(step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,7 +144,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
step.Stage = stage;
|
step.Stage = stage;
|
||||||
step.Condition = stepData.Condition;
|
step.Condition = stepData.Condition;
|
||||||
ExecutionContext.Root.EmbeddedIntraActionState.TryGetValue(step.Action.Id, out var intraActionState);
|
ExecutionContext.Root.EmbeddedIntraActionState.TryGetValue(step.Action.Id, out var intraActionState);
|
||||||
step.ExecutionContext = ExecutionContext.CreateEmbeddedChild(childScopeName, stepData.ContextName, step.Action.Id, intraActionState: intraActionState, siblingScopeName: siblingScopeName);
|
step.ExecutionContext = ExecutionContext.CreateEmbeddedChild(childScopeName, stepData.ContextName, step.Action.Id, stage, intraActionState: intraActionState, siblingScopeName: siblingScopeName);
|
||||||
step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
|
step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
|
||||||
if (!String.IsNullOrEmpty(ExecutionContext.SiblingScopeName))
|
if (!String.IsNullOrEmpty(ExecutionContext.SiblingScopeName))
|
||||||
{
|
{
|
||||||
@@ -241,6 +242,10 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<FailureFunction>(PipelineTemplateConstants.Failure, 0, 0));
|
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<FailureFunction>(PipelineTemplateConstants.Failure, 0, 0));
|
||||||
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<SuccessFunction>(PipelineTemplateConstants.Success, 0, 0));
|
step.ExecutionContext.ExpressionFunctions.Add(new FunctionInfo<SuccessFunction>(PipelineTemplateConstants.Success, 0, 0));
|
||||||
|
|
||||||
|
// Set action_status to the success of the current composite action
|
||||||
|
var actionResult = ExecutionContext.Result?.ToActionResult() ?? ActionResult.Success;
|
||||||
|
step.ExecutionContext.SetGitHubContext("action_status", actionResult.ToString());
|
||||||
|
|
||||||
// Initialize env context
|
// Initialize env context
|
||||||
Trace.Info("Initialize Env context for embedded step");
|
Trace.Info("Initialize Env context for embedded step");
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
@@ -295,108 +300,100 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
CancellationTokenRegistration? jobCancelRegister = null;
|
CancellationTokenRegistration? jobCancelRegister = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// For main steps just run the action
|
// Register job cancellation call back only if job cancellation token not been fire before each step run
|
||||||
if (stage == ActionRunStage.Main)
|
if (!ExecutionContext.Root.CancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// Test the condition again. The job was canceled after the condition was originally evaluated.
|
||||||
|
jobCancelRegister = ExecutionContext.Root.CancellationToken.Register(() =>
|
||||||
|
{
|
||||||
|
// Mark job as cancelled
|
||||||
|
ExecutionContext.Root.Result = TaskResult.Canceled;
|
||||||
|
ExecutionContext.Root.JobContext.Status = ExecutionContext.Root.Result?.ToActionResult();
|
||||||
|
|
||||||
|
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
||||||
|
var conditionReTestTraceWriter = new ConditionTraceWriter(Trace, null); // host tracing only
|
||||||
|
var conditionReTestResult = false;
|
||||||
|
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionReTestTraceWriter);
|
||||||
|
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
||||||
|
conditionReTestResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Cancel the step since we get exception while re-evaluate step condition
|
||||||
|
Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
|
||||||
|
step.ExecutionContext.Error(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!conditionReTestResult)
|
||||||
|
{
|
||||||
|
// Cancel the step
|
||||||
|
Trace.Info("Cancel current running step.");
|
||||||
|
step.ExecutionContext.CancelToken();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ExecutionContext.Root.Result != TaskResult.Canceled)
|
||||||
|
{
|
||||||
|
// Mark job as cancelled
|
||||||
|
ExecutionContext.Root.Result = TaskResult.Canceled;
|
||||||
|
ExecutionContext.Root.JobContext.Status = ExecutionContext.Root.Result?.ToActionResult();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Evaluate condition
|
||||||
|
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
|
||||||
|
var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext);
|
||||||
|
var conditionResult = false;
|
||||||
|
var conditionEvaluateError = default(Exception);
|
||||||
|
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
||||||
|
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
||||||
|
conditionResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Info("Caught exception from expression.");
|
||||||
|
Trace.Error(ex);
|
||||||
|
conditionEvaluateError = ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!conditionResult && conditionEvaluateError == null)
|
||||||
|
{
|
||||||
|
// Condition is false
|
||||||
|
Trace.Info("Skipping step due to condition evaluation.");
|
||||||
|
step.ExecutionContext.Result = TaskResult.Skipped;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (conditionEvaluateError != null)
|
||||||
|
{
|
||||||
|
// Condition error
|
||||||
|
step.ExecutionContext.Error(conditionEvaluateError);
|
||||||
|
step.ExecutionContext.Result = TaskResult.Failed;
|
||||||
|
ExecutionContext.Result = TaskResult.Failed;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
await RunStepAsync(step);
|
await RunStepAsync(step);
|
||||||
}
|
}
|
||||||
// We need to evaluate conditions for pre/post steps
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Register job cancellation call back only if job cancellation token not been fire before each step run
|
|
||||||
if (!ExecutionContext.Root.CancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
// Test the condition again. The job was canceled after the condition was originally evaluated.
|
|
||||||
jobCancelRegister = ExecutionContext.Root.CancellationToken.Register(() =>
|
|
||||||
{
|
|
||||||
// Mark job as cancelled
|
|
||||||
ExecutionContext.Root.Result = TaskResult.Canceled;
|
|
||||||
ExecutionContext.Root.JobContext.Status = ExecutionContext.Root.Result?.ToActionResult();
|
|
||||||
|
|
||||||
step.ExecutionContext.Debug($"Re-evaluate condition on job cancellation for step: '{step.DisplayName}'.");
|
|
||||||
var conditionReTestTraceWriter = new ConditionTraceWriter(Trace, null); // host tracing only
|
|
||||||
var conditionReTestResult = false;
|
|
||||||
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
step.ExecutionContext.Debug($"Skip Re-evaluate condition on runner shutdown.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionReTestTraceWriter);
|
|
||||||
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
|
||||||
conditionReTestResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// Cancel the step since we get exception while re-evaluate step condition
|
|
||||||
Trace.Info("Caught exception from expression when re-test condition on job cancellation.");
|
|
||||||
step.ExecutionContext.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!conditionReTestResult)
|
|
||||||
{
|
|
||||||
// Cancel the step
|
|
||||||
Trace.Info("Cancel current running step.");
|
|
||||||
step.ExecutionContext.CancelToken();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (ExecutionContext.Root.Result != TaskResult.Canceled)
|
|
||||||
{
|
|
||||||
// Mark job as cancelled
|
|
||||||
ExecutionContext.Root.Result = TaskResult.Canceled;
|
|
||||||
ExecutionContext.Root.JobContext.Status = ExecutionContext.Root.Result?.ToActionResult();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Evaluate condition
|
|
||||||
step.ExecutionContext.Debug($"Evaluating condition for step: '{step.DisplayName}'");
|
|
||||||
var conditionTraceWriter = new ConditionTraceWriter(Trace, step.ExecutionContext);
|
|
||||||
var conditionResult = false;
|
|
||||||
var conditionEvaluateError = default(Exception);
|
|
||||||
if (HostContext.RunnerShutdownToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
step.ExecutionContext.Debug($"Skip evaluate condition on runner shutdown.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var templateEvaluator = step.ExecutionContext.ToPipelineTemplateEvaluator(conditionTraceWriter);
|
|
||||||
var condition = new BasicExpressionToken(null, null, null, step.Condition);
|
|
||||||
conditionResult = templateEvaluator.EvaluateStepIf(condition, step.ExecutionContext.ExpressionValues, step.ExecutionContext.ExpressionFunctions, step.ExecutionContext.ToExpressionState());
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Trace.Info("Caught exception from expression.");
|
|
||||||
Trace.Error(ex);
|
|
||||||
conditionEvaluateError = ex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!conditionResult && conditionEvaluateError == null)
|
|
||||||
{
|
|
||||||
// Condition is false
|
|
||||||
Trace.Info("Skipping step due to condition evaluation.");
|
|
||||||
step.ExecutionContext.Result = TaskResult.Skipped;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else if (conditionEvaluateError != null)
|
|
||||||
{
|
|
||||||
// Condition error
|
|
||||||
step.ExecutionContext.Error(conditionEvaluateError);
|
|
||||||
step.ExecutionContext.Result = TaskResult.Failed;
|
|
||||||
ExecutionContext.Result = TaskResult.Failed;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await RunStepAsync(step);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -412,12 +409,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
{
|
{
|
||||||
Trace.Info($"Update job result with current composite step result '{step.ExecutionContext.Result}'.");
|
Trace.Info($"Update job result with current composite step result '{step.ExecutionContext.Result}'.");
|
||||||
ExecutionContext.Result = TaskResultUtil.MergeTaskResults(ExecutionContext.Result, step.ExecutionContext.Result.Value);
|
ExecutionContext.Result = TaskResultUtil.MergeTaskResults(ExecutionContext.Result, step.ExecutionContext.Result.Value);
|
||||||
|
|
||||||
// We should run cleanup even if one of the cleanup step fails
|
|
||||||
if (stage != ActionRunStage.Post)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||||
event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||||
|
|
||||||
IExecutionContext ExecutionContext { get; set; }
|
|
||||||
|
|
||||||
string ResolvePathForStepHost(string path);
|
string ResolvePathForStepHost(string path);
|
||||||
|
|
||||||
Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext);
|
Task<string> DetermineNodeRuntimeVersion(IExecutionContext executionContext);
|
||||||
@@ -55,8 +53,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||||
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||||
|
|
||||||
public IExecutionContext ExecutionContext { get; set; }
|
|
||||||
|
|
||||||
public string ResolvePathForStepHost(string path)
|
public string ResolvePathForStepHost(string path)
|
||||||
{
|
{
|
||||||
return path;
|
return path;
|
||||||
@@ -103,8 +99,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> OutputDataReceived;
|
||||||
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
public event EventHandler<ProcessDataReceivedEventArgs> ErrorDataReceived;
|
||||||
|
|
||||||
public IExecutionContext ExecutionContext { get; set; }
|
|
||||||
|
|
||||||
public string ResolvePathForStepHost(string path)
|
public string ResolvePathForStepHost(string path)
|
||||||
{
|
{
|
||||||
// make sure container exist.
|
// make sure container exist.
|
||||||
@@ -180,138 +174,69 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
ArgUtil.NotNull(Container, nameof(Container));
|
ArgUtil.NotNull(Container, nameof(Container));
|
||||||
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
ArgUtil.NotNullOrEmpty(Container.ContainerId, nameof(Container.ContainerId));
|
||||||
|
|
||||||
var podManHandler = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Bin), "kubectlHandler", "index.js");
|
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
||||||
if (File.Exists(podManHandler))
|
string dockerClientPath = dockerManager.DockerPath;
|
||||||
|
|
||||||
|
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
||||||
|
IList<string> dockerCommandArgs = new List<string>();
|
||||||
|
dockerCommandArgs.Add($"exec");
|
||||||
|
|
||||||
|
// [OPTIONS]
|
||||||
|
dockerCommandArgs.Add($"-i");
|
||||||
|
dockerCommandArgs.Add($"--workdir {workingDirectory}");
|
||||||
|
foreach (var env in environment)
|
||||||
{
|
{
|
||||||
var podmanInput = new ContainerEngineHandlerInput()
|
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
||||||
{
|
// the value directly in the command
|
||||||
Command = "Exec",
|
dockerCommandArgs.Add($"-e {env.Key}");
|
||||||
ExecInput = new JobContainerExecInput()
|
|
||||||
{
|
|
||||||
JobContainer = this.Container,
|
|
||||||
WorkingDirectory = workingDirectory,
|
|
||||||
FileName = fileName,
|
|
||||||
Arguments = arguments,
|
|
||||||
EnvironmentKeys = environment.Keys.ToList(),
|
|
||||||
EnvironmentVariables = environment.ToDictionary(x => x.Key, y => y.Value)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// make sure all env are using container path
|
|
||||||
foreach (var envKey in environment.Keys.ToList())
|
|
||||||
{
|
|
||||||
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContainerEngineHandlerOutput podmanOutput = null;
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
var redirectStandardIn = Channel.CreateUnbounded<string>(new UnboundedChannelOptions() { SingleReader = true, SingleWriter = true });
|
|
||||||
redirectStandardIn.Writer.TryWrite(JsonUtility.ToString(podmanInput));
|
|
||||||
|
|
||||||
// processInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
|
||||||
// {
|
|
||||||
// ExecutionContext.Output(message.Data);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// processInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs message)
|
|
||||||
// {
|
|
||||||
// executionContext.Output(message.Data);
|
|
||||||
// if (podmanOutput == null && message.Data.IndexOf("___CONTAINER_ENGINE_HANDLER_OUTPUT___") >= 0)
|
|
||||||
// {
|
|
||||||
// try
|
|
||||||
// {
|
|
||||||
// podmanOutput = JsonUtility.FromString<ContainerEngineHandlerOutput>(message.Data.Replace("___CONTAINER_ENGINE_HANDLER_OUTPUT___", ""));
|
|
||||||
// }
|
|
||||||
// catch (Exception ex)
|
|
||||||
// {
|
|
||||||
// executionContext.Error(ex);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
processInvoker.OutputDataReceived += OutputDataReceived;
|
|
||||||
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
|
||||||
|
|
||||||
// Execute the process. Exit code 0 should always be returned.
|
|
||||||
// A non-zero exit code indicates infrastructural failure.
|
|
||||||
// Task failure should be communicated over STDOUT using ## commands.
|
|
||||||
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
|
||||||
fileName: Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), "node12", "bin", $"node{IOUtil.ExeExtension}"),
|
|
||||||
arguments: podManHandler,
|
|
||||||
environment: environment,
|
|
||||||
requireExitCodeZero: requireExitCodeZero,
|
|
||||||
outputEncoding: Encoding.UTF8,
|
|
||||||
killProcessOnCancel: killProcessOnCancel,
|
|
||||||
redirectStandardIn: redirectStandardIn,
|
|
||||||
cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
if (!string.IsNullOrEmpty(PrependPath))
|
||||||
{
|
{
|
||||||
var dockerManager = HostContext.GetService<IDockerCommandManager>();
|
// Prepend tool paths to container's PATH
|
||||||
string dockerClientPath = dockerManager.DockerPath;
|
var fullPath = !string.IsNullOrEmpty(Container.ContainerRuntimePath) ? $"{PrependPath}:{Container.ContainerRuntimePath}" : PrependPath;
|
||||||
|
dockerCommandArgs.Add($"-e PATH=\"{fullPath}\"");
|
||||||
|
}
|
||||||
|
|
||||||
// Usage: docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
|
// CONTAINER
|
||||||
IList<string> dockerCommandArgs = new List<string>();
|
dockerCommandArgs.Add($"{Container.ContainerId}");
|
||||||
dockerCommandArgs.Add($"exec");
|
|
||||||
|
|
||||||
// [OPTIONS]
|
// COMMAND
|
||||||
dockerCommandArgs.Add($"-i");
|
dockerCommandArgs.Add(fileName);
|
||||||
dockerCommandArgs.Add($"--workdir {workingDirectory}");
|
|
||||||
foreach (var env in environment)
|
|
||||||
{
|
|
||||||
// e.g. -e MY_SECRET maps the value into the exec'ed process without exposing
|
|
||||||
// the value directly in the command
|
|
||||||
dockerCommandArgs.Add($"-e {env.Key}");
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrEmpty(PrependPath))
|
|
||||||
{
|
|
||||||
// Prepend tool paths to container's PATH
|
|
||||||
var fullPath = !string.IsNullOrEmpty(Container.ContainerRuntimePath) ? $"{PrependPath}:{Container.ContainerRuntimePath}" : PrependPath;
|
|
||||||
dockerCommandArgs.Add($"-e PATH=\"{fullPath}\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
// CONTAINER
|
// [ARG...]
|
||||||
dockerCommandArgs.Add($"{Container.ContainerId}");
|
dockerCommandArgs.Add(arguments);
|
||||||
|
|
||||||
// COMMAND
|
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
|
||||||
dockerCommandArgs.Add(fileName);
|
|
||||||
|
|
||||||
// [ARG...]
|
// make sure all env are using container path
|
||||||
dockerCommandArgs.Add(arguments);
|
foreach (var envKey in environment.Keys.ToList())
|
||||||
|
{
|
||||||
|
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
||||||
|
}
|
||||||
|
|
||||||
string dockerCommandArgstring = string.Join(" ", dockerCommandArgs);
|
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
|
{
|
||||||
// make sure all env are using container path
|
processInvoker.OutputDataReceived += OutputDataReceived;
|
||||||
foreach (var envKey in environment.Keys.ToList())
|
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
||||||
{
|
|
||||||
environment[envKey] = this.Container.TranslateToContainerPath(environment[envKey]);
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var processInvoker = HostContext.CreateService<IProcessInvoker>())
|
|
||||||
{
|
|
||||||
processInvoker.OutputDataReceived += OutputDataReceived;
|
|
||||||
processInvoker.ErrorDataReceived += ErrorDataReceived;
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
// It appears that node.exe outputs UTF8 when not in TTY mode.
|
// It appears that node.exe outputs UTF8 when not in TTY mode.
|
||||||
outputEncoding = Encoding.UTF8;
|
outputEncoding = Encoding.UTF8;
|
||||||
#else
|
#else
|
||||||
// Let .NET choose the default.
|
// Let .NET choose the default.
|
||||||
outputEncoding = null;
|
outputEncoding = null;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
return await processInvoker.ExecuteAsync(workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Work),
|
||||||
fileName: dockerClientPath,
|
fileName: dockerClientPath,
|
||||||
arguments: dockerCommandArgstring,
|
arguments: dockerCommandArgstring,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
requireExitCodeZero: requireExitCodeZero,
|
requireExitCodeZero: requireExitCodeZero,
|
||||||
outputEncoding: outputEncoding,
|
outputEncoding: outputEncoding,
|
||||||
killProcessOnCancel: killProcessOnCancel,
|
killProcessOnCancel: killProcessOnCancel,
|
||||||
redirectStandardIn: null,
|
redirectStandardIn: null,
|
||||||
inheritConsoleHandler: inheritConsoleHandler,
|
inheritConsoleHandler: inheritConsoleHandler,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ namespace GitHub.Runner.Worker
|
|||||||
ArgUtil.NotNull(message, nameof(message));
|
ArgUtil.NotNull(message, nameof(message));
|
||||||
|
|
||||||
// Create a new timeline record for 'Set up job'
|
// Create a new timeline record for 'Set up job'
|
||||||
IExecutionContext context = jobContext.CreateChild(Guid.NewGuid(), "Set up job", $"{nameof(JobExtension)}_Init", null, null);
|
IExecutionContext context = jobContext.CreateChild(Guid.NewGuid(), "Set up job", $"{nameof(JobExtension)}_Init", null, null, ActionRunStage.Pre);
|
||||||
|
|
||||||
List<IStep> preJobSteps = new List<IStep>();
|
List<IStep> preJobSteps = new List<IStep>();
|
||||||
List<IStep> jobSteps = new List<IStep>();
|
List<IStep> jobSteps = new List<IStep>();
|
||||||
@@ -306,13 +306,13 @@ namespace GitHub.Runner.Worker
|
|||||||
JobExtensionRunner extensionStep = step as JobExtensionRunner;
|
JobExtensionRunner extensionStep = step as JobExtensionRunner;
|
||||||
ArgUtil.NotNull(extensionStep, extensionStep.DisplayName);
|
ArgUtil.NotNull(extensionStep, extensionStep.DisplayName);
|
||||||
Guid stepId = Guid.NewGuid();
|
Guid stepId = Guid.NewGuid();
|
||||||
extensionStep.ExecutionContext = jobContext.CreateChild(stepId, extensionStep.DisplayName, null, null, stepId.ToString("N"));
|
extensionStep.ExecutionContext = jobContext.CreateChild(stepId, extensionStep.DisplayName, null, null, stepId.ToString("N"), ActionRunStage.Pre);
|
||||||
}
|
}
|
||||||
else if (step is IActionRunner actionStep)
|
else if (step is IActionRunner actionStep)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(actionStep, step.DisplayName);
|
ArgUtil.NotNull(actionStep, step.DisplayName);
|
||||||
Guid stepId = Guid.NewGuid();
|
Guid stepId = Guid.NewGuid();
|
||||||
actionStep.ExecutionContext = jobContext.CreateChild(stepId, actionStep.DisplayName, stepId.ToString("N"), null, null, intraActionStates[actionStep.Action.Id]);
|
actionStep.ExecutionContext = jobContext.CreateChild(stepId, actionStep.DisplayName, stepId.ToString("N"), null, null, ActionRunStage.Pre, intraActionStates[actionStep.Action.Id]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,7 +323,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
ArgUtil.NotNull(actionStep, step.DisplayName);
|
ArgUtil.NotNull(actionStep, step.DisplayName);
|
||||||
intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState);
|
intraActionStates.TryGetValue(actionStep.Action.Id, out var intraActionState);
|
||||||
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, null, actionStep.Action.ContextName, intraActionState);
|
actionStep.ExecutionContext = jobContext.CreateChild(actionStep.Action.Id, actionStep.DisplayName, actionStep.Action.Name, null, actionStep.Action.ContextName, ActionRunStage.Main, intraActionState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,7 +394,7 @@ namespace GitHub.Runner.Worker
|
|||||||
ArgUtil.NotNull(jobContext, nameof(jobContext));
|
ArgUtil.NotNull(jobContext, nameof(jobContext));
|
||||||
|
|
||||||
// create a new timeline record node for 'Finalize job'
|
// create a new timeline record node for 'Finalize job'
|
||||||
IExecutionContext context = jobContext.CreateChild(Guid.NewGuid(), "Complete job", $"{nameof(JobExtension)}_Final", null, null);
|
IExecutionContext context = jobContext.CreateChild(Guid.NewGuid(), "Complete job", $"{nameof(JobExtension)}_Final", null, null, ActionRunStage.Post);
|
||||||
using (var register = jobContext.CancellationToken.Register(() => { context.CancelToken(); }))
|
using (var register = jobContext.CancellationToken.Register(() => { context.CancelToken(); }))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
jobContext.SetRunnerContext("os", VarUtil.OS);
|
jobContext.SetRunnerContext("os", VarUtil.OS);
|
||||||
|
jobContext.SetRunnerContext("arch", VarUtil.OSArchitecture);
|
||||||
|
|
||||||
var runnerSettings = HostContext.GetService<IConfigurationStore>().GetSettings();
|
var runnerSettings = HostContext.GetService<IConfigurationStore>().GetSettings();
|
||||||
jobContext.SetRunnerContext("name", runnerSettings.AgentName);
|
jobContext.SetRunnerContext("name", runnerSettings.AgentName);
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
<TieredCompilationQuickJit>true</TieredCompilationQuickJit>
|
||||||
|
|||||||
@@ -123,6 +123,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": "string-steps-context",
|
"name": "string-steps-context",
|
||||||
"id": "non-empty-string",
|
"id": "non-empty-string",
|
||||||
|
"if": "step-if",
|
||||||
"run": {
|
"run": {
|
||||||
"type": "string-steps-context",
|
"type": "string-steps-context",
|
||||||
"required": true
|
"required": true
|
||||||
@@ -141,6 +142,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"name": "string-steps-context",
|
"name": "string-steps-context",
|
||||||
"id": "non-empty-string",
|
"id": "non-empty-string",
|
||||||
|
"if": "step-if",
|
||||||
"uses": {
|
"uses": {
|
||||||
"type": "non-empty-string",
|
"type": "non-empty-string",
|
||||||
"required": true
|
"required": true
|
||||||
@@ -216,6 +218,24 @@
|
|||||||
"loose-value-type": "string"
|
"loose-value-type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"step-if": {
|
||||||
|
"context": [
|
||||||
|
"github",
|
||||||
|
"inputs",
|
||||||
|
"strategy",
|
||||||
|
"matrix",
|
||||||
|
"steps",
|
||||||
|
"job",
|
||||||
|
"runner",
|
||||||
|
"env",
|
||||||
|
"always(0,0)",
|
||||||
|
"failure(0,0)",
|
||||||
|
"cancelled(0,0)",
|
||||||
|
"success(0,0)",
|
||||||
|
"hashFiles(1,255)"
|
||||||
|
],
|
||||||
|
"string": {}
|
||||||
|
},
|
||||||
"step-with": {
|
"step-with": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
|
|||||||
@@ -28,14 +28,6 @@ namespace GitHub.Services.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IDictionary<string, object> Properties
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return m_request.Properties;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerable<String> IHttpHeaders.GetValues(String name)
|
IEnumerable<String> IHttpHeaders.GetValues(String name)
|
||||||
{
|
{
|
||||||
IEnumerable<String> values;
|
IEnumerable<String> values;
|
||||||
|
|||||||
@@ -14,10 +14,5 @@ namespace GitHub.Services.Common
|
|||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
IDictionary<string, object> Properties
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,11 @@ namespace GitHub.Services.Common.Diagnostics
|
|||||||
|
|
||||||
public static VssTraceActivity GetActivity(this HttpRequestMessage message)
|
public static VssTraceActivity GetActivity(this HttpRequestMessage message)
|
||||||
{
|
{
|
||||||
Object traceActivity;
|
if (!message.Options.TryGetValue(VssTraceActivity.PropertyName, out VssTraceActivity traceActivity))
|
||||||
if (!message.Properties.TryGetValue(VssTraceActivity.PropertyName, out traceActivity))
|
|
||||||
{
|
{
|
||||||
return VssTraceActivity.Empty;
|
return VssTraceActivity.Empty;
|
||||||
}
|
}
|
||||||
return (VssTraceActivity)traceActivity;
|
return traceActivity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
using System.Net.Http;
|
||||||
|
|
||||||
namespace GitHub.Services.Common.Diagnostics
|
namespace GitHub.Services.Common.Diagnostics
|
||||||
{
|
{
|
||||||
@@ -98,7 +99,7 @@ namespace GitHub.Services.Common.Diagnostics
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the property name used to cache this object on extensible objects.
|
/// Gets the property name used to cache this object on extensible objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const String PropertyName = "MS.VSS.Diagnostics.TraceActivity";
|
public static readonly HttpRequestOptionsKey<VssTraceActivity> PropertyName = new HttpRequestOptionsKey<VssTraceActivity>("MS.VSS.Diagnostics.TraceActivity");
|
||||||
private static Lazy<VssTraceActivity> s_empty = new Lazy<VssTraceActivity>(() => new VssTraceActivity(Guid.Empty));
|
private static Lazy<VssTraceActivity> s_empty = new Lazy<VssTraceActivity>(() => new VssTraceActivity(Guid.Empty));
|
||||||
|
|
||||||
private sealed class CorrelationScope : IDisposable
|
private sealed class CorrelationScope : IDisposable
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ namespace GitHub.Services.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static readonly String PropertyName = "MS.VS.MessageHandler";
|
internal static readonly HttpRequestOptionsKey<VssHttpMessageHandler> PropertyName = new HttpRequestOptionsKey<VssHttpMessageHandler>("MS.VS.MessageHandler");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles the authentication hand-shake for a Visual Studio service.
|
/// Handles the authentication hand-shake for a Visual Studio service.
|
||||||
@@ -169,7 +169,7 @@ namespace GitHub.Services.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add ourselves to the message so the underlying token issuers may use it if necessary
|
// Add ourselves to the message so the underlying token issuers may use it if necessary
|
||||||
request.Properties[VssHttpMessageHandler.PropertyName] = this;
|
request.Options.Set(VssHttpMessageHandler.PropertyName, this);
|
||||||
|
|
||||||
Boolean succeeded = false;
|
Boolean succeeded = false;
|
||||||
Boolean lastResponseDemandedProxyAuth = false;
|
Boolean lastResponseDemandedProxyAuth = false;
|
||||||
@@ -409,7 +409,7 @@ namespace GitHub.Services.Common
|
|||||||
// Read the completion option provided by the caller. If we don't find the property then we
|
// Read the completion option provided by the caller. If we don't find the property then we
|
||||||
// assume it is OK to buffer by default.
|
// assume it is OK to buffer by default.
|
||||||
HttpCompletionOption completionOption;
|
HttpCompletionOption completionOption;
|
||||||
if (!request.Properties.TryGetValue(VssHttpRequestSettings.HttpCompletionOptionPropertyName, out completionOption))
|
if (!request.Options.TryGetValue(VssHttpRequestSettings.HttpCompletionOptionPropertyName, out completionOption))
|
||||||
{
|
{
|
||||||
completionOption = HttpCompletionOption.ResponseContentRead;
|
completionOption = HttpCompletionOption.ResponseContentRead;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace GitHub.Services.Common
|
|||||||
{
|
{
|
||||||
DateTime _lastTime;
|
DateTime _lastTime;
|
||||||
|
|
||||||
static readonly String TfsTraceInfoKey = "TFS_TraceInfo";
|
private static readonly HttpRequestOptionsKey<VssHttpMessageHandlerTraceInfo> TfsTraceInfoKey = new HttpRequestOptionsKey<VssHttpMessageHandlerTraceInfo>("TFS_TraceInfo");
|
||||||
|
|
||||||
public int TokenRetries { get; internal set; }
|
public int TokenRetries { get; internal set; }
|
||||||
|
|
||||||
@@ -76,10 +76,9 @@ namespace GitHub.Services.Common
|
|||||||
/// <param name="traceInfo"></param>
|
/// <param name="traceInfo"></param>
|
||||||
public static void SetTraceInfo(HttpRequestMessage message, VssHttpMessageHandlerTraceInfo traceInfo)
|
public static void SetTraceInfo(HttpRequestMessage message, VssHttpMessageHandlerTraceInfo traceInfo)
|
||||||
{
|
{
|
||||||
object existingTraceInfo;
|
if (!message.Options.TryGetValue(TfsTraceInfoKey, out var _))
|
||||||
if (!message.Properties.TryGetValue(TfsTraceInfoKey, out existingTraceInfo))
|
|
||||||
{
|
{
|
||||||
message.Properties.Add(TfsTraceInfoKey, traceInfo);
|
message.Options.Set(TfsTraceInfoKey, traceInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,13 +89,8 @@ namespace GitHub.Services.Common
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static VssHttpMessageHandlerTraceInfo GetTraceInfo(HttpRequestMessage message)
|
public static VssHttpMessageHandlerTraceInfo GetTraceInfo(HttpRequestMessage message)
|
||||||
{
|
{
|
||||||
VssHttpMessageHandlerTraceInfo traceInfo = null;
|
VssHttpMessageHandlerTraceInfo traceInfo;
|
||||||
|
message.Options.TryGetValue(TfsTraceInfoKey, out traceInfo);
|
||||||
if (message.Properties.TryGetValue(TfsTraceInfoKey, out object traceInfoObject))
|
|
||||||
{
|
|
||||||
traceInfo = traceInfoObject as VssHttpMessageHandlerTraceInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return traceInfo;
|
return traceInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -291,12 +291,12 @@ namespace GitHub.Services.Common
|
|||||||
protected internal virtual Boolean ApplyTo(HttpRequestMessage request)
|
protected internal virtual Boolean ApplyTo(HttpRequestMessage request)
|
||||||
{
|
{
|
||||||
// Make sure we only apply the settings to the request once
|
// Make sure we only apply the settings to the request once
|
||||||
if (request.Properties.ContainsKey(PropertyName))
|
if (request.Options.TryGetValue(PropertyName, out var _))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
request.Properties.Add(PropertyName, this);
|
request.Options.Set(PropertyName, this);
|
||||||
|
|
||||||
if (this.AcceptLanguages != null && this.AcceptLanguages.Count > 0)
|
if (this.AcceptLanguages != null && this.AcceptLanguages.Count > 0)
|
||||||
{
|
{
|
||||||
@@ -366,12 +366,12 @@ namespace GitHub.Services.Common
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the property name used to reference this object.
|
/// Gets the property name used to reference this object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const String PropertyName = "MS.VS.RequestSettings";
|
public static readonly HttpRequestOptionsKey<VssHttpRequestSettings> PropertyName = new HttpRequestOptionsKey<VssHttpRequestSettings>("MS.VS.RequestSettings");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the property name used to reference the completion option for a specific request.
|
/// Gets the property name used to reference the completion option for a specific request.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const String HttpCompletionOptionPropertyName = "MS.VS.HttpCompletionOption";
|
public static readonly HttpRequestOptionsKey<HttpCompletionOption> HttpCompletionOptionPropertyName = new HttpRequestOptionsKey<HttpCompletionOption>("MS.VS.HttpCompletionOption");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Header to include the light weight response client option.
|
/// Header to include the light weight response client option.
|
||||||
|
|||||||
@@ -53,23 +53,14 @@ namespace GitHub.Services.Common
|
|||||||
VssTraceActivity traceActivity = VssTraceActivity.Current;
|
VssTraceActivity traceActivity = VssTraceActivity.Current;
|
||||||
|
|
||||||
// Allow overriding default retry options per request
|
// Allow overriding default retry options per request
|
||||||
VssHttpRetryOptions retryOptions = m_retryOptions;
|
VssHttpRetryOptions retryOptions;
|
||||||
object retryOptionsObject;
|
request.Options.TryGetValue(HttpRetryOptionsKey, out retryOptions);
|
||||||
if (request.Properties.TryGetValue(HttpRetryOptionsKey, out retryOptionsObject)) // NETSTANDARD compliant, TryGetValue<T> is not
|
|
||||||
{
|
TimeSpan minBackoff = (retryOptions ?? m_retryOptions).MinBackoff;
|
||||||
// Fallback to default options if object of unexpected type was passed
|
Int32 maxAttempts = (retryOptions ?? m_retryOptions).MaxRetries + 1;
|
||||||
retryOptions = retryOptionsObject as VssHttpRetryOptions ?? m_retryOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
TimeSpan minBackoff = retryOptions.MinBackoff;
|
|
||||||
Int32 maxAttempts = retryOptions.MaxRetries + 1;
|
|
||||||
|
|
||||||
IVssHttpRetryInfo retryInfo = null;
|
IVssHttpRetryInfo retryInfo = null;
|
||||||
object retryInfoObject;
|
request.Options.TryGetValue(HttpRetryInfoKey, out retryInfo);
|
||||||
if (request.Properties.TryGetValue(HttpRetryInfoKey, out retryInfoObject)) // NETSTANDARD compliant, TryGetValue<T> is not
|
|
||||||
{
|
|
||||||
retryInfo = retryInfoObject as IVssHttpRetryInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsLowPriority(request))
|
if (IsLowPriority(request))
|
||||||
{
|
{
|
||||||
@@ -225,8 +216,8 @@ namespace GitHub.Services.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
private VssHttpRetryOptions m_retryOptions;
|
private VssHttpRetryOptions m_retryOptions;
|
||||||
public const string HttpRetryInfoKey = "HttpRetryInfo";
|
public static readonly HttpRequestOptionsKey<IVssHttpRetryInfo> HttpRetryInfoKey = new HttpRequestOptionsKey<IVssHttpRetryInfo>("HttpRetryInfo");
|
||||||
public const string HttpRetryOptionsKey = "VssHttpRetryOptions";
|
public static readonly HttpRequestOptionsKey<VssHttpRetryOptions> HttpRetryOptionsKey = new HttpRequestOptionsKey<VssHttpRetryOptions>("VssHttpRetryOptions");
|
||||||
private string m_clientName = "";
|
private string m_clientName = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -638,6 +638,7 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Matrix),
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Matrix),
|
||||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Steps),
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Steps),
|
||||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.GitHub),
|
||||||
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Inputs),
|
||||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Job),
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Job),
|
||||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Runner),
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Runner),
|
||||||
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
|
new NamedValueInfo<NoOperationNamedValue>(PipelineTemplateConstants.Env),
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603</NoWarn>
|
<NoWarn>NU1701;NU1603</NoWarn>
|
||||||
<Version>$(Version)</Version>
|
<Version>$(Version)</Version>
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
|||||||
@@ -833,7 +833,7 @@ namespace GitHub.Services.WebApi
|
|||||||
{
|
{
|
||||||
if (userState != null)
|
if (userState != null)
|
||||||
{
|
{
|
||||||
message.Properties[UserStatePropertyName] = userState;
|
message.Options.Set(UserStatePropertyName, userState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!message.Headers.Contains(Common.Internal.HttpHeaders.VssE2EID))
|
if (!message.Headers.Contains(Common.Internal.HttpHeaders.VssE2EID))
|
||||||
@@ -842,11 +842,11 @@ namespace GitHub.Services.WebApi
|
|||||||
}
|
}
|
||||||
VssHttpEventSource.Log.HttpRequestStart(traceActivity, message);
|
VssHttpEventSource.Log.HttpRequestStart(traceActivity, message);
|
||||||
message.Trace();
|
message.Trace();
|
||||||
message.Properties[VssTraceActivity.PropertyName] = traceActivity;
|
message.Options.Set(VssTraceActivity.PropertyName, traceActivity);
|
||||||
|
|
||||||
// Send the completion option to the inner handler stack so we know when it's safe to buffer
|
// Send the completion option to the inner handler stack so we know when it's safe to buffer
|
||||||
// and when we should avoid buffering.
|
// and when we should avoid buffering.
|
||||||
message.Properties[VssHttpRequestSettings.HttpCompletionOptionPropertyName] = completionOption;
|
message.Options.Set(VssHttpRequestSettings.HttpCompletionOptionPropertyName, completionOption);
|
||||||
|
|
||||||
//ConfigureAwait(false) enables the continuation to be run outside
|
//ConfigureAwait(false) enables the continuation to be run outside
|
||||||
//any captured SyncronizationContext (such as ASP.NET's) which keeps things
|
//any captured SyncronizationContext (such as ASP.NET's) which keeps things
|
||||||
@@ -1154,7 +1154,9 @@ namespace GitHub.Services.WebApi
|
|||||||
{
|
{
|
||||||
if (BaseAddress != null)
|
if (BaseAddress != null)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable SYSLIB0014
|
||||||
ServicePoint servicePoint = ServicePointManager.FindServicePoint(BaseAddress);
|
ServicePoint servicePoint = ServicePointManager.FindServicePoint(BaseAddress);
|
||||||
|
#pragma warning restore SYSLIB0014
|
||||||
servicePoint.UseNagleAlgorithm = false;
|
servicePoint.UseNagleAlgorithm = false;
|
||||||
servicePoint.SetTcpKeepAlive(
|
servicePoint.SetTcpKeepAlive(
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@@ -1272,7 +1274,7 @@ namespace GitHub.Services.WebApi
|
|||||||
|
|
||||||
private const String c_jsonMediaType = "application/json";
|
private const String c_jsonMediaType = "application/json";
|
||||||
|
|
||||||
public readonly static String UserStatePropertyName = "VssClientBaseUserState";
|
public static readonly HttpRequestOptionsKey<object> UserStatePropertyName = new HttpRequestOptionsKey<object>("VssClientBaseUserState");
|
||||||
|
|
||||||
protected sealed class OperationScope : IDisposable
|
protected sealed class OperationScope : IDisposable
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ namespace GitHub.Services.WebApi
|
|||||||
|
|
||||||
if (routeReplacementOptions.HasFlag(RouteReplacementOptions.EscapeUri))
|
if (routeReplacementOptions.HasFlag(RouteReplacementOptions.EscapeUri))
|
||||||
{
|
{
|
||||||
sbResult = new StringBuilder(Uri.EscapeUriString(sbResult.ToString()));
|
sbResult = new StringBuilder(Uri.EscapeDataString(sbResult.ToString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (routeReplacementOptions.HasFlag(RouteReplacementOptions.AppendUnusedAsQueryParams) && unusedValues.Count > 0)
|
if (routeReplacementOptions.HasFlag(RouteReplacementOptions.AppendUnusedAsQueryParams) && unusedValues.Count > 0)
|
||||||
|
|||||||
@@ -6,27 +6,24 @@ using System.Globalization;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace GitHub.Services.WebApi
|
namespace GitHub.Services.WebApi
|
||||||
{
|
{
|
||||||
internal static class HttpMessageExtensions
|
internal static class HttpMessageExtensions
|
||||||
{
|
{
|
||||||
private const string tracerKey = "VSS_HTTP_TIMER_TRACE";
|
private static readonly HttpRequestOptionsKey<VssRequestTimerTrace> tracerKey = new HttpRequestOptionsKey<VssRequestTimerTrace>("VSS_HTTP_TIMER_TRACE");
|
||||||
|
|
||||||
internal static void Trace(this HttpRequestMessage request)
|
internal static void Trace(this HttpRequestMessage request)
|
||||||
{
|
{
|
||||||
Object tracerObj = null;
|
VssRequestTimerTrace tracer;
|
||||||
VssRequestTimerTrace tracer = null;
|
if (request.Options.TryGetValue(tracerKey, out tracer))
|
||||||
if (request.Properties.TryGetValue(tracerKey, out tracerObj))
|
|
||||||
{
|
{
|
||||||
tracer = tracerObj as VssRequestTimerTrace;
|
|
||||||
Debug.Assert(tracer != null, "Tracer object is the wrong type!");
|
Debug.Assert(tracer != null, "Tracer object is the wrong type!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tracer = new VssRequestTimerTrace();
|
tracer = new VssRequestTimerTrace();
|
||||||
request.Properties[tracerKey] = tracer;
|
request.Options.Set(tracerKey, tracer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tracer != null)
|
if (tracer != null)
|
||||||
@@ -37,11 +34,9 @@ namespace GitHub.Services.WebApi
|
|||||||
|
|
||||||
internal static void Trace(this HttpResponseMessage response)
|
internal static void Trace(this HttpResponseMessage response)
|
||||||
{
|
{
|
||||||
Object tracerObj = null;
|
VssRequestTimerTrace tracer;
|
||||||
VssRequestTimerTrace tracer = null;
|
if (response.RequestMessage.Options.TryGetValue(tracerKey, out tracer))
|
||||||
if (response.RequestMessage.Properties.TryGetValue(tracerKey, out tracerObj))
|
|
||||||
{
|
{
|
||||||
tracer = tracerObj as VssRequestTimerTrace;
|
|
||||||
Debug.Assert(tracer != null, "Tracer object is the wrong type!");
|
Debug.Assert(tracer != null, "Tracer object is the wrong type!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -547,6 +547,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OS_WINDOWS
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", nameof(CommandSettings))]
|
[Trait("Category", nameof(CommandSettings))]
|
||||||
@@ -574,6 +575,7 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Assert.Equal("some windows logon account", actual);
|
Assert.Equal("some windows logon account", actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
|
|||||||
@@ -626,6 +626,32 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
Teardown();
|
Teardown();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public void Load_ConditionalCompositeAction()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//Arrange
|
||||||
|
Setup();
|
||||||
|
|
||||||
|
var actionManifest = new ActionManifestManager();
|
||||||
|
actionManifest.Initialize(_hc);
|
||||||
|
|
||||||
|
//Act
|
||||||
|
var result = actionManifest.Load(_ec.Object, Path.Combine(TestUtil.GetTestDataPath(), "conditional_composite_action.yml"));
|
||||||
|
|
||||||
|
//Assert
|
||||||
|
Assert.Equal("Conditional Composite", result.Name);
|
||||||
|
Assert.Equal(ActionExecutionType.Composite, result.Execution.ExecutionType);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Teardown();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|||||||
@@ -193,9 +193,9 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
// Act.
|
// Act.
|
||||||
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
var action1 = jobContext.CreateChild(Guid.NewGuid(), "action_1", "action_1", null, null);
|
var action1 = jobContext.CreateChild(Guid.NewGuid(), "action_1", "action_1", null, null, 0);
|
||||||
action1.IntraActionState["state"] = "1";
|
action1.IntraActionState["state"] = "1";
|
||||||
var action2 = jobContext.CreateChild(Guid.NewGuid(), "action_2", "action_2", null, null);
|
var action2 = jobContext.CreateChild(Guid.NewGuid(), "action_2", "action_2", null, null, 0);
|
||||||
action2.IntraActionState["state"] = "2";
|
action2.IntraActionState["state"] = "2";
|
||||||
|
|
||||||
|
|
||||||
@@ -291,8 +291,8 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
// Act.
|
// Act.
|
||||||
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
jobContext.InitializeJob(jobRequest, CancellationToken.None);
|
||||||
|
|
||||||
var action1 = jobContext.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null);
|
var action1 = jobContext.CreateChild(Guid.NewGuid(), "action_1_pre", "action_1_pre", null, null, 0);
|
||||||
var action2 = jobContext.CreateChild(Guid.NewGuid(), "action_1_main", "action_1_main", null, null);
|
var action2 = jobContext.CreateChild(Guid.NewGuid(), "action_1_main", "action_1_main", null, null, 0);
|
||||||
|
|
||||||
var actionId = Guid.NewGuid();
|
var actionId = Guid.NewGuid();
|
||||||
var postRunner1 = hc.CreateService<IActionRunner>();
|
var postRunner1 = hc.CreateService<IActionRunner>();
|
||||||
|
|||||||
@@ -105,6 +105,36 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
[InlineData(ActionResult.Failure, ActionResult.Failure, true)]
|
||||||
|
[InlineData(ActionResult.Failure, ActionResult.Success, false)]
|
||||||
|
[InlineData(ActionResult.Success, ActionResult.Failure, true)]
|
||||||
|
[InlineData(ActionResult.Success, ActionResult.Success, false)]
|
||||||
|
[InlineData(ActionResult.Success, null, false)]
|
||||||
|
public void FailureFunctionComposite(ActionResult jobStatus, ActionResult? actionStatus, bool expected)
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
var executionContext = InitializeExecutionContext(hc);
|
||||||
|
executionContext.Setup(x => x.GetGitHubContext("action_status")).Returns(actionStatus.ToString());
|
||||||
|
executionContext.Setup( x=> x.IsEmbedded).Returns(true);
|
||||||
|
executionContext.Setup( x=> x.Stage).Returns(ActionRunStage.Main);
|
||||||
|
|
||||||
|
_jobContext.Status = jobStatus;
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
bool actual = Evaluate("failure()");
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.Equal(expected, actual);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -134,12 +164,43 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Theory]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
[InlineData(ActionResult.Failure, ActionResult.Failure, false)]
|
||||||
|
[InlineData(ActionResult.Failure, ActionResult.Success, true)]
|
||||||
|
[InlineData(ActionResult.Success, ActionResult.Failure, false)]
|
||||||
|
[InlineData(ActionResult.Success, ActionResult.Success, true)]
|
||||||
|
[InlineData(ActionResult.Success, null, true)]
|
||||||
|
public void SuccessFunctionComposite(ActionResult jobStatus, ActionResult? actionStatus, bool expected)
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
|
||||||
|
var executionContext = InitializeExecutionContext(hc);
|
||||||
|
executionContext.Setup(x => x.GetGitHubContext("action_status")).Returns(actionStatus.ToString());
|
||||||
|
executionContext.Setup( x=> x.IsEmbedded).Returns(true);
|
||||||
|
executionContext.Setup( x=> x.Stage).Returns(ActionRunStage.Main);
|
||||||
|
|
||||||
|
_jobContext.Status = jobStatus;
|
||||||
|
|
||||||
|
// Act.
|
||||||
|
bool actual = Evaluate("success()");
|
||||||
|
|
||||||
|
// Assert.
|
||||||
|
Assert.Equal(expected, actual);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
private TestHostContext CreateTestContext([CallerMemberName] String testName = "")
|
||||||
{
|
{
|
||||||
return new TestHostContext(this, testName);
|
return new TestHostContext(this, testName);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeExecutionContext(TestHostContext hc)
|
private Mock<IExecutionContext> InitializeExecutionContext(TestHostContext hc)
|
||||||
{
|
{
|
||||||
_jobContext = new JobContext();
|
_jobContext = new JobContext();
|
||||||
|
|
||||||
@@ -149,6 +210,8 @@ namespace GitHub.Runner.Common.Tests.Worker.Expressions
|
|||||||
|
|
||||||
_templateContext = new TemplateContext();
|
_templateContext = new TemplateContext();
|
||||||
_templateContext.State[nameof(IExecutionContext)] = executionContext.Object;
|
_templateContext.State[nameof(IExecutionContext)] = executionContext.Object;
|
||||||
|
|
||||||
|
return executionContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool Evaluate(string expression)
|
private bool Evaluate(string expression)
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>net6</TargetFramework>
|
||||||
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
<RuntimeIdentifiers>win-x64;win-x86;linux-x64;linux-arm64;linux-arm;osx-x64</RuntimeIdentifiers>
|
||||||
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
|
||||||
<AssetTargetFallback>portable-net45+win8</AssetTargetFallback>
|
|
||||||
<NoWarn>NU1701;NU1603;NU1603;xUnit2013;</NoWarn>
|
<NoWarn>NU1701;NU1603;NU1603;xUnit2013;</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
|||||||
49
src/Test/TestData/conditional_composite_action.yml
Normal file
49
src/Test/TestData/conditional_composite_action.yml
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
name: 'Conditional Composite'
|
||||||
|
description: 'Test composite run step conditionals'
|
||||||
|
inputs:
|
||||||
|
exit-code:
|
||||||
|
description: 'Action fails if set to non-zero'
|
||||||
|
default: '0'
|
||||||
|
outputs:
|
||||||
|
default:
|
||||||
|
description: "Did step run with default?"
|
||||||
|
value: ${{ steps.default-conditional.outputs.default }}
|
||||||
|
success:
|
||||||
|
description: "Did step run with success?"
|
||||||
|
value: ${{ steps.success-conditional.outputs.success }}
|
||||||
|
failure:
|
||||||
|
description: "Did step run with failure?"
|
||||||
|
value: ${{ steps.failure-conditional.outputs.failure }}
|
||||||
|
always:
|
||||||
|
description: "Did step run with always?"
|
||||||
|
value: ${{ steps.always-conditional.outputs.always }}
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- run: exit ${{ inputs.exit-code }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- run: echo "::set-output name=default::true"
|
||||||
|
id: default-conditional
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- run: echo "::set-output name=success::true"
|
||||||
|
id: success-conditional
|
||||||
|
shell: bash
|
||||||
|
if: success()
|
||||||
|
|
||||||
|
- run: echo "::set-output name=failure::true"
|
||||||
|
id: failure-conditional
|
||||||
|
shell: bash
|
||||||
|
if: failure()
|
||||||
|
|
||||||
|
- run: echo "::set-output name=always::true"
|
||||||
|
id: always-conditional
|
||||||
|
shell: bash
|
||||||
|
if: always()
|
||||||
|
|
||||||
|
- run: echo "failed"
|
||||||
|
shell: bash
|
||||||
|
if: ${{ inputs.exit-code == 1 && failure() }}
|
||||||
@@ -14,10 +14,10 @@ DEV_TARGET_RUNTIME=$3
|
|||||||
|
|
||||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
||||||
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/net6"
|
||||||
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
PACKAGE_DIR="$SCRIPT_DIR/../_package"
|
||||||
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
DOTNETSDK_ROOT="$SCRIPT_DIR/../_dotnetsdk"
|
||||||
DOTNETSDK_VERSION="3.1.302"
|
DOTNETSDK_VERSION="6.0.100"
|
||||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||||
RUNNER_VERSION=$(cat runnerversion)
|
RUNNER_VERSION=$(cat runnerversion)
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
<Project ToolsVersion="14.0" DefaultTargets="Build"
|
<Project ToolsVersion="14.0" DefaultTargets="Build"
|
||||||
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<Target Name="GenerateConstant">
|
<Target Name="GenerateConstant">
|
||||||
<!-- <Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true">
|
<Exec Command="git rev-parse HEAD" ConsoleToMSBuild="true">
|
||||||
<Output TaskParameter="ConsoleOutput" PropertyName="GitInfoCommitHash" />
|
<Output TaskParameter="ConsoleOutput" PropertyName="GitInfoCommitHash" />
|
||||||
</Exec> -->
|
</Exec>
|
||||||
<Message Text="Building $(Product): --- $(PackageRuntime)" Importance="high"/>
|
<Message Text="Building $(Product): $(GitInfoCommitHash) --- $(PackageRuntime)" Importance="high"/>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<BuildConstants Include="namespace GitHub.Runner.Sdk"/>
|
<BuildConstants Include="namespace GitHub.Runner.Sdk"/>
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
<BuildConstants Include="%20%20%20%20{"/>
|
<BuildConstants Include="%20%20%20%20{"/>
|
||||||
<BuildConstants Include="%20%20%20%20%20%20%20%20public static class Source"/>
|
<BuildConstants Include="%20%20%20%20%20%20%20%20public static class Source"/>
|
||||||
<BuildConstants Include="%20%20%20%20%20%20%20%20{"/>
|
<BuildConstants Include="%20%20%20%20%20%20%20%20{"/>
|
||||||
<BuildConstants Include="%20%20%20%20%20%20%20%20%20%20%20%20public static readonly string CommitHash = %22dfcfae49e59b6dc3c2bb5295c649b33c4b49c964%22%3B"/>
|
<BuildConstants Include="%20%20%20%20%20%20%20%20%20%20%20%20public static readonly string CommitHash = %22$(GitInfoCommitHash)%22%3B"/>
|
||||||
<BuildConstants Include="%20%20%20%20%20%20%20%20}%0A"/>
|
<BuildConstants Include="%20%20%20%20%20%20%20%20}%0A"/>
|
||||||
<BuildConstants Include="%20%20%20%20%20%20%20%20public static class RunnerPackage"/>
|
<BuildConstants Include="%20%20%20%20%20%20%20%20public static class RunnerPackage"/>
|
||||||
<BuildConstants Include="%20%20%20%20%20%20%20%20{"/>
|
<BuildConstants Include="%20%20%20%20%20%20%20%20{"/>
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
<WriteLinesToFile File="Runner.Sdk/BuildConstants.cs" Lines="@(BuildConstants)" Overwrite="true" />
|
<WriteLinesToFile File="Runner.Sdk/BuildConstants.cs" Lines="@(BuildConstants)" Overwrite="true" />
|
||||||
|
|
||||||
|
<Exec Command="git update-index --assume-unchanged ./Runner.Sdk/BuildConstants.cs" ConsoleToMSBuild="true" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "3.1.302"
|
"version": "net6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.283.3
|
2.284.0
|
||||||
|
|||||||
Reference in New Issue
Block a user