mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
Compare commits
11 Commits
v2.274.2
...
users/tihu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8f3726265 | ||
|
|
ef72239ff8 | ||
|
|
993357df7d | ||
|
|
c62ab23bdd | ||
|
|
9d48d2be87 | ||
|
|
69aa8d8984 | ||
|
|
7da6739eae | ||
|
|
58afa42109 | ||
|
|
3dc52b28af | ||
|
|
993edc3172 | ||
|
|
6395efe7e0 |
40
.github/workflows/build.yml
vendored
40
.github/workflows/build.yml
vendored
@@ -18,28 +18,12 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
runtime: [ linux-x64, linux-arm64, linux-arm, win-x64, osx-x64 ]
|
runtime: [ linux-x64 ]
|
||||||
include:
|
include:
|
||||||
- runtime: linux-x64
|
- runtime: linux-x64
|
||||||
os: ubuntu-latest
|
os: ubuntu-latest
|
||||||
devScript: ./dev.sh
|
devScript: ./dev.sh
|
||||||
|
|
||||||
- runtime: linux-arm64
|
|
||||||
os: ubuntu-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: linux-arm
|
|
||||||
os: ubuntu-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: osx-x64
|
|
||||||
os: macOS-latest
|
|
||||||
devScript: ./dev.sh
|
|
||||||
|
|
||||||
- runtime: win-x64
|
|
||||||
os: windows-latest
|
|
||||||
devScript: ./dev
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
@@ -50,13 +34,6 @@ jobs:
|
|||||||
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
||||||
working-directory: src
|
working-directory: src
|
||||||
|
|
||||||
# Run tests
|
|
||||||
- name: L0
|
|
||||||
run: |
|
|
||||||
${{ matrix.devScript }} test
|
|
||||||
working-directory: src
|
|
||||||
if: matrix.runtime != 'linux-arm64' && matrix.runtime != 'linux-arm'
|
|
||||||
|
|
||||||
# Create runner package tar.gz/zip
|
# Create runner package tar.gz/zip
|
||||||
- name: Package Release
|
- name: Package Release
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
@@ -71,3 +48,18 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: runner-package-${{ matrix.runtime }}
|
name: runner-package-${{ matrix.runtime }}
|
||||||
path: _package
|
path: _package
|
||||||
|
|
||||||
|
- name: Build old version
|
||||||
|
run: |
|
||||||
|
echo 2.270.0 > runnerversion
|
||||||
|
${{ matrix.devScript }} layout Release ${{ matrix.runtime }}
|
||||||
|
${{ matrix.devScript }} package Release
|
||||||
|
working-directory: src
|
||||||
|
|
||||||
|
# Upload runner package tar.gz/zip as artifact
|
||||||
|
- name: Publish Artifact old
|
||||||
|
if: github.event_name != 'pull_request'
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: runner-package-${{ matrix.runtime }}-old
|
||||||
|
path: _package
|
||||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -1,7 +1,6 @@
|
|||||||
name: Runner CD
|
name: Runner CD
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
|
||||||
push:
|
push:
|
||||||
paths:
|
paths:
|
||||||
- releaseVersion
|
- releaseVersion
|
||||||
|
|||||||
57
Dockerfile
Normal file
57
Dockerfile
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
FROM mcr.microsoft.com/dotnet/core/runtime-deps:3.1-buster-slim
|
||||||
|
|
||||||
|
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 \
|
||||||
|
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
|
||||||
|
WORKDIR /actions-runner
|
||||||
|
COPY ./src/Misc/download-runner.sh /actions-runner/download-runner.sh
|
||||||
|
COPY ./src/Misc/entrypoint.sh /actions-runner/entrypoint.sh
|
||||||
|
# COPY ./src/Misc/jobstart.sh /actions-runner/jobstart.sh
|
||||||
|
# COPY ./src/Misc/jobrunning.sh /actions-runner/jobrunning.sh
|
||||||
|
# COPY ./src/Misc/jobcomplete.sh /actions-runner/jobcomplete.sh
|
||||||
|
COPY ./src/Misc/runner_lifecycle.sh /actions-runner/runner_lifecycle.sh
|
||||||
|
|
||||||
|
RUN /actions-runner/download-runner.sh
|
||||||
|
RUN rm -f /actions-runner/download-runner.sh
|
||||||
|
|
||||||
|
# ENV _INTERNAL_JOBSTART_NOTIFICATION=/actions-runner/jobstart.sh
|
||||||
|
# ENV _INTERNAL_JOBRUNNING_NOTIFICATION=/actions-runner/jobrunning.sh
|
||||||
|
# ENV _INTERNAL_JOBCOMPLETE_NOTIFICATION=/actions-runner/jobcomplete.sh
|
||||||
|
ENV _INTERNAL_RUNNER_LIFECYCLE_NOTIFICATION=/actions-runner/runner_lifecycle.sh
|
||||||
|
|
||||||
|
|
||||||
|
ENTRYPOINT ["./entrypoint.sh"]
|
||||||
46
Dockerfile.dind
Normal file
46
Dockerfile.dind
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
FROM docker:19.03
|
||||||
|
|
||||||
|
# https://github.com/docker/docker/blob/master/project/PACKAGERS.md#runtime-dependencies
|
||||||
|
RUN set -eux; \
|
||||||
|
apk add --no-cache \
|
||||||
|
btrfs-progs \
|
||||||
|
e2fsprogs \
|
||||||
|
e2fsprogs-extra \
|
||||||
|
iptables \
|
||||||
|
openssl \
|
||||||
|
shadow-uidmap \
|
||||||
|
xfsprogs \
|
||||||
|
xz \
|
||||||
|
# pigz: https://github.com/moby/moby/pull/35697 (faster gzip implementation)
|
||||||
|
pigz \
|
||||||
|
; \
|
||||||
|
# only install zfs if it's available for the current architecture
|
||||||
|
# https://git.alpinelinux.org/cgit/aports/tree/main/zfs/APKBUILD?h=3.6-stable#n9 ("all !armhf !ppc64le" as of 2017-11-01)
|
||||||
|
# "apk info XYZ" exits with a zero exit code but no output when the package exists but not for this arch
|
||||||
|
if zfs="$(apk info --no-cache --quiet zfs)" && [ -n "$zfs" ]; then \
|
||||||
|
apk add --no-cache zfs; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# TODO aufs-tools
|
||||||
|
|
||||||
|
# set up subuid/subgid so that "--userns-remap=default" works out-of-the-box
|
||||||
|
RUN set -x \
|
||||||
|
&& addgroup -S dockremap \
|
||||||
|
&& adduser -S -G dockremap dockremap \
|
||||||
|
&& echo 'dockremap:165536:65536' >> /etc/subuid \
|
||||||
|
&& echo 'dockremap:165536:65536' >> /etc/subgid
|
||||||
|
|
||||||
|
# https://github.com/docker/docker/tree/master/hack/dind
|
||||||
|
ENV DIND_COMMIT ed89041433a031cafc0a0f19cfe573c31688d377
|
||||||
|
|
||||||
|
RUN set -eux; \
|
||||||
|
wget -O /usr/local/bin/dind "https://raw.githubusercontent.com/docker/docker/${DIND_COMMIT}/hack/dind"; \
|
||||||
|
chmod +x /usr/local/bin/dind
|
||||||
|
|
||||||
|
COPY dockerd-entrypoint.sh /usr/local/bin/
|
||||||
|
|
||||||
|
VOLUME /var/lib/docker
|
||||||
|
EXPOSE 6788 6789
|
||||||
|
|
||||||
|
ENTRYPOINT ["dockerd-entrypoint.sh"]
|
||||||
|
CMD []
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
[](https://github.com/actions/runner/actions)
|
[](https://github.com/actions/runner/actions)
|
||||||
|
|
||||||
The runner is the application that runs a job from a GitHub Actions workflow. It is used by GitHub Actions in the [hosted virtual environments](https://github.com/actions/virtual-environments), or you can [self-host the runner](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners) in your own environment.
|
The runner is the application that runs a job from a GitHub Actions workflow. The runner can run on the [hosted machine pools](https://github.com/actions/virtual-environments) or run on [self-hosted environments](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/about-self-hosted-runners).
|
||||||
|
|
||||||
## Get Started
|
## Get Started
|
||||||
|
|
||||||
|
|||||||
14
autoscalev0.yaml
Normal file
14
autoscalev0.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: actions.summerwind.dev/v1alpha1
|
||||||
|
kind: RunnerDeployment
|
||||||
|
metadata:
|
||||||
|
name: auto-scale-runners
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
maxRunnerLimit: 5
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
configURL: https://github.com/bbq-beets/ting-test
|
||||||
|
githubTokenSecretKeyRef:
|
||||||
|
name: githubtoken
|
||||||
|
key: GITHUB_PAT
|
||||||
|
|
||||||
63
deployment.yaml
Normal file
63
deployment.yaml
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: runner-pod
|
||||||
|
labels:
|
||||||
|
name: runner-pod
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: runner-pod
|
||||||
|
image: huangtingluo/autoscale-runner:v0.0
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: GITHUB_PAT
|
||||||
|
value: 62c13e14e947958516c103a9584f66227697c447
|
||||||
|
- name: GITHUB_RUNNER_SCOPE
|
||||||
|
value: monalisa/main123
|
||||||
|
- name: K8S_HOST_IP
|
||||||
|
value: "192.168.120.1"
|
||||||
|
|
||||||
|
# apiVersion: apps/v1
|
||||||
|
# kind: Deployment
|
||||||
|
# metadata:
|
||||||
|
# name: runner-deployment
|
||||||
|
# spec:
|
||||||
|
# replicas: 1
|
||||||
|
# selector:
|
||||||
|
# matchLabels:
|
||||||
|
# app: runners
|
||||||
|
# template:
|
||||||
|
# metadata:
|
||||||
|
# labels:
|
||||||
|
# app: runners
|
||||||
|
# spec:
|
||||||
|
# # hostNetwork: true
|
||||||
|
# # volumes:
|
||||||
|
# # - name: docker-storage
|
||||||
|
# # emptyDir: {}
|
||||||
|
# # containers:
|
||||||
|
# # - name: docker-host
|
||||||
|
# # image: docker:18.05-dind
|
||||||
|
# # imagePullPolicy: Always
|
||||||
|
# # securityContext:
|
||||||
|
# # privileged: true
|
||||||
|
# # volumeMounts:
|
||||||
|
# # - name: docker-storage
|
||||||
|
# # mountPath: /var/lib/docker
|
||||||
|
|
||||||
|
# # hostNetwork: true
|
||||||
|
# containers:
|
||||||
|
# - name: runner
|
||||||
|
# image: huangtingluo/autoscale-runner:v0.0
|
||||||
|
# imagePullPolicy: Always
|
||||||
|
# env:
|
||||||
|
# - name: GITHUB_PAT
|
||||||
|
# value: 62c13e14e947958516c103a9584f66227697c447
|
||||||
|
# - name: GITHUB_RUNNER_SCOPE
|
||||||
|
# value: monalisa/main123
|
||||||
|
# - name: K8S_HOST_IP
|
||||||
|
# value: "192.168.120.1"
|
||||||
|
# resources:
|
||||||
|
# limits:
|
||||||
|
# memory: "128Mi"
|
||||||
|
# cpu: "500m"
|
||||||
186
dockerd-entrypoint.sh
Executable file
186
dockerd-entrypoint.sh
Executable file
@@ -0,0 +1,186 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
_tls_ensure_private() {
|
||||||
|
local f="$1"; shift
|
||||||
|
[ -s "$f" ] || openssl genrsa -out "$f" 4096
|
||||||
|
}
|
||||||
|
_tls_san() {
|
||||||
|
{
|
||||||
|
ip -oneline address | awk '{ gsub(/\/.+$/, "", $4); print "IP:" $4 }'
|
||||||
|
{
|
||||||
|
cat /etc/hostname
|
||||||
|
echo 'docker'
|
||||||
|
echo 'localhost'
|
||||||
|
hostname -f
|
||||||
|
hostname -s
|
||||||
|
} | sed 's/^/DNS:/'
|
||||||
|
[ -z "${DOCKER_TLS_SAN:-}" ] || echo "$DOCKER_TLS_SAN"
|
||||||
|
} | sort -u | xargs printf '%s,' | sed "s/,\$//"
|
||||||
|
}
|
||||||
|
_tls_generate_certs() {
|
||||||
|
local dir="$1"; shift
|
||||||
|
|
||||||
|
# if ca/key.pem || !ca/cert.pem, generate CA public if necessary
|
||||||
|
# if ca/key.pem, generate server public
|
||||||
|
# if ca/key.pem, generate client public
|
||||||
|
# (regenerating public certs every startup to account for SAN/IP changes and/or expiration)
|
||||||
|
|
||||||
|
# https://github.com/FiloSottile/mkcert/issues/174
|
||||||
|
local certValidDays='825'
|
||||||
|
|
||||||
|
if [ -s "$dir/ca/key.pem" ] || [ ! -s "$dir/ca/cert.pem" ]; then
|
||||||
|
# if we either have a CA private key or do *not* have a CA public key, then we should create/manage the CA
|
||||||
|
mkdir -p "$dir/ca"
|
||||||
|
_tls_ensure_private "$dir/ca/key.pem"
|
||||||
|
openssl req -new -key "$dir/ca/key.pem" \
|
||||||
|
-out "$dir/ca/cert.pem" \
|
||||||
|
-subj '/CN=docker:dind CA' -x509 -days "$certValidDays"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$dir/ca/key.pem" ]; then
|
||||||
|
# if we have a CA private key, we should create/manage a server key
|
||||||
|
mkdir -p "$dir/server"
|
||||||
|
_tls_ensure_private "$dir/server/key.pem"
|
||||||
|
openssl req -new -key "$dir/server/key.pem" \
|
||||||
|
-out "$dir/server/csr.pem" \
|
||||||
|
-subj '/CN=docker:dind server'
|
||||||
|
cat > "$dir/server/openssl.cnf" <<-EOF
|
||||||
|
[ x509_exts ]
|
||||||
|
subjectAltName = $(_tls_san)
|
||||||
|
EOF
|
||||||
|
openssl x509 -req \
|
||||||
|
-in "$dir/server/csr.pem" \
|
||||||
|
-CA "$dir/ca/cert.pem" \
|
||||||
|
-CAkey "$dir/ca/key.pem" \
|
||||||
|
-CAcreateserial \
|
||||||
|
-out "$dir/server/cert.pem" \
|
||||||
|
-days "$certValidDays" \
|
||||||
|
-extfile "$dir/server/openssl.cnf" \
|
||||||
|
-extensions x509_exts
|
||||||
|
cp "$dir/ca/cert.pem" "$dir/server/ca.pem"
|
||||||
|
openssl verify -CAfile "$dir/server/ca.pem" "$dir/server/cert.pem"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -s "$dir/ca/key.pem" ]; then
|
||||||
|
# if we have a CA private key, we should create/manage a client key
|
||||||
|
mkdir -p "$dir/client"
|
||||||
|
_tls_ensure_private "$dir/client/key.pem"
|
||||||
|
chmod 0644 "$dir/client/key.pem" # openssl defaults to 0600 for the private key, but this one needs to be shared with arbitrary client contexts
|
||||||
|
openssl req -new \
|
||||||
|
-key "$dir/client/key.pem" \
|
||||||
|
-out "$dir/client/csr.pem" \
|
||||||
|
-subj '/CN=docker:dind client'
|
||||||
|
cat > "$dir/client/openssl.cnf" <<-'EOF'
|
||||||
|
[ x509_exts ]
|
||||||
|
extendedKeyUsage = clientAuth
|
||||||
|
EOF
|
||||||
|
openssl x509 -req \
|
||||||
|
-in "$dir/client/csr.pem" \
|
||||||
|
-CA "$dir/ca/cert.pem" \
|
||||||
|
-CAkey "$dir/ca/key.pem" \
|
||||||
|
-CAcreateserial \
|
||||||
|
-out "$dir/client/cert.pem" \
|
||||||
|
-days "$certValidDays" \
|
||||||
|
-extfile "$dir/client/openssl.cnf" \
|
||||||
|
-extensions x509_exts
|
||||||
|
cp "$dir/ca/cert.pem" "$dir/client/ca.pem"
|
||||||
|
openssl verify -CAfile "$dir/client/ca.pem" "$dir/client/cert.pem"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# no arguments passed
|
||||||
|
# or first arg is `-f` or `--some-option`
|
||||||
|
if [ "$#" -eq 0 ] || [ "${1#-}" != "$1" ]; then
|
||||||
|
# set "dockerSocket" to the default "--host" *unix socket* value (for both standard or rootless)
|
||||||
|
uid="$(id -u)"
|
||||||
|
if [ "$uid" = '0' ]; then
|
||||||
|
dockerSocket='unix:///var/run/docker.sock'
|
||||||
|
else
|
||||||
|
# if we're not root, we must be trying to run rootless
|
||||||
|
: "${XDG_RUNTIME_DIR:=/run/user/$uid}"
|
||||||
|
dockerSocket="unix://$XDG_RUNTIME_DIR/docker.sock"
|
||||||
|
fi
|
||||||
|
case "${DOCKER_HOST:-}" in
|
||||||
|
unix://*)
|
||||||
|
dockerSocket="$DOCKER_HOST"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# add our default arguments
|
||||||
|
if [ -n "${DOCKER_TLS_CERTDIR:-}" ] \
|
||||||
|
&& _tls_generate_certs "$DOCKER_TLS_CERTDIR" \
|
||||||
|
&& [ -s "$DOCKER_TLS_CERTDIR/server/ca.pem" ] \
|
||||||
|
&& [ -s "$DOCKER_TLS_CERTDIR/server/cert.pem" ] \
|
||||||
|
&& [ -s "$DOCKER_TLS_CERTDIR/server/key.pem" ] \
|
||||||
|
; then
|
||||||
|
# generate certs and use TLS if requested/possible (default in 19.03+)
|
||||||
|
set -- dockerd \
|
||||||
|
--host="$dockerSocket" \
|
||||||
|
--host=tcp://0.0.0.0:6789 \
|
||||||
|
--tlsverify \
|
||||||
|
--tlscacert "$DOCKER_TLS_CERTDIR/server/ca.pem" \
|
||||||
|
--tlscert "$DOCKER_TLS_CERTDIR/server/cert.pem" \
|
||||||
|
--tlskey "$DOCKER_TLS_CERTDIR/server/key.pem" \
|
||||||
|
"$@"
|
||||||
|
DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:6789:6789/tcp"
|
||||||
|
else
|
||||||
|
# TLS disabled (-e DOCKER_TLS_CERTDIR='') or missing certs
|
||||||
|
set -- dockerd \
|
||||||
|
--host="$dockerSocket" \
|
||||||
|
--host=tcp://0.0.0.0:6788 \
|
||||||
|
"$@"
|
||||||
|
DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS="${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} -p 0.0.0.0:6788:6788/tcp"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$1" = 'dockerd' ]; then
|
||||||
|
# explicitly remove Docker's default PID file to ensure that it can start properly if it was stopped uncleanly (and thus didn't clean up the PID file)
|
||||||
|
find /run /var/run -iname 'docker*.pid' -delete || :
|
||||||
|
|
||||||
|
uid="$(id -u)"
|
||||||
|
if [ "$uid" != '0' ]; then
|
||||||
|
# if we're not root, we must be trying to run rootless
|
||||||
|
if ! command -v rootlesskit > /dev/null; then
|
||||||
|
echo >&2 "error: attempting to run rootless dockerd but missing 'rootlesskit' (perhaps the 'docker:dind-rootless' image variant is intended?)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
user="$(id -un 2>/dev/null || :)"
|
||||||
|
if ! grep -qE "^($uid${user:+|$user}):" /etc/subuid || ! grep -qE "^($uid${user:+|$user}):" /etc/subgid; then
|
||||||
|
echo >&2 "error: attempting to run rootless dockerd but missing necessary entries in /etc/subuid and/or /etc/subgid for $uid"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
: "${XDG_RUNTIME_DIR:=/run/user/$uid}"
|
||||||
|
export XDG_RUNTIME_DIR
|
||||||
|
if ! mkdir -p "$XDG_RUNTIME_DIR" || [ ! -w "$XDG_RUNTIME_DIR" ] || ! mkdir -p "$HOME/.local/share/docker" || [ ! -w "$HOME/.local/share/docker" ]; then
|
||||||
|
echo >&2 "error: attempting to run rootless dockerd but need writable HOME ($HOME) and XDG_RUNTIME_DIR ($XDG_RUNTIME_DIR) for user $uid"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -f /proc/sys/kernel/unprivileged_userns_clone ] && unprivClone="$(cat /proc/sys/kernel/unprivileged_userns_clone)" && [ "$unprivClone" != '1' ]; then
|
||||||
|
echo >&2 "error: attempting to run rootless dockerd but need 'kernel.unprivileged_userns_clone' (/proc/sys/kernel/unprivileged_userns_clone) set to 1"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -f /proc/sys/user/max_user_namespaces ] && maxUserns="$(cat /proc/sys/user/max_user_namespaces)" && [ "$maxUserns" = '0' ]; then
|
||||||
|
echo >&2 "error: attempting to run rootless dockerd but need 'user.max_user_namespaces' (/proc/sys/user/max_user_namespaces) set to a sufficiently large value"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# TODO overlay support detection?
|
||||||
|
exec rootlesskit \
|
||||||
|
--net="${DOCKERD_ROOTLESS_ROOTLESSKIT_NET:-vpnkit}" \
|
||||||
|
--mtu="${DOCKERD_ROOTLESS_ROOTLESSKIT_MTU:-1500}" \
|
||||||
|
--disable-host-loopback \
|
||||||
|
--port-driver=builtin \
|
||||||
|
--copy-up=/etc \
|
||||||
|
--copy-up=/run \
|
||||||
|
${DOCKERD_ROOTLESS_ROOTLESSKIT_FLAGS:-} \
|
||||||
|
"$@"
|
||||||
|
elif [ -x '/usr/local/bin/dind' ]; then
|
||||||
|
# if we have the (mostly defunct now) Docker-in-Docker wrapper script, use it
|
||||||
|
set -- '/usr/local/bin/dind' "$@"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# if it isn't `dockerd` we're trying to run, pass it through `docker-entrypoint.sh` so it gets `DOCKER_HOST` set appropriately too
|
||||||
|
set -- docker-entrypoint.sh "$@"
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec "$@"
|
||||||
@@ -22,7 +22,7 @@ These are described in detail below:
|
|||||||
- http://proxy.com
|
- http://proxy.com
|
||||||
- http://127.0.0.1:8080
|
- http://127.0.0.1:8080
|
||||||
- http://user:password@proxy.com
|
- http://user:password@proxy.com
|
||||||
- `no_proxy` a comma separated list of hosts that should not use the proxy. An optional port may be specified
|
- `no_proxy` a comma seperated list of hosts that should not use the proxy. An optional port may be specified
|
||||||
- `google.com`
|
- `google.com`
|
||||||
- `yahoo.com:443`
|
- `yahoo.com:443`
|
||||||
- `google.com,bing.com`
|
- `google.com,bing.com`
|
||||||
@@ -31,9 +31,9 @@ We won't use `http_proxy` for https traffic when `https_proxy` is not set, this
|
|||||||
Otherwise action authors and workflow users need to adjust to differences between the runner proxy convention, and tools used by their actions and scripts.
|
Otherwise action authors and workflow users need to adjust to differences between the runner proxy convention, and tools used by their actions and scripts.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Customer set `http_proxy=http://127.0.0.1:8888` and configure the runner against `https://github.com/owner/repo`, with the `https_proxy` -> `http_proxy` fallback, the runner will connect to the server without any problem. However, if a user runs `git push` to `https://github.com/owner/repo`, `git` won't use the proxy since it requires `https_proxy` to be set for any https traffic.
|
Customer set `http_proxy=http://127.0.0.1:8888` and configure the runner against `https://github.com/owner/repo`, with the `https_proxy` -> `http_proxy` fallback, the runner will connect to server without any problem. However, if user runs `git push` to `https://github.com/owner/repo`, `git` won't use the proxy since it require `https_proxy` to be set for any https traffic.
|
||||||
|
|
||||||
> `golang`, `node.js` and other dev tools from the linux community use `http_proxy` for both http and https traffic based on my research.
|
> `golang`, `node.js` and other dev tools from the linux community use `http_proxy` for both http and https traffic base on my research.
|
||||||
|
|
||||||
A majority of our users are using Linux where these variables are commonly required to be set by various programs. By reading these values, we simplify the process for self hosted runners to set up proxy, and expose it in a way users are already familiar with.
|
A majority of our users are using Linux where these variables are commonly required to be set by various programs. By reading these values, we simplify the process for self hosted runners to set up proxy, and expose it in a way users are already familiar with.
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ We will support the lowercase and uppercase variants, with lowercase taking prio
|
|||||||
|
|
||||||
### No Proxy Format
|
### No Proxy Format
|
||||||
|
|
||||||
While exact implementations are different per application on handle `no_proxy` env, most applications accept a comma separated list of hosts. Some accept wildcard characters (*). We are going to do exact case-insensitive matches, and not support wildcards at this time.
|
While exact implementations are different per application on handle `no_proxy` env, most applications accept a comma separated list of hosts. Some accept wildcard characters (*). We are going to do exact case-insentive matches, and not support wildcards at this time.
|
||||||
For example:
|
For example:
|
||||||
- example.com will match example.com, foo.example.com, foo.bar.example.com
|
- example.com will match example.com, foo.example.com, foo.bar.example.com
|
||||||
- foo.example.com will match bar.foo.example.com and foo.example.com
|
- foo.example.com will match bar.foo.example.com and foo.example.com
|
||||||
@@ -57,5 +57,5 @@ We will not support IP addresses for `no_proxy`, only hostnames.
|
|||||||
3. The runner will read from the environmental variables during config and runtime and use the provided proxy if it exists
|
3. The runner will read from the environmental variables during config and runtime and use the provided proxy if it exists
|
||||||
4. Users may need to pass these environmental variables into other applications if they do not natively take these variables
|
4. Users may need to pass these environmental variables into other applications if they do not natively take these variables
|
||||||
5. Action authors may need to update their workflows to react to the these environment variables
|
5. Action authors may need to update their workflows to react to the these environment variables
|
||||||
6. We will document the way of setting environmental variables for runners using the environment variables and how the runner uses them
|
6. We will document the way of setting environmental variables for runners using the environmental variables and how the runner uses them
|
||||||
7. Like all other secrets, users will be able to relatively easily figure out proxy password if they can modify a workflow file running on a self hosted machine
|
7. Like all other secrets, users will be able to relatively easily figure out proxy password if they can modify a workflow file running on a self hosted machine
|
||||||
@@ -34,7 +34,7 @@ A way out for rare cases where scoping is a problem.
|
|||||||
|
|
||||||
`##[remove-matcher]owner`
|
`##[remove-matcher]owner`
|
||||||
|
|
||||||
For this to be usable, the `owner` needs to be discoverable. Therefore, debug print the owner on registration.
|
For the this to be usable, the `owner` needs to be discoverable. Therefore, debug print the owner on registration.
|
||||||
|
|
||||||
### Single line matcher
|
### Single line matcher
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ Solving this problem means:
|
|||||||
- Use the `github.workspace` (where the repo is cloned on disk)
|
- Use the `github.workspace` (where the repo is cloned on disk)
|
||||||
- Match against a repository to determine the relative path within the repo
|
- Match against a repository to determine the relative path within the repo
|
||||||
|
|
||||||
This is a place where we diverge from VSCode. VSCode task configurations are specific to the local workspace (workspace root is known or can be specified). We're solving a more generic problem, so we need more information - specifically the `fromPath` property - in order to accurately root the path.
|
This is a place where we diverge from VSCode. VSCode task configuration are specific to the local workspace (workspace root is known or can be specified). We're solving a more generic problem, so we need more information - specifically the `fromPath` property - in order to accurately root the path.
|
||||||
|
|
||||||
In order to avoid creating inaccurate hyperlinks on the error issues, the agent will verify the file exists and is in the main repository. Otherwise omit the file property from the error issue and debug trace what happened.
|
In order to avoid creating inaccurate hyperlinks on the error issues, the agent will verify the file exists and is in the main repository. Otherwise omit the file property from the error issue and debug trace what happened.
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ Problem matchers are unable to interpret severity strings other than `warning` a
|
|||||||
|
|
||||||
However some tools indicate error/warning in different ways. For example `flake8` uses codes like `E100`, `W200`, and `F300` (error, warning, fatal, respectively).
|
However some tools indicate error/warning in different ways. For example `flake8` uses codes like `E100`, `W200`, and `F300` (error, warning, fatal, respectively).
|
||||||
|
|
||||||
Therefore, allow a property `severity`, sibling to `owner`, which identifies the default severity for the problem matcher. This allows two problem matchers to be registered - one for warnings and one for errors.
|
Therefore, allow a property `severity`, sibling to `owner`, which identifies the default severity for the problem matcher. This allows two problem matchers are registered - one for warnings and one for errors.
|
||||||
|
|
||||||
For example, given the following `flake8` output:
|
For example, given the following `flake8` output:
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ powershell/pwsh
|
|||||||
- Users can always opt out by not using the builtins, and providing a shell option like: `pwsh -File {0}`, or `powershell -Command "& '{0}'"`, depending on need
|
- Users can always opt out by not using the builtins, and providing a shell option like: `pwsh -File {0}`, or `powershell -Command "& '{0}'"`, depending on need
|
||||||
|
|
||||||
cmd
|
cmd
|
||||||
- There doesn't seem to be a way to fully opt in to fail-fast behavior other than writing your script to check each error code and respond accordingly, so we can't actually provide that behavior by default, it will be completely up to the user to write this behavior into their script
|
- There doesnt seem to be a way to fully opt in to fail-fast behavior other than writing your script to check each error code and respond accordingly, so we cant actually provide that behavior by default, it will be completely up to the user to write this behavior into their script
|
||||||
- cmd.exe will exit (return the error code to the runner) with the errorlevel of the last program it executed. This is internally consistent with the previous default behavior (sh, pwsh) and is the cmd.exe default, so we keep that behavior
|
- cmd.exe will exit (return the error code to the runner) with the errorlevel of the last program it executed. This is internally consistent with the previous default behavior (sh, pwsh) and is the cmd.exe default, so we keep that behavior
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|||||||
@@ -16,32 +16,11 @@ We don't want the workflow author to need to know how the internal workings of t
|
|||||||
|
|
||||||
A composite action is treated as **one** individual job step (this is known as encapsulation).
|
A composite action is treated as **one** individual job step (this is known as encapsulation).
|
||||||
|
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
**In this ADR, we only support running multiple run steps in an Action.** In doing so, we build in support for mapping and flowing the inputs, outputs, and env variables (ex: All nested steps should have access to its parents' input variables and nested steps can overwrite the input variables).
|
**In this ADR, we only support running multiple run steps in an Action.** In doing so, we build in support for mapping and flowing the inputs, outputs, and env variables (ex: All nested steps should have access to its parents' input variables and nested steps can overwrite the input variables).
|
||||||
|
|
||||||
### Composite Run Steps Features
|
|
||||||
This feature supports at the top action level:
|
|
||||||
- name
|
|
||||||
- description
|
|
||||||
- inputs
|
|
||||||
- runs
|
|
||||||
- outputs
|
|
||||||
|
|
||||||
This feature supports at the run step level:
|
|
||||||
- name
|
|
||||||
- id
|
|
||||||
- run
|
|
||||||
- env
|
|
||||||
- shell
|
|
||||||
- working-directory
|
|
||||||
|
|
||||||
This feature **does not support** at the run step level:
|
|
||||||
- timeout-minutes
|
|
||||||
- secrets
|
|
||||||
- conditionals (needs, if, etc.)
|
|
||||||
- continue-on-error
|
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
Example `workflow.yml`
|
Example `workflow.yml`
|
||||||
@@ -70,9 +49,7 @@ runs:
|
|||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- run: pip install -r requirements.txt
|
- run: pip install -r requirements.txt
|
||||||
shell: bash
|
|
||||||
- run: npm install
|
- run: npm install
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Example Output
|
Example Output
|
||||||
@@ -86,69 +63,6 @@ echo hello world 4
|
|||||||
|
|
||||||
We add a token called "composite" which allows our Runner code to process composite actions. By invoking "using: composite", our Runner code then processes the "steps" attribute, converts this template code to a list of steps, and finally runs each run step sequentially. If any step fails and there are no `if` conditions defined, the whole composite action job fails.
|
We add a token called "composite" which allows our Runner code to process composite actions. By invoking "using: composite", our Runner code then processes the "steps" attribute, converts this template code to a list of steps, and finally runs each run step sequentially. If any step fails and there are no `if` conditions defined, the whole composite action job fails.
|
||||||
|
|
||||||
### Defaults
|
|
||||||
|
|
||||||
We will not support "defaults" in a composite action.
|
|
||||||
|
|
||||||
### Shell and Working-directory
|
|
||||||
|
|
||||||
For each run step in a composite action, the action author can set the `shell` and `working-directory` attributes for that step. The shell attribute is **required** for each run step because the action author does not know what the workflow author is using for the operating system so we need to explicitly prevent unknown behavior by making sure that each run step has an explicit shell **set by the action author.** On the other hand, `working-directory` is optional. Moreover, the composite action author can map in values from the `inputs` for it's `shell` and `working-directory` attributes at the step level for an action.
|
|
||||||
|
|
||||||
For example,
|
|
||||||
|
|
||||||
`action.yml`
|
|
||||||
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
inputs:
|
|
||||||
shell_1:
|
|
||||||
description: 'Your name'
|
|
||||||
default: 'pwsh'
|
|
||||||
steps:
|
|
||||||
- run: echo 1
|
|
||||||
shell: ${{ inputs.shell_1 }}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note, the workflow file and action file are treated as separate entities. **So, the workflow `defaults` will never change the `shell` and `working-directory` value in the run steps in a composite action.** Note, `defaults` in a workflow only apply to run steps not "uses" steps (steps that use an action).
|
|
||||||
|
|
||||||
### Running Local Scripts
|
|
||||||
|
|
||||||
Example 'workflow.yml':
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- uses: user/composite@v1
|
|
||||||
```
|
|
||||||
|
|
||||||
Example `user/composite/action.yml`:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
runs:
|
|
||||||
using: "composite"
|
|
||||||
steps:
|
|
||||||
- run: chmod +x ${{ github.action_path }}/test/script2.sh
|
|
||||||
shell: bash
|
|
||||||
- run: chmod +x $GITHUB_ACTION_PATH/script.sh
|
|
||||||
shell: bash
|
|
||||||
- run: ${{ github.action_path }}/test/script2.sh
|
|
||||||
shell: bash
|
|
||||||
- run: $GITHUB_ACTION_PATH/script.sh
|
|
||||||
shell: bash
|
|
||||||
```
|
|
||||||
Where `user/composite` has the file structure:
|
|
||||||
```
|
|
||||||
.
|
|
||||||
+-- action.yml
|
|
||||||
+-- script.sh
|
|
||||||
+-- test
|
|
||||||
| +-- script2.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Users will be able to run scripts located in their action folder by first prepending the relative path and script name with `$GITHUB_ACTION_PATH` or `github.action_path` which contains the path in which the composite action is downloaded to and where those "files" live. Note, you'll have to use `chmod` before running each script if you do not git check in your script files into your github repo with the executable bit turned on.
|
|
||||||
|
|
||||||
### Inputs
|
### Inputs
|
||||||
|
|
||||||
Example `workflow.yml`:
|
Example `workflow.yml`:
|
||||||
@@ -172,7 +86,6 @@ runs:
|
|||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- run: echo hello ${{ inputs.your_name }}
|
- run: echo hello ${{ inputs.your_name }}
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Example Output:
|
Example Output:
|
||||||
@@ -193,7 +106,6 @@ steps:
|
|||||||
- id: foo
|
- id: foo
|
||||||
uses: user/composite@v1
|
uses: user/composite@v1
|
||||||
- run: echo random-number ${{ steps.foo.outputs.random-number }}
|
- run: echo random-number ${{ steps.foo.outputs.random-number }}
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Example `user/composite/action.yml`:
|
Example `user/composite/action.yml`:
|
||||||
@@ -207,8 +119,7 @@ runs:
|
|||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- id: random-number-generator
|
- id: random-number-generator
|
||||||
run: echo "::set-output name=random-id::$(echo $RANDOM)"
|
run: echo "::set-output name=random-number::$(echo $RANDOM)"
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Example Output:
|
Example Output:
|
||||||
@@ -232,17 +143,13 @@ In the Composite Action, you'll only be able to use `::set-env::` to set environ
|
|||||||
|
|
||||||
### Secrets
|
### Secrets
|
||||||
|
|
||||||
**We will not support "Secrets" in a composite action for now. This functionality will be focused on in a future ADR.**
|
**Note** : This feature will be focused on in a future ADR.
|
||||||
|
|
||||||
We'll pass the secrets from the composite action's parents (ex: the workflow file) to the composite action. Secrets can be created in the composite action with the secrets context. In the actions yaml, we'll automatically mask the secret.
|
We'll pass the secrets from the composite action's parents (ex: the workflow file) to the composite action. Secrets can be created in the composite action with the secrets context. In the actions yaml, we'll automatically mask the secret.
|
||||||
|
|
||||||
|
|
||||||
### If Condition
|
### If Condition
|
||||||
|
|
||||||
** If and needs conditions will not be supported in the composite run steps feature. It will be supported later on in a new feature. **
|
|
||||||
|
|
||||||
Old reasoning:
|
|
||||||
|
|
||||||
Example `workflow.yml`:
|
Example `workflow.yml`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -259,18 +166,12 @@ runs:
|
|||||||
using: "composite"
|
using: "composite"
|
||||||
steps:
|
steps:
|
||||||
- run: echo "just succeeding"
|
- run: echo "just succeeding"
|
||||||
shell: bash
|
|
||||||
- run: echo "I will run, as my current scope is succeeding"
|
- run: echo "I will run, as my current scope is succeeding"
|
||||||
shell: bash
|
|
||||||
if: success()
|
if: success()
|
||||||
- run: exit 1
|
- run: exit 1
|
||||||
shell: bash
|
|
||||||
- run: echo "I will not run, as my current scope is now failing"
|
- run: echo "I will not run, as my current scope is now failing"
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**We will not support "if Condition" in a composite action for now. This functionality will be focused on in a future ADR.**
|
|
||||||
|
|
||||||
See the paragraph below for a rudimentary approach (thank you to @cybojenix for the idea, example, and explanation for this approach):
|
See the paragraph below for a rudimentary approach (thank you to @cybojenix for the idea, example, and explanation for this approach):
|
||||||
|
|
||||||
The `if` statement in the parent (in the example above, this is the `workflow.yml`) shows whether or not we should run the composite action. So, our composite action will run since the `if` condition for running the composite action is `always()`.
|
The `if` statement in the parent (in the example above, this is the `workflow.yml`) shows whether or not we should run the composite action. So, our composite action will run since the `if` condition for running the composite action is `always()`.
|
||||||
@@ -302,18 +203,13 @@ runs:
|
|||||||
- id: foo1
|
- id: foo1
|
||||||
run: echo test 1
|
run: echo test 1
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
shell: bash
|
|
||||||
- id: foo2
|
- id: foo2
|
||||||
run: echo test 2
|
run: echo test 2
|
||||||
shell: bash
|
|
||||||
- id: foo3
|
- id: foo3
|
||||||
run: echo test 3
|
run: echo test 3
|
||||||
timeout-minutes: 10
|
timeout-minutes: 10
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**We will not support "timeout-minutes" in a composite action for now. This functionality will be focused on in a future ADR.**
|
|
||||||
|
|
||||||
A composite action in its entirety is a job. You can set both timeout-minutes for the whole composite action or its steps as long as the the sum of the `timeout-minutes` for each composite action step that has the attribute `timeout-minutes` is less than or equals to `timeout-minutes` for the composite action. There is no default timeout-minutes for each composite action step.
|
A composite action in its entirety is a job. You can set both timeout-minutes for the whole composite action or its steps as long as the the sum of the `timeout-minutes` for each composite action step that has the attribute `timeout-minutes` is less than or equals to `timeout-minutes` for the composite action. There is no default timeout-minutes for each composite action step.
|
||||||
|
|
||||||
If the time taken for any of the steps in combination or individually exceed the whole composite action `timeout-minutes` attribute, the whole job will fail (1). If an individual step exceeds its own `timeout-minutes` attribute but the total time that has been used including this step is below the overall composite action `timeout-minutes`, the individual step will fail but the rest of the steps will run based on their own `timeout-minutes` attribute (they will still abide by condition (1) though).
|
If the time taken for any of the steps in combination or individually exceed the whole composite action `timeout-minutes` attribute, the whole job will fail (1). If an individual step exceeds its own `timeout-minutes` attribute but the total time that has been used including this step is below the overall composite action `timeout-minutes`, the individual step will fail but the rest of the steps will run based on their own `timeout-minutes` attribute (they will still abide by condition (1) though).
|
||||||
@@ -347,17 +243,36 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- run: exit 1
|
- run: exit 1
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
shell: bash
|
|
||||||
- run: echo "Hello World 2" <----- This step will run
|
- run: echo "Hello World 2" <----- This step will run
|
||||||
shell: bash
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**We will not support "continue-on-error" in a composite action for now. This functionality will be focused on in a future ADR.**
|
|
||||||
|
|
||||||
If any of the steps fail in the composite action and the `continue-on-error` is set to `false` for the whole composite action step in the workflow file, then the steps below it will run. On the flip side, if `continue-on-error` is set to `true` for the whole composite action step in the workflow file, the next job step will run.
|
If any of the steps fail in the composite action and the `continue-on-error` is set to `false` for the whole composite action step in the workflow file, then the steps below it will run. On the flip side, if `continue-on-error` is set to `true` for the whole composite action step in the workflow file, the next job step will run.
|
||||||
|
|
||||||
For the composite action steps, it follows the same logic as above. In this example, `"Hello World 2"` will be outputted because the previous step has `continue-on-error` set to `true` although that previous step errored.
|
For the composite action steps, it follows the same logic as above. In this example, `"Hello World 2"` will be outputted because the previous step has `continue-on-error` set to `true` although that previous step errored.
|
||||||
|
|
||||||
|
### Defaults
|
||||||
|
We will not support "defaults" in a composite action.
|
||||||
|
|
||||||
|
### Shell and Working-directory
|
||||||
|
For each run step in a composite action, the action author can set the `shell` and `working-directory` attributes for that step. These attributes are optional for each run step - by default, the `shell` is set to whatever default value is associated with the runner os (ex: bash =\> Mac). Moreover, the composite action author can map in values from the `inputs` for it's `shell` and `working-directory` attributes at the step level for an action.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
`action.yml`
|
||||||
|
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
inputs:
|
||||||
|
shell_1:
|
||||||
|
description: 'Your name'
|
||||||
|
default: 'pwsh'
|
||||||
|
steps:
|
||||||
|
- run: echo 1
|
||||||
|
shell: ${{ inputs.shell_1 }}
|
||||||
|
```
|
||||||
|
|
||||||
|
Note, the workflow file and action file are treated as separate entities. **So, the workflow `defaults` will never change the `shell` and `working-directory` value in the run steps in a composite action.** Note, `defaults` in a workflow only apply to run steps not "uses" steps (steps that use an action).
|
||||||
|
|
||||||
### Visualizing Composite Action in the GitHub Actions UI
|
### Visualizing Composite Action in the GitHub Actions UI
|
||||||
We want all the composite action's steps to be condensed into the original composite action node.
|
We want all the composite action's steps to be condensed into the original composite action node.
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ Issues in this repository should be for the runner application. Note that the V
|
|||||||
|
|
||||||
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
|
We ask that before significant effort is put into code changes, that we have agreement on taking the change before time is invested in code changes.
|
||||||
|
|
||||||
1. Create a feature request. Once agreed we will take the enhancement
|
1. Create a feature request. Once agreed we will take the enhancment
|
||||||
2. Create an ADR to agree on the details of the change.
|
2. Create an ADR to agree on the details of the change.
|
||||||
|
|
||||||
An ADR is an Architectural Decision Record. This allows consensus on the direction forward and also serves as a record of the change and motivation. [Read more here](adrs/README.md)
|
An ADR is an Architectural Decision Record. This allows consensus on the direction forward and also serves as a record of the change and motivation. [Read more here](adrs/README.md)
|
||||||
|
|||||||
48
ephemeralJob.yaml
Normal file
48
ephemeralJob.yaml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
apiVersion: batch.github.actions/v1
|
||||||
|
kind: CronJob
|
||||||
|
metadata:
|
||||||
|
name: cronjob-sample
|
||||||
|
spec:
|
||||||
|
schedule: "*/1 * * * *"
|
||||||
|
jobTemplate:
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
hostNetwork: true
|
||||||
|
containers:
|
||||||
|
- name: k8srunner
|
||||||
|
image: huangtingluo/autoscale-runner:v0.0
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: GITHUB_PAT
|
||||||
|
value: 62c13e14e947958516c103a9584f66227697c447
|
||||||
|
- name: GITHUB_RUNNER_SCOPE
|
||||||
|
value: monalisa/main123
|
||||||
|
restartPolicy: Never
|
||||||
|
# spec:
|
||||||
|
# containers:
|
||||||
|
# - name: hello
|
||||||
|
# image: busybox
|
||||||
|
# args:
|
||||||
|
# - /bin/sh
|
||||||
|
# - -c
|
||||||
|
# - date; echo Hello from the Kubernetes cluster
|
||||||
|
# restartPolicy: Never
|
||||||
|
# jobTemplate:
|
||||||
|
# spec:
|
||||||
|
# template:
|
||||||
|
# spec:
|
||||||
|
# hostNetwork: true
|
||||||
|
# containers:
|
||||||
|
# - name: k8srunner
|
||||||
|
# image: huangtingluo/autoscale-runner:v0.0
|
||||||
|
# imagePullPolicy: Always
|
||||||
|
# env:
|
||||||
|
# - name: GITHUB_PAT
|
||||||
|
# value: 62c13e14e947958516c103a9584f66227697c447
|
||||||
|
# - name: GITHUB_RUNNER_SCOPE
|
||||||
|
# value: monalisa/main123
|
||||||
|
# restartPolicy: Never
|
||||||
|
# backoffLimit: 1
|
||||||
|
# completions: 0
|
||||||
|
# parallelism: 3
|
||||||
56
hpa-v2.yaml
Normal file
56
hpa-v2.yaml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
items:
|
||||||
|
- apiVersion: autoscaling/v2beta2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
creationTimestamp: "2020-08-05T19:14:04Z"
|
||||||
|
name: runner-deployment
|
||||||
|
namespace: default
|
||||||
|
resourceVersion: "167447"
|
||||||
|
selfLink: /apis/autoscaling/v2beta2/namespaces/default/horizontalpodautoscalers/runner-deployment
|
||||||
|
uid: 54d86943-eca9-468c-9698-c843f6b6183a
|
||||||
|
spec:
|
||||||
|
maxReplicas: 10
|
||||||
|
metrics:
|
||||||
|
- type: Object
|
||||||
|
object:
|
||||||
|
metric:
|
||||||
|
name: test-metric
|
||||||
|
describedObject:
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
name: kubernetes
|
||||||
|
target:
|
||||||
|
type: Value
|
||||||
|
value: 300m
|
||||||
|
- resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
averageUtilization: 50
|
||||||
|
type: Utilization
|
||||||
|
type: Resource
|
||||||
|
minReplicas: 1
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
name: runner-deployment
|
||||||
|
status:
|
||||||
|
conditions:
|
||||||
|
- lastTransitionTime: "2020-08-05T19:14:19Z"
|
||||||
|
message: the HPA controller was able to get the target's current scale
|
||||||
|
reason: SucceededGetScale
|
||||||
|
status: "True"
|
||||||
|
type: AbleToScale
|
||||||
|
- lastTransitionTime: "2020-08-05T19:14:19Z"
|
||||||
|
message: 'the HPA was unable to compute the replica count: unable to get metrics
|
||||||
|
for resource cpu: no metrics returned from resource metrics API'
|
||||||
|
reason: FailedGetResourceMetric
|
||||||
|
status: "False"
|
||||||
|
type: ScalingActive
|
||||||
|
currentMetrics: null
|
||||||
|
currentReplicas: 1
|
||||||
|
desiredReplicas: 0
|
||||||
|
kind: List
|
||||||
|
metadata:
|
||||||
|
resourceVersion: ""
|
||||||
|
selfLink: ""
|
||||||
92
job.yaml
Normal file
92
job.yaml
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
name: pod-admin
|
||||||
|
namespace: default
|
||||||
|
rules:
|
||||||
|
- apiGroups: [ "" ]
|
||||||
|
resources: [ "pods", "pods/ephemeralcontainers", "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: docker-storage
|
||||||
|
emptyDir: {}
|
||||||
|
- name: runner-working
|
||||||
|
emptyDir: {}
|
||||||
|
containers:
|
||||||
|
- name: docker-host
|
||||||
|
image: docker:18.05-dind
|
||||||
|
imagePullPolicy: Always
|
||||||
|
securityContext:
|
||||||
|
privileged: true
|
||||||
|
volumeMounts:
|
||||||
|
- name: docker-storage
|
||||||
|
mountPath: /var/lib/docker
|
||||||
|
- mountPath: /actions-runner/_work
|
||||||
|
name: runner-working
|
||||||
|
- name: k8srunner
|
||||||
|
image: huangtingluo/autoscale-runner:v0.0
|
||||||
|
volumeMounts:
|
||||||
|
- mountPath: /actions-runner/_work
|
||||||
|
name: runner-working
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: GITHUB_PAT
|
||||||
|
value: 62c13e14e947958516c103a9584f66227697c447
|
||||||
|
- name: GITHUB_RUNNER_SCOPE
|
||||||
|
value: monalisa/main123
|
||||||
|
- name: K8S_HOST_IP
|
||||||
|
value: "192.168.120.1"
|
||||||
|
- name: DOCKER_HOST
|
||||||
|
value: tcp://localhost:2375
|
||||||
|
- 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: 20
|
||||||
|
parallelism: 3
|
||||||
34
prereq.yaml
Normal file
34
prereq.yaml
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
namespace: default
|
||||||
|
name: pod-patcher
|
||||||
|
rules:
|
||||||
|
- apiGroups: [""] # "" indicates the core API group
|
||||||
|
resources: ["pods"]
|
||||||
|
verbs: ["get", "watch", "list", "patch"]
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
name: default-pod-patcher
|
||||||
|
namespace: default
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: pod-patcher
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: default
|
||||||
|
namespace: default
|
||||||
|
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: githubtoken
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
GITHUB_PAT: "xxx"
|
||||||
@@ -1,12 +1,18 @@
|
|||||||
## Features
|
## Features
|
||||||
- N/A
|
- Resolve action download info from server (#508, #515, #550)
|
||||||
|
- Print runner and machine name to log. (#539)
|
||||||
## Bugs
|
## Bugs
|
||||||
- N/A
|
- Reduce input validation warnings (#506)
|
||||||
|
- Fix null ref exception in SecretMasker caused by `hashfiles` timeout. (#516)
|
||||||
|
- Add libicu66 to `./installDependencies.sh` for Ubuntu 20.04 (#535)
|
||||||
|
- Fix DataContract with Token service (#532)
|
||||||
|
- Skip search $PATH on command with fully qualified path (#526)
|
||||||
|
- Restore SELinux context on service file when SELinux is enabled (#525)
|
||||||
## Misc
|
## Misc
|
||||||
- Disabled add-path and set-env runner commands (#779)
|
- Remove SPS/Token migration code. Remove GHES url manipulate code. (#513)
|
||||||
- Updated dotnet install scripts (#779)
|
- Add sub-step for developer flow for clarity (#523)
|
||||||
|
- Update Links and Language to Git + VSCode (#522)
|
||||||
|
- Update runner configuration exception message (#540)
|
||||||
|
|
||||||
## Windows x64
|
## Windows x64
|
||||||
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
We recommend configuring the runner in a root folder of the Windows drive (e.g. "C:\actions-runner"). This will help avoid issues related to service identity folder permissions and long file path restrictions on Windows.
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.274.2
|
<Update to ./src/runnerversion when creating release>
|
||||||
|
|||||||
12
runner.yaml
Normal file
12
runner.yaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
apiVersion: actions.github.com/v1alpha1
|
||||||
|
kind: Runner
|
||||||
|
metadata:
|
||||||
|
name: auto-scale-runners
|
||||||
|
spec:
|
||||||
|
organization: monalisa
|
||||||
|
group: default
|
||||||
|
repository: main123
|
||||||
|
githubAdminToken: 62c13e14e947958516c103a9584f66227697c447
|
||||||
|
env:
|
||||||
|
- name: K8S_HOST_IP
|
||||||
|
value: "192.168.120.1"
|
||||||
46
runners.yaml
Normal file
46
runners.yaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
apiVersion: actions.github.com/v1alpha1
|
||||||
|
kind: AutoScaleRunner
|
||||||
|
metadata:
|
||||||
|
name: auto-scale-runners
|
||||||
|
spec:
|
||||||
|
minReplicas: 1
|
||||||
|
maxReplicas: 5
|
||||||
|
configURL: https://github.com/TingluoHuang/example-services
|
||||||
|
githubTokenSecretKeyRef:
|
||||||
|
name: githubtoken
|
||||||
|
key: GITHUB_PAT
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
setupDockerInDocker: true
|
||||||
|
imagePullPolicy: Always
|
||||||
|
runnerUpdateHandler:
|
||||||
|
containers:
|
||||||
|
- name: update-image
|
||||||
|
image: huangtingluo/workflow_dispatch:latest
|
||||||
|
imagePullPolicy: Always
|
||||||
|
env:
|
||||||
|
- name: GITHUB_TOKEN
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: githubtoken
|
||||||
|
key: GITHUB_PAT
|
||||||
|
- name: GITHUB_OWNER
|
||||||
|
value: tingluohuang
|
||||||
|
- name: GITHUB_REPO
|
||||||
|
value: "workflow_dispatch"
|
||||||
|
- name: GITHUB_EXTRA_CURL_ARG
|
||||||
|
value: "-v"
|
||||||
|
- name: GITHUB_WORKFLOW
|
||||||
|
value: "2539181"
|
||||||
|
- name: GITHUB_WORKFLOW_INPUTS
|
||||||
|
value: "{\"test_input\":\"test\"}"
|
||||||
|
|
||||||
|
# - name: GITHUB_REPO
|
||||||
|
# value: "k8s-runner-image"
|
||||||
|
# - name: GITHUB_EXTRA_CURL_ARG
|
||||||
|
# value: "-v"
|
||||||
|
# - name: GITHUB_WORKFLOW
|
||||||
|
# value: "docker-publish.yml"
|
||||||
|
# - name: GITHUB_WORKFLOW_INPUTS
|
||||||
|
# value: "{\"runnerDownloadUrl\":\"https://github.com/TingluoHuang/runner/releases/download/test/actions-runner-linux-x64-2.299.0.tar.gz\"}"
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
[*.cs]
|
|
||||||
charset = utf-8
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
csharp_new_line_before_else = true
|
|
||||||
csharp_new_line_before_catch = true
|
|
||||||
csharp_new_line_before_finally = true
|
|
||||||
csharp_new_line_before_open_brace = all
|
|
||||||
|
|
||||||
csharp_space_after_keywords_in_control_flow_statements = true
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 16
|
# Visual Studio Version 16
|
||||||
VisualStudioVersion = 16.0.29411.138
|
VisualStudioVersion = 16.0.29411.138
|
||||||
@@ -21,11 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sdk", "Sdk\Sdk.csproj", "{D
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{C932061F-F6A1-4F1E-B854-A6C6B30DC3EF}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{C932061F-F6A1-4F1E-B854-A6C6B30DC3EF}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EFB254FC-7927-445E-BA64-6676ADB309E9}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|||||||
338
src/Misc/dotnet-install.ps1
vendored
338
src/Misc/dotnet-install.ps1
vendored
@@ -69,8 +69,6 @@
|
|||||||
.PARAMETER ProxyUseDefaultCredentials
|
.PARAMETER ProxyUseDefaultCredentials
|
||||||
Default: false
|
Default: false
|
||||||
Use default credentials, when using proxy address.
|
Use default credentials, when using proxy address.
|
||||||
.PARAMETER ProxyBypassList
|
|
||||||
If set with ProxyAddress, will provide the list of comma separated urls that will bypass the proxy
|
|
||||||
.PARAMETER SkipNonVersionedFiles
|
.PARAMETER SkipNonVersionedFiles
|
||||||
Default: false
|
Default: false
|
||||||
Skips installing non-versioned files if they already exist, such as dotnet.exe.
|
Skips installing non-versioned files if they already exist, such as dotnet.exe.
|
||||||
@@ -98,7 +96,6 @@ param(
|
|||||||
[string]$FeedCredential,
|
[string]$FeedCredential,
|
||||||
[string]$ProxyAddress,
|
[string]$ProxyAddress,
|
||||||
[switch]$ProxyUseDefaultCredentials,
|
[switch]$ProxyUseDefaultCredentials,
|
||||||
[string[]]$ProxyBypassList=@(),
|
|
||||||
[switch]$SkipNonVersionedFiles,
|
[switch]$SkipNonVersionedFiles,
|
||||||
[switch]$NoCdn
|
[switch]$NoCdn
|
||||||
)
|
)
|
||||||
@@ -122,27 +119,11 @@ $VersionRegEx="/\d+\.\d+[^/]+/"
|
|||||||
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles
|
$OverrideNonVersionedFiles = !$SkipNonVersionedFiles
|
||||||
|
|
||||||
function Say($str) {
|
function Say($str) {
|
||||||
try
|
Write-Host "dotnet-install: $str"
|
||||||
{
|
|
||||||
Write-Host "dotnet-install: $str"
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
# Some platforms cannot utilize Write-Host (Azure Functions, for instance). Fall back to Write-Output
|
|
||||||
Write-Output "dotnet-install: $str"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Say-Verbose($str) {
|
function Say-Verbose($str) {
|
||||||
try
|
Write-Verbose "dotnet-install: $str"
|
||||||
{
|
|
||||||
Write-Verbose "dotnet-install: $str"
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
# Some platforms cannot utilize Write-Verbose (Azure Functions, for instance). Fall back to Write-Output
|
|
||||||
Write-Output "dotnet-install: $str"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Say-Invocation($Invocation) {
|
function Say-Invocation($Invocation) {
|
||||||
@@ -195,7 +176,7 @@ function Get-CLIArchitecture-From-Architecture([string]$Architecture) {
|
|||||||
{ $_ -eq "x86" } { return "x86" }
|
{ $_ -eq "x86" } { return "x86" }
|
||||||
{ $_ -eq "arm" } { return "arm" }
|
{ $_ -eq "arm" } { return "arm" }
|
||||||
{ $_ -eq "arm64" } { return "arm64" }
|
{ $_ -eq "arm64" } { return "arm64" }
|
||||||
default { throw "Architecture '$Architecture' not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues" }
|
default { throw "Architecture not supported. If you think this is a bug, report it at https://github.com/dotnet/sdk/issues" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,11 +237,7 @@ function GetHTTPResponse([Uri] $Uri)
|
|||||||
|
|
||||||
if($ProxyAddress) {
|
if($ProxyAddress) {
|
||||||
$HttpClientHandler = New-Object System.Net.Http.HttpClientHandler
|
$HttpClientHandler = New-Object System.Net.Http.HttpClientHandler
|
||||||
$HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{
|
$HttpClientHandler.Proxy = New-Object System.Net.WebProxy -Property @{Address=$ProxyAddress;UseDefaultCredentials=$ProxyUseDefaultCredentials}
|
||||||
Address=$ProxyAddress;
|
|
||||||
UseDefaultCredentials=$ProxyUseDefaultCredentials;
|
|
||||||
BypassList = $ProxyBypassList;
|
|
||||||
}
|
|
||||||
$HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler
|
$HttpClient = New-Object System.Net.Http.HttpClient -ArgumentList $HttpClientHandler
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -395,20 +372,17 @@ function Get-Specific-Version-From-Version([string]$AzureFeed, [string]$Channel,
|
|||||||
function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) {
|
function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) {
|
||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
# If anything fails in this lookup it will default to $SpecificVersion
|
|
||||||
$SpecificProductVersion = Get-Product-Version -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion
|
|
||||||
|
|
||||||
if ($Runtime -eq "dotnet") {
|
if ($Runtime -eq "dotnet") {
|
||||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/dotnet-runtime-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||||
}
|
}
|
||||||
elseif ($Runtime -eq "aspnetcore") {
|
elseif ($Runtime -eq "aspnetcore") {
|
||||||
$PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
$PayloadURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/aspnetcore-runtime-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||||
}
|
}
|
||||||
elseif ($Runtime -eq "windowsdesktop") {
|
elseif ($Runtime -eq "windowsdesktop") {
|
||||||
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
$PayloadURL = "$AzureFeed/Runtime/$SpecificVersion/windowsdesktop-runtime-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||||
}
|
}
|
||||||
elseif (-not $Runtime) {
|
elseif (-not $Runtime) {
|
||||||
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificProductVersion-win-$CLIArchitecture.zip"
|
$PayloadURL = "$AzureFeed/Sdk/$SpecificVersion/dotnet-sdk-$SpecificVersion-win-$CLIArchitecture.zip"
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw "Invalid value for `$Runtime"
|
throw "Invalid value for `$Runtime"
|
||||||
@@ -416,7 +390,7 @@ function Get-Download-Link([string]$AzureFeed, [string]$SpecificVersion, [string
|
|||||||
|
|
||||||
Say-Verbose "Constructed primary named payload URL: $PayloadURL"
|
Say-Verbose "Constructed primary named payload URL: $PayloadURL"
|
||||||
|
|
||||||
return $PayloadURL, $SpecificProductVersion
|
return $PayloadURL
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) {
|
function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [string]$CLIArchitecture) {
|
||||||
@@ -437,51 +411,6 @@ function Get-LegacyDownload-Link([string]$AzureFeed, [string]$SpecificVersion, [
|
|||||||
return $PayloadURL
|
return $PayloadURL
|
||||||
}
|
}
|
||||||
|
|
||||||
function Get-Product-Version([string]$AzureFeed, [string]$SpecificVersion) {
|
|
||||||
Say-Invocation $MyInvocation
|
|
||||||
|
|
||||||
if ($Runtime -eq "dotnet") {
|
|
||||||
$ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt"
|
|
||||||
}
|
|
||||||
elseif ($Runtime -eq "aspnetcore") {
|
|
||||||
$ProductVersionTxtURL = "$AzureFeed/aspnetcore/Runtime/$SpecificVersion/productVersion.txt"
|
|
||||||
}
|
|
||||||
elseif ($Runtime -eq "windowsdesktop") {
|
|
||||||
$ProductVersionTxtURL = "$AzureFeed/Runtime/$SpecificVersion/productVersion.txt"
|
|
||||||
}
|
|
||||||
elseif (-not $Runtime) {
|
|
||||||
$ProductVersionTxtURL = "$AzureFeed/Sdk/$SpecificVersion/productVersion.txt"
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw "Invalid value '$Runtime' specified for `$Runtime"
|
|
||||||
}
|
|
||||||
|
|
||||||
Say-Verbose "Checking for existence of $ProductVersionTxtURL"
|
|
||||||
|
|
||||||
try {
|
|
||||||
$productVersionResponse = GetHTTPResponse($productVersionTxtUrl)
|
|
||||||
|
|
||||||
if ($productVersionResponse.StatusCode -eq 200) {
|
|
||||||
$productVersion = $productVersionResponse.Content.ReadAsStringAsync().Result.Trim()
|
|
||||||
if ($productVersion -ne $SpecificVersion)
|
|
||||||
{
|
|
||||||
Say "Using alternate version $productVersion found in $ProductVersionTxtURL"
|
|
||||||
}
|
|
||||||
|
|
||||||
return $productVersion
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Say-Verbose "Got StatusCode $($productVersionResponse.StatusCode) trying to get productVersion.txt at $productVersionTxtUrl, so using default value of $SpecificVersion"
|
|
||||||
$productVersion = $SpecificVersion
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
Say-Verbose "Could not read productVersion.txt at $productVersionTxtUrl, so using default value of $SpecificVersion (Exception: '$($_.Exception.Message)' )"
|
|
||||||
$productVersion = $SpecificVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
return $productVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
function Get-User-Share-Path() {
|
function Get-User-Share-Path() {
|
||||||
Say-Invocation $MyInvocation
|
Say-Invocation $MyInvocation
|
||||||
|
|
||||||
@@ -635,14 +564,9 @@ function Prepend-Sdk-InstallRoot-To-Path([string]$InstallRoot, [string]$BinFolde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
|
|
||||||
Say "- The SDK needs to be installed without user interaction and without admin rights."
|
|
||||||
Say "- The SDK installation doesn't need to persist across multiple CI runs."
|
|
||||||
Say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.`r`n"
|
|
||||||
|
|
||||||
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
|
$CLIArchitecture = Get-CLIArchitecture-From-Architecture $Architecture
|
||||||
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile
|
$SpecificVersion = Get-Specific-Version-From-Version -AzureFeed $AzureFeed -Channel $Channel -Version $Version -JSonFile $JSonFile
|
||||||
$DownloadLink, $EffectiveVersion = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
$DownloadLink = Get-Download-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
||||||
$LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
$LegacyDownloadLink = Get-LegacyDownload-Link -AzureFeed $AzureFeed -SpecificVersion $SpecificVersion -CLIArchitecture $CLIArchitecture
|
||||||
|
|
||||||
$InstallRoot = Resolve-Installation-Path $InstallDir
|
$InstallRoot = Resolve-Installation-Path $InstallDir
|
||||||
@@ -668,11 +592,6 @@ if ($DryRun) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Say "Repeatable invocation: $RepeatableCommand"
|
Say "Repeatable invocation: $RepeatableCommand"
|
||||||
if ($SpecificVersion -ne $EffectiveVersion)
|
|
||||||
{
|
|
||||||
Say "NOTE: Due to finding a version manifest with this runtime, it would actually install with version '$EffectiveVersion'"
|
|
||||||
}
|
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -696,12 +615,6 @@ else {
|
|||||||
throw "Invalid value for `$Runtime"
|
throw "Invalid value for `$Runtime"
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($SpecificVersion -ne $EffectiveVersion)
|
|
||||||
{
|
|
||||||
Say "Performing installation checks for effective version: $EffectiveVersion"
|
|
||||||
$SpecificVersion = $EffectiveVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if the SDK version is already installed.
|
# Check if the SDK version is already installed.
|
||||||
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
|
$isAssetInstalled = Is-Dotnet-Package-Installed -InstallRoot $InstallRoot -RelativePathToPackage $dotnetPackageRelativePath -SpecificVersion $SpecificVersion
|
||||||
if ($isAssetInstalled) {
|
if ($isAssetInstalled) {
|
||||||
@@ -778,15 +691,14 @@ Remove-Item $ZipPath
|
|||||||
|
|
||||||
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
Prepend-Sdk-InstallRoot-To-Path -InstallRoot $InstallRoot -BinFolderRelativePath $BinFolderRelativePath
|
||||||
|
|
||||||
Say "Note that the script does not resolve dependencies during installation."
|
|
||||||
Say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install/windows#dependencies"
|
|
||||||
Say "Installation finished"
|
Say "Installation finished"
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
# SIG # Begin signature block
|
# SIG # Begin signature block
|
||||||
# MIIjlgYJKoZIhvcNAQcCoIIjhzCCI4MCAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
# MIIjhwYJKoZIhvcNAQcCoIIjeDCCI3QCAQExDzANBglghkgBZQMEAgEFADB5Bgor
|
||||||
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
|
||||||
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCA+isugNMwZSGLd
|
# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCAiKYSY4KtkeThH
|
||||||
# kfBd0C2Ud//U2Nbj31s1jg3Yf9gh4KCCDYUwggYDMIID66ADAgECAhMzAAABiK9S
|
# d5M1aXqv1K0/pff07QwfUbYZ/qX5LqCCDYUwggYDMIID66ADAgECAhMzAAABiK9S
|
||||||
# 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
# 1rmSbej5AAAAAAGIMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNVBAYTAlVTMRMwEQYD
|
||||||
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
# VQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNy
|
||||||
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
# b3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01pY3Jvc29mdCBDb2RlIFNpZ25p
|
||||||
@@ -858,119 +770,119 @@ exit 0
|
|||||||
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
|
# BL7fQccOKO7eZS/sl/ahXJbYANahRr1Z85elCUtIEJmAH9AAKcWxm6U/RXceNcbS
|
||||||
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
|
# oqKfenoi+kiVH6v7RyOA9Z74v2u3S5fi63V4GuzqN5l5GEv/1rMjaHXmr/r8i+sL
|
||||||
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
|
# gOppO6/8MO0ETI7f33VtY5E90Z1WTk+/gFcioXgRMiF670EKsT/7qMykXcGhiJtX
|
||||||
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFWcwghVjAgEBMIGVMH4x
|
# cVZOSEXAQsmbdlsKgEhr/Xmfwb1tbWrJUnMTDXpQzTGCFVgwghVUAgEBMIGVMH4x
|
||||||
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
|
# CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRt
|
||||||
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
|
# b25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xKDAmBgNVBAMTH01p
|
||||||
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA
|
# Y3Jvc29mdCBDb2RlIFNpZ25pbmcgUENBIDIwMTECEzMAAAGIr1LWuZJt6PkAAAAA
|
||||||
# AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
|
# AYgwDQYJYIZIAWUDBAIBBQCgga4wGQYJKoZIhvcNAQkDMQwGCisGAQQBgjcCAQQw
|
||||||
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIK4I
|
# HAYKKwYBBAGCNwIBCzEOMAwGCisGAQQBgjcCARUwLwYJKoZIhvcNAQkEMSIEIFxZ
|
||||||
# CDH7/r/eeMqTtDETJ67ogfneVRo0/P6ogV2vy4tXMEIGCisGAQQBgjcCAQwxNDAy
|
# Yezh3liQqiGQuXNa+zYfoSIbLqOpdEn2ZKskBkisMEIGCisGAQQBgjcCAQwxNDAy
|
||||||
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
|
# oBSAEgBNAGkAYwByAG8AcwBvAGYAdKEagBhodHRwOi8vd3d3Lm1pY3Jvc29mdC5j
|
||||||
# b20wDQYJKoZIhvcNAQEBBQAEggEAOnmVmILEjI6ZiuuSOvvTvijidkBez61Vz97A
|
# b20wDQYJKoZIhvcNAQEBBQAEggEAjLUrwCXJCPHZulZuKAQSX+MfnIRFAhlN7ru2
|
||||||
# jV3AOsfmUvLpVaTVa1Mt2iPDuq1QLqRPaT7BD8PAUwr91pYllVgEd8NqivCIaCZg
|
# 6H8rudvhkWgqMISkLb9gFDPR5FhR4sqdYgKW4P0ERao9ypCGi1FWDLqygC2XBbHj
|
||||||
# QyIRiTmHQxbozWsLcjxMvX2VxSmNKDw7IOHzUbXtmiEGhygyZpdh/uiCj7ziSxp3
|
# NEQHBxHJs5SMsMAXNSIcYHqVAvhF3nXoseaNBkhOTrkQ1FS/fW7AfDGRbsiiESzv
|
||||||
# lQBR8mUE1NL9dxaxKWLhGeORqAepw6nId9oO+mHRh4JRK7uqZOFAES7/21M9vPZi
|
# lebf92shZylBFKOsKQLAL0mF/B7xrxHJIj5dgQoD1phATRNHOEQj3jgmkidFWowV
|
||||||
# XYilJLgIoyMkvqYSdoouzn6+m74kgzkNkyK9GYz2mmO2BCMnai9Njze2d0+kY+37
|
# 4r8MzbxRhAEORbnJexlUoDQJQH3YwxuUyXkTvrYMTKSbGJLlwRaZQbrcBU0k4gCH
|
||||||
# kt10BmJDw3FHaZ+/fH/TMTgo0ZcAOicP9ccdIh/CzzpU52o+Q6GCEvEwghLtBgor
|
# y8Sci+p9Rq+aOTzLCoNrZyh9E7OdwVDm1FJAtY30bV50T2WSFKGCEuIwghLeBgor
|
||||||
# BgEEAYI3AwMBMYIS3TCCEtkGCSqGSIb3DQEHAqCCEsowghLGAgEDMQ8wDQYJYIZI
|
# BgEEAYI3AwMBMYISzjCCEsoGCSqGSIb3DQEHAqCCErswghK3AgEDMQ8wDQYJYIZI
|
||||||
# AWUDBAIBBQAwggFVBgsqhkiG9w0BCRABBKCCAUQEggFAMIIBPAIBAQYKKwYBBAGE
|
# AWUDBAIBBQAwggFRBgsqhkiG9w0BCRABBKCCAUAEggE8MIIBOAIBAQYKKwYBBAGE
|
||||||
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCBSbhMJwNER+BICn3iLUnPrP8dptyUphcFC
|
# WQoDATAxMA0GCWCGSAFlAwQCAQUABCD7JNcBBSfhlKPL1tN3CEKRKJuT/dZ8RO9K
|
||||||
# A/NsIgnPLwIGX4hEzP6WGBMyMDIwMTEwOTE0NDY1Mi4yMzNaMASAAgH0oIHUpIHR
|
# orYLXJeLTwIGXvN89YD7GBMyMDIwMDcwMTE0MTYyMC40MDVaMASAAgH0oIHQpIHN
|
||||||
# MIHOMQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
# MIHKMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1JlZG1vbmQx
|
||||||
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQL
|
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEtMCsGA1UECxMkTWljcm9z
|
||||||
# EyBNaWNyb3NvZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhh
|
# b2Z0IElyZWxhbmQgT3BlcmF0aW9ucyBMaW1pdGVkMSYwJAYDVQQLEx1UaGFsZXMg
|
||||||
# bGVzIFRTUyBFU046MEE1Ni1FMzI5LTRENEQxJTAjBgNVBAMTHE1pY3Jvc29mdCBU
|
# VFNTIEVTTjoxNzlFLTRCQjAtODI0NjElMCMGA1UEAxMcTWljcm9zb2Z0IFRpbWUt
|
||||||
# aW1lLVN0YW1wIFNlcnZpY2Wggg5EMIIE9TCCA92gAwIBAgITMwAAAScvbqPvkagZ
|
# U3RhbXAgU2VydmljZaCCDjkwggTxMIID2aADAgECAhMzAAABDKp4btzMQkzBAAAA
|
||||||
# qAAAAAABJzANBgkqhkiG9w0BAQsFADB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMK
|
# AAEMMA0GCSqGSIb3DQEBCwUAMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNo
|
||||||
# V2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0
|
# aW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29y
|
||||||
# IENvcnBvcmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0Eg
|
# cG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEw
|
||||||
# MjAxMDAeFw0xOTEyMTkwMTE0NTlaFw0yMTAzMTcwMTE0NTlaMIHOMQswCQYDVQQG
|
# MB4XDTE5MTAyMzIzMTkxNloXDTIxMDEyMTIzMTkxNlowgcoxCzAJBgNVBAYTAlVT
|
||||||
# EwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwG
|
# MQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9z
|
||||||
# A1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3NvZnQg
|
# b2Z0IENvcnBvcmF0aW9uMS0wKwYDVQQLEyRNaWNyb3NvZnQgSXJlbGFuZCBPcGVy
|
||||||
# T3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046
|
# YXRpb25zIExpbWl0ZWQxJjAkBgNVBAsTHVRoYWxlcyBUU1MgRVNOOjE3OUUtNEJC
|
||||||
# MEE1Ni1FMzI5LTRENEQxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNl
|
# MC04MjQ2MSUwIwYDVQQDExxNaWNyb3NvZnQgVGltZS1TdGFtcCBTZXJ2aWNlMIIB
|
||||||
# cnZpY2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD4Ad5xEZ5On0uN
|
# IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5011+XqVJmQKtiw39igeEMv
|
||||||
# L71ng9xwoDPRKeMUyEIj5yVxPRPh5GVbU7D3pqDsoXzQMhfeRP61L1zlU1HCRS+1
|
# CLcZ1forbmxsDkpnCN1SrThKI+n2Pr3zqTzJVgdJFCoKm1ks1gtRJ7HaL6tDkrOw
|
||||||
# 29eo0yj1zjbAlmPAwosUgyIonesWt9E4hFlXCGUcIg5XMdvQ+Ouzk2r+awNRuk8A
|
# 8XJmfJaxyQAluCQ+e40NI+A4w+u59Gy89AVY5lJNrmCva6gozfg1kxw6abV5WWr+
|
||||||
# BGOa0I4VBy6zqCYHyX2pGauiB43frJSNP6pcrO0CBmpBZNjgepof5Z/50vBuJDUS
|
# PjEpNCshO4hxv3UqgMcCKnT2YVSZzF1Gy7APub1fY0P1vNEuOFKrNCEEvWIKRrqs
|
||||||
# ug6OIMQ7ZwUhSzX4bEmZUUjAycBb62dhQpGqHsXe6ypVDTgAEnGONdSBKkHiNT8H
|
# eyBB73G8KD2yw6jfz0VKxNSRAdhJV/ghOyrDt5a+L6C3m1rpr8sqiof3iohv3ANI
|
||||||
# 0Zt2lm0vCLwHyTwtgIdi67T/LCp+X2mlPHqXsY3u72X3GYn/3G8YFCkrSc6m3b0w
|
# gNqw6ex+4+G+B7JMbIHbGpPdebedL6ePbuBCnbgJoDn340k0aw6ij21GvvUnkQID
|
||||||
# TXPd5/2fAgMBAAGjggEbMIIBFzAdBgNVHQ4EFgQU5fSWVYBfOTEkW2JTiV24WNNt
|
# AQABo4IBGzCCARcwHQYDVR0OBBYEFAlCOq9DDIa0A0oqgKtM5vjuZeK+MB8GA1Ud
|
||||||
# lfIwHwYDVR0jBBgwFoAU1WM6XIoxkPNDe3xGG8UzaFqFbVUwVgYDVR0fBE8wTTBL
|
# IwQYMBaAFNVjOlyKMZDzQ3t8RhvFM2hahW1VMFYGA1UdHwRPME0wS6BJoEeGRWh0
|
||||||
# oEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQuY29tL3BraS9jcmwvcHJvZHVjdHMv
|
# dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kvY3JsL3Byb2R1Y3RzL01pY1RpbVN0
|
||||||
# TWljVGltU3RhUENBXzIwMTAtMDctMDEuY3JsMFoGCCsGAQUFBwEBBE4wTDBKBggr
|
# YVBDQV8yMDEwLTA3LTAxLmNybDBaBggrBgEFBQcBAQROMEwwSgYIKwYBBQUHMAKG
|
||||||
# BgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraS9jZXJ0cy9NaWNU
|
# Pmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2kvY2VydHMvTWljVGltU3RhUENB
|
||||||
# aW1TdGFQQ0FfMjAxMC0wNy0wMS5jcnQwDAYDVR0TAQH/BAIwADATBgNVHSUEDDAK
|
# XzIwMTAtMDctMDEuY3J0MAwGA1UdEwEB/wQCMAAwEwYDVR0lBAwwCgYIKwYBBQUH
|
||||||
# BggrBgEFBQcDCDANBgkqhkiG9w0BAQsFAAOCAQEACsqNfNFVxwalZ42cEMuzZc12
|
# AwgwDQYJKoZIhvcNAQELBQADggEBAET3xBg/IZ9zdOfwbDGK7cK3qKYt/qUOlbRB
|
||||||
# 6Nvluanx8UewDVeUQZEZHRmppMFHAzS/g6RzmxTyR2tKE3mChNGW5dTL730vEbRh
|
# zgeNjb32K86nGeRGkBee10dVOEGWUw6KtBeWh1LQ70b64/tLtiLcsf9JzaAyDYb1
|
||||||
# nYRmBgiX/gT3f4AQrOPnZGXY7zszcrlbgzxpakOX+x0u4rkP3Ashh3B2CdJ11XsB
|
# sRmMi5fjRZ753TquaT8V7NJ7RfEuYfvZlubfQD0MVbU4tzsdZdYuxE37V2J9pN89
|
||||||
# di5PiZa1spB6U5S8D15gqTUfoIniLT4v1DBdkWExsKI1vsiFcDcjGJ4xRlMRF+fw
|
# j7GoFNtAnSnCn1MRxENAILgt9XzeQzTEDhFYW0N2DNphTkRPXGjpDmwi6WtkJ5fv
|
||||||
# 7SY0WZoOzwRzKxDTdg4DusAXpaeKbch9iithLFk/vIxQrqCr/niW8tEA+eSzeX/E
|
# 0iTyB4dwEC+/ed0lGbFLcytJoMwfTNMdH6gcnHlMzsniornGFZa5PPiV78XoZ9Fe
|
||||||
# q1D0ZyvOn4e2lTnwoJUKH6OQAWSBogyK4OCbFeJOqdKAUiBTgHKkQIYh/tbKQjCC
|
# upKo8ZKNGhLLLB5GTtqfHex5no3ioVSq+NthvhX0I/V+iXJsopowggZxMIIEWaAD
|
||||||
# BnEwggRZoAMCAQICCmEJgSoAAAAAAAIwDQYJKoZIhvcNAQELBQAwgYgxCzAJBgNV
|
# AgECAgphCYEqAAAAAAACMA0GCSqGSIb3DQEBCwUAMIGIMQswCQYDVQQGEwJVUzET
|
||||||
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
|
# MBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMV
|
||||||
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xMjAwBgNVBAMTKU1pY3Jvc29m
|
# TWljcm9zb2Z0IENvcnBvcmF0aW9uMTIwMAYDVQQDEylNaWNyb3NvZnQgUm9vdCBD
|
||||||
# dCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAyMDEwMB4XDTEwMDcwMTIxMzY1
|
# ZXJ0aWZpY2F0ZSBBdXRob3JpdHkgMjAxMDAeFw0xMDA3MDEyMTM2NTVaFw0yNTA3
|
||||||
# NVoXDTI1MDcwMTIxNDY1NVowfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hp
|
# MDEyMTQ2NTVaMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAw
|
||||||
# bmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jw
|
# DgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24x
|
||||||
# b3JhdGlvbjEmMCQGA1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAw
|
# JjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBDQSAyMDEwMIIBIjANBgkq
|
||||||
# ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCpHQ28dxGKOiDs/BOX9fp/
|
# hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqR0NvHcRijog7PwTl/X6f2mUa3RUENWl
|
||||||
# aZRrdFQQ1aUKAIKF++18aEssX8XD5WHCdrc+Zitb8BVTJwQxH0EbGpUdzgkTjnxh
|
# CgCChfvtfGhLLF/Fw+Vhwna3PmYrW/AVUycEMR9BGxqVHc4JE458YTBZsTBED/Fg
|
||||||
# MFmxMEQP8WCIhFRDDNdNuDgIs0Ldk6zWczBXJoKjRQ3Q6vVHgc2/JGAyWGBG8lhH
|
# iIRUQwzXTbg4CLNC3ZOs1nMwVyaCo0UN0Or1R4HNvyRgMlhgRvJYR4YyhB50YWeR
|
||||||
# hjKEHnRhZ5FfgVSxz5NMksHEpl3RYRNuKMYa+YaAu99h/EbBJx0kZxJyGiGKr0tk
|
# X4FUsc+TTJLBxKZd0WETbijGGvmGgLvfYfxGwScdJGcSchohiq9LZIlQYrFd/Xcf
|
||||||
# iVBisV39dx898Fd1rL2KQk1AUdEPnAY+Z3/1ZsADlkR+79BL/W7lmsqxqPJ6Kgox
|
# PfBXday9ikJNQFHRD5wGPmd/9WbAA5ZEfu/QS/1u5ZrKsajyeioKMfDaTgaRtogI
|
||||||
# 8NpOBpG2iAg16HgcsOmZzTznL0S6p/TcZL2kAcEgCZN4zfy8wMlEXV4WnAEFTyJN
|
# Neh4HLDpmc085y9Euqf03GS9pAHBIAmTeM38vMDJRF1eFpwBBU8iTQIDAQABo4IB
|
||||||
# AgMBAAGjggHmMIIB4jAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQU1WM6XIox
|
# 5jCCAeIwEAYJKwYBBAGCNxUBBAMCAQAwHQYDVR0OBBYEFNVjOlyKMZDzQ3t8RhvF
|
||||||
# kPNDe3xGG8UzaFqFbVUwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEwCwYDVR0P
|
# M2hahW1VMBkGCSsGAQQBgjcUAgQMHgoAUwB1AGIAQwBBMAsGA1UdDwQEAwIBhjAP
|
||||||
# BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAU1fZWy4/oolxiaNE9
|
# BgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNX2VsuP6KJcYmjRPZSQW9fOmhjE
|
||||||
# lJBb186aGMQwVgYDVR0fBE8wTTBLoEmgR4ZFaHR0cDovL2NybC5taWNyb3NvZnQu
|
# MFYGA1UdHwRPME0wS6BJoEeGRWh0dHA6Ly9jcmwubWljcm9zb2Z0LmNvbS9wa2kv
|
||||||
# Y29tL3BraS9jcmwvcHJvZHVjdHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3Js
|
# Y3JsL3Byb2R1Y3RzL01pY1Jvb0NlckF1dF8yMDEwLTA2LTIzLmNybDBaBggrBgEF
|
||||||
# MFoGCCsGAQUFBwEBBE4wTDBKBggrBgEFBQcwAoY+aHR0cDovL3d3dy5taWNyb3Nv
|
# BQcBAQROMEwwSgYIKwYBBQUHMAKGPmh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9w
|
||||||
# ZnQuY29tL3BraS9jZXJ0cy9NaWNSb29DZXJBdXRfMjAxMC0wNi0yMy5jcnQwgaAG
|
# a2kvY2VydHMvTWljUm9vQ2VyQXV0XzIwMTAtMDYtMjMuY3J0MIGgBgNVHSABAf8E
|
||||||
# A1UdIAEB/wSBlTCBkjCBjwYJKwYBBAGCNy4DMIGBMD0GCCsGAQUFBwIBFjFodHRw
|
# gZUwgZIwgY8GCSsGAQQBgjcuAzCBgTA9BggrBgEFBQcCARYxaHR0cDovL3d3dy5t
|
||||||
# Oi8vd3d3Lm1pY3Jvc29mdC5jb20vUEtJL2RvY3MvQ1BTL2RlZmF1bHQuaHRtMEAG
|
# aWNyb3NvZnQuY29tL1BLSS9kb2NzL0NQUy9kZWZhdWx0Lmh0bTBABggrBgEFBQcC
|
||||||
# CCsGAQUFBwICMDQeMiAdAEwAZQBnAGEAbABfAFAAbwBsAGkAYwB5AF8AUwB0AGEA
|
# AjA0HjIgHQBMAGUAZwBhAGwAXwBQAG8AbABpAGMAeQBfAFMAdABhAHQAZQBtAGUA
|
||||||
# dABlAG0AZQBuAHQALiAdMA0GCSqGSIb3DQEBCwUAA4ICAQAH5ohRDeLG4Jg/gXED
|
# bgB0AC4gHTANBgkqhkiG9w0BAQsFAAOCAgEAB+aIUQ3ixuCYP4FxAz2do6Ehb7Pr
|
||||||
# PZ2joSFvs+umzPUxvs8F4qn++ldtGTCzwsVmyWrf9efweL3HqJ4l4/m87WtUVwgr
|
# psz1Mb7PBeKp/vpXbRkws8LFZslq3/Xn8Hi9x6ieJeP5vO1rVFcIK1GCRBL7uVOM
|
||||||
# UYJEEvu5U4zM9GASinbMQEBBm9xcF/9c+V4XNZgkVkt070IQyK+/f8Z/8jd9Wj8c
|
# zPRgEop2zEBAQZvcXBf/XPleFzWYJFZLdO9CEMivv3/Gf/I3fVo/HPKZeUqRUgCv
|
||||||
# 8pl5SpFSAK84Dxf1L3mBZdmptWvkx872ynoAb0swRCQiPM/tA6WWj1kpvLb9BOFw
|
# OA8X9S95gWXZqbVr5MfO9sp6AG9LMEQkIjzP7QOllo9ZKby2/QThcJ8ySif9Va8v
|
||||||
# nzJKJ/1Vry/+tuWOM7tiX5rbV0Dp8c6ZZpCM/2pif93FSguRJuI57BlKcWOdeyFt
|
# /rbljjO7Yl+a21dA6fHOmWaQjP9qYn/dxUoLkSbiOewZSnFjnXshbcOco6I8+n99
|
||||||
# w5yjojz6f32WapB4pm3S4Zz5Hfw42JT0xqUKloakvZ4argRCg7i1gJsiOCC1JeVk
|
# lmqQeKZt0uGc+R38ONiU9MalCpaGpL2eGq4EQoO4tYCbIjggtSXlZOz39L9+Y1kl
|
||||||
# 7Pf0v35jWSUPei45V3aicaoGig+JFrphpxHLmtgOR5qAxdDNp9DvfYPw4TtxCd9d
|
# D3ouOVd2onGqBooPiRa6YacRy5rYDkeagMXQzafQ732D8OE7cQnfXXSYIghh2rBQ
|
||||||
# dJgiCGHasFAeb73x4QDf5zEHpJM692VHeOj4qEir995yfmFrb3epgcunCaw5u+zG
|
# Hm+98eEA3+cxB6STOvdlR3jo+KhIq/fecn5ha293qYHLpwmsObvsxsvYgrRyzR30
|
||||||
# y9iCtHLNHfS4hQEegPsbiSpUObJb2sgNVZl6h3M7COaYLeqN4DMuEin1wC9UJyH3
|
# uIUBHoD7G4kqVDmyW9rIDVWZeodzOwjmmC3qjeAzLhIp9cAvVCch98isTtoouLGp
|
||||||
# yKxO2ii4sanblrKnQqLJzxlBTeCG+SqaoxFmMNO7dDJL32N79ZmKLxvHIa9Zta7c
|
# 25ayp0Kiyc8ZQU3ghvkqmqMRZjDTu3QyS99je/WZii8bxyGvWbWu3EQ8l1Bx16HS
|
||||||
# RDyXUHHXodLFVeNp3lfB0d4wwP3M5k37Db9dT+mdHhk4L7zPWAUu7w2gUDXa7wkn
|
# xVXjad5XwdHeMMD9zOZN+w2/XU/pnR4ZOC+8z1gFLu8NoFA12u8JJxzVs341Hgi6
|
||||||
# HNWzfjUeCLraNtvTX4/edIhJEqGCAtIwggI7AgEBMIH8oYHUpIHRMIHOMQswCQYD
|
# 2jbb01+P3nSISRKhggLLMIICNAIBATCB+KGB0KSBzTCByjELMAkGA1UEBhMCVVMx
|
||||||
# VQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEe
|
# CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
|
||||||
# MBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSkwJwYDVQQLEyBNaWNyb3Nv
|
# ZnQgQ29ycG9yYXRpb24xLTArBgNVBAsTJE1pY3Jvc29mdCBJcmVsYW5kIE9wZXJh
|
||||||
# ZnQgT3BlcmF0aW9ucyBQdWVydG8gUmljbzEmMCQGA1UECxMdVGhhbGVzIFRTUyBF
|
# dGlvbnMgTGltaXRlZDEmMCQGA1UECxMdVGhhbGVzIFRTUyBFU046MTc5RS00QkIw
|
||||||
# U046MEE1Ni1FMzI5LTRENEQxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1w
|
# LTgyNDYxJTAjBgNVBAMTHE1pY3Jvc29mdCBUaW1lLVN0YW1wIFNlcnZpY2WiIwoB
|
||||||
# IFNlcnZpY2WiIwoBATAHBgUrDgMCGgMVALOVuE5sgxzETO4s+poBqI6r1x8zoIGD
|
# ATAHBgUrDgMCGgMVAMsg9FQ9pgPLXI2Ld5z7xDS0QAZ9oIGDMIGApH4wfDELMAkG
|
||||||
# MIGApH4wfDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNV
|
# A1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQx
|
||||||
# BAcTB1JlZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQG
|
# HjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEmMCQGA1UEAxMdTWljcm9z
|
||||||
# A1UEAxMdTWljcm9zb2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEF
|
# b2Z0IFRpbWUtU3RhbXAgUENBIDIwMTAwDQYJKoZIhvcNAQEFBQACBQDipo0MMCIY
|
||||||
# BQACBQDjU7byMCIYDzIwMjAxMTA5MTYzOTE0WhgPMjAyMDExMTAxNjM5MTRaMHcw
|
# DzIwMjAwNzAxMTIxODIwWhgPMjAyMDA3MDIxMjE4MjBaMHQwOgYKKwYBBAGEWQoE
|
||||||
# PQYKKwYBBAGEWQoEATEvMC0wCgIFAONTtvICAQAwCgIBAAICIt0CAf8wBwIBAAIC
|
# ATEsMCowCgIFAOKmjQwCAQAwBwIBAAICE70wBwIBAAICEeIwCgIFAOKn3owCAQAw
|
||||||
# EcQwCgIFAONVCHICAQAwNgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAK
|
# NgYKKwYBBAGEWQoEAjEoMCYwDAYKKwYBBAGEWQoDAqAKMAgCAQACAwehIKEKMAgC
|
||||||
# MAgCAQACAwehIKEKMAgCAQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQAQhyIIAC/A
|
# AQACAwGGoDANBgkqhkiG9w0BAQUFAAOBgQCOPjlHOH8nYtgt2XnpKXenxPUR03ED
|
||||||
# P+VJdbhL9IQgm8WTa1DmPPE+BQSuRbBy2MmzC1KostixdEkr2OaNSjcYuZBNIJgv
|
# xPBm8XR5Z1vIq53RU9jG6yYcYNTdK+q38SGZtu0W/SgagTfKCQhjhRakuv7rGSs2
|
||||||
# vE8CWhVDD+sbBpVcOdoSfoBwHXKfvqSTiWvovoexkF0X5aon7yr3PkJ/kEqoLyUM
|
# dlhx9LGCoc/q1vqmZpRSjkqWVcc/NzmldUWIWnLlV6rmLGoDmfCH5BcsiU6Eo6wU
|
||||||
# xRvdWKJdHOL1sT0/aWHn048c6aGin/zc8DGCAw0wggMJAgEBMIGTMHwxCzAJBgNV
|
# iUVwnnXoqsCaBzGCAw0wggMJAgEBMIGTMHwxCzAJBgNVBAYTAlVTMRMwEQYDVQQI
|
||||||
# BAYTAlVTMRMwEQYDVQQIEwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4w
|
# EwpXYXNoaW5ndG9uMRAwDgYDVQQHEwdSZWRtb25kMR4wHAYDVQQKExVNaWNyb3Nv
|
||||||
# HAYDVQQKExVNaWNyb3NvZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29m
|
# ZnQgQ29ycG9yYXRpb24xJjAkBgNVBAMTHU1pY3Jvc29mdCBUaW1lLVN0YW1wIFBD
|
||||||
# dCBUaW1lLVN0YW1wIFBDQSAyMDEwAhMzAAABJy9uo++RqBmoAAAAAAEnMA0GCWCG
|
# QSAyMDEwAhMzAAABDKp4btzMQkzBAAAAAAEMMA0GCWCGSAFlAwQCAQUAoIIBSjAa
|
||||||
# SAFlAwQCAQUAoIIBSjAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZI
|
# BgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwLwYJKoZIhvcNAQkEMSIEIDpwhjyu
|
||||||
# hvcNAQkEMSIEIJZkrbvF4R8oqYYpN6ZPGOj+QEZTQriEi/Yw9gW6zMqRMIH6Bgsq
|
# zgu3Kmxpnpz86ZlthBqEzG5vaEMOkYRyuFCaMIH6BgsqhkiG9w0BCRACLzGB6jCB
|
||||||
# hkiG9w0BCRACLzGB6jCB5zCB5DCBvQQgG5LoSxKGHWoW/wVMlbMztlQ4upAdzEmq
|
# 5zCB5DCBvQQgg5AWKX7M1+m2//+V7qmRvt1K/ww5Muu8XzGJBqygVCkwgZgwgYCk
|
||||||
# H//vLu0jPiIwgZgwgYCkfjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGlu
|
# fjB8MQswCQYDVQQGEwJVUzETMBEGA1UECBMKV2FzaGluZ3RvbjEQMA4GA1UEBxMH
|
||||||
# Z3RvbjEQMA4GA1UEBxMHUmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBv
|
# UmVkbW9uZDEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMSYwJAYDVQQD
|
||||||
# cmF0aW9uMSYwJAYDVQQDEx1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAIT
|
# Ex1NaWNyb3NvZnQgVGltZS1TdGFtcCBQQ0EgMjAxMAITMwAAAQyqeG7czEJMwQAA
|
||||||
# MwAAAScvbqPvkagZqAAAAAABJzAiBCDwhEViCRvqKwQV3MxociF2iGYrDP4p1BK+
|
# AAABDDAiBCD11urvv5vgo4gFVQ2NMVrzgxT87Yuiq16YdswYbaYeITANBgkqhkiG
|
||||||
# s4tStO4vSDANBgkqhkiG9w0BAQsFAASCAQAkgmDo8lVmar0ZIqTG1it3skG8PZC9
|
# 9w0BAQsFAASCAQAi3q8hwcT2ft4b2EleaiyZxOImV/cKusmth1dtCh5/Jb0GbOld
|
||||||
# iqEEC1vxcz8OSfsjl2QSkQ5T2+3xWpxWA4uy2+Byv0bi8EsfQEnnn4vtdthS6/kb
|
# f5cSalrjf42MNPodWAtgmWozkYrQF6HxnsOiYiamfRA8E3E7xyRMy7AFfAhjcwMi
|
||||||
# vB/LLQiqoMhJ0rasf3/y/4KnQZEtztpg1+cCaNwFUgI6o+E8YEFt1frhLwFs/0WH
|
# xaW4Iye6E1Ec6LtULANxfDtG/KIdCWdZxKqOezL3nzFNQWmm1mXPV+UnKpnJkA3E
|
||||||
# 5pyBFx9ECEs0M22SLIpW13gexv9fgk6ZboIfSreAI28DLveeJpkgwggxHRpuVOVD
|
# DsQOUWk8J6ojDurhrP536WI+3arg8PcnppHBLd/xNKYdlsTb+6qndgzKXkDDt1CV
|
||||||
# 4D7QQJAvJ0VU6p+yJlbvQXR9iltwb1REhlsJ5mADJ/FkzPVX/swMSUIoyE2inlxK
|
# 4zCyuZ7bO8eyZAmNoSZz22k7vus9UjBz/CDhXylo20N43nr29rWPItUgH4uvOGQn
|
||||||
# LEiPkkZYwiFYCifFYUTnQjWU1Ls0EV+ysosL+jhzCxO8S6oRdp5TAi4F
|
# t26Y/yjBaQImz32psrfJEMbQ7cl789s8WOx8
|
||||||
# SIG # End signature block
|
# SIG # End signature block
|
||||||
105
src/Misc/dotnet-install.sh
vendored
105
src/Misc/dotnet-install.sh
vendored
@@ -241,6 +241,42 @@ check_min_reqs() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_pre_reqs() {
|
||||||
|
eval $invocation
|
||||||
|
|
||||||
|
if [ "${DOTNET_INSTALL_SKIP_PREREQS:-}" = "1" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$(uname)" = "Linux" ]; then
|
||||||
|
if is_musl_based_distro; then
|
||||||
|
if ! command -v scanelf > /dev/null; then
|
||||||
|
say_warning "scanelf not found, please install pax-utils package."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
LDCONFIG_COMMAND="scanelf --ldpath -BF '%f'"
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep libintl)" ] && say_warning "Unable to locate libintl. Probable prerequisite missing; install libintl (or gettext)."
|
||||||
|
else
|
||||||
|
if [ ! -x "$(command -v ldconfig)" ]; then
|
||||||
|
say_verbose "ldconfig is not in PATH, trying /sbin/ldconfig."
|
||||||
|
LDCONFIG_COMMAND="/sbin/ldconfig"
|
||||||
|
else
|
||||||
|
LDCONFIG_COMMAND="ldconfig"
|
||||||
|
fi
|
||||||
|
local librarypath=${LD_LIBRARY_PATH:-}
|
||||||
|
LDCONFIG_COMMAND="$LDCONFIG_COMMAND -NXv ${librarypath//:/ }"
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep zlib)" ] && say_warning "Unable to locate zlib. Probable prerequisite missing; install zlib."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep ssl)" ] && say_warning "Unable to locate libssl. Probable prerequisite missing; install libssl."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep libicu)" ] && say_warning "Unable to locate libicu. Probable prerequisite missing; install libicu."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep lttng)" ] && say_warning "Unable to locate liblttng. Probable prerequisite missing; install libcurl."
|
||||||
|
[ -z "$($LDCONFIG_COMMAND 2>/dev/null | grep libcurl)" ] && say_warning "Unable to locate libcurl. Probable prerequisite missing; install libcurl."
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
# args:
|
# args:
|
||||||
# input - $1
|
# input - $1
|
||||||
to_lowercase() {
|
to_lowercase() {
|
||||||
@@ -337,7 +373,7 @@ get_normalized_architecture_from_architecture() {
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
say_err "Architecture \`$architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/install-scripts/issues"
|
say_err "Architecture \`$architecture\` not supported. If you think this is a bug, report it at https://github.com/dotnet/sdk/issues"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,6 +468,7 @@ parse_jsonfile_for_version() {
|
|||||||
sdk_list=$(echo $sdk_section | awk -F"[{}]" '{print $2}')
|
sdk_list=$(echo $sdk_section | awk -F"[{}]" '{print $2}')
|
||||||
sdk_list=${sdk_list//[\" ]/}
|
sdk_list=${sdk_list//[\" ]/}
|
||||||
sdk_list=${sdk_list//,/$'\n'}
|
sdk_list=${sdk_list//,/$'\n'}
|
||||||
|
sdk_list="$(echo -e "${sdk_list}" | tr -d '[[:space:]]')"
|
||||||
|
|
||||||
local version_info=""
|
local version_info=""
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
@@ -508,18 +545,17 @@ construct_download_link() {
|
|||||||
local channel="$2"
|
local channel="$2"
|
||||||
local normalized_architecture="$3"
|
local normalized_architecture="$3"
|
||||||
local specific_version="${4//[$'\t\r\n']}"
|
local specific_version="${4//[$'\t\r\n']}"
|
||||||
local specific_product_version="$(get_specific_product_version "$1" "$4")"
|
|
||||||
|
|
||||||
local osname
|
local osname
|
||||||
osname="$(get_current_os_name)" || return 1
|
osname="$(get_current_os_name)" || return 1
|
||||||
|
|
||||||
local download_link=null
|
local download_link=null
|
||||||
if [[ "$runtime" == "dotnet" ]]; then
|
if [[ "$runtime" == "dotnet" ]]; then
|
||||||
download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_product_version-$osname-$normalized_architecture.tar.gz"
|
download_link="$azure_feed/Runtime/$specific_version/dotnet-runtime-$specific_version-$osname-$normalized_architecture.tar.gz"
|
||||||
elif [[ "$runtime" == "aspnetcore" ]]; then
|
elif [[ "$runtime" == "aspnetcore" ]]; then
|
||||||
download_link="$azure_feed/aspnetcore/Runtime/$specific_version/aspnetcore-runtime-$specific_product_version-$osname-$normalized_architecture.tar.gz"
|
download_link="$azure_feed/aspnetcore/Runtime/$specific_version/aspnetcore-runtime-$specific_version-$osname-$normalized_architecture.tar.gz"
|
||||||
elif [ -z "$runtime" ]; then
|
elif [ -z "$runtime" ]; then
|
||||||
download_link="$azure_feed/Sdk/$specific_version/dotnet-sdk-$specific_product_version-$osname-$normalized_architecture.tar.gz"
|
download_link="$azure_feed/Sdk/$specific_version/dotnet-sdk-$specific_version-$osname-$normalized_architecture.tar.gz"
|
||||||
else
|
else
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -528,50 +564,6 @@ construct_download_link() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
# args:
|
|
||||||
# azure_feed - $1
|
|
||||||
# specific_version - $2
|
|
||||||
get_specific_product_version() {
|
|
||||||
# If we find a 'productVersion.txt' at the root of any folder, we'll use its contents
|
|
||||||
# to resolve the version of what's in the folder, superseding the specified version.
|
|
||||||
eval $invocation
|
|
||||||
|
|
||||||
local azure_feed="$1"
|
|
||||||
local specific_version="${2//[$'\t\r\n']}"
|
|
||||||
local specific_product_version=$specific_version
|
|
||||||
|
|
||||||
local download_link=null
|
|
||||||
if [[ "$runtime" == "dotnet" ]]; then
|
|
||||||
download_link="$azure_feed/Runtime/$specific_version/productVersion.txt${feed_credential}"
|
|
||||||
elif [[ "$runtime" == "aspnetcore" ]]; then
|
|
||||||
download_link="$azure_feed/aspnetcore/Runtime/$specific_version/productVersion.txt${feed_credential}"
|
|
||||||
elif [ -z "$runtime" ]; then
|
|
||||||
download_link="$azure_feed/Sdk/$specific_version/productVersion.txt${feed_credential}"
|
|
||||||
else
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if machine_has "curl"
|
|
||||||
then
|
|
||||||
specific_product_version=$(curl -s --fail "$download_link")
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
specific_product_version=$specific_version
|
|
||||||
fi
|
|
||||||
elif machine_has "wget"
|
|
||||||
then
|
|
||||||
specific_product_version=$(wget -qO- "$download_link")
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
specific_product_version=$specific_version
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
specific_product_version="${specific_product_version//[$'\t\r\n']}"
|
|
||||||
|
|
||||||
echo "$specific_product_version"
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# args:
|
# args:
|
||||||
# azure_feed - $1
|
# azure_feed - $1
|
||||||
# channel - $2
|
# channel - $2
|
||||||
@@ -779,7 +771,6 @@ calculate_vars() {
|
|||||||
say_verbose "normalized_architecture=$normalized_architecture"
|
say_verbose "normalized_architecture=$normalized_architecture"
|
||||||
|
|
||||||
specific_version="$(get_specific_version_from_version "$azure_feed" "$channel" "$normalized_architecture" "$version" "$json_file")"
|
specific_version="$(get_specific_version_from_version "$azure_feed" "$channel" "$normalized_architecture" "$version" "$json_file")"
|
||||||
specific_product_version="$(get_specific_product_version "$azure_feed" "$specific_version")"
|
|
||||||
say_verbose "specific_version=$specific_version"
|
say_verbose "specific_version=$specific_version"
|
||||||
if [ -z "$specific_version" ]; then
|
if [ -z "$specific_version" ]; then
|
||||||
say_err "Could not resolve version information."
|
say_err "Could not resolve version information."
|
||||||
@@ -878,12 +869,12 @@ install_dotnet() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if the standard SDK version is installed.
|
# Check if the standard SDK version is installed.
|
||||||
say_verbose "Checking installation: version = $specific_product_version"
|
say_verbose "Checking installation: version = $specific_version"
|
||||||
if is_dotnet_package_installed "$install_root" "$asset_relative_path" "$specific_product_version"; then
|
if is_dotnet_package_installed "$install_root" "$asset_relative_path" "$specific_version"; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say_err "\`$asset_name\` with version = $specific_product_version failed to install with an unknown error."
|
say_err "\`$asset_name\` with version = $specific_version failed to install with an unknown error."
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,11 +1058,6 @@ if [ "$no_cdn" = true ]; then
|
|||||||
azure_feed="$uncached_feed"
|
azure_feed="$uncached_feed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say "Note that the intended use of this script is for Continuous Integration (CI) scenarios, where:"
|
|
||||||
say "- The SDK needs to be installed without user interaction and without admin rights."
|
|
||||||
say "- The SDK installation doesn't need to persist across multiple CI runs."
|
|
||||||
say "To set up a development environment or to run apps, use installers rather than this script. Visit https://dotnet.microsoft.com/download to get the installer.\n"
|
|
||||||
|
|
||||||
check_min_reqs
|
check_min_reqs
|
||||||
calculate_vars
|
calculate_vars
|
||||||
script_name=$(basename "$0")
|
script_name=$(basename "$0")
|
||||||
@@ -1093,6 +1079,7 @@ if [ "$dry_run" = true ]; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
check_pre_reqs
|
||||||
install_dotnet
|
install_dotnet
|
||||||
|
|
||||||
bin_path="$(get_absolute_path "$(combine_paths "$install_root" "$bin_folder_relative_path")")"
|
bin_path="$(get_absolute_path "$(combine_paths "$install_root" "$bin_folder_relative_path")")"
|
||||||
@@ -1103,6 +1090,4 @@ else
|
|||||||
say "Binaries of dotnet can be found in $bin_path"
|
say "Binaries of dotnet can be found in $bin_path"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
say "Note that the script does not resolve dependencies during installation."
|
|
||||||
say "To check the list of dependencies, go to https://docs.microsoft.com/dotnet/core/install, select your operating system and check the \"Dependencies\" section."
|
|
||||||
say "Installation finished successfully."
|
say "Installation finished successfully."
|
||||||
|
|||||||
18
src/Misc/download-runner.sh
Executable file
18
src/Misc/download-runner.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# 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_DOWNLOAD_URL=$(curl -s -X GET ${GITHUB_API_URL}/${orgs_or_repos}/${GITHUB_RUNNER_SCOPE}/actions/runners/downloads -H "authorization: token $GITHUB_PAT" -H "accept: application/vnd.github.everest-preview+json" | jq -r '.[]|select(.os=="linux" and .architecture=="x64")|.download_url')
|
||||||
|
|
||||||
|
# download actions and unzip it
|
||||||
|
#curl -Ls ${RUNNER_DOWNLOAD_URL} | tar xz \
|
||||||
|
|
||||||
|
curl -Ls https://github.com/TingluoHuang/runner/releases/download/test/actions-runner-linux-x64-2.299.0.tar.gz | tar xz
|
||||||
|
|
||||||
|
# delete the download tar.gz file
|
||||||
|
rm -f ${RUNNER_DOWNLOAD_URL##*/}
|
||||||
77
src/Misc/entrypoint.sh
Executable file
77
src/Misc/entrypoint.sh
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/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 --name $RUNNER_NAME --url $RUNNER_CONFIG_URL --pat $GITHUB_PAT $RUNNER_LABELS_ARG $RUNNER_GROUP_ARG --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
|
||||||
|
unset RUNNER_NAME
|
||||||
|
unset RUNNER_GROUP
|
||||||
|
unset RUNNER_LABELS
|
||||||
|
unset RUNNER_LABELS_ARG
|
||||||
|
unset RUNNER_GROUP_ARG
|
||||||
|
|
||||||
|
# Run it
|
||||||
|
./bin/runsvc.sh interactive
|
||||||
|
|
||||||
|
# export http_proxy=""
|
||||||
|
# dockerdpid=$(kubectl exec $K8S_POD_NAME --container docker-host -- pidof dockerd)
|
||||||
|
# kubectl exec $K8S_POD_NAME --container docker-host -- kill -SIGINT $dockerdpid
|
||||||
@@ -5,9 +5,9 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": {
|
"@actions/core": {
|
||||||
"version": "1.2.6",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.2.0.tgz",
|
||||||
"integrity": "sha512-ZQYitnqiyBc3D+k7LsgSBmMDVkOVidaagDG7j3fOym77jNunWRuYx7VSHa9GNfFZh+zh61xsCjRj4JxMZlDqTA=="
|
"integrity": "sha512-ZKdyhlSlyz38S6YFfPnyNgCDZuAF2T0Qv5eHflNWytPS8Qjvz39bZFMry9Bb/dpSnqWcNeav5yM2CTYpJeY+Dw=="
|
||||||
},
|
},
|
||||||
"@actions/glob": {
|
"@actions/glob": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
|
|||||||
25
src/Misc/jobcomplete.sh
Executable file
25
src/Misc/jobcomplete.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "Test-0"
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "Test-1"
|
||||||
|
function fatal() {
|
||||||
|
echo "error: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Test-2"
|
||||||
|
[ -n "${K8S_POD_NAME:-""}" ] || fatal "K8S_POD_NAME variable must be set"
|
||||||
|
|
||||||
|
echo "Test-3"
|
||||||
|
# echo $http_proxy
|
||||||
|
# unset http_proxy
|
||||||
|
# unset https_proxy
|
||||||
|
# export http_proxy=
|
||||||
|
# export HTTP_PROXY=
|
||||||
|
|
||||||
|
echo "Test-4"
|
||||||
|
kubectl annotate pods $K8S_POD_NAME JOBCOMPLETE=$(date +%s) || fatal "Can't annotate job complete"
|
||||||
|
|
||||||
|
echo "Test-5"
|
||||||
|
exit 0
|
||||||
25
src/Misc/jobrunning.sh
Executable file
25
src/Misc/jobrunning.sh
Executable file
@@ -0,0 +1,25 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "Test-0"
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "Test-1"
|
||||||
|
function fatal() {
|
||||||
|
echo "error: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Test-2"
|
||||||
|
[ -n "${K8S_POD_NAME:-""}" ] || fatal "K8S_POD_NAME variable must be set"
|
||||||
|
|
||||||
|
echo "Test-3"
|
||||||
|
# echo $http_proxy
|
||||||
|
# unset http_proxy
|
||||||
|
# unset https_proxy
|
||||||
|
# export http_proxy=
|
||||||
|
# export HTTP_PROXY=
|
||||||
|
|
||||||
|
echo "Test-4"
|
||||||
|
kubectl annotate pods $K8S_POD_NAME JOBRUNNING=$(date +%s) --overwrite || fatal "Can't annotate job running"
|
||||||
|
|
||||||
|
echo "Test-5"
|
||||||
|
exit 0
|
||||||
32
src/Misc/jobstart.sh
Executable file
32
src/Misc/jobstart.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
echo "Test-0"
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
echo "Test-1"
|
||||||
|
function fatal() {
|
||||||
|
echo "error: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Test-2"
|
||||||
|
[ -n "${K8S_POD_NAME:-""}" ] || fatal "K8S_POD_NAME variable must be set"
|
||||||
|
|
||||||
|
echo "Test-3"
|
||||||
|
# echo $http_proxy
|
||||||
|
# # unset http_proxy
|
||||||
|
# # unset https_proxy
|
||||||
|
# export http_proxy=
|
||||||
|
# export HTTP_PROXY=
|
||||||
|
|
||||||
|
echo "Test-4"
|
||||||
|
kubectl -v9 get pod
|
||||||
|
|
||||||
|
echo "Test-5"
|
||||||
|
echo $K8S_POD_NAME
|
||||||
|
timestamp=$(date +%s)
|
||||||
|
echo $timestamp
|
||||||
|
|
||||||
|
kubectl annotate pods $K8S_POD_NAME JOBSTART=$timestamp
|
||||||
|
|
||||||
|
echo "Test-5"
|
||||||
@@ -23,7 +23,5 @@
|
|||||||
<key>ACTIONS_RUNNER_SVC</key>
|
<key>ACTIONS_RUNNER_SVC</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
</dict>
|
</dict>
|
||||||
<key>ProcessType</key>
|
|
||||||
<string>Interactive</string>
|
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -49,67 +49,69 @@ then
|
|||||||
cat /etc/debian_version
|
cat /etc/debian_version
|
||||||
echo "------------------------------"
|
echo "------------------------------"
|
||||||
|
|
||||||
# prefer apt-get over apt
|
# prefer apt over apt-get
|
||||||
command -v apt-get
|
command -v apt
|
||||||
if [ $? -eq 0 ]
|
if [ $? -eq 0 ]
|
||||||
then
|
then
|
||||||
apt_get=apt-get
|
apt update && apt install -y liblttng-ust0 libkrb5-3 zlib1g
|
||||||
else
|
if [ $? -ne 0 ]
|
||||||
command -v apt
|
|
||||||
if [ $? -eq 0 ]
|
|
||||||
then
|
then
|
||||||
apt_get=apt
|
echo "'apt' failed with exit code '$?'"
|
||||||
else
|
|
||||||
echo "Found neither 'apt-get' nor 'apt'"
|
|
||||||
print_errormessage
|
print_errormessage
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
|
||||||
|
|
||||||
$apt_get update && $apt_get install -y liblttng-ust0 libkrb5-3 zlib1g
|
# libissl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
||||||
if [ $? -ne 0 ]
|
apt install -y libssl1.1$ || apt install -y libssl1.0.2$ || apt install -y libssl1.0.0$
|
||||||
then
|
if [ $? -ne 0 ]
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
|
||||||
print_errormessage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
apt_get_with_fallbacks() {
|
|
||||||
$apt_get install -y $1
|
|
||||||
fail=$?
|
|
||||||
if [ $fail -eq 0 ]
|
|
||||||
then
|
then
|
||||||
if [ "${1#"${1%?}"}" = '$' ]; then
|
echo "'apt' failed with exit code '$?'"
|
||||||
dpkg -l "${1%?}" > /dev/null 2> /dev/null
|
print_errormessage
|
||||||
fail=$?
|
exit 1
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
if [ $fail -ne 0 ]
|
|
||||||
|
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
||||||
|
apt install -y libicu66 || apt install -y libicu63 || apt install -y libicu60 || apt install -y libicu57 || apt install -y libicu55 || apt install -y libicu52
|
||||||
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
shift
|
echo "'apt' failed with exit code '$?'"
|
||||||
if [ -n "$1" ]
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
command -v apt-get
|
||||||
|
if [ $? -eq 0 ]
|
||||||
|
then
|
||||||
|
apt-get update && apt-get install -y liblttng-ust0 libkrb5-3 zlib1g
|
||||||
|
if [ $? -ne 0 ]
|
||||||
then
|
then
|
||||||
apt_get_with_fallbacks "$@"
|
echo "'apt-get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# libissl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
||||||
|
apt-get install -y libssl1.1$ || apt-get install -y libssl1.0.2$ || apt install -y libssl1.0.0$
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "'apt-get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
||||||
|
apt-get install -y libicu66 || apt-get install -y libicu63 || apt-get install -y libicu60 || apt install -y libicu57 || apt install -y libicu55 || apt install -y libicu52
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "'apt-get' failed with exit code '$?'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Can not find 'apt' or 'apt-get'"
|
||||||
|
print_errormessage
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
|
||||||
|
|
||||||
# libssl version prefer: libssl1.1 -> libssl1.0.2 -> libssl1.0.0
|
|
||||||
apt_get_with_fallbacks libssl1.1$ libssl1.0.2$ libssl1.0.0$
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
|
||||||
print_errormessage
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# libicu version prefer: libicu66 -> libicu63 -> libicu60 -> libicu57 -> libicu55 -> libicu52
|
|
||||||
apt_get_with_fallbacks libicu66 libicu63 libicu60 libicu57 libicu55 libicu52
|
|
||||||
if [ $? -ne 0 ]
|
|
||||||
then
|
|
||||||
echo "'$apt_get' failed with exit code '$?'"
|
|
||||||
print_errormessage
|
|
||||||
exit 1
|
|
||||||
fi
|
fi
|
||||||
elif [ -e /etc/redhat-release ]
|
elif [ -e /etc/redhat-release ]
|
||||||
then
|
then
|
||||||
|
|||||||
4
src/Misc/layoutbin/update.sh.template
Executable file → Normal file
4
src/Misc/layoutbin/update.sh.template
Executable file → Normal file
@@ -28,13 +28,13 @@ date "+[%F %T-%4N] Waiting for $runnerprocessname ($runnerpid) to complete" >> "
|
|||||||
while [ -e /proc/$runnerpid ]
|
while [ -e /proc/$runnerpid ]
|
||||||
do
|
do
|
||||||
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Process $runnerpid still running" >> "$logfile" 2>&1
|
||||||
sleep 2
|
ping -c 2 127.0.0.1 >nul
|
||||||
done
|
done
|
||||||
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Process $runnerpid finished running" >> "$logfile" 2>&1
|
||||||
|
|
||||||
# start re-organize folders
|
# start re-organize folders
|
||||||
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
date "+[%F %T-%4N] Sleep 1 more second to make sure process exited" >> "$logfile" 2>&1
|
||||||
sleep 1
|
ping -c 2 127.0.0.1 >nul
|
||||||
|
|
||||||
# the folder structure under runner root will be
|
# the folder structure under runner root will be
|
||||||
# ./bin -> bin.2.100.0 (junction folder)
|
# ./bin -> bin.2.100.0 (junction folder)
|
||||||
|
|||||||
@@ -18,26 +18,24 @@ then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
message="Execute sudo ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
|
||||||
|
|
||||||
ldd ./bin/libcoreclr.so | grep 'not found'
|
ldd ./bin/libcoreclr.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ldd ./bin/System.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
ldd ./bin/System.Security.Cryptography.Native.OpenSsl.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
ldd ./bin/System.IO.Compression.Native.so | grep 'not found'
|
ldd ./bin/System.IO.Compression.Native.so | grep 'not found'
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "Dependencies is missing for Dotnet Core 3.0"
|
echo "Dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -52,10 +50,10 @@ then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
libpath=${LD_LIBRARY_PATH:-}
|
libpath=${LD_LIBRARY_PATH:-}
|
||||||
$LDCONFIG_COMMAND -NXv ${libpath//:/ } 2>&1 | grep libicu >/dev/null 2>&1
|
$LDCONFIG_COMMAND -NXv ${libpath//:/} 2>&1 | grep libicu >/dev/null 2>&1
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
echo "Libicu's dependencies is missing for Dotnet Core 3.0"
|
echo "Libicu's dependencies is missing for Dotnet Core 3.0"
|
||||||
echo $message
|
echo "Execute ./bin/installdependencies.sh to install any missing Dotnet Core 3.0 dependencies."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
23
src/Misc/runner_lifecycle.sh
Executable file
23
src/Misc/runner_lifecycle.sh
Executable file
@@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
EVENT=$1
|
||||||
|
TIMESTAMP=$2
|
||||||
|
|
||||||
|
echo $EVENT
|
||||||
|
echo $TIMESTAMP
|
||||||
|
|
||||||
|
function fatal() {
|
||||||
|
echo "error: $1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[ -n "${K8S_POD_NAME:-""}" ] || fatal "K8S_POD_NAME variable must be set"
|
||||||
|
echo $K8S_POD_NAME
|
||||||
|
|
||||||
|
kubectl get pod
|
||||||
|
|
||||||
|
kubectl annotate pods $K8S_POD_NAME $EVENT=$TIMESTAMP
|
||||||
|
|
||||||
|
echo "DONE"
|
||||||
@@ -33,6 +33,9 @@ namespace GitHub.Runner.Common
|
|||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string PoolName { get; set; }
|
public string PoolName { get; set; }
|
||||||
|
|
||||||
|
[DataMember(EmitDefaultValue = false)]
|
||||||
|
public bool Ephemeral { get; set; }
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public string ServerUrl { get; set; }
|
public string ServerUrl { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ namespace GitHub.Runner.Common
|
|||||||
public static readonly string Labels = "labels";
|
public static readonly string Labels = "labels";
|
||||||
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
public static readonly string MonitorSocketAddress = "monitorsocketaddress";
|
||||||
public static readonly string Name = "name";
|
public static readonly string Name = "name";
|
||||||
public static readonly string RunnerGroup = "runnergroup";
|
public static readonly string Pool = "pool";
|
||||||
public static readonly string StartupType = "startuptype";
|
public static readonly string StartupType = "startuptype";
|
||||||
public static readonly string Url = "url";
|
public static readonly string Url = "url";
|
||||||
public static readonly string UserName = "username";
|
public static readonly string UserName = "username";
|
||||||
@@ -99,9 +99,11 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
// Secret args. Must be added to the "Secrets" getter as well.
|
// Secret args. Must be added to the "Secrets" getter as well.
|
||||||
public static readonly string Token = "token";
|
public static readonly string Token = "token";
|
||||||
|
public static readonly string PAT = "pat";
|
||||||
public static readonly string WindowsLogonPassword = "windowslogonpassword";
|
public static readonly string WindowsLogonPassword = "windowslogonpassword";
|
||||||
public static string[] Secrets => new[]
|
public static string[] Secrets => new[]
|
||||||
{
|
{
|
||||||
|
PAT,
|
||||||
Token,
|
Token,
|
||||||
WindowsLogonPassword,
|
WindowsLogonPassword,
|
||||||
};
|
};
|
||||||
@@ -120,9 +122,9 @@ namespace GitHub.Runner.Common
|
|||||||
public static class Flags
|
public static class Flags
|
||||||
{
|
{
|
||||||
public static readonly string Commit = "commit";
|
public static readonly string Commit = "commit";
|
||||||
|
public static readonly string Ephemeral = "ephemeral";
|
||||||
public static readonly string Help = "help";
|
public static readonly string Help = "help";
|
||||||
public static readonly string Replace = "replace";
|
public static readonly string Replace = "replace";
|
||||||
public static readonly string Once = "once";
|
|
||||||
public static readonly string RunAsService = "runasservice";
|
public static readonly string RunAsService = "runasservice";
|
||||||
public static readonly string Unattended = "unattended";
|
public static readonly string Unattended = "unattended";
|
||||||
public static readonly string Version = "version";
|
public static readonly string Version = "version";
|
||||||
@@ -140,8 +142,6 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
public static readonly string InternalTelemetryIssueDataKey = "_internal_telemetry";
|
||||||
public static readonly string WorkerCrash = "WORKER_CRASH";
|
public static readonly string WorkerCrash = "WORKER_CRASH";
|
||||||
public static readonly string UnsupportedCommand = "UNSUPPORTED_COMMAND";
|
|
||||||
public static readonly string UnsupportedCommandMessageDisabled = "The `{0}` command is disabled. Please upgrade to using Environment Files or opt into unsecure command execution by setting the `ACTIONS_ALLOW_UNSECURE_COMMANDS` environment variable to `true`. For more information see: https://github.blog/changelog/2020-10-01-github-actions-deprecating-set-env-and-add-path-commands/";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RunnerEvent
|
public static class RunnerEvent
|
||||||
@@ -200,7 +200,6 @@ namespace GitHub.Runner.Common
|
|||||||
//
|
//
|
||||||
// Keep alphabetical
|
// Keep alphabetical
|
||||||
//
|
//
|
||||||
public static readonly string AllowUnsupportedCommands = "ACTIONS_ALLOW_UNSECURE_COMMANDS";
|
|
||||||
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
public static readonly string RunnerDebug = "ACTIONS_RUNNER_DEBUG";
|
||||||
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
public static readonly string StepDebug = "ACTIONS_STEP_DEBUG";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,10 +56,6 @@ namespace GitHub.Runner.Common
|
|||||||
Add<T>(extensions, "GitHub.Runner.Worker.EndGroupCommandExtension, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.EndGroupCommandExtension, Runner.Worker");
|
||||||
Add<T>(extensions, "GitHub.Runner.Worker.EchoCommandExtension, Runner.Worker");
|
Add<T>(extensions, "GitHub.Runner.Worker.EchoCommandExtension, Runner.Worker");
|
||||||
break;
|
break;
|
||||||
case "GitHub.Runner.Worker.IFileCommandExtension":
|
|
||||||
Add<T>(extensions, "GitHub.Runner.Worker.AddPathFileCommand, Runner.Worker");
|
|
||||||
Add<T>(extensions, "GitHub.Runner.Worker.SetEnvFileCommand, Runner.Worker");
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
throw new NotSupportedException($"Unexpected extension type: '{typeof(T).FullName}'");
|
throw new NotSupportedException($"Unexpected extension type: '{typeof(T).FullName}'");
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ namespace GitHub.Runner.Common
|
|||||||
// logging and console
|
// logging and console
|
||||||
Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken);
|
Task<TaskLog> AppendLogContentAsync(Guid scopeIdentifier, string hubName, Guid planId, int logId, Stream uploadStream, CancellationToken cancellationToken);
|
||||||
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, CancellationToken cancellationToken);
|
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, CancellationToken cancellationToken);
|
||||||
Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long startLine, CancellationToken cancellationToken);
|
|
||||||
Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken);
|
Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, String type, String name, Stream uploadStream, CancellationToken cancellationToken);
|
||||||
Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken);
|
Task<TaskLog> CreateLogAsync(Guid scopeIdentifier, string hubName, Guid planId, TaskLog log, CancellationToken cancellationToken);
|
||||||
Task<Timeline> CreateTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
Task<Timeline> CreateTimelineAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, CancellationToken cancellationToken);
|
||||||
@@ -80,12 +79,6 @@ namespace GitHub.Runner.Common
|
|||||||
return _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, cancellationToken: cancellationToken);
|
return _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AppendTimelineRecordFeedAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, Guid stepId, IList<string> lines, long startLine, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
CheckConnection();
|
|
||||||
return _taskClient.AppendTimelineRecordFeedAsync(scopeIdentifier, hubName, planId, timelineId, timelineRecordId, stepId, lines, startLine, cancellationToken: cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, string type, string name, Stream uploadStream, CancellationToken cancellationToken)
|
public Task<TaskAttachment> CreateAttachmentAsync(Guid scopeIdentifier, string hubName, Guid planId, Guid timelineId, Guid timelineRecordId, string type, string name, Stream uploadStream, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
CheckConnection();
|
CheckConnection();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace GitHub.Runner.Common
|
|||||||
event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
event EventHandler<ThrottlingEventArgs> JobServerQueueThrottling;
|
||||||
Task ShutdownAsync();
|
Task ShutdownAsync();
|
||||||
void Start(Pipelines.AgentJobRequestMessage jobRequest);
|
void Start(Pipelines.AgentJobRequestMessage jobRequest);
|
||||||
void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber = null);
|
void QueueWebConsoleLine(Guid stepRecordId, string line);
|
||||||
void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource);
|
void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource);
|
||||||
void QueueTimelineRecordUpdate(Guid timelineId, TimelineRecord timelineRecord);
|
void QueueTimelineRecordUpdate(Guid timelineId, TimelineRecord timelineRecord);
|
||||||
}
|
}
|
||||||
@@ -155,10 +155,10 @@ namespace GitHub.Runner.Common
|
|||||||
Trace.Info("All queue process tasks have been stopped, and all queues are drained.");
|
Trace.Info("All queue process tasks have been stopped, and all queues are drained.");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueWebConsoleLine(Guid stepRecordId, string line, long? lineNumber)
|
public void QueueWebConsoleLine(Guid stepRecordId, string line)
|
||||||
{
|
{
|
||||||
Trace.Verbose("Enqueue web console line queue: {0}", line);
|
Trace.Verbose("Enqueue web console line queue: {0}", line);
|
||||||
_webConsoleLineQueue.Enqueue(new ConsoleLineInfo(stepRecordId, line, lineNumber));
|
_webConsoleLineQueue.Enqueue(new ConsoleLineInfo(stepRecordId, line));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource)
|
public void QueueFileUpload(Guid timelineId, Guid timelineRecordId, string type, string name, string path, bool deleteSource)
|
||||||
@@ -214,7 +214,7 @@ namespace GitHub.Runner.Common
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Group consolelines by timeline record of each step
|
// Group consolelines by timeline record of each step
|
||||||
Dictionary<Guid, List<TimelineRecordLogLine>> stepsConsoleLines = new Dictionary<Guid, List<TimelineRecordLogLine>>();
|
Dictionary<Guid, List<string>> stepsConsoleLines = new Dictionary<Guid, List<string>>();
|
||||||
List<Guid> stepRecordIds = new List<Guid>(); // We need to keep lines in order
|
List<Guid> stepRecordIds = new List<Guid>(); // We need to keep lines in order
|
||||||
int linesCounter = 0;
|
int linesCounter = 0;
|
||||||
ConsoleLineInfo lineInfo;
|
ConsoleLineInfo lineInfo;
|
||||||
@@ -222,7 +222,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
if (!stepsConsoleLines.ContainsKey(lineInfo.StepRecordId))
|
if (!stepsConsoleLines.ContainsKey(lineInfo.StepRecordId))
|
||||||
{
|
{
|
||||||
stepsConsoleLines[lineInfo.StepRecordId] = new List<TimelineRecordLogLine>();
|
stepsConsoleLines[lineInfo.StepRecordId] = new List<string>();
|
||||||
stepRecordIds.Add(lineInfo.StepRecordId);
|
stepRecordIds.Add(lineInfo.StepRecordId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +232,7 @@ namespace GitHub.Runner.Common
|
|||||||
lineInfo.Line = $"{lineInfo.Line.Substring(0, 1024)}...";
|
lineInfo.Line = $"{lineInfo.Line.Substring(0, 1024)}...";
|
||||||
}
|
}
|
||||||
|
|
||||||
stepsConsoleLines[lineInfo.StepRecordId].Add(new TimelineRecordLogLine(lineInfo.Line, lineInfo.LineNumber));
|
stepsConsoleLines[lineInfo.StepRecordId].Add(lineInfo.Line);
|
||||||
linesCounter++;
|
linesCounter++;
|
||||||
|
|
||||||
// process at most about 500 lines of web console line during regular timer dequeue task.
|
// process at most about 500 lines of web console line during regular timer dequeue task.
|
||||||
@@ -247,13 +247,13 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
// Split consolelines into batch, each batch will container at most 100 lines.
|
// Split consolelines into batch, each batch will container at most 100 lines.
|
||||||
int batchCounter = 0;
|
int batchCounter = 0;
|
||||||
List<List<TimelineRecordLogLine>> batchedLines = new List<List<TimelineRecordLogLine>>();
|
List<List<string>> batchedLines = new List<List<string>>();
|
||||||
foreach (var line in stepsConsoleLines[stepRecordId])
|
foreach (var line in stepsConsoleLines[stepRecordId])
|
||||||
{
|
{
|
||||||
var currentBatch = batchedLines.ElementAtOrDefault(batchCounter);
|
var currentBatch = batchedLines.ElementAtOrDefault(batchCounter);
|
||||||
if (currentBatch == null)
|
if (currentBatch == null)
|
||||||
{
|
{
|
||||||
batchedLines.Add(new List<TimelineRecordLogLine>());
|
batchedLines.Add(new List<string>());
|
||||||
currentBatch = batchedLines.ElementAt(batchCounter);
|
currentBatch = batchedLines.ElementAt(batchCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -275,6 +275,7 @@ namespace GitHub.Runner.Common
|
|||||||
{
|
{
|
||||||
Trace.Info($"Skip {batchedLines.Count - 2} batches web console lines for last run");
|
Trace.Info($"Skip {batchedLines.Count - 2} batches web console lines for last run");
|
||||||
batchedLines = batchedLines.TakeLast(2).ToList();
|
batchedLines = batchedLines.TakeLast(2).ToList();
|
||||||
|
batchedLines[0].Insert(0, "...");
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorCount = 0;
|
int errorCount = 0;
|
||||||
@@ -283,15 +284,7 @@ namespace GitHub.Runner.Common
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// we will not requeue failed batch, since the web console lines are time sensitive.
|
// we will not requeue failed batch, since the web console lines are time sensitive.
|
||||||
if (batch[0].LineNumber.HasValue)
|
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch, default(CancellationToken));
|
||||||
{
|
|
||||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), batch[0].LineNumber.Value, default(CancellationToken));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
await _jobServer.AppendTimelineRecordFeedAsync(_scopeIdentifier, _hubName, _planId, _jobTimelineId, _jobTimelineRecordId, stepRecordId, batch.Select(logLine => logLine.Line).ToList(), default(CancellationToken));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_firstConsoleOutputs)
|
if (_firstConsoleOutputs)
|
||||||
{
|
{
|
||||||
HostContext.WritePerfCounter($"WorkerJobServerQueueAppendFirstConsoleOutput_{_planId.ToString()}");
|
HostContext.WritePerfCounter($"WorkerJobServerQueueAppendFirstConsoleOutput_{_planId.ToString()}");
|
||||||
@@ -660,15 +653,13 @@ namespace GitHub.Runner.Common
|
|||||||
|
|
||||||
internal class ConsoleLineInfo
|
internal class ConsoleLineInfo
|
||||||
{
|
{
|
||||||
public ConsoleLineInfo(Guid recordId, string line, long? lineNumber)
|
public ConsoleLineInfo(Guid recordId, string line)
|
||||||
{
|
{
|
||||||
this.StepRecordId = recordId;
|
this.StepRecordId = recordId;
|
||||||
this.Line = line;
|
this.Line = line;
|
||||||
this.LineNumber = lineNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid StepRecordId { get; set; }
|
public Guid StepRecordId { get; set; }
|
||||||
public string Line { get; set; }
|
public string Line { get; set; }
|
||||||
public long? LineNumber { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ namespace GitHub.Runner.Listener
|
|||||||
private readonly string[] validFlags =
|
private readonly string[] validFlags =
|
||||||
{
|
{
|
||||||
Constants.Runner.CommandLine.Flags.Commit,
|
Constants.Runner.CommandLine.Flags.Commit,
|
||||||
|
Constants.Runner.CommandLine.Flags.Ephemeral,
|
||||||
Constants.Runner.CommandLine.Flags.Help,
|
Constants.Runner.CommandLine.Flags.Help,
|
||||||
Constants.Runner.CommandLine.Flags.Replace,
|
Constants.Runner.CommandLine.Flags.Replace,
|
||||||
Constants.Runner.CommandLine.Flags.RunAsService,
|
Constants.Runner.CommandLine.Flags.RunAsService,
|
||||||
Constants.Runner.CommandLine.Flags.Once,
|
|
||||||
Constants.Runner.CommandLine.Flags.Unattended,
|
Constants.Runner.CommandLine.Flags.Unattended,
|
||||||
Constants.Runner.CommandLine.Flags.Version
|
Constants.Runner.CommandLine.Flags.Version
|
||||||
};
|
};
|
||||||
@@ -42,7 +42,8 @@ namespace GitHub.Runner.Listener
|
|||||||
Constants.Runner.CommandLine.Args.Labels,
|
Constants.Runner.CommandLine.Args.Labels,
|
||||||
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
Constants.Runner.CommandLine.Args.MonitorSocketAddress,
|
||||||
Constants.Runner.CommandLine.Args.Name,
|
Constants.Runner.CommandLine.Args.Name,
|
||||||
Constants.Runner.CommandLine.Args.RunnerGroup,
|
Constants.Runner.CommandLine.Args.PAT,
|
||||||
|
Constants.Runner.CommandLine.Args.Pool,
|
||||||
Constants.Runner.CommandLine.Args.StartupType,
|
Constants.Runner.CommandLine.Args.StartupType,
|
||||||
Constants.Runner.CommandLine.Args.Token,
|
Constants.Runner.CommandLine.Args.Token,
|
||||||
Constants.Runner.CommandLine.Args.Url,
|
Constants.Runner.CommandLine.Args.Url,
|
||||||
@@ -63,8 +64,7 @@ namespace GitHub.Runner.Listener
|
|||||||
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
public bool Help => TestFlag(Constants.Runner.CommandLine.Flags.Help);
|
||||||
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
public bool Unattended => TestFlag(Constants.Runner.CommandLine.Flags.Unattended);
|
||||||
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
public bool Version => TestFlag(Constants.Runner.CommandLine.Flags.Version);
|
||||||
|
public bool Ephemeral => TestFlag(Constants.Runner.CommandLine.Flags.Ephemeral);
|
||||||
public bool RunOnce => TestFlag(Constants.Runner.CommandLine.Flags.Once);
|
|
||||||
|
|
||||||
// Constructor.
|
// Constructor.
|
||||||
public CommandSettings(IHostContext context, string[] args)
|
public CommandSettings(IHostContext context, string[] args)
|
||||||
@@ -169,15 +169,6 @@ namespace GitHub.Runner.Listener
|
|||||||
validator: Validators.NonEmptyValidator);
|
validator: Validators.NonEmptyValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetRunnerGroupName(string defaultPoolName = null)
|
|
||||||
{
|
|
||||||
return GetArgOrPrompt(
|
|
||||||
name: Constants.Runner.CommandLine.Args.RunnerGroup,
|
|
||||||
description: "Enter the name of the runner group to add this runner to:",
|
|
||||||
defaultValue: defaultPoolName ?? "default",
|
|
||||||
validator: Validators.NonEmptyValidator);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string GetToken()
|
public string GetToken()
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
@@ -187,6 +178,11 @@ namespace GitHub.Runner.Listener
|
|||||||
validator: Validators.NonEmptyValidator);
|
validator: Validators.NonEmptyValidator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetGitHubPersonalAccessToken()
|
||||||
|
{
|
||||||
|
return GetArg(name: Constants.Runner.CommandLine.Args.PAT);
|
||||||
|
}
|
||||||
|
|
||||||
public string GetRunnerRegisterToken()
|
public string GetRunnerRegisterToken()
|
||||||
{
|
{
|
||||||
return GetArgOrPrompt(
|
return GetArgOrPrompt(
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ using GitHub.Services.OAuth;
|
|||||||
using GitHub.Services.WebApi;
|
using GitHub.Services.WebApi;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
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;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace GitHub.Runner.Listener.Configuration
|
namespace GitHub.Runner.Listener.Configuration
|
||||||
@@ -107,8 +109,21 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
runnerSettings.GitHubUrl = inputUrl;
|
runnerSettings.GitHubUrl = inputUrl;
|
||||||
var githubToken = command.GetRunnerRegisterToken();
|
var githubPAT = command.GetGitHubPersonalAccessToken();
|
||||||
GitHubAuthResult authResult = await GetTenantCredential(inputUrl, githubToken, Constants.RunnerEvent.Register);
|
var registerToken = string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(githubPAT))
|
||||||
|
{
|
||||||
|
Trace.Info("Retriving runner register token using GitHub PAT.");
|
||||||
|
var jitToken = await GetJITRunnerTokenAsync(inputUrl, githubPAT, "registration");
|
||||||
|
Trace.Info($"Retrived runner register token is good to {jitToken.ExpiresAt}.");
|
||||||
|
HostContext.SecretMasker.AddValue(jitToken.Token);
|
||||||
|
registerToken = jitToken.Token;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(registerToken))
|
||||||
|
{
|
||||||
|
registerToken = command.GetRunnerRegisterToken();
|
||||||
|
}
|
||||||
|
GitHubAuthResult authResult = await GetTenantCredential(inputUrl, registerToken, Constants.RunnerEvent.Register);
|
||||||
runnerSettings.ServerUrl = authResult.TenantUrl;
|
runnerSettings.ServerUrl = authResult.TenantUrl;
|
||||||
creds = authResult.ToVssCredentials();
|
creds = authResult.ToVssCredentials();
|
||||||
Trace.Info("cred retrieved via GitHub auth");
|
Trace.Info("cred retrieved via GitHub auth");
|
||||||
@@ -159,34 +174,17 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
|
|
||||||
_term.WriteSection("Runner Registration");
|
_term.WriteSection("Runner Registration");
|
||||||
|
|
||||||
// If we have more than one runner group available, allow the user to specify which one to be added into
|
//Get all the agent pools, and select the first private pool
|
||||||
string poolName = null;
|
|
||||||
TaskAgentPool agentPool = null;
|
|
||||||
List<TaskAgentPool> agentPools = await _runnerServer.GetAgentPoolsAsync();
|
List<TaskAgentPool> agentPools = await _runnerServer.GetAgentPoolsAsync();
|
||||||
TaskAgentPool defaultPool = agentPools?.Where(x => x.IsInternal).FirstOrDefault();
|
TaskAgentPool agentPool = agentPools?.Where(x => x.IsHosted == false).FirstOrDefault();
|
||||||
|
|
||||||
if (agentPools?.Where(x => !x.IsHosted).Count() > 1)
|
if (agentPool == null)
|
||||||
{
|
{
|
||||||
poolName = command.GetRunnerGroupName(defaultPool?.Name);
|
throw new TaskAgentPoolNotFoundException($"Could not find any private pool. Contact support.");
|
||||||
_term.WriteLine();
|
|
||||||
agentPool = agentPools.Where(x => string.Equals(poolName, x.Name, StringComparison.OrdinalIgnoreCase) && !x.IsHosted).FirstOrDefault();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
agentPool = defaultPool;
|
Trace.Info("Found a private pool with id {1} and name {2}", agentPool.Id, agentPool.Name);
|
||||||
}
|
|
||||||
|
|
||||||
if (agentPool == null && poolName == null)
|
|
||||||
{
|
|
||||||
throw new TaskAgentPoolNotFoundException($"Could not find any self-hosted runner groups. Contact support.");
|
|
||||||
}
|
|
||||||
else if (agentPool == null && poolName != null)
|
|
||||||
{
|
|
||||||
throw new TaskAgentPoolNotFoundException($"Could not find any self-hosted runner group named \"{poolName}\".");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Trace.Info("Found a self-hosted runner group with id {1} and name {2}", agentPool.Id, agentPool.Name);
|
|
||||||
runnerSettings.PoolId = agentPool.Id;
|
runnerSettings.PoolId = agentPool.Id;
|
||||||
runnerSettings.PoolName = agentPool.Name;
|
runnerSettings.PoolName = agentPool.Name;
|
||||||
}
|
}
|
||||||
@@ -194,6 +192,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
TaskAgent agent;
|
TaskAgent agent;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
runnerSettings.Ephemeral = command.Ephemeral;
|
||||||
runnerSettings.AgentName = command.GetRunnerName();
|
runnerSettings.AgentName = command.GetRunnerName();
|
||||||
|
|
||||||
_term.WriteLine();
|
_term.WriteLine();
|
||||||
@@ -210,7 +209,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
if (command.GetReplace())
|
if (command.GetReplace())
|
||||||
{
|
{
|
||||||
// Update existing agent with new PublicKey, agent version.
|
// Update existing agent with new PublicKey, agent version.
|
||||||
agent = UpdateExistingAgent(agent, publicKey, userLabels);
|
agent = UpdateExistingAgent(agent, publicKey, userLabels, runnerSettings.Ephemeral);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -233,7 +232,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create a new agent.
|
// Create a new agent.
|
||||||
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels);
|
agent = CreateNewAgent(runnerSettings.AgentName, publicKey, userLabels, runnerSettings.Ephemeral);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -373,8 +372,22 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var githubToken = command.GetRunnerDeletionToken();
|
var githubPAT = command.GetGitHubPersonalAccessToken();
|
||||||
GitHubAuthResult authResult = await GetTenantCredential(settings.GitHubUrl, githubToken, Constants.RunnerEvent.Remove);
|
var deletionToken = string.Empty;
|
||||||
|
if (!string.IsNullOrEmpty(githubPAT))
|
||||||
|
{
|
||||||
|
Trace.Info("Retriving runner deletion token using GitHub PAT.");
|
||||||
|
var jitToken = await GetJITRunnerTokenAsync(settings.GitHubUrl, githubPAT, "remove");
|
||||||
|
Trace.Info($"Retrived runner deletion token is good to {jitToken.ExpiresAt}.");
|
||||||
|
HostContext.SecretMasker.AddValue(jitToken.Token);
|
||||||
|
deletionToken = jitToken.Token;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(deletionToken))
|
||||||
|
{
|
||||||
|
deletionToken = command.GetRunnerDeletionToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
GitHubAuthResult authResult = await GetTenantCredential(settings.GitHubUrl, deletionToken, Constants.RunnerEvent.Remove);
|
||||||
creds = authResult.ToVssCredentials();
|
creds = authResult.ToVssCredentials();
|
||||||
Trace.Info("cred retrieved via GitHub auth");
|
Trace.Info("cred retrieved via GitHub auth");
|
||||||
}
|
}
|
||||||
@@ -457,7 +470,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels)
|
private TaskAgent UpdateExistingAgent(TaskAgent agent, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral)
|
||||||
{
|
{
|
||||||
ArgUtil.NotNull(agent, nameof(agent));
|
ArgUtil.NotNull(agent, nameof(agent));
|
||||||
agent.Authorization = new TaskAgentAuthorization
|
agent.Authorization = new TaskAgentAuthorization
|
||||||
@@ -468,6 +481,8 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
// update should replace the existing labels
|
// update should replace the existing labels
|
||||||
agent.Version = BuildConstants.RunnerPackage.Version;
|
agent.Version = BuildConstants.RunnerPackage.Version;
|
||||||
agent.OSDescription = RuntimeInformation.OSDescription;
|
agent.OSDescription = RuntimeInformation.OSDescription;
|
||||||
|
agent.Ephemeral = ephemeral;
|
||||||
|
agent.MaxParallelism = 1;
|
||||||
|
|
||||||
agent.Labels.Clear();
|
agent.Labels.Clear();
|
||||||
|
|
||||||
@@ -483,7 +498,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels)
|
private TaskAgent CreateNewAgent(string agentName, RSAParameters publicKey, ISet<string> userLabels, bool ephemeral)
|
||||||
{
|
{
|
||||||
TaskAgent agent = new TaskAgent(agentName)
|
TaskAgent agent = new TaskAgent(agentName)
|
||||||
{
|
{
|
||||||
@@ -494,6 +509,7 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
MaxParallelism = 1,
|
MaxParallelism = 1,
|
||||||
Version = BuildConstants.RunnerPackage.Version,
|
Version = BuildConstants.RunnerPackage.Version,
|
||||||
OSDescription = RuntimeInformation.OSDescription,
|
OSDescription = RuntimeInformation.OSDescription,
|
||||||
|
Ephemeral = ephemeral,
|
||||||
};
|
};
|
||||||
|
|
||||||
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
agent.Labels.Add(new AgentLabel("self-hosted", LabelType.System));
|
||||||
@@ -515,6 +531,72 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
string.Equals(gitHubUrl.Host, "github.localhost", StringComparison.OrdinalIgnoreCase);
|
string.Equals(gitHubUrl.Host, "github.localhost", StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task<GitHubRunnerRegisterToken> GetJITRunnerTokenAsync(string githubUrl, string githubToken, string tokenType)
|
||||||
|
{
|
||||||
|
var githubApiUrl = "";
|
||||||
|
var gitHubUrlBuilder = new UriBuilder(githubUrl);
|
||||||
|
var path = gitHubUrlBuilder.Path.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
if (path.Length == 1)
|
||||||
|
{
|
||||||
|
if (IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/orgs/{path[0]}/actions/runners/{tokenType}-token";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/orgs/{path[0]}/actions/runners/{tokenType}-token";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path.Length == 2)
|
||||||
|
{
|
||||||
|
var repoScope = "repos/";
|
||||||
|
if (string.Equals(path[0], "enterprises", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
repoScope = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsHostedServer(gitHubUrlBuilder))
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://api.{gitHubUrlBuilder.Host}/{repoScope}{path[0]}/{path[1]}/actions/runners/{tokenType}-token";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
githubApiUrl = $"{gitHubUrlBuilder.Scheme}://{gitHubUrlBuilder.Host}/api/v3/{repoScope}{path[0]}/{path[1]}/actions/runners/{tokenType}-token";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"'{githubUrl}' should point to an org or repository.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var httpClientHandler = HostContext.CreateHttpClientHandler())
|
||||||
|
using (var httpClient = new HttpClient(httpClientHandler))
|
||||||
|
{
|
||||||
|
var base64EncodingToken = Convert.ToBase64String(Encoding.UTF8.GetBytes($"github:{githubToken}"));
|
||||||
|
HostContext.SecretMasker.AddValue(base64EncodingToken);
|
||||||
|
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("basic", base64EncodingToken);
|
||||||
|
httpClient.DefaultRequestHeaders.UserAgent.AddRange(HostContext.UserAgents);
|
||||||
|
httpClient.DefaultRequestHeaders.Accept.ParseAdd("application/vnd.github.v3+json");
|
||||||
|
|
||||||
|
var response = await httpClient.PostAsync(githubApiUrl, new StringContent(string.Empty));
|
||||||
|
|
||||||
|
if (response.IsSuccessStatusCode)
|
||||||
|
{
|
||||||
|
Trace.Info($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
|
var jsonResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
return StringUtil.ConvertFromJson<GitHubRunnerRegisterToken>(jsonResponse);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_term.WriteError($"Http response code: {response.StatusCode} from 'POST {githubApiUrl}'");
|
||||||
|
var errorResponse = await response.Content.ReadAsStringAsync();
|
||||||
|
_term.WriteError(errorResponse);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
private async Task<GitHubAuthResult> GetTenantCredential(string githubUrl, string githubToken, string runnerEvent)
|
||||||
{
|
{
|
||||||
var githubApiUrl = "";
|
var githubApiUrl = "";
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ namespace GitHub.Runner.Listener.Configuration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[DataContract]
|
||||||
|
public sealed class GitHubRunnerRegisterToken
|
||||||
|
{
|
||||||
|
[DataMember(Name = "token")]
|
||||||
|
public string Token { get; set; }
|
||||||
|
|
||||||
|
[DataMember(Name = "expires_at")]
|
||||||
|
public string ExpiresAt { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
public sealed class GitHubAuthResult
|
public sealed class GitHubAuthResult
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -477,6 +477,53 @@ namespace GitHub.Runner.Listener
|
|||||||
var systemConnection = message.Resources.Endpoints.SingleOrDefault(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
var systemConnection = message.Resources.Endpoints.SingleOrDefault(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||||
var accessToken = systemConnection?.Authorization?.Parameters["AccessToken"];
|
var accessToken = systemConnection?.Authorization?.Parameters["AccessToken"];
|
||||||
notification.JobStarted(message.JobId, accessToken, systemConnection.Url);
|
notification.JobStarted(message.JobId, accessToken, systemConnection.Url);
|
||||||
|
var jobStartNotification = Environment.GetEnvironmentVariable("_INTERNAL_RUNNER_LIFECYCLE_NOTIFICATION");
|
||||||
|
if (!string.IsNullOrEmpty(jobStartNotification))
|
||||||
|
{
|
||||||
|
term.WriteLine($"{DateTime.UtcNow:u}: Publish JobStart to {jobStartNotification}");
|
||||||
|
using (var jobStartInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
|
{
|
||||||
|
jobStartInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stdout)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stdout.Data))
|
||||||
|
{
|
||||||
|
Trace.Info($"JobStartNotification: {stdout.Data}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jobStartInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stderr)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
Trace.Error($"JobStartNotification: {stderr.Data}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await jobStartInvoker.ExecuteAsync(
|
||||||
|
workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
|
||||||
|
fileName: WhichUtil.Which("bash"),
|
||||||
|
arguments: $"-c \"{jobStartNotification} JOBSTART {DateTime.UtcNow.ToString("O")}\"",
|
||||||
|
environment: null,
|
||||||
|
requireExitCodeZero: true,
|
||||||
|
outputEncoding: null,
|
||||||
|
killProcessOnCancel: true,
|
||||||
|
redirectStandardIn: null,
|
||||||
|
inheritConsoleHandler: false,
|
||||||
|
keepStandardInOpen: false,
|
||||||
|
highPriorityProcess: true,
|
||||||
|
cancellationToken: new CancellationTokenSource(10000).Token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error($"Fail to publish JobStart notification: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HostContext.WritePerfCounter($"SentJobToWorker_{requestId.ToString()}");
|
HostContext.WritePerfCounter($"SentJobToWorker_{requestId.ToString()}");
|
||||||
|
|
||||||
@@ -613,6 +660,53 @@ namespace GitHub.Runner.Listener
|
|||||||
{
|
{
|
||||||
// This should be the last thing to run so we don't notify external parties until actually finished
|
// This should be the last thing to run so we don't notify external parties until actually finished
|
||||||
await notification.JobCompleted(message.JobId);
|
await notification.JobCompleted(message.JobId);
|
||||||
|
var jobCompleteNotification = Environment.GetEnvironmentVariable("_INTERNAL_RUNNER_LIFECYCLE_NOTIFICATION");
|
||||||
|
if (!string.IsNullOrEmpty(jobCompleteNotification))
|
||||||
|
{
|
||||||
|
term.WriteLine($"{DateTime.UtcNow:u}: Publish JobComplete to {jobCompleteNotification}");
|
||||||
|
using (var jobCompleteInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
|
{
|
||||||
|
jobCompleteInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stdout)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stdout.Data))
|
||||||
|
{
|
||||||
|
Trace.Info($"jobCompleteNotification: {stdout.Data}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jobCompleteInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stderr)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
Trace.Error($"jobCompleteNotification: {stderr.Data}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await jobCompleteInvoker.ExecuteAsync(
|
||||||
|
workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
|
||||||
|
fileName: WhichUtil.Which("bash"),
|
||||||
|
arguments: $"-c \"{jobCompleteNotification} JOBCOMPLETE {DateTime.UtcNow.ToString("O")}\"",
|
||||||
|
environment: null,
|
||||||
|
requireExitCodeZero: true,
|
||||||
|
outputEncoding: null,
|
||||||
|
killProcessOnCancel: true,
|
||||||
|
redirectStandardIn: null,
|
||||||
|
inheritConsoleHandler: false,
|
||||||
|
keepStandardInOpen: false,
|
||||||
|
highPriorityProcess: true,
|
||||||
|
cancellationToken: new CancellationTokenSource(10000).Token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error($"Fail to publish JobComplete notification: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -645,7 +739,56 @@ namespace GitHub.Runner.Listener
|
|||||||
// fire first renew succeed event.
|
// fire first renew succeed event.
|
||||||
firstJobRequestRenewed.TrySetResult(0);
|
firstJobRequestRenewed.TrySetResult(0);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var jobRunningNotification = Environment.GetEnvironmentVariable("_INTERNAL_RUNNER_LIFECYCLE_NOTIFICATION");
|
||||||
|
if (!string.IsNullOrEmpty(jobRunningNotification))
|
||||||
|
{
|
||||||
|
HostContext.GetService<ITerminal>().WriteLine($"{DateTime.UtcNow:u}: Publish JobRunning to {jobRunningNotification}");
|
||||||
|
using (var jobRunningInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
|
{
|
||||||
|
jobRunningInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stdout)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stdout.Data))
|
||||||
|
{
|
||||||
|
Trace.Info($"JobRunningNotification: {stdout.Data}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jobRunningInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stderr)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
Trace.Error($"JobRunningNotification: {stderr.Data}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await jobRunningInvoker.ExecuteAsync(
|
||||||
|
workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
|
||||||
|
fileName: WhichUtil.Which("bash"),
|
||||||
|
arguments: $"-c \"{jobRunningNotification} JOBRUNNING {DateTime.UtcNow.ToString("O")}\"",
|
||||||
|
environment: null,
|
||||||
|
requireExitCodeZero: true,
|
||||||
|
outputEncoding: null,
|
||||||
|
killProcessOnCancel: true,
|
||||||
|
redirectStandardIn: null,
|
||||||
|
inheritConsoleHandler: false,
|
||||||
|
keepStandardInOpen: false,
|
||||||
|
highPriorityProcess: true,
|
||||||
|
cancellationToken: new CancellationTokenSource(10000).Token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error($"Fail to publish JobRunning notification: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (encounteringError > 0)
|
if (encounteringError > 0)
|
||||||
{
|
{
|
||||||
encounteringError = 0;
|
encounteringError = 0;
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ namespace GitHub.Runner.Listener
|
|||||||
HostContext.StartupType = startType;
|
HostContext.StartupType = startType;
|
||||||
|
|
||||||
// Run the runner interactively or as service
|
// Run the runner interactively or as service
|
||||||
return await RunAsync(settings, command.RunOnce);
|
return await RunAsync(settings, settings.Ephemeral);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -462,20 +462,19 @@ Options:
|
|||||||
--commit Prints the runner commit
|
--commit Prints the runner commit
|
||||||
|
|
||||||
Config Options:
|
Config Options:
|
||||||
--unattended Disable interactive prompts for missing arguments. Defaults will be used for missing options
|
--unattended Disable interactive prompts for missing arguments. Defaults will be used for missing options
|
||||||
--url string Repository to add the runner to. Required if unattended
|
--url string Repository to add the runner to. Required if unattended
|
||||||
--token string Registration token. Required if unattended
|
--token string Registration token. Required if unattended
|
||||||
--name string Name of the runner to configure (default {Environment.MachineName ?? "myrunner"})
|
--name string Name of the runner to configure (default {Environment.MachineName ?? "myrunner"})
|
||||||
--runnergroup string Name of the runner group to add this runner to (defaults to the default runner group)
|
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
||||||
--labels string Extra labels in addition to the default: 'self-hosted,{Constants.Runner.Platform},{Constants.Runner.PlatformArchitecture}'
|
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
||||||
--work string Relative runner work directory (default {Constants.Path.WorkDirectory})
|
--replace Replace any existing runner with the same name (default false)");
|
||||||
--replace Replace any existing runner with the same name (default false)");
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
_term.WriteLine($@" --runasservice Run the runner as a service");
|
_term.WriteLine($@" --runasservice Run the runner as a service");
|
||||||
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");
|
_term.WriteLine($@" --windowslogonaccount string Account to run the service as. Requires runasservice");
|
||||||
_term.WriteLine($@" --windowslogonpassword string Password for the service account. Requires runasservice");
|
_term.WriteLine($@" --windowslogonpassword string Password for the service account. Requires runasservice");
|
||||||
#endif
|
#endif
|
||||||
_term.WriteLine($@"
|
_term.WriteLine($@"
|
||||||
Examples:
|
Examples:
|
||||||
Configure a runner non-interactively:
|
Configure a runner non-interactively:
|
||||||
.{separator}config.{ext} --unattended --url <url> --token <token>
|
.{separator}config.{ext} --unattended --url <url> --token <token>
|
||||||
|
|||||||
@@ -59,6 +59,53 @@ namespace GitHub.Runner.Listener
|
|||||||
|
|
||||||
Trace.Info($"An update is available.");
|
Trace.Info($"An update is available.");
|
||||||
|
|
||||||
|
var runnerUpdateNotification = Environment.GetEnvironmentVariable("_INTERNAL_RUNNER_LIFECYCLE_NOTIFICATION");
|
||||||
|
if (!string.IsNullOrEmpty(runnerUpdateNotification))
|
||||||
|
{
|
||||||
|
HostContext.GetService<ITerminal>().WriteLine($"{DateTime.UtcNow:u}: Publish RunnerUpdate to {runnerUpdateNotification}");
|
||||||
|
using (var runnerUpdateInvoker = HostContext.CreateService<IProcessInvoker>())
|
||||||
|
{
|
||||||
|
runnerUpdateInvoker.OutputDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stdout)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stdout.Data))
|
||||||
|
{
|
||||||
|
Trace.Info($"RunnerUpdateNotification: {stdout.Data}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
runnerUpdateInvoker.ErrorDataReceived += delegate (object sender, ProcessDataReceivedEventArgs stderr)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(stderr.Data))
|
||||||
|
{
|
||||||
|
Trace.Error($"RunnerUpdateNotification: {stderr.Data}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await runnerUpdateInvoker.ExecuteAsync(
|
||||||
|
workingDirectory: HostContext.GetDirectory(WellKnownDirectory.Root),
|
||||||
|
fileName: WhichUtil.Which("bash"),
|
||||||
|
arguments: $"-c \"{runnerUpdateNotification} RUNNERUPDATE {DateTime.UtcNow.ToString("O")}\"",
|
||||||
|
environment: null,
|
||||||
|
requireExitCodeZero: true,
|
||||||
|
outputEncoding: null,
|
||||||
|
killProcessOnCancel: true,
|
||||||
|
redirectStandardIn: null,
|
||||||
|
inheritConsoleHandler: false,
|
||||||
|
keepStandardInOpen: false,
|
||||||
|
highPriorityProcess: true,
|
||||||
|
cancellationToken: new CancellationTokenSource(10000).Token);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Trace.Error($"Fail to publish RunnerUpdate notification: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// Print console line that warn user not shutdown runner.
|
// Print console line that warn user not shutdown runner.
|
||||||
await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner.");
|
await UpdateRunnerUpdateStateAsync("Runner update in progress, do not shutdown runner.");
|
||||||
await UpdateRunnerUpdateStateAsync($"Downloading {_targetPackage.Version} runner");
|
await UpdateRunnerUpdateStateAsync($"Downloading {_targetPackage.Version} runner");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -71,7 +71,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(httpProxyAddress) && Uri.TryCreate(httpProxyAddress, UriKind.Absolute, out var proxyHttpUri))
|
if (!string.IsNullOrEmpty(httpProxyAddress) && Uri.TryCreate(httpProxyAddress, UriKind.Absolute, out var proxyHttpUri))
|
||||||
{
|
{
|
||||||
_httpProxyAddress = proxyHttpUri.OriginalString;
|
_httpProxyAddress = proxyHttpUri.AbsoluteUri;
|
||||||
|
|
||||||
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
||||||
Environment.SetEnvironmentVariable("HTTP_PROXY", _httpProxyAddress);
|
Environment.SetEnvironmentVariable("HTTP_PROXY", _httpProxyAddress);
|
||||||
@@ -101,7 +101,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(httpsProxyAddress) && Uri.TryCreate(httpsProxyAddress, UriKind.Absolute, out var proxyHttpsUri))
|
if (!string.IsNullOrEmpty(httpsProxyAddress) && Uri.TryCreate(httpsProxyAddress, UriKind.Absolute, out var proxyHttpsUri))
|
||||||
{
|
{
|
||||||
_httpsProxyAddress = proxyHttpsUri.OriginalString;
|
_httpsProxyAddress = proxyHttpsUri.AbsoluteUri;
|
||||||
|
|
||||||
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
// Set both environment variables since there are tools support both casing (curl, wget) and tools support only one casing (docker)
|
||||||
Environment.SetEnvironmentVariable("HTTPS_PROXY", _httpsProxyAddress);
|
Environment.SetEnvironmentVariable("HTTPS_PROXY", _httpsProxyAddress);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using GitHub.DistributedTask.Pipelines;
|
using GitHub.DistributedTask.Pipelines;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using GitHub.Runner.Worker.Container;
|
using GitHub.Runner.Worker.Container;
|
||||||
@@ -184,48 +183,11 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
var allowUnsecureCommands = false;
|
|
||||||
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
|
||||||
|
|
||||||
// Apply environment from env context, env context contains job level env and action's env block
|
|
||||||
#if OS_WINDOWS
|
|
||||||
var envContext = context.ExpressionValues["env"] as DictionaryContextData;
|
|
||||||
#else
|
|
||||||
var envContext = context.ExpressionValues["env"] as CaseSensitiveDictionaryContextData;
|
|
||||||
#endif
|
|
||||||
if (!allowUnsecureCommands && envContext.ContainsKey(Constants.Variables.Actions.AllowUnsupportedCommands))
|
|
||||||
{
|
|
||||||
bool.TryParse(envContext[Constants.Variables.Actions.AllowUnsupportedCommands].ToString(), out allowUnsecureCommands);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowUnsecureCommands)
|
|
||||||
{
|
|
||||||
throw new Exception(String.Format(Constants.Runner.UnsupportedCommandMessageDisabled, this.Command));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!command.Properties.TryGetValue(SetEnvCommandProperties.Name, out string envName) || string.IsNullOrEmpty(envName))
|
if (!command.Properties.TryGetValue(SetEnvCommandProperties.Name, out string envName) || string.IsNullOrEmpty(envName))
|
||||||
{
|
{
|
||||||
throw new Exception("Required field 'name' is missing in ##[set-env] command.");
|
throw new Exception("Required field 'name' is missing in ##[set-env] command.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
foreach (var blocked in _setEnvBlockList)
|
|
||||||
{
|
|
||||||
if (string.Equals(blocked, envName, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
// Log Telemetry and let user know they shouldn't do this
|
|
||||||
var issue = new Issue()
|
|
||||||
{
|
|
||||||
Type = IssueType.Error,
|
|
||||||
Message = $"Can't update {blocked} environment variable using ::set-env:: command."
|
|
||||||
};
|
|
||||||
issue.Data[Constants.Runner.InternalTelemetryIssueDataKey] = $"{Constants.Runner.UnsupportedCommand}_{envName}";
|
|
||||||
context.AddIssue(issue);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Global.EnvironmentVariables[envName] = command.Data;
|
context.Global.EnvironmentVariables[envName] = command.Data;
|
||||||
context.SetEnvContext(envName, command.Data);
|
context.SetEnvContext(envName, command.Data);
|
||||||
context.Debug($"{envName}='{command.Data}'");
|
context.Debug($"{envName}='{command.Data}'");
|
||||||
@@ -235,11 +197,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
public const String Name = "name";
|
public const String Name = "name";
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] _setEnvBlockList =
|
|
||||||
{
|
|
||||||
"NODE_OPTIONS"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class SetOutputCommandExtension : RunnerService, IActionCommandExtension
|
public sealed class SetOutputCommandExtension : RunnerService, IActionCommandExtension
|
||||||
@@ -324,26 +281,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public Type ExtensionType => typeof(IActionCommandExtension);
|
public Type ExtensionType => typeof(IActionCommandExtension);
|
||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
public void ProcessCommand(IExecutionContext context, string line, ActionCommand command, ContainerInfo container)
|
||||||
{
|
{
|
||||||
var allowUnsecureCommands = false;
|
|
||||||
bool.TryParse(Environment.GetEnvironmentVariable(Constants.Variables.Actions.AllowUnsupportedCommands), out allowUnsecureCommands);
|
|
||||||
|
|
||||||
// Apply environment from env context, env context contains job level env and action's env block
|
|
||||||
#if OS_WINDOWS
|
|
||||||
var envContext = context.ExpressionValues["env"] as DictionaryContextData;
|
|
||||||
#else
|
|
||||||
var envContext = context.ExpressionValues["env"] as CaseSensitiveDictionaryContextData;
|
|
||||||
#endif
|
|
||||||
if (!allowUnsecureCommands && envContext.ContainsKey(Constants.Variables.Actions.AllowUnsupportedCommands))
|
|
||||||
{
|
|
||||||
bool.TryParse(envContext[Constants.Variables.Actions.AllowUnsupportedCommands].ToString(), out allowUnsecureCommands);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!allowUnsecureCommands)
|
|
||||||
{
|
|
||||||
throw new Exception(String.Format(Constants.Runner.UnsupportedCommandMessageDisabled, this.Command));
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgUtil.NotNullOrEmpty(command.Data, "path");
|
ArgUtil.NotNullOrEmpty(command.Data, "path");
|
||||||
context.Global.PrependPath.RemoveAll(x => string.Equals(x, command.Data, StringComparison.CurrentCulture));
|
context.Global.PrependPath.RemoveAll(x => string.Equals(x, command.Data, StringComparison.CurrentCulture));
|
||||||
context.Global.PrependPath.Add(command.Data);
|
context.Global.PrependPath.Add(command.Data);
|
||||||
|
|||||||
@@ -395,7 +395,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info($"Action cleanup plugin: {plugin.PluginTypeName}.");
|
Trace.Info($"Action cleanup plugin: {plugin.PluginTypeName}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (definition.Data.Execution.ExecutionType == ActionExecutionType.Composite)
|
else if (definition.Data.Execution.ExecutionType == ActionExecutionType.Composite && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
|
||||||
{
|
{
|
||||||
var compositeAction = definition.Data.Execution as CompositeActionExecutionData;
|
var compositeAction = definition.Data.Execution as CompositeActionExecutionData;
|
||||||
Trace.Info($"Load {compositeAction.Steps?.Count ?? 0} action steps.");
|
Trace.Info($"Load {compositeAction.Steps?.Count ?? 0} action steps.");
|
||||||
@@ -492,7 +492,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
executionContext.Output("##[endgroup]");
|
executionContext.Output("##[endgroup");
|
||||||
|
|
||||||
if (retryCount == 3 && pullExitCode != 0)
|
if (retryCount == 3 && pullExitCode != 0)
|
||||||
{
|
{
|
||||||
@@ -1048,7 +1048,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info($"Action plugin: {(actionDefinitionData.Execution as PluginActionExecutionData).Plugin}, no more preparation.");
|
Trace.Info($"Action plugin: {(actionDefinitionData.Execution as PluginActionExecutionData).Plugin}, no more preparation.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else if (actionDefinitionData.Execution.ExecutionType == ActionExecutionType.Composite)
|
else if (actionDefinitionData.Execution.ExecutionType == ActionExecutionType.Composite && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
|
||||||
{
|
{
|
||||||
Trace.Info($"Action composite: {(actionDefinitionData.Execution as CompositeActionExecutionData).Steps}, no more preparation.");
|
Trace.Info($"Action composite: {(actionDefinitionData.Execution as CompositeActionExecutionData).Steps}, no more preparation.");
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -105,7 +105,12 @@ namespace GitHub.Runner.Worker
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "outputs":
|
case "outputs":
|
||||||
actionOutputs = actionPair.Value.AssertMapping("outputs");
|
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
|
||||||
|
{
|
||||||
|
actionOutputs = actionPair.Value.AssertMapping("outputs");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Trace.Info($"Ignore action property outputs. Outputs for a whole action is not supported yet.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "description":
|
case "description":
|
||||||
@@ -418,10 +423,14 @@ namespace GitHub.Runner.Worker
|
|||||||
preIfToken = run.Value.AssertString("pre-if");
|
preIfToken = run.Value.AssertString("pre-if");
|
||||||
break;
|
break;
|
||||||
case "steps":
|
case "steps":
|
||||||
var stepsToken = run.Value.AssertSequence("steps");
|
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
|
||||||
steps = PipelineTemplateConverter.ConvertToSteps(templateContext, stepsToken);
|
{
|
||||||
templateContext.Errors.Check();
|
var stepsToken = run.Value.AssertSequence("steps");
|
||||||
break;
|
steps = PipelineTemplateConverter.ConvertToSteps(templateContext, stepsToken);
|
||||||
|
templateContext.Errors.Check();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
throw new Exception("You aren't supposed to be using Composite Actions yet!");
|
||||||
default:
|
default:
|
||||||
Trace.Info($"Ignore run property {runsKey}.");
|
Trace.Info($"Ignore run property {runsKey}.");
|
||||||
break;
|
break;
|
||||||
@@ -469,7 +478,7 @@ namespace GitHub.Runner.Worker
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (string.Equals(usingToken.Value, "composite", StringComparison.OrdinalIgnoreCase))
|
else if (string.Equals(usingToken.Value, "composite", StringComparison.OrdinalIgnoreCase) && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TESTING_COMPOSITE_ACTIONS_ALPHA")))
|
||||||
{
|
{
|
||||||
if (steps == null)
|
if (steps == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -135,14 +135,6 @@ namespace GitHub.Runner.Worker
|
|||||||
ExecutionContext.SetGitHubContext("event_path", workflowFile);
|
ExecutionContext.SetGitHubContext("event_path", workflowFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set GITHUB_ACTION_REPOSITORY if this Action is from a repository
|
|
||||||
if (Action.Reference is Pipelines.RepositoryPathReference repoPathReferenceAction &&
|
|
||||||
!string.Equals(repoPathReferenceAction.RepositoryType, Pipelines.PipelineConstants.SelfAlias, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
ExecutionContext.SetGitHubContext("action_repository", repoPathReferenceAction.Name);
|
|
||||||
ExecutionContext.SetGitHubContext("action_ref", repoPathReferenceAction.Ref);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup container stephost for running inside the container.
|
// Setup container stephost for running inside the container.
|
||||||
if (ExecutionContext.Global.Container != null)
|
if (ExecutionContext.Global.Container != null)
|
||||||
{
|
{
|
||||||
@@ -153,10 +145,6 @@ namespace GitHub.Runner.Worker
|
|||||||
stepHost = containerStepHost;
|
stepHost = containerStepHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup File Command Manager
|
|
||||||
var fileCommandManager = HostContext.CreateService<IFileCommandManager>();
|
|
||||||
fileCommandManager.InitializeFiles(ExecutionContext, null);
|
|
||||||
|
|
||||||
// Load the inputs.
|
// Load the inputs.
|
||||||
ExecutionContext.Debug("Loading inputs");
|
ExecutionContext.Debug("Loading inputs");
|
||||||
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
var templateEvaluator = ExecutionContext.ToPipelineTemplateEvaluator();
|
||||||
@@ -250,15 +238,7 @@ namespace GitHub.Runner.Worker
|
|||||||
handler.PrintActionDetails(Stage);
|
handler.PrintActionDetails(Stage);
|
||||||
|
|
||||||
// Run the task.
|
// Run the task.
|
||||||
try
|
await handler.RunAsync(Stage);
|
||||||
{
|
|
||||||
await handler.RunAsync(Stage);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
fileCommandManager.ProcessFiles(ExecutionContext, ExecutionContext.Global.Container);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryEvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context)
|
public bool TryEvaluateDisplayName(DictionaryContextData contextData, IExecutionContext context)
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
_environmentVariables = container.Environment;
|
_environmentVariables = container.Environment;
|
||||||
this.IsJobContainer = isJobContainer;
|
this.IsJobContainer = isJobContainer;
|
||||||
this.ContainerNetworkAlias = networkAlias;
|
this.ContainerNetworkAlias = networkAlias;
|
||||||
this.RegistryAuthUsername = container.Credentials?.Username;
|
|
||||||
this.RegistryAuthPassword = container.Credentials?.Password;
|
|
||||||
this.RegistryServer = DockerUtil.ParseRegistryHostnameFromImageName(this.ContainerImage);
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
_pathMappings.Add(new PathMapping(hostContext.GetDirectory(WellKnownDirectory.Work), "C:\\__w"));
|
_pathMappings.Add(new PathMapping(hostContext.GetDirectory(WellKnownDirectory.Work), "C:\\__w"));
|
||||||
@@ -82,9 +79,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
public string ContainerWorkDirectory { get; set; }
|
public string ContainerWorkDirectory { get; set; }
|
||||||
public string ContainerCreateOptions { get; private set; }
|
public string ContainerCreateOptions { get; private set; }
|
||||||
public string ContainerRuntimePath { get; set; }
|
public string ContainerRuntimePath { get; set; }
|
||||||
public string RegistryServer { get; set; }
|
|
||||||
public string RegistryAuthUsername { get; set; }
|
|
||||||
public string RegistryAuthPassword { get; set; }
|
|
||||||
public bool IsJobContainer { get; set; }
|
public bool IsJobContainer { get; set; }
|
||||||
|
|
||||||
public IDictionary<string, string> ContainerEnvironmentVariables
|
public IDictionary<string, string> ContainerEnvironmentVariables
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ using System.IO;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Channels;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
@@ -18,7 +17,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
string DockerInstanceLabel { get; }
|
string DockerInstanceLabel { get; }
|
||||||
Task<DockerVersion> DockerVersion(IExecutionContext context);
|
Task<DockerVersion> DockerVersion(IExecutionContext context);
|
||||||
Task<int> DockerPull(IExecutionContext context, string image);
|
Task<int> DockerPull(IExecutionContext context, string image);
|
||||||
Task<int> DockerPull(IExecutionContext context, string image, string configFileDirectory);
|
|
||||||
Task<int> DockerBuild(IExecutionContext context, string workingDirectory, string dockerFile, string dockerContext, string tag);
|
Task<int> DockerBuild(IExecutionContext context, string workingDirectory, string dockerFile, string dockerContext, string tag);
|
||||||
Task<string> DockerCreate(IExecutionContext context, ContainerInfo container);
|
Task<string> DockerCreate(IExecutionContext context, ContainerInfo container);
|
||||||
Task<int> DockerRun(IExecutionContext context, ContainerInfo container, EventHandler<ProcessDataReceivedEventArgs> stdoutDataReceived, EventHandler<ProcessDataReceivedEventArgs> stderrDataReceived);
|
Task<int> DockerRun(IExecutionContext context, ContainerInfo container, EventHandler<ProcessDataReceivedEventArgs> stdoutDataReceived, EventHandler<ProcessDataReceivedEventArgs> stderrDataReceived);
|
||||||
@@ -33,7 +31,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
Task<int> DockerExec(IExecutionContext context, string containerId, string options, string command, List<string> outputs);
|
Task<int> DockerExec(IExecutionContext context, string containerId, string options, string command, List<string> outputs);
|
||||||
Task<List<string>> DockerInspect(IExecutionContext context, string dockerObject, string options);
|
Task<List<string>> DockerInspect(IExecutionContext context, string dockerObject, string options);
|
||||||
Task<List<PortMapping>> DockerPort(IExecutionContext context, string containerId);
|
Task<List<PortMapping>> DockerPort(IExecutionContext context, string containerId);
|
||||||
Task<int> DockerLogin(IExecutionContext context, string configFileDirectory, string registry, string username, string password);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DockerCommandManager : RunnerService, IDockerCommandManager
|
public class DockerCommandManager : RunnerService, IDockerCommandManager
|
||||||
@@ -85,18 +82,9 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
return new DockerVersion(serverVersion, clientVersion);
|
return new DockerVersion(serverVersion, clientVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> DockerPull(IExecutionContext context, string image)
|
public async Task<int> DockerPull(IExecutionContext context, string image)
|
||||||
{
|
{
|
||||||
return DockerPull(context, image, null);
|
return await ExecuteDockerCommandAsync(context, "pull", image, context.CancellationToken);
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<int> DockerPull(IExecutionContext context, string image, string configFileDirectory)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(configFileDirectory))
|
|
||||||
{
|
|
||||||
return await ExecuteDockerCommandAsync(context, $"pull", image, context.CancellationToken);
|
|
||||||
}
|
|
||||||
return await ExecuteDockerCommandAsync(context, $"--config {configFileDirectory} pull", image, context.CancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> DockerBuild(IExecutionContext context, string workingDirectory, string dockerFile, string dockerContext, string tag)
|
public async Task<int> DockerBuild(IExecutionContext context, string workingDirectory, string dockerFile, string dockerContext, string tag)
|
||||||
@@ -358,28 +346,6 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
return DockerUtil.ParseDockerPort(portMappingLines);
|
return DockerUtil.ParseDockerPort(portMappingLines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<int> DockerLogin(IExecutionContext context, string configFileDirectory, string registry, string username, string password)
|
|
||||||
{
|
|
||||||
string args = $"--config {configFileDirectory} login {registry} -u {username} --password-stdin";
|
|
||||||
context.Command($"{DockerPath} {args}");
|
|
||||||
|
|
||||||
var input = Channel.CreateBounded<string>(new BoundedChannelOptions(1) { SingleReader = true, SingleWriter = true });
|
|
||||||
input.Writer.TryWrite(password);
|
|
||||||
|
|
||||||
var processInvoker = HostContext.CreateService<IProcessInvoker>();
|
|
||||||
|
|
||||||
return processInvoker.ExecuteAsync(
|
|
||||||
workingDirectory: context.GetGitHubContext("workspace"),
|
|
||||||
fileName: DockerPath,
|
|
||||||
arguments: args,
|
|
||||||
environment: null,
|
|
||||||
requireExitCodeZero: false,
|
|
||||||
outputEncoding: null,
|
|
||||||
killProcessOnCancel: false,
|
|
||||||
redirectStandardIn: input,
|
|
||||||
cancellationToken: context.CancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<int> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options, CancellationToken cancellationToken = default(CancellationToken))
|
private Task<int> ExecuteDockerCommandAsync(IExecutionContext context, string command, string options, CancellationToken cancellationToken = default(CancellationToken))
|
||||||
{
|
{
|
||||||
return ExecuteDockerCommandAsync(context, command, options, null, cancellationToken);
|
return ExecuteDockerCommandAsync(context, command, options, null, cancellationToken);
|
||||||
|
|||||||
@@ -45,21 +45,5 @@ namespace GitHub.Runner.Worker.Container
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string ParseRegistryHostnameFromImageName(string name)
|
|
||||||
{
|
|
||||||
var nameSplit = name.Split('/');
|
|
||||||
// Single slash is implictly from Dockerhub, unless first part has .tld or :port
|
|
||||||
if (nameSplit.Length == 2 && (nameSplit[0].Contains(":") || nameSplit[0].Contains(".")))
|
|
||||||
{
|
|
||||||
return nameSplit[0];
|
|
||||||
}
|
|
||||||
// All other non Dockerhub registries
|
|
||||||
else if (nameSplit.Length > 2)
|
|
||||||
{
|
|
||||||
return nameSplit[0];
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -140,6 +140,11 @@ namespace GitHub.Runner.Worker
|
|||||||
executionContext.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
executionContext.JobContext.Container["network"] = new StringContextData(containerNetwork);
|
||||||
executionContext.Output("##[endgroup]");
|
executionContext.Output("##[endgroup]");
|
||||||
|
|
||||||
|
if (Environment.GetEnvironmentVariable("K8S_POD_NAME") != null)
|
||||||
|
{
|
||||||
|
IOUtil.CopyDirectory(HostContext.GetDirectory(WellKnownDirectory.Externals), Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Work), "__externals_copy"), CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var container in containers)
|
foreach (var container in containers)
|
||||||
{
|
{
|
||||||
container.ContainerNetwork = containerNetwork;
|
container.ContainerNetwork = containerNetwork;
|
||||||
@@ -198,18 +203,12 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add at a later date. This currently no local package registry to test with
|
|
||||||
// UpdateRegistryAuthForGitHubToken(executionContext, container);
|
|
||||||
|
|
||||||
// Before pulling, generate client authentication if required
|
|
||||||
var configLocation = await ContainerRegistryLogin(executionContext, container);
|
|
||||||
|
|
||||||
// Pull down docker image with retry up to 3 times
|
// Pull down docker image with retry up to 3 times
|
||||||
int retryCount = 0;
|
int retryCount = 0;
|
||||||
int pullExitCode = 0;
|
int pullExitCode = 0;
|
||||||
while (retryCount < 3)
|
while (retryCount < 3)
|
||||||
{
|
{
|
||||||
pullExitCode = await _dockerManger.DockerPull(executionContext, container.ContainerImage, configLocation);
|
pullExitCode = await _dockerManger.DockerPull(executionContext, container.ContainerImage);
|
||||||
if (pullExitCode == 0)
|
if (pullExitCode == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
@@ -226,9 +225,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove credentials after pulling
|
|
||||||
ContainerRegistryLogout(configLocation);
|
|
||||||
|
|
||||||
if (retryCount == 3 && pullExitCode != 0)
|
if (retryCount == 3 && pullExitCode != 0)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Docker pull failed with exit code {pullExitCode}");
|
throw new InvalidOperationException($"Docker pull failed with exit code {pullExitCode}");
|
||||||
@@ -245,7 +241,14 @@ namespace GitHub.Runner.Worker
|
|||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals))));
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals))));
|
||||||
#else
|
#else
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
if (Environment.GetEnvironmentVariable("K8S_POD_NAME") != null)
|
||||||
|
{
|
||||||
|
container.MountVolumes.Add(new MountVolume(Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Work), "__externals_copy"), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Externals), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Externals)), true));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
container.MountVolumes.Add(new MountVolume(HostContext.GetDirectory(WellKnownDirectory.Temp), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Temp))));
|
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.Actions), container.TranslateToContainerPath(HostContext.GetDirectory(WellKnownDirectory.Actions))));
|
||||||
@@ -446,83 +449,5 @@ namespace GitHub.Runner.Worker
|
|||||||
throw new InvalidOperationException($"Failed to initialize, {container.ContainerNetworkAlias} service is {serviceHealth}.");
|
throw new InvalidOperationException($"Failed to initialize, {container.ContainerNetworkAlias} service is {serviceHealth}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> ContainerRegistryLogin(IExecutionContext executionContext, ContainerInfo container)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(container.RegistryAuthUsername) || string.IsNullOrEmpty(container.RegistryAuthPassword))
|
|
||||||
{
|
|
||||||
// No valid client config can be generated
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
var configLocation = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), $".docker_{Guid.NewGuid()}");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var dirInfo = Directory.CreateDirectory(configLocation);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Failed to create directory to store registry client credentials: {e.Message}");
|
|
||||||
}
|
|
||||||
var loginExitCode = await _dockerManger.DockerLogin(
|
|
||||||
executionContext,
|
|
||||||
configLocation,
|
|
||||||
container.RegistryServer,
|
|
||||||
container.RegistryAuthUsername,
|
|
||||||
container.RegistryAuthPassword);
|
|
||||||
|
|
||||||
if (loginExitCode != 0)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Docker login for '{container.RegistryServer}' failed with exit code {loginExitCode}");
|
|
||||||
}
|
|
||||||
return configLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ContainerRegistryLogout(string configLocation)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(configLocation) && Directory.Exists(configLocation))
|
|
||||||
{
|
|
||||||
Directory.Delete(configLocation, recursive: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Failed to remove directory containing Docker client credentials: {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateRegistryAuthForGitHubToken(IExecutionContext executionContext, ContainerInfo container)
|
|
||||||
{
|
|
||||||
var registryIsTokenCompatible = container.RegistryServer.Equals("docker.pkg.github.com", StringComparison.OrdinalIgnoreCase);
|
|
||||||
if (!registryIsTokenCompatible)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var registryMatchesWorkflow = false;
|
|
||||||
|
|
||||||
// REGISTRY/OWNER/REPO/IMAGE[:TAG]
|
|
||||||
var imageParts = container.ContainerImage.Split('/');
|
|
||||||
if (imageParts.Length != 4)
|
|
||||||
{
|
|
||||||
executionContext.Warning($"Could not identify owner and repo for container image {container.ContainerImage}. Skipping automatic token auth");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var owner = imageParts[1];
|
|
||||||
var repo = imageParts[2];
|
|
||||||
var nwo = $"{owner}/{repo}";
|
|
||||||
if (nwo.Equals(executionContext.GetGitHubContext("repository"), StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
registryMatchesWorkflow = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var registryCredentialsNotSupplied = string.IsNullOrEmpty(container.RegistryAuthUsername) && string.IsNullOrEmpty(container.RegistryAuthPassword);
|
|
||||||
if (registryCredentialsNotSupplied && registryMatchesWorkflow)
|
|
||||||
{
|
|
||||||
container.RegistryAuthUsername = executionContext.GetGitHubContext("actor");
|
|
||||||
container.RegistryAuthPassword = executionContext.GetGitHubContext("token");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,27 +48,24 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
Dictionary<string, string> IntraActionState { get; }
|
Dictionary<string, string> IntraActionState { get; }
|
||||||
Dictionary<string, VariableValue> JobOutputs { get; }
|
Dictionary<string, VariableValue> JobOutputs { get; }
|
||||||
ActionsEnvironmentReference ActionsEnvironment { get; }
|
|
||||||
DictionaryContextData ExpressionValues { get; }
|
DictionaryContextData ExpressionValues { get; }
|
||||||
IList<IFunctionInfo> ExpressionFunctions { get; }
|
IList<IFunctionInfo> ExpressionFunctions { get; }
|
||||||
JobContext JobContext { get; }
|
JobContext JobContext { get; }
|
||||||
|
|
||||||
// Only job level ExecutionContext has JobSteps
|
// Only job level ExecutionContext has JobSteps
|
||||||
Queue<IStep> JobSteps { get; }
|
List<IStep> JobSteps { get; }
|
||||||
|
|
||||||
// Only job level ExecutionContext has PostJobSteps
|
// Only job level ExecutionContext has PostJobSteps
|
||||||
Stack<IStep> PostJobSteps { get; }
|
Stack<IStep> PostJobSteps { get; }
|
||||||
|
|
||||||
bool EchoOnActionCommand { get; set; }
|
bool EchoOnActionCommand { get; set; }
|
||||||
|
|
||||||
bool InsideComposite { get; }
|
|
||||||
|
|
||||||
ExecutionContext Root { get; }
|
ExecutionContext Root { get; }
|
||||||
|
|
||||||
// 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 insideComposite = false, CancellationTokenSource cancellationTokenSource = null);
|
IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, CancellationTokenSource cancellationTokenSource = null);
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
long Write(string tag, string message);
|
long Write(string tag, string message);
|
||||||
@@ -138,8 +135,6 @@ namespace GitHub.Runner.Worker
|
|||||||
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; }
|
||||||
public Dictionary<string, VariableValue> JobOutputs { get; private set; }
|
public Dictionary<string, VariableValue> JobOutputs { get; private set; }
|
||||||
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment { get; private set; }
|
|
||||||
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
public DictionaryContextData ExpressionValues { get; } = new DictionaryContextData();
|
||||||
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
public IList<IFunctionInfo> ExpressionFunctions { get; } = new List<IFunctionInfo>();
|
||||||
|
|
||||||
@@ -147,7 +142,7 @@ namespace GitHub.Runner.Worker
|
|||||||
public GlobalContext Global { get; private set; }
|
public GlobalContext Global { get; private set; }
|
||||||
|
|
||||||
// Only job level ExecutionContext has JobSteps
|
// Only job level ExecutionContext has JobSteps
|
||||||
public Queue<IStep> JobSteps { get; private set; }
|
public List<IStep> JobSteps { get; private set; }
|
||||||
|
|
||||||
// Only job level ExecutionContext has PostJobSteps
|
// Only job level ExecutionContext has PostJobSteps
|
||||||
public Stack<IStep> PostJobSteps { get; private set; }
|
public Stack<IStep> PostJobSteps { get; private set; }
|
||||||
@@ -157,8 +152,6 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
public bool EchoOnActionCommand { get; set; }
|
public bool EchoOnActionCommand { get; set; }
|
||||||
|
|
||||||
public bool InsideComposite { get; private set; }
|
|
||||||
|
|
||||||
public TaskResult? Result
|
public TaskResult? Result
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -255,7 +248,7 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Helper function used in CompositeActionHandler::RunAsync to
|
/// Helper function used in CompositeActionHandler::RunAsync to
|
||||||
/// add a child node, aka a step, to the current job to the Root.JobSteps based on the location.
|
/// add a child node, aka a step, to the current job to the Root.JobSteps based on the location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IStep CreateCompositeStep(
|
public IStep CreateCompositeStep(
|
||||||
string scopeName,
|
string scopeName,
|
||||||
@@ -263,7 +256,7 @@ namespace GitHub.Runner.Worker
|
|||||||
DictionaryContextData inputsData,
|
DictionaryContextData inputsData,
|
||||||
Dictionary<string, string> envData)
|
Dictionary<string, string> envData)
|
||||||
{
|
{
|
||||||
step.ExecutionContext = Root.CreateChild(_record.Id, _record.Name, _record.Id.ToString("N"), scopeName, step.Action.ContextName, logger: _logger, insideComposite: true, cancellationTokenSource: CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token));
|
step.ExecutionContext = Root.CreateChild(_record.Id, step.DisplayName, _record.Id.ToString("N"), scopeName, step.Action.ContextName, logger: _logger, cancellationTokenSource: CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token));
|
||||||
step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
|
step.ExecutionContext.ExpressionValues["inputs"] = inputsData;
|
||||||
step.ExecutionContext.ExpressionValues["steps"] = Global.StepsContext.GetScope(step.ExecutionContext.GetFullyQualifiedContextName());
|
step.ExecutionContext.ExpressionValues["steps"] = Global.StepsContext.GetScope(step.ExecutionContext.GetFullyQualifiedContextName());
|
||||||
|
|
||||||
@@ -282,7 +275,7 @@ namespace GitHub.Runner.Worker
|
|||||||
return step;
|
return 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 insideComposite = false, CancellationTokenSource cancellationTokenSource = null)
|
public IExecutionContext CreateChild(Guid recordId, string displayName, string refName, string scopeName, string contextName, Dictionary<string, string> intraActionState = null, int? recordOrder = null, IPagingLogger logger = null, CancellationTokenSource cancellationTokenSource = null)
|
||||||
{
|
{
|
||||||
Trace.Entering();
|
Trace.Entering();
|
||||||
|
|
||||||
@@ -329,8 +322,6 @@ namespace GitHub.Runner.Worker
|
|||||||
child._logger.Setup(_mainTimelineId, recordId);
|
child._logger.Setup(_mainTimelineId, recordId);
|
||||||
}
|
}
|
||||||
|
|
||||||
child.InsideComposite = insideComposite;
|
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,14 +372,14 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
if (Root != this)
|
if (Root != this)
|
||||||
{
|
{
|
||||||
// only dispose TokenSource for step level ExecutionContext
|
// only dispose TokenSource for step level ExecutionContext
|
||||||
_cancellationTokenSource?.Dispose();
|
_cancellationTokenSource?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.End();
|
_logger.End();
|
||||||
|
|
||||||
// Skip if generated context name. Generated context names start with "__". After M271-ish the server will never send an empty context name.
|
// todo: Skip if generated context name. After M271-ish the server will never send an empty context name. Generated context names will start with "__"
|
||||||
if (!string.IsNullOrEmpty(ContextName) && !ContextName.StartsWith("__", StringComparison.Ordinal))
|
if (!string.IsNullOrEmpty(ContextName))
|
||||||
{
|
{
|
||||||
Global.StepsContext.SetOutcome(ScopeName, ContextName, (Outcome ?? Result ?? TaskResult.Succeeded).ToActionResult());
|
Global.StepsContext.SetOutcome(ScopeName, ContextName, (Outcome ?? Result ?? TaskResult.Succeeded).ToActionResult());
|
||||||
Global.StepsContext.SetConclusion(ScopeName, ContextName, (Result ?? TaskResult.Succeeded).ToActionResult());
|
Global.StepsContext.SetConclusion(ScopeName, ContextName, (Result ?? TaskResult.Succeeded).ToActionResult());
|
||||||
@@ -450,8 +441,8 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
ArgUtil.NotNullOrEmpty(name, nameof(name));
|
ArgUtil.NotNullOrEmpty(name, nameof(name));
|
||||||
|
|
||||||
// Skip if generated context name. Generated context names start with "__". After M271-ish the server will never send an empty context name.
|
// todo: Skip if generated context name. After M271-ish the server will never send an empty context name. Generated context names will start with "__"
|
||||||
if (string.IsNullOrEmpty(ContextName) || ContextName.StartsWith("__", StringComparison.Ordinal))
|
if (string.IsNullOrEmpty(ContextName))
|
||||||
{
|
{
|
||||||
reference = null;
|
reference = null;
|
||||||
return;
|
return;
|
||||||
@@ -614,9 +605,6 @@ namespace GitHub.Runner.Worker
|
|||||||
// Job Outputs
|
// Job Outputs
|
||||||
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
JobOutputs = new Dictionary<string, VariableValue>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
// Actions environment
|
|
||||||
ActionsEnvironment = message.ActionsEnvironment;
|
|
||||||
|
|
||||||
// Service container info
|
// Service container info
|
||||||
Global.ServiceContainers = new List<ContainerInfo>();
|
Global.ServiceContainers = new List<ContainerInfo>();
|
||||||
|
|
||||||
@@ -669,7 +657,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Global.PrependPath = new List<string>();
|
Global.PrependPath = new List<string>();
|
||||||
|
|
||||||
// JobSteps for job ExecutionContext
|
// JobSteps for job ExecutionContext
|
||||||
JobSteps = new Queue<IStep>();
|
JobSteps = new List<IStep>();
|
||||||
|
|
||||||
// PostJobSteps for job ExecutionContext
|
// PostJobSteps for job ExecutionContext
|
||||||
PostJobSteps = new Stack<IStep>();
|
PostJobSteps = new Stack<IStep>();
|
||||||
@@ -723,7 +711,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_jobServerQueue.QueueWebConsoleLine(_record.Id, msg, totalLines);
|
_jobServerQueue.QueueWebConsoleLine(_record.Id, msg);
|
||||||
return totalLines;
|
return totalLines;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,262 +0,0 @@
|
|||||||
using GitHub.DistributedTask.WebApi;
|
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Common;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Worker
|
|
||||||
{
|
|
||||||
[ServiceLocator(Default = typeof(FileCommandManager))]
|
|
||||||
public interface IFileCommandManager : IRunnerService
|
|
||||||
{
|
|
||||||
void InitializeFiles(IExecutionContext context, ContainerInfo container);
|
|
||||||
void ProcessFiles(IExecutionContext context, ContainerInfo container);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class FileCommandManager : RunnerService, IFileCommandManager
|
|
||||||
{
|
|
||||||
private const string _folderName = "_runner_file_commands";
|
|
||||||
private List<IFileCommandExtension> _commandExtensions;
|
|
||||||
private string _fileSuffix = String.Empty;
|
|
||||||
private string _fileCommandDirectory;
|
|
||||||
private Tracing _trace;
|
|
||||||
|
|
||||||
public override void Initialize(IHostContext hostContext)
|
|
||||||
{
|
|
||||||
base.Initialize(hostContext);
|
|
||||||
_trace = HostContext.GetTrace(nameof(FileCommandManager));
|
|
||||||
|
|
||||||
_fileCommandDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Temp), _folderName);
|
|
||||||
if (!Directory.Exists(_fileCommandDirectory))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(_fileCommandDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
var extensionManager = hostContext.GetService<IExtensionManager>();
|
|
||||||
_commandExtensions = extensionManager.GetExtensions<IFileCommandExtension>() ?? new List<IFileCommandExtension>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InitializeFiles(IExecutionContext context, ContainerInfo container)
|
|
||||||
{
|
|
||||||
var oldSuffix = _fileSuffix;
|
|
||||||
_fileSuffix = Guid.NewGuid().ToString();
|
|
||||||
foreach (var fileCommand in _commandExtensions)
|
|
||||||
{
|
|
||||||
var oldPath = Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + oldSuffix);
|
|
||||||
if (oldSuffix != String.Empty && File.Exists(oldPath))
|
|
||||||
{
|
|
||||||
TryDeleteFile(oldPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var newPath = Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix);
|
|
||||||
TryDeleteFile(newPath);
|
|
||||||
File.Create(newPath).Dispose();
|
|
||||||
|
|
||||||
var pathToSet = container != null ? container.TranslateToContainerPath(newPath) : newPath;
|
|
||||||
context.SetGitHubContext(fileCommand.ContextName, pathToSet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ProcessFiles(IExecutionContext context, ContainerInfo container)
|
|
||||||
{
|
|
||||||
foreach (var fileCommand in _commandExtensions)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
fileCommand.ProcessCommand(context, Path.Combine(_fileCommandDirectory, fileCommand.FilePrefix + _fileSuffix),container);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
context.Error($"Unable to process file command '{fileCommand.ContextName}' successfully.");
|
|
||||||
context.Error(ex);
|
|
||||||
context.CommandResult = TaskResult.Failed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryDeleteFile(string path)
|
|
||||||
{
|
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(path);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_trace.Warning($"Unable to delete file {path} for reason: {e.ToString()}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IFileCommandExtension : IExtension
|
|
||||||
{
|
|
||||||
string ContextName { get; }
|
|
||||||
string FilePrefix { get; }
|
|
||||||
|
|
||||||
void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container);
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class AddPathFileCommand : RunnerService, IFileCommandExtension
|
|
||||||
{
|
|
||||||
public string ContextName => "path";
|
|
||||||
public string FilePrefix => "add_path_";
|
|
||||||
|
|
||||||
public Type ExtensionType => typeof(IFileCommandExtension);
|
|
||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
|
||||||
{
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
{
|
|
||||||
var lines = File.ReadAllLines(filePath, Encoding.UTF8);
|
|
||||||
foreach(var line in lines)
|
|
||||||
{
|
|
||||||
if (line == string.Empty)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
context.Global.PrependPath.RemoveAll(x => string.Equals(x, line, StringComparison.CurrentCulture));
|
|
||||||
context.Global.PrependPath.Add(line);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SetEnvFileCommand : RunnerService, IFileCommandExtension
|
|
||||||
{
|
|
||||||
public string ContextName => "env";
|
|
||||||
public string FilePrefix => "set_env_";
|
|
||||||
|
|
||||||
public Type ExtensionType => typeof(IFileCommandExtension);
|
|
||||||
|
|
||||||
public void ProcessCommand(IExecutionContext context, string filePath, ContainerInfo container)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var text = File.ReadAllText(filePath) ?? string.Empty;
|
|
||||||
var index = 0;
|
|
||||||
var line = ReadLine(text, ref index);
|
|
||||||
while (line != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(line))
|
|
||||||
{
|
|
||||||
var equalsIndex = line.IndexOf("=", StringComparison.Ordinal);
|
|
||||||
var heredocIndex = line.IndexOf("<<", StringComparison.Ordinal);
|
|
||||||
|
|
||||||
// Normal style NAME=VALUE
|
|
||||||
if (equalsIndex >= 0 && (heredocIndex < 0 || equalsIndex < heredocIndex))
|
|
||||||
{
|
|
||||||
var split = line.Split(new[] { '=' }, 2, StringSplitOptions.None);
|
|
||||||
if (string.IsNullOrEmpty(line))
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable format '{line}'. Environment variable name must not be empty");
|
|
||||||
}
|
|
||||||
SetEnvironmentVariable(context, split[0], split[1]);
|
|
||||||
}
|
|
||||||
// Heredoc style NAME<<EOF
|
|
||||||
else if (heredocIndex >= 0 && (equalsIndex < 0 || heredocIndex < equalsIndex))
|
|
||||||
{
|
|
||||||
var split = line.Split(new[] { "<<" }, 2, StringSplitOptions.None);
|
|
||||||
if (string.IsNullOrEmpty(split[0]) || string.IsNullOrEmpty(split[1]))
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable format '{line}'. Environment variable name must not be empty and delimiter must not be empty");
|
|
||||||
}
|
|
||||||
var name = split[0];
|
|
||||||
var delimiter = split[1];
|
|
||||||
var startIndex = index; // Start index of the value (inclusive)
|
|
||||||
var endIndex = index; // End index of the value (exclusive)
|
|
||||||
var tempLine = ReadLine(text, ref index, out var newline);
|
|
||||||
while (!string.Equals(tempLine, delimiter, StringComparison.Ordinal))
|
|
||||||
{
|
|
||||||
if (tempLine == null)
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable value. Matching delimiter not found '{delimiter}'");
|
|
||||||
}
|
|
||||||
endIndex = index - newline.Length;
|
|
||||||
tempLine = ReadLine(text, ref index, out newline);
|
|
||||||
}
|
|
||||||
|
|
||||||
var value = endIndex > startIndex ? text.Substring(startIndex, endIndex - startIndex) : string.Empty;
|
|
||||||
SetEnvironmentVariable(context, name, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception($"Invalid environment variable format '{line}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
line = ReadLine(text, ref index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (DirectoryNotFoundException)
|
|
||||||
{
|
|
||||||
context.Debug($"Environment variables file does not exist '{filePath}'");
|
|
||||||
}
|
|
||||||
catch (FileNotFoundException)
|
|
||||||
{
|
|
||||||
context.Debug($"Environment variables file does not exist '{filePath}'");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetEnvironmentVariable(
|
|
||||||
IExecutionContext context,
|
|
||||||
string name,
|
|
||||||
string value)
|
|
||||||
{
|
|
||||||
context.Global.EnvironmentVariables[name] = value;
|
|
||||||
context.SetEnvContext(name, value);
|
|
||||||
context.Debug($"{name}='{value}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadLine(
|
|
||||||
string text,
|
|
||||||
ref int index)
|
|
||||||
{
|
|
||||||
return ReadLine(text, ref index, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string ReadLine(
|
|
||||||
string text,
|
|
||||||
ref int index,
|
|
||||||
out string newline)
|
|
||||||
{
|
|
||||||
if (index >= text.Length)
|
|
||||||
{
|
|
||||||
newline = null;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var originalIndex = index;
|
|
||||||
var lfIndex = text.IndexOf("\n", index, StringComparison.Ordinal);
|
|
||||||
if (lfIndex < 0)
|
|
||||||
{
|
|
||||||
index = text.Length;
|
|
||||||
newline = null;
|
|
||||||
return text.Substring(originalIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
var crLFIndex = text.IndexOf("\r\n", index, StringComparison.Ordinal);
|
|
||||||
if (crLFIndex >= 0 && crLFIndex < lfIndex)
|
|
||||||
{
|
|
||||||
index = crLFIndex + 2; // Skip over CRLF
|
|
||||||
newline = "\r\n";
|
|
||||||
return text.Substring(originalIndex, crLFIndex - originalIndex);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
index = lfIndex + 1; // Skip over LF
|
|
||||||
newline = "\n";
|
|
||||||
return text.Substring(originalIndex, lfIndex - originalIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,26 +6,20 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
public sealed class GitHubContext : DictionaryContextData, IEnvironmentContextData
|
public sealed class GitHubContext : DictionaryContextData, IEnvironmentContextData
|
||||||
{
|
{
|
||||||
private readonly HashSet<string> _contextEnvAllowlist = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
private readonly HashSet<string> _contextEnvWhitelist = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
|
||||||
{
|
{
|
||||||
"action",
|
"action",
|
||||||
"action_path",
|
|
||||||
"action_ref",
|
|
||||||
"action_repository",
|
|
||||||
"actor",
|
"actor",
|
||||||
"api_url",
|
"api_url",
|
||||||
"base_ref",
|
"base_ref",
|
||||||
"env",
|
|
||||||
"event_name",
|
"event_name",
|
||||||
"event_path",
|
"event_path",
|
||||||
"graphql_url",
|
"graphql_url",
|
||||||
"head_ref",
|
"head_ref",
|
||||||
"job",
|
"job",
|
||||||
"path",
|
|
||||||
"ref",
|
"ref",
|
||||||
"repository",
|
"repository",
|
||||||
"repository_owner",
|
"repository_owner",
|
||||||
"retention_days",
|
|
||||||
"run_id",
|
"run_id",
|
||||||
"run_number",
|
"run_number",
|
||||||
"server_url",
|
"server_url",
|
||||||
@@ -38,23 +32,11 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
foreach (var data in this)
|
foreach (var data in this)
|
||||||
{
|
{
|
||||||
if (_contextEnvAllowlist.Contains(data.Key) && data.Value is StringContextData value)
|
if (_contextEnvWhitelist.Contains(data.Key) && data.Value is StringContextData value)
|
||||||
{
|
{
|
||||||
yield return new KeyValuePair<string, string>($"GITHUB_{data.Key.ToUpperInvariant()}", value);
|
yield return new KeyValuePair<string, string>($"GITHUB_{data.Key.ToUpperInvariant()}", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public GitHubContext ShallowCopy()
|
|
||||||
{
|
|
||||||
var copy = new GitHubContext();
|
|
||||||
|
|
||||||
foreach (var pair in this)
|
|
||||||
{
|
|
||||||
copy[pair.Key] = pair.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,9 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
ArgUtil.NotNull(Inputs, nameof(Inputs));
|
ArgUtil.NotNull(Inputs, nameof(Inputs));
|
||||||
ArgUtil.NotNull(Data.Steps, nameof(Data.Steps));
|
ArgUtil.NotNull(Data.Steps, nameof(Data.Steps));
|
||||||
|
|
||||||
|
var githubContext = ExecutionContext.ExpressionValues["github"] as GitHubContext;
|
||||||
|
ArgUtil.NotNull(githubContext, nameof(githubContext));
|
||||||
|
|
||||||
// Resolve action steps
|
// Resolve action steps
|
||||||
var actionSteps = Data.Steps;
|
var actionSteps = Data.Steps;
|
||||||
|
|
||||||
@@ -61,16 +64,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
actionRunner.Condition = actionStep.Condition;
|
actionRunner.Condition = actionStep.Condition;
|
||||||
|
|
||||||
var step = ExecutionContext.CreateCompositeStep(childScopeName, actionRunner, inputsData, Environment);
|
var step = ExecutionContext.CreateCompositeStep(childScopeName, actionRunner, inputsData, Environment);
|
||||||
|
|
||||||
// Shallow copy github context
|
|
||||||
var gitHubContext = step.ExecutionContext.ExpressionValues["github"] as GitHubContext;
|
|
||||||
ArgUtil.NotNull(gitHubContext, nameof(gitHubContext));
|
|
||||||
gitHubContext = gitHubContext.ShallowCopy();
|
|
||||||
step.ExecutionContext.ExpressionValues["github"] = gitHubContext;
|
|
||||||
|
|
||||||
// Set GITHUB_ACTION_PATH
|
|
||||||
step.ExecutionContext.SetGitHubContext("action_path", ActionDirectory);
|
|
||||||
|
|
||||||
compositeSteps.Add(step);
|
compositeSteps.Add(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,8 +77,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
ExecutionContext.ExpressionValues["steps"] = ExecutionContext.Global.StepsContext.GetScope(ExecutionContext.GetFullyQualifiedContextName());
|
ExecutionContext.ExpressionValues["steps"] = ExecutionContext.Global.StepsContext.GetScope(ExecutionContext.GetFullyQualifiedContextName());
|
||||||
|
|
||||||
ProcessCompositeActionOutputs();
|
ProcessCompositeActionOutputs();
|
||||||
|
|
||||||
ExecutionContext.Global.StepsContext.ClearScope(childScopeName);
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -131,19 +122,12 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
var outputsName = pair.Key;
|
var outputsName = pair.Key;
|
||||||
var outputsAttributes = pair.Value as DictionaryContextData;
|
var outputsAttributes = pair.Value as DictionaryContextData;
|
||||||
outputsAttributes.TryGetValue("value", out var val);
|
outputsAttributes.TryGetValue("value", out var val);
|
||||||
|
var outputsValue = val as StringContextData;
|
||||||
|
|
||||||
if (val != null)
|
// Set output in the whole composite scope.
|
||||||
|
if (!String.IsNullOrEmpty(outputsName) && !String.IsNullOrEmpty(outputsValue))
|
||||||
{
|
{
|
||||||
var outputsValue = val as StringContextData;
|
ExecutionContext.SetOutput(outputsName, outputsValue, out _);
|
||||||
// Set output in the whole composite scope.
|
|
||||||
if (!String.IsNullOrEmpty(outputsValue))
|
|
||||||
{
|
|
||||||
ExecutionContext.SetOutput(outputsName, outputsValue, out _);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExecutionContext.SetOutput(outputsName, "", out _);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,6 +176,9 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
var actionStep = step as IActionRunner;
|
var actionStep = step as IActionRunner;
|
||||||
|
|
||||||
|
// Set GITHUB_ACTION
|
||||||
|
step.ExecutionContext.SetGitHubContext("action", step.ExecutionContext.GetFullyQualifiedContextName());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Evaluate and merge action's env block to env context
|
// Evaluate and merge action's env block to env context
|
||||||
@@ -228,6 +215,12 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
private async Task RunStepAsync(IStep step)
|
private async Task RunStepAsync(IStep step)
|
||||||
{
|
{
|
||||||
|
// Try to evaluate the display name
|
||||||
|
if (step is IActionRunner actionRunner && actionRunner.Stage == ActionRunStage.Main)
|
||||||
|
{
|
||||||
|
actionRunner.TryEvaluateDisplayName(step.ExecutionContext.ExpressionValues, step.ExecutionContext);
|
||||||
|
}
|
||||||
|
|
||||||
// Start the step.
|
// Start the step.
|
||||||
Trace.Info("Starting the step.");
|
Trace.Info("Starting the step.");
|
||||||
step.ExecutionContext.Debug($"Starting: {step.DisplayName}");
|
step.ExecutionContext.Debug($"Starting: {step.DisplayName}");
|
||||||
|
|||||||
@@ -161,21 +161,16 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
Directory.CreateDirectory(tempHomeDirectory);
|
Directory.CreateDirectory(tempHomeDirectory);
|
||||||
this.Environment["HOME"] = tempHomeDirectory;
|
this.Environment["HOME"] = tempHomeDirectory;
|
||||||
|
|
||||||
var tempFileCommandDirectory = Path.Combine(tempDirectory, "_runner_file_commands");
|
|
||||||
ArgUtil.Directory(tempFileCommandDirectory, nameof(tempFileCommandDirectory));
|
|
||||||
|
|
||||||
var tempWorkflowDirectory = Path.Combine(tempDirectory, "_github_workflow");
|
var tempWorkflowDirectory = Path.Combine(tempDirectory, "_github_workflow");
|
||||||
ArgUtil.Directory(tempWorkflowDirectory, nameof(tempWorkflowDirectory));
|
ArgUtil.Directory(tempWorkflowDirectory, nameof(tempWorkflowDirectory));
|
||||||
|
|
||||||
container.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock"));
|
container.MountVolumes.Add(new MountVolume("/var/run/docker.sock", "/var/run/docker.sock"));
|
||||||
container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home"));
|
container.MountVolumes.Add(new MountVolume(tempHomeDirectory, "/github/home"));
|
||||||
container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow"));
|
container.MountVolumes.Add(new MountVolume(tempWorkflowDirectory, "/github/workflow"));
|
||||||
container.MountVolumes.Add(new MountVolume(tempFileCommandDirectory, "/github/file_commands"));
|
|
||||||
container.MountVolumes.Add(new MountVolume(defaultWorkingDirectory, "/github/workspace"));
|
container.MountVolumes.Add(new MountVolume(defaultWorkingDirectory, "/github/workspace"));
|
||||||
|
|
||||||
container.AddPathTranslateMapping(tempHomeDirectory, "/github/home");
|
container.AddPathTranslateMapping(tempHomeDirectory, "/github/home");
|
||||||
container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow");
|
container.AddPathTranslateMapping(tempWorkflowDirectory, "/github/workflow");
|
||||||
container.AddPathTranslateMapping(tempFileCommandDirectory, "/github/file_commands");
|
|
||||||
container.AddPathTranslateMapping(defaultWorkingDirectory, "/github/workspace");
|
container.AddPathTranslateMapping(defaultWorkingDirectory, "/github/workspace");
|
||||||
|
|
||||||
container.ContainerWorkDirectory = "/github/workspace";
|
container.ContainerWorkDirectory = "/github/workspace";
|
||||||
|
|||||||
@@ -82,6 +82,10 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext);
|
var nodeRuntimeVersion = await StepHost.DetermineNodeRuntimeVersion(ExecutionContext);
|
||||||
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
string file = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Externals), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
if (System.Environment.GetEnvironmentVariable("K8S_POD_NAME") != null)
|
||||||
|
{
|
||||||
|
file = Path.Combine(Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Work), "__externals_copy"), nodeRuntimeVersion, "bin", $"node{IOUtil.ExeExtension}");
|
||||||
|
}
|
||||||
|
|
||||||
// Format the arguments passed to node.
|
// Format the arguments passed to node.
|
||||||
// 1) Wrap the script file path in double quotes.
|
// 1) Wrap the script file path in double quotes.
|
||||||
|
|||||||
@@ -23,19 +23,6 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
public override void PrintActionDetails(ActionRunStage stage)
|
public override void PrintActionDetails(ActionRunStage stage)
|
||||||
{
|
{
|
||||||
// We don't want to display the internal workings if composite (similar/equivalent information can be found in debug)
|
|
||||||
void writeDetails(string message)
|
|
||||||
{
|
|
||||||
if (ExecutionContext.InsideComposite)
|
|
||||||
{
|
|
||||||
ExecutionContext.Debug(message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExecutionContext.Output(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stage == ActionRunStage.Post)
|
if (stage == ActionRunStage.Post)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Script action should not have 'Post' job action.");
|
throw new NotSupportedException("Script action should not have 'Post' job action.");
|
||||||
@@ -52,7 +39,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
firstLine = firstLine.Substring(0, firstNewLine);
|
firstLine = firstLine.Substring(0, firstNewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
writeDetails(ExecutionContext.InsideComposite ? $"Run {firstLine}" : $"##[group]Run {firstLine}");
|
ExecutionContext.Output($"##[group]Run {firstLine}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -63,7 +50,7 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
foreach (var line in multiLines)
|
foreach (var line in multiLines)
|
||||||
{
|
{
|
||||||
// Bright Cyan color
|
// Bright Cyan color
|
||||||
writeDetails($"\x1b[36;1m{line}\x1b[0m");
|
ExecutionContext.Output($"\x1b[36;1m{line}\x1b[0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
string argFormat;
|
string argFormat;
|
||||||
@@ -122,23 +109,23 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(shellCommandPath))
|
if (!string.IsNullOrEmpty(shellCommandPath))
|
||||||
{
|
{
|
||||||
writeDetails($"shell: {shellCommandPath} {argFormat}");
|
ExecutionContext.Output($"shell: {shellCommandPath} {argFormat}");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
writeDetails($"shell: {shellCommand} {argFormat}");
|
ExecutionContext.Output($"shell: {shellCommand} {argFormat}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.Environment?.Count > 0)
|
if (this.Environment?.Count > 0)
|
||||||
{
|
{
|
||||||
writeDetails("env:");
|
ExecutionContext.Output("env:");
|
||||||
foreach (var env in this.Environment)
|
foreach (var env in this.Environment)
|
||||||
{
|
{
|
||||||
writeDetails($" {env.Key}: {env.Value}");
|
ExecutionContext.Output($" {env.Key}: {env.Value}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
writeDetails(ExecutionContext.InsideComposite ? "" : "##[endgroup]");
|
ExecutionContext.Output("##[endgroup]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RunAsync(ActionRunStage stage)
|
public async Task RunAsync(ActionRunStage stage)
|
||||||
@@ -164,6 +151,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
string workingDirectory = null;
|
string workingDirectory = null;
|
||||||
if (!Inputs.TryGetValue("workingDirectory", out workingDirectory))
|
if (!Inputs.TryGetValue("workingDirectory", out workingDirectory))
|
||||||
{
|
{
|
||||||
|
// TODO: figure out how defaults interact with template later
|
||||||
|
// for now, we won't check job.defaults if we are inside a template.
|
||||||
if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults))
|
if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults))
|
||||||
{
|
{
|
||||||
if (runDefaults.TryGetValue("working-directory", out workingDirectory))
|
if (runDefaults.TryGetValue("working-directory", out workingDirectory))
|
||||||
@@ -178,6 +167,8 @@ namespace GitHub.Runner.Worker.Handlers
|
|||||||
string shell = null;
|
string shell = null;
|
||||||
if (!Inputs.TryGetValue("shell", out shell) || string.IsNullOrEmpty(shell))
|
if (!Inputs.TryGetValue("shell", out shell) || string.IsNullOrEmpty(shell))
|
||||||
{
|
{
|
||||||
|
// TODO: figure out how defaults interact with template later
|
||||||
|
// for now, we won't check job.defaults if we are inside a template.
|
||||||
if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults))
|
if (string.IsNullOrEmpty(ExecutionContext.ScopeName) && ExecutionContext.Global.JobDefaults.TryGetValue("run", out var runDefaults))
|
||||||
{
|
{
|
||||||
if (runDefaults.TryGetValue("shell", out shell))
|
if (runDefaults.TryGetValue("shell", out shell))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@@ -74,10 +74,6 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
// print out HostName for self-hosted runner
|
// print out HostName for self-hosted runner
|
||||||
context.Output($"Runner name: '{setting.AgentName}'");
|
context.Output($"Runner name: '{setting.AgentName}'");
|
||||||
if (message.Variables.TryGetValue("system.runnerGroupName", out VariableValue runnerGroupName))
|
|
||||||
{
|
|
||||||
context.Output($"Runner group name: '{runnerGroupName.Value}'");
|
|
||||||
}
|
|
||||||
context.Output($"Machine name: '{Environment.MachineName}'");
|
context.Output($"Machine name: '{Environment.MachineName}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,24 +361,6 @@ namespace GitHub.Runner.Worker
|
|||||||
context.Start();
|
context.Start();
|
||||||
context.Debug("Starting: Complete job");
|
context.Debug("Starting: Complete job");
|
||||||
|
|
||||||
Trace.Info("Initialize Env context");
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
var envContext = new DictionaryContextData();
|
|
||||||
#else
|
|
||||||
var envContext = new CaseSensitiveDictionaryContextData();
|
|
||||||
#endif
|
|
||||||
context.ExpressionValues["env"] = envContext;
|
|
||||||
foreach (var pair in context.Global.EnvironmentVariables)
|
|
||||||
{
|
|
||||||
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate env context for each step
|
|
||||||
Trace.Info("Initialize steps context");
|
|
||||||
context.ExpressionValues["steps"] = context.Global.StepsContext.GetScope(context.ScopeName);
|
|
||||||
|
|
||||||
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
|
||||||
// Evaluate job outputs
|
// Evaluate job outputs
|
||||||
if (message.JobOutputs != null && message.JobOutputs.Type != TokenType.Null)
|
if (message.JobOutputs != null && message.JobOutputs.Type != TokenType.Null)
|
||||||
{
|
{
|
||||||
@@ -392,7 +370,21 @@ namespace GitHub.Runner.Worker
|
|||||||
|
|
||||||
// Populate env context for each step
|
// Populate env context for each step
|
||||||
Trace.Info("Initialize Env context for evaluating job outputs");
|
Trace.Info("Initialize Env context for evaluating job outputs");
|
||||||
|
#if OS_WINDOWS
|
||||||
|
var envContext = new DictionaryContextData();
|
||||||
|
#else
|
||||||
|
var envContext = new CaseSensitiveDictionaryContextData();
|
||||||
|
#endif
|
||||||
|
context.ExpressionValues["env"] = envContext;
|
||||||
|
foreach (var pair in context.Global.EnvironmentVariables)
|
||||||
|
{
|
||||||
|
envContext[pair.Key] = new StringContextData(pair.Value ?? string.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
Trace.Info("Initialize steps context for evaluating job outputs");
|
||||||
|
context.ExpressionValues["steps"] = context.Global.StepsContext.GetScope(context.ScopeName);
|
||||||
|
|
||||||
|
var templateEvaluator = context.ToPipelineTemplateEvaluator();
|
||||||
var outputs = templateEvaluator.EvaluateJobOutput(message.JobOutputs, context.ExpressionValues, context.ExpressionFunctions);
|
var outputs = templateEvaluator.EvaluateJobOutput(message.JobOutputs, context.ExpressionValues, context.ExpressionFunctions);
|
||||||
foreach (var output in outputs)
|
foreach (var output in outputs)
|
||||||
{
|
{
|
||||||
@@ -421,34 +413,6 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate environment data
|
|
||||||
if (jobContext.ActionsEnvironment?.Url != null && jobContext.ActionsEnvironment?.Url.Type != TokenType.Null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
context.Output($"Evaluate and set environment url");
|
|
||||||
|
|
||||||
var environmentUrlToken = templateEvaluator.EvaluateEnvironmentUrl(jobContext.ActionsEnvironment.Url, context.ExpressionValues, context.ExpressionFunctions);
|
|
||||||
var environmentUrl = environmentUrlToken.AssertString("environment.url");
|
|
||||||
if (!string.Equals(environmentUrl.Value, HostContext.SecretMasker.MaskSecrets(environmentUrl.Value)))
|
|
||||||
{
|
|
||||||
context.Warning($"Skip setting environment url as environment '{jobContext.ActionsEnvironment.Name}' may contain secret.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
context.Output($"Evaluated environment url: {environmentUrl}");
|
|
||||||
jobContext.ActionsEnvironment.Url = environmentUrlToken;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
context.Result = TaskResult.Failed;
|
|
||||||
context.Error($"Failed to evaluate environment url");
|
|
||||||
context.Error(ex);
|
|
||||||
jobContext.Result = TaskResultUtil.MergeTaskResults(jobContext.Result, TaskResult.Failed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (context.Global.Variables.GetBoolean(Constants.Variables.Actions.RunnerDebug) ?? false)
|
if (context.Global.Variables.GetBoolean(Constants.Variables.Actions.RunnerDebug) ?? false)
|
||||||
{
|
{
|
||||||
Trace.Info("Support log upload starting.");
|
Trace.Info("Support log upload starting.");
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
foreach (var step in jobSteps)
|
foreach (var step in jobSteps)
|
||||||
{
|
{
|
||||||
jobContext.JobSteps.Enqueue(step);
|
jobContext.JobSteps.Add(step);
|
||||||
}
|
}
|
||||||
|
|
||||||
await stepsRunner.RunAsync(jobContext);
|
await stepsRunner.RunAsync(jobContext);
|
||||||
@@ -216,7 +216,7 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
|
|
||||||
Trace.Info("Raising job completed event.");
|
Trace.Info("Raising job completed event.");
|
||||||
var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, result, jobContext.JobOutputs, jobContext.ActionsEnvironment);
|
var jobCompletedEvent = new JobCompletedEvent(message.RequestId, message.JobId, result, jobContext.JobOutputs);
|
||||||
|
|
||||||
var completeJobRetryLimit = 5;
|
var completeJobRetryLimit = 5;
|
||||||
var exceptions = new List<Exception>();
|
var exceptions = new List<Exception>();
|
||||||
|
|||||||
@@ -15,14 +15,6 @@ namespace GitHub.Runner.Worker
|
|||||||
private static readonly Regex _propertyRegex = new Regex("^[a-zA-Z_][a-zA-Z0-9_]*$", RegexOptions.Compiled);
|
private static readonly Regex _propertyRegex = new Regex("^[a-zA-Z_][a-zA-Z0-9_]*$", RegexOptions.Compiled);
|
||||||
private readonly DictionaryContextData _contextData = new DictionaryContextData();
|
private readonly DictionaryContextData _contextData = new DictionaryContextData();
|
||||||
|
|
||||||
public void ClearScope(string scopeName)
|
|
||||||
{
|
|
||||||
if (_contextData.TryGetValue(scopeName, out _))
|
|
||||||
{
|
|
||||||
_contextData[scopeName] = new DictionaryContextData();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public DictionaryContextData GetScope(string scopeName)
|
public DictionaryContextData GetScope(string scopeName)
|
||||||
{
|
{
|
||||||
if (scopeName == null)
|
if (scopeName == null)
|
||||||
|
|||||||
@@ -59,13 +59,14 @@ namespace GitHub.Runner.Worker
|
|||||||
checkPostJobActions = true;
|
checkPostJobActions = true;
|
||||||
while (jobContext.PostJobSteps.TryPop(out var postStep))
|
while (jobContext.PostJobSteps.TryPop(out var postStep))
|
||||||
{
|
{
|
||||||
jobContext.JobSteps.Enqueue(postStep);
|
jobContext.JobSteps.Add(postStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var step = jobContext.JobSteps.Dequeue();
|
var step = jobContext.JobSteps[0];
|
||||||
|
jobContext.JobSteps.RemoveAt(0);
|
||||||
|
|
||||||
Trace.Info($"Processing step: DisplayName='{step.DisplayName}'");
|
Trace.Info($"Processing step: DisplayName='{step.DisplayName}'");
|
||||||
ArgUtil.NotNull(step.ExecutionContext, nameof(step.ExecutionContext));
|
ArgUtil.NotNull(step.ExecutionContext, nameof(step.ExecutionContext));
|
||||||
@@ -104,7 +105,16 @@ namespace GitHub.Runner.Worker
|
|||||||
if (step is IActionRunner actionStep)
|
if (step is IActionRunner actionStep)
|
||||||
{
|
{
|
||||||
// Set GITHUB_ACTION
|
// Set GITHUB_ACTION
|
||||||
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name);
|
// Warning: Do not turn on FF DistributedTask.UseContextNameForGITHUBACTION until after M271-ish. After M271-ish
|
||||||
|
// the server will never send an empty context name. Generated context names start with "__"
|
||||||
|
if (step.ExecutionContext.Global.Variables.GetBoolean("DistributedTask.UseContextNameForGITHUBACTION") ?? false)
|
||||||
|
{
|
||||||
|
step.ExecutionContext.SetGitHubContext("action", actionStep.Action.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
step.ExecutionContext.SetGitHubContext("action", step.ExecutionContext.GetFullyQualifiedContextName());
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -108,26 +108,19 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"composite-steps": {
|
"composite-steps": {
|
||||||
|
"context": [
|
||||||
|
"github",
|
||||||
|
"strategy",
|
||||||
|
"matrix",
|
||||||
|
"steps",
|
||||||
|
"inputs",
|
||||||
|
"job",
|
||||||
|
"runner",
|
||||||
|
"env",
|
||||||
|
"hashFiles(1,255)"
|
||||||
|
],
|
||||||
"sequence": {
|
"sequence": {
|
||||||
"item-type": "composite-step"
|
"item-type": "any"
|
||||||
}
|
|
||||||
},
|
|
||||||
"composite-step": {
|
|
||||||
"mapping": {
|
|
||||||
"properties": {
|
|
||||||
"name": "string-steps-context",
|
|
||||||
"id": "non-empty-string",
|
|
||||||
"run": {
|
|
||||||
"type": "string-steps-context",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"env": "step-env",
|
|
||||||
"working-directory": "string-steps-context",
|
|
||||||
"shell": {
|
|
||||||
"type": "non-empty-string",
|
|
||||||
"required": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"container-runs-context": {
|
"container-runs-context": {
|
||||||
@@ -164,37 +157,6 @@
|
|||||||
"string": {
|
"string": {
|
||||||
"require-non-empty": true
|
"require-non-empty": true
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"string-steps-context": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"inputs",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"steps",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env",
|
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
|
||||||
"string": {}
|
|
||||||
},
|
|
||||||
"step-env": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"inputs",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"steps",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env",
|
|
||||||
"hashFiles(1,255)"
|
|
||||||
],
|
|
||||||
"mapping": {
|
|
||||||
"loose-key-type": "non-empty-string",
|
|
||||||
"loose-value-type": "string"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,6 @@ namespace GitHub.DistributedTask.ObjectTemplating
|
|||||||
internal const String String = "string";
|
internal const String String = "string";
|
||||||
internal const String StringDefinition = "string-definition";
|
internal const String StringDefinition = "string-definition";
|
||||||
internal const String StringDefinitionProperties = "string-definition-properties";
|
internal const String StringDefinitionProperties = "string-definition-properties";
|
||||||
internal const String StringRunnerContextNoSecrets = "string-runner-context-no-secrets";
|
|
||||||
internal const String Structure = "structure";
|
internal const String Structure = "structure";
|
||||||
internal const String TemplateSchema = "template-schema";
|
internal const String TemplateSchema = "template-schema";
|
||||||
internal const String True = "true";
|
internal const String True = "true";
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
IEnumerable<JobStep> steps,
|
IEnumerable<JobStep> steps,
|
||||||
IList<String> fileTable,
|
IList<String> fileTable,
|
||||||
TemplateToken jobOutputs,
|
TemplateToken jobOutputs,
|
||||||
IList<TemplateToken> defaults,
|
IList<TemplateToken> defaults)
|
||||||
ActionsEnvironmentReference actionsEnvironment)
|
|
||||||
{
|
{
|
||||||
this.MessageType = JobRequestMessageTypes.PipelineAgentJobRequest;
|
this.MessageType = JobRequestMessageTypes.PipelineAgentJobRequest;
|
||||||
this.Plan = plan;
|
this.Plan = plan;
|
||||||
@@ -55,7 +54,7 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
this.Resources = jobResources;
|
this.Resources = jobResources;
|
||||||
this.Workspace = workspaceOptions;
|
this.Workspace = workspaceOptions;
|
||||||
this.JobOutputs = jobOutputs;
|
this.JobOutputs = jobOutputs;
|
||||||
this.ActionsEnvironment = actionsEnvironment;
|
|
||||||
m_variables = new Dictionary<String, VariableValue>(variables, StringComparer.OrdinalIgnoreCase);
|
m_variables = new Dictionary<String, VariableValue>(variables, StringComparer.OrdinalIgnoreCase);
|
||||||
m_maskHints = new List<MaskHint>(maskHints);
|
m_maskHints = new List<MaskHint>(maskHints);
|
||||||
m_steps = new List<JobStep>(steps);
|
m_steps = new List<JobStep>(steps);
|
||||||
@@ -229,13 +228,6 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the collection of variables associated with the current context.
|
/// Gets the collection of variables associated with the current context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -56,36 +56,5 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the credentials used for pulling the container iamge.
|
|
||||||
/// </summary>
|
|
||||||
public ContainerRegistryCredentials Credentials
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public sealed class ContainerRegistryCredentials
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the user to authenticate to a registry with
|
|
||||||
/// </summary>
|
|
||||||
public String Username
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the password to authenticate to a registry with
|
|
||||||
/// </summary>
|
|
||||||
public String Password
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,10 +14,8 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String Clean= "clean";
|
public const String Clean= "clean";
|
||||||
public const String Container = "container";
|
public const String Container = "container";
|
||||||
public const String ContinueOnError = "continue-on-error";
|
public const String ContinueOnError = "continue-on-error";
|
||||||
public const String Credentials = "credentials";
|
|
||||||
public const String Defaults = "defaults";
|
public const String Defaults = "defaults";
|
||||||
public const String Env = "env";
|
public const String Env = "env";
|
||||||
public const String Environment = "environment";
|
|
||||||
public const String Event = "event";
|
public const String Event = "event";
|
||||||
public const String EventPattern = "github.event";
|
public const String EventPattern = "github.event";
|
||||||
public const String Exclude = "exclude";
|
public const String Exclude = "exclude";
|
||||||
@@ -47,7 +45,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String Options = "options";
|
public const String Options = "options";
|
||||||
public const String Outputs = "outputs";
|
public const String Outputs = "outputs";
|
||||||
public const String OutputsPattern = "needs.*.outputs";
|
public const String OutputsPattern = "needs.*.outputs";
|
||||||
public const String Password = "password";
|
|
||||||
public const String Path = "path";
|
public const String Path = "path";
|
||||||
public const String Pool = "pool";
|
public const String Pool = "pool";
|
||||||
public const String Ports = "ports";
|
public const String Ports = "ports";
|
||||||
@@ -71,7 +68,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
public const String Success = "success";
|
public const String Success = "success";
|
||||||
public const String Template = "template";
|
public const String Template = "template";
|
||||||
public const String TimeoutMinutes = "timeout-minutes";
|
public const String TimeoutMinutes = "timeout-minutes";
|
||||||
public const String Username = "username";
|
|
||||||
public const String Uses = "uses";
|
public const String Uses = "uses";
|
||||||
public const String VmImage = "vmImage";
|
public const String VmImage = "vmImage";
|
||||||
public const String Volumes = "volumes";
|
public const String Volumes = "volumes";
|
||||||
|
|||||||
@@ -209,30 +209,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return (Int32)numberToken.Value;
|
return (Int32)numberToken.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static ContainerRegistryCredentials ConvertToContainerCredentials(TemplateToken token)
|
|
||||||
{
|
|
||||||
var credentials = token.AssertMapping(PipelineTemplateConstants.Credentials);
|
|
||||||
var result = new ContainerRegistryCredentials();
|
|
||||||
foreach (var credentialProperty in credentials)
|
|
||||||
{
|
|
||||||
var propertyName = credentialProperty.Key.AssertString($"{PipelineTemplateConstants.Credentials} key");
|
|
||||||
switch (propertyName.Value)
|
|
||||||
{
|
|
||||||
case PipelineTemplateConstants.Username:
|
|
||||||
result.Username = credentialProperty.Value.AssertString(PipelineTemplateConstants.Username).Value;
|
|
||||||
break;
|
|
||||||
case PipelineTemplateConstants.Password:
|
|
||||||
result.Password = credentialProperty.Value.AssertString(PipelineTemplateConstants.Password).Value;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Credentials} key {propertyName}");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static JobContainer ConvertToJobContainer(
|
internal static JobContainer ConvertToJobContainer(
|
||||||
TemplateContext context,
|
TemplateContext context,
|
||||||
TemplateToken value,
|
TemplateToken value,
|
||||||
@@ -299,9 +275,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
}
|
}
|
||||||
result.Volumes = volumeList;
|
result.Volumes = volumeList;
|
||||||
break;
|
break;
|
||||||
case PipelineTemplateConstants.Credentials:
|
|
||||||
result.Credentials = ConvertToContainerCredentials(containerPropertyPair.Value);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Container} key");
|
propertyName.AssertUnexpectedValue($"{PipelineTemplateConstants.Container} key");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -279,33 +279,6 @@ namespace GitHub.DistributedTask.Pipelines.ObjectTemplating
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemplateToken EvaluateEnvironmentUrl(
|
|
||||||
TemplateToken token,
|
|
||||||
DictionaryContextData contextData,
|
|
||||||
IList<IFunctionInfo> expressionFunctions)
|
|
||||||
{
|
|
||||||
var result = default(TemplateToken);
|
|
||||||
if (token != null && token.Type != TokenType.Null)
|
|
||||||
{
|
|
||||||
var context = CreateContext(contextData, expressionFunctions);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
token = TemplateEvaluator.Evaluate(context, TemplateConstants.StringRunnerContextNoSecrets, token, 0, null, omitHeader: true);
|
|
||||||
context.Errors.Check();
|
|
||||||
result = token.AssertString("environment.url");
|
|
||||||
}
|
|
||||||
catch (Exception ex) when (!(ex is TemplateValidationException))
|
|
||||||
{
|
|
||||||
context.Errors.Add(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.Errors.Check();
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Dictionary<String, String> EvaluateJobDefaultsRun(
|
public Dictionary<String, String> EvaluateJobDefaultsRun(
|
||||||
TemplateToken token,
|
TemplateToken token,
|
||||||
DictionaryContextData contextData,
|
DictionaryContextData contextData,
|
||||||
|
|||||||
@@ -373,8 +373,7 @@
|
|||||||
"options": "non-empty-string",
|
"options": "non-empty-string",
|
||||||
"env": "container-env",
|
"env": "container-env",
|
||||||
"ports": "sequence-of-non-empty-string",
|
"ports": "sequence-of-non-empty-string",
|
||||||
"volumes": "sequence-of-non-empty-string",
|
"volumes": "sequence-of-non-empty-string"
|
||||||
"credentials": "container-registry-credentials"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -405,20 +404,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
"container-registry-credentials": {
|
|
||||||
"context": [
|
|
||||||
"secrets",
|
|
||||||
"env",
|
|
||||||
"github"
|
|
||||||
],
|
|
||||||
"mapping": {
|
|
||||||
"properties": {
|
|
||||||
"username": "non-empty-string",
|
|
||||||
"password": "non-empty-string"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"container-env": {
|
"container-env": {
|
||||||
"mapping": {
|
"mapping": {
|
||||||
"loose-key-type": "non-empty-string",
|
"loose-key-type": "non-empty-string",
|
||||||
@@ -515,20 +500,6 @@
|
|||||||
"string": {}
|
"string": {}
|
||||||
},
|
},
|
||||||
|
|
||||||
"string-runner-context-no-secrets": {
|
|
||||||
"context": [
|
|
||||||
"github",
|
|
||||||
"needs",
|
|
||||||
"strategy",
|
|
||||||
"matrix",
|
|
||||||
"steps",
|
|
||||||
"job",
|
|
||||||
"runner",
|
|
||||||
"env"
|
|
||||||
],
|
|
||||||
"string": {}
|
|
||||||
},
|
|
||||||
|
|
||||||
"string-steps-context": {
|
"string-steps-context": {
|
||||||
"context": [
|
"context": [
|
||||||
"github",
|
"github",
|
||||||
@@ -545,4 +516,4 @@
|
|||||||
"string": {}
|
"string": {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
using System.Runtime.Serialization;
|
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.WebApi
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Information about an environment parsed from YML with evaluated name, URL will be evaluated on runner
|
|
||||||
/// </summary>
|
|
||||||
[DataContract]
|
|
||||||
public class ActionsEnvironmentReference
|
|
||||||
{
|
|
||||||
public ActionsEnvironmentReference(string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public TemplateToken Url { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -131,17 +131,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.Outputs = outputs;
|
this.Outputs = outputs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JobCompletedEvent(
|
|
||||||
Int64 requestId,
|
|
||||||
Guid jobId,
|
|
||||||
TaskResult result,
|
|
||||||
Dictionary<String, VariableValue> outputs,
|
|
||||||
ActionsEnvironmentReference actionsEnvironment)
|
|
||||||
: this(requestId, jobId, result, outputs)
|
|
||||||
{
|
|
||||||
this.ActionsEnvironment = actionsEnvironment;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public Int64 RequestId
|
public Int64 RequestId
|
||||||
{
|
{
|
||||||
@@ -162,13 +151,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
get;
|
get;
|
||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
|
||||||
public ActionsEnvironmentReference ActionsEnvironment
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[DataContract]
|
[DataContract]
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.PoolType = referenceToBeCloned.PoolType;
|
this.PoolType = referenceToBeCloned.PoolType;
|
||||||
this.Size = referenceToBeCloned.Size;
|
this.Size = referenceToBeCloned.Size;
|
||||||
this.IsLegacy = referenceToBeCloned.IsLegacy;
|
this.IsLegacy = referenceToBeCloned.IsLegacy;
|
||||||
this.IsInternal = referenceToBeCloned.IsInternal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TaskAgentPoolReference Clone()
|
public TaskAgentPoolReference Clone()
|
||||||
@@ -68,16 +67,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether or not this pool is internal and can't be modified by users
|
|
||||||
/// </summary>
|
|
||||||
[DataMember]
|
|
||||||
public bool IsInternal
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the type of the pool
|
/// Gets or sets the type of the pool
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.OSDescription = referenceToBeCloned.OSDescription;
|
this.OSDescription = referenceToBeCloned.OSDescription;
|
||||||
this.ProvisioningState = referenceToBeCloned.ProvisioningState;
|
this.ProvisioningState = referenceToBeCloned.ProvisioningState;
|
||||||
this.AccessPoint = referenceToBeCloned.AccessPoint;
|
this.AccessPoint = referenceToBeCloned.AccessPoint;
|
||||||
|
this.Ephemeral = referenceToBeCloned.Ephemeral;
|
||||||
|
|
||||||
if (referenceToBeCloned.m_links != null)
|
if (referenceToBeCloned.m_links != null)
|
||||||
{
|
{
|
||||||
@@ -81,6 +82,16 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
set;
|
set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Signifies that this Agent can only run one job and will be removed by the server after that one job finish.
|
||||||
|
/// </summary>
|
||||||
|
[DataMember]
|
||||||
|
public bool? Ephemeral
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether or not the agent is online.
|
/// Whether or not the agent is online.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
: base(baseUrl, pipeline, disposeHandler)
|
: base(baseUrl, pipeline, disposeHandler)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AppendTimelineRecordFeedAsync(
|
public Task AppendTimelineRecordFeedAsync(
|
||||||
Guid scopeIdentifier,
|
Guid scopeIdentifier,
|
||||||
String planType,
|
String planType,
|
||||||
@@ -91,28 +91,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
userState,
|
userState,
|
||||||
cancellationToken);
|
cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task AppendTimelineRecordFeedAsync(
|
|
||||||
Guid scopeIdentifier,
|
|
||||||
String planType,
|
|
||||||
Guid planId,
|
|
||||||
Guid timelineId,
|
|
||||||
Guid recordId,
|
|
||||||
Guid stepId,
|
|
||||||
IList<String> lines,
|
|
||||||
long startLine,
|
|
||||||
CancellationToken cancellationToken = default(CancellationToken),
|
|
||||||
Object userState = null)
|
|
||||||
{
|
|
||||||
return AppendTimelineRecordFeedAsync(scopeIdentifier,
|
|
||||||
planType,
|
|
||||||
planId,
|
|
||||||
timelineId,
|
|
||||||
recordId,
|
|
||||||
new TimelineRecordFeedLinesWrapper(stepId, lines, startLine),
|
|
||||||
userState,
|
|
||||||
cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RaisePlanEventAsync<T>(
|
public async Task RaisePlanEventAsync<T>(
|
||||||
Guid scopeIdentifier,
|
Guid scopeIdentifier,
|
||||||
|
|||||||
@@ -20,12 +20,6 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
this.Count = lines.Count;
|
this.Count = lines.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelineRecordFeedLinesWrapper(Guid stepId, IList<string> lines, Int64 startLine)
|
|
||||||
: this(stepId, lines)
|
|
||||||
{
|
|
||||||
this.StartLine = startLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember(Order = 0)]
|
[DataMember(Order = 0)]
|
||||||
public Int32 Count { get; private set; }
|
public Int32 Count { get; private set; }
|
||||||
|
|
||||||
@@ -37,8 +31,5 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
|
|
||||||
[DataMember(EmitDefaultValue = false)]
|
[DataMember(EmitDefaultValue = false)]
|
||||||
public Guid StepId { get; set; }
|
public Guid StepId { get; set; }
|
||||||
|
|
||||||
[DataMember (EmitDefaultValue = false)]
|
|
||||||
public Int64? StartLine { get; private set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace GitHub.DistributedTask.WebApi
|
|
||||||
{
|
|
||||||
[DataContract]
|
|
||||||
public sealed class TimelineRecordLogLine
|
|
||||||
{
|
|
||||||
public TimelineRecordLogLine(String line, long? lineNumber)
|
|
||||||
{
|
|
||||||
this.Line = line;
|
|
||||||
this.LineNumber = lineNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember]
|
|
||||||
public String Line
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
|
|
||||||
[DataMember (EmitDefaultValue = false)]
|
|
||||||
public long? LineNumber
|
|
||||||
{
|
|
||||||
get;
|
|
||||||
set;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -126,23 +126,5 @@ namespace GitHub.Runner.Common.Tests.Worker.Container
|
|||||||
Assert.NotNull(result5);
|
Assert.NotNull(result5);
|
||||||
Assert.Equal("/foo/bar:/baz", result5);
|
Assert.Equal("/foo/bar:/baz", result5);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
[InlineData("dockerhub/repo", "")]
|
|
||||||
[InlineData("localhost/doesnt_work", "")]
|
|
||||||
[InlineData("localhost:port/works", "localhost:port")]
|
|
||||||
[InlineData("host.tld/works", "host.tld")]
|
|
||||||
[InlineData("ghcr.io/owner/image", "ghcr.io")]
|
|
||||||
[InlineData("gcr.io/project/image", "gcr.io")]
|
|
||||||
[InlineData("myregistry.azurecr.io/namespace/image", "myregistry.azurecr.io")]
|
|
||||||
[InlineData("account.dkr.ecr.region.amazonaws.com/image", "account.dkr.ecr.region.amazonaws.com")]
|
|
||||||
[InlineData("docker.pkg.github.com/owner/repo/image", "docker.pkg.github.com")]
|
|
||||||
public void ParseRegistryHostnameFromImageName(string input, string expected)
|
|
||||||
{
|
|
||||||
var actual = DockerUtil.ParseRegistryHostnameFromImageName(input);
|
|
||||||
Assert.Equal(expected, actual);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,58 +1,58 @@
|
|||||||
using Xunit;
|
// using Xunit;
|
||||||
using System.IO;
|
// using System.IO;
|
||||||
using System.Net.Http;
|
// using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
// using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests
|
// namespace GitHub.Runner.Common.Tests
|
||||||
{
|
// {
|
||||||
public sealed class DotnetsdkDownloadScriptL0
|
// public sealed class DotnetsdkDownloadScriptL0
|
||||||
{
|
// {
|
||||||
[Fact]
|
// [Fact]
|
||||||
[Trait("Level", "L0")]
|
// [Trait("Level", "L0")]
|
||||||
[Trait("Category", "Runner")]
|
// [Trait("Category", "Runner")]
|
||||||
public async Task EnsureDotnetsdkBashDownloadScriptUpToDate()
|
// public async Task EnsureDotnetsdkBashDownloadScriptUpToDate()
|
||||||
{
|
// {
|
||||||
string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh";
|
// string shDownloadUrl = "https://dot.net/v1/dotnet-install.sh";
|
||||||
|
|
||||||
using (HttpClient downloadClient = new HttpClient())
|
// using (HttpClient downloadClient = new HttpClient())
|
||||||
{
|
// {
|
||||||
var response = await downloadClient.GetAsync("https://www.bing.com");
|
// var response = await downloadClient.GetAsync("https://www.bing.com");
|
||||||
if (!response.IsSuccessStatusCode)
|
// if (!response.IsSuccessStatusCode)
|
||||||
{
|
// {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
string shScript = await downloadClient.GetStringAsync(shDownloadUrl);
|
// string shScript = await downloadClient.GetStringAsync(shDownloadUrl);
|
||||||
|
|
||||||
string existingShScript = File.ReadAllText(Path.Combine(TestUtil.GetSrcPath(), "Misc/dotnet-install.sh"));
|
// string existingShScript = File.ReadAllText(Path.Combine(TestUtil.GetSrcPath(), "Misc/dotnet-install.sh"));
|
||||||
|
|
||||||
bool shScriptMatched = string.Equals(shScript.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"), existingShScript.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"));
|
// bool shScriptMatched = string.Equals(shScript.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"), existingShScript.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"));
|
||||||
Assert.True(shScriptMatched, "Fix the test by updating Src/Misc/dotnet-install.sh with content from https://dot.net/v1/dotnet-install.sh");
|
// Assert.True(shScriptMatched, "Fix the test by updating Src/Misc/dotnet-install.sh with content from https://dot.net/v1/dotnet-install.sh");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
[Fact]
|
// [Fact]
|
||||||
[Trait("Level", "L0")]
|
// [Trait("Level", "L0")]
|
||||||
[Trait("Category", "Runner")]
|
// [Trait("Category", "Runner")]
|
||||||
public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate()
|
// public async Task EnsureDotnetsdkPowershellDownloadScriptUpToDate()
|
||||||
{
|
// {
|
||||||
string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1";
|
// string ps1DownloadUrl = "https://dot.net/v1/dotnet-install.ps1";
|
||||||
|
|
||||||
using (HttpClient downloadClient = new HttpClient())
|
// using (HttpClient downloadClient = new HttpClient())
|
||||||
{
|
// {
|
||||||
var response = await downloadClient.GetAsync("https://www.bing.com");
|
// var response = await downloadClient.GetAsync("https://www.bing.com");
|
||||||
if (!response.IsSuccessStatusCode)
|
// if (!response.IsSuccessStatusCode)
|
||||||
{
|
// {
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
string ps1Script = await downloadClient.GetStringAsync(ps1DownloadUrl);
|
// string ps1Script = await downloadClient.GetStringAsync(ps1DownloadUrl);
|
||||||
|
|
||||||
string existingPs1Script = File.ReadAllText(Path.Combine(TestUtil.GetSrcPath(), "Misc/dotnet-install.ps1"));
|
// string existingPs1Script = File.ReadAllText(Path.Combine(TestUtil.GetSrcPath(), "Misc/dotnet-install.ps1"));
|
||||||
|
|
||||||
bool ps1ScriptMatched = string.Equals(ps1Script.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"), existingPs1Script.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"));
|
// bool ps1ScriptMatched = string.Equals(ps1Script.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"), existingPs1Script.TrimEnd('\n', '\r', '\0').Replace("\r\n", "\n").Replace("\r", "\n"));
|
||||||
Assert.True(ps1ScriptMatched, "Fix the test by updating Src/Misc/dotnet-install.ps1 with content from https://dot.net/v1/dotnet-install.ps1");
|
// Assert.True(ps1ScriptMatched, "Fix the test by updating Src/Misc/dotnet-install.ps1 with content from https://dot.net/v1/dotnet-install.ps1");
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -39,12 +39,10 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
private string _expectedToken = "expectedToken";
|
private string _expectedToken = "expectedToken";
|
||||||
private string _expectedServerUrl = "https://codedev.ms";
|
private string _expectedServerUrl = "https://codedev.ms";
|
||||||
private string _expectedAgentName = "expectedAgentName";
|
private string _expectedAgentName = "expectedAgentName";
|
||||||
private string _defaultRunnerGroupName = "defaultRunnerGroup";
|
private string _expectedPoolName = "poolName";
|
||||||
private string _secondRunnerGroupName = "secondRunnerGroup";
|
|
||||||
private string _expectedAuthType = "pat";
|
private string _expectedAuthType = "pat";
|
||||||
private string _expectedWorkFolder = "_work";
|
private string _expectedWorkFolder = "_work";
|
||||||
private int _defaultRunnerGroupId = 1;
|
private int _expectedPoolId = 1;
|
||||||
private int _secondRunnerGroupId = 2;
|
|
||||||
private RSACryptoServiceProvider rsa = null;
|
private RSACryptoServiceProvider rsa = null;
|
||||||
private RunnerSettings _configMgrAgentSettings = new RunnerSettings();
|
private RunnerSettings _configMgrAgentSettings = new RunnerSettings();
|
||||||
|
|
||||||
@@ -99,7 +97,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
_serviceControlManager.Setup(x => x.GenerateScripts(It.IsAny<RunnerSettings>()));
|
_serviceControlManager.Setup(x => x.GenerateScripts(It.IsAny<RunnerSettings>()));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var expectedPools = new List<TaskAgentPool>() { new TaskAgentPool(_defaultRunnerGroupName) { Id = _defaultRunnerGroupId, IsInternal = true }, new TaskAgentPool(_secondRunnerGroupName) { Id = _secondRunnerGroupId } };
|
var expectedPools = new List<TaskAgentPool>() { new TaskAgentPool(_expectedPoolName) { Id = _expectedPoolId } };
|
||||||
_runnerServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.IsAny<TaskAgentPoolType>())).Returns(Task.FromResult(expectedPools));
|
_runnerServer.Setup(x => x.GetAgentPoolsAsync(It.IsAny<string>(), It.IsAny<TaskAgentPoolType>())).Returns(Task.FromResult(expectedPools));
|
||||||
|
|
||||||
var expectedAgents = new List<TaskAgent>();
|
var expectedAgents = new List<TaskAgent>();
|
||||||
@@ -157,7 +155,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
"configure",
|
"configure",
|
||||||
"--url", _expectedServerUrl,
|
"--url", _expectedServerUrl,
|
||||||
"--name", _expectedAgentName,
|
"--name", _expectedAgentName,
|
||||||
"--runnergroup", _secondRunnerGroupName,
|
"--pool", _expectedPoolName,
|
||||||
"--work", _expectedWorkFolder,
|
"--work", _expectedWorkFolder,
|
||||||
"--auth", _expectedAuthType,
|
"--auth", _expectedAuthType,
|
||||||
"--token", _expectedToken,
|
"--token", _expectedToken,
|
||||||
@@ -177,7 +175,7 @@ namespace GitHub.Runner.Common.Tests.Listener.Configuration
|
|||||||
Assert.NotNull(s);
|
Assert.NotNull(s);
|
||||||
Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
|
Assert.True(s.ServerUrl.Equals(_expectedServerUrl));
|
||||||
Assert.True(s.AgentName.Equals(_expectedAgentName));
|
Assert.True(s.AgentName.Equals(_expectedAgentName));
|
||||||
Assert.True(s.PoolId.Equals(_secondRunnerGroupId));
|
Assert.True(s.PoolId.Equals(_expectedPoolId));
|
||||||
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
|
Assert.True(s.WorkFolder.Equals(_expectedWorkFolder));
|
||||||
|
|
||||||
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
// validate GetAgentPoolsAsync gets called twice with automation pool type
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
TimelineReference timeline = null;
|
TimelineReference timeline = null;
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var result = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "someJob", "someJob", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
result.ContextData["github"] = new Pipelines.ContextData.DictionaryContextData();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
TimelineReference timeline = null;
|
TimelineReference timeline = null;
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
return new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JobCancelMessage CreateJobCancelMessage()
|
private JobCancelMessage CreateJobCancelMessage()
|
||||||
@@ -243,7 +243,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
PoolId = 43242
|
PoolId = 43242,
|
||||||
|
Ephemeral = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var message = new TaskAgentMessage()
|
var message = new TaskAgentMessage()
|
||||||
@@ -294,7 +295,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
|
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
|
||||||
//Act
|
//Act
|
||||||
var command = new CommandSettings(hc, new string[] { "run", "--once" });
|
var command = new CommandSettings(hc, new string[] { "run" });
|
||||||
Task<int> runnerTask = runner.ExecuteCommand(command);
|
Task<int> runnerTask = runner.ExecuteCommand(command);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@@ -332,7 +333,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
runner.Initialize(hc);
|
runner.Initialize(hc);
|
||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
PoolId = 43242
|
PoolId = 43242,
|
||||||
|
Ephemeral = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var message1 = new TaskAgentMessage()
|
var message1 = new TaskAgentMessage()
|
||||||
@@ -390,7 +392,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
|
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
|
||||||
//Act
|
//Act
|
||||||
var command = new CommandSettings(hc, new string[] { "run", "--once" });
|
var command = new CommandSettings(hc, new string[] { "run" });
|
||||||
Task<int> runnerTask = runner.ExecuteCommand(command);
|
Task<int> runnerTask = runner.ExecuteCommand(command);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
@@ -431,7 +433,8 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
var settings = new RunnerSettings
|
var settings = new RunnerSettings
|
||||||
{
|
{
|
||||||
PoolId = 43242,
|
PoolId = 43242,
|
||||||
AgentId = 5678
|
AgentId = 5678,
|
||||||
|
Ephemeral = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var message1 = new TaskAgentMessage()
|
var message1 = new TaskAgentMessage()
|
||||||
@@ -475,7 +478,7 @@ namespace GitHub.Runner.Common.Tests.Listener
|
|||||||
|
|
||||||
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
|
_configStore.Setup(x => x.IsServiceConfigured()).Returns(false);
|
||||||
//Act
|
//Act
|
||||||
var command = new CommandSettings(hc, new string[] { "run", "--once" });
|
var command = new CommandSettings(hc, new string[] { "run" });
|
||||||
Task<int> runnerTask = runner.ExecuteCommand(command);
|
Task<int> runnerTask = runner.ExecuteCommand(command);
|
||||||
|
|
||||||
//Assert
|
//Assert
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -127,11 +127,11 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://127.0.0.1:8888", proxy.HttpProxyAddress);
|
Assert.Equal("http://127.0.0.1:8888/", proxy.HttpProxyAddress);
|
||||||
Assert.Null(proxy.HttpProxyUsername);
|
Assert.Null(proxy.HttpProxyUsername);
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
Assert.Null(proxy.HttpProxyPassword);
|
||||||
|
|
||||||
Assert.Equal("http://user:pass@127.0.0.1:9999", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user:pass@127.0.0.1:9999/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user", proxy.HttpsProxyUsername);
|
Assert.Equal("user", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
@@ -161,11 +161,11 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("NO_PROXY", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("NO_PROXY", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://127.0.0.1:7777", proxy.HttpProxyAddress);
|
Assert.Equal("http://127.0.0.1:7777/", proxy.HttpProxyAddress);
|
||||||
Assert.Null(proxy.HttpProxyUsername);
|
Assert.Null(proxy.HttpProxyUsername);
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
Assert.Null(proxy.HttpProxyPassword);
|
||||||
|
|
||||||
Assert.Equal("http://user:pass@127.0.0.1:8888", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user:pass@127.0.0.1:8888/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user", proxy.HttpsProxyUsername);
|
Assert.Equal("user", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
@@ -218,19 +218,19 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://user1@127.0.0.1:8888", proxy.HttpProxyAddress);
|
Assert.Equal("http://user1@127.0.0.1:8888/", proxy.HttpProxyAddress);
|
||||||
Assert.Equal("user1", proxy.HttpProxyUsername);
|
Assert.Equal("user1", proxy.HttpProxyUsername);
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
Assert.Null(proxy.HttpProxyPassword);
|
||||||
|
|
||||||
var cred = proxy.Credentials.GetCredential(new Uri("http://user1@127.0.0.1:8888"), "Basic");
|
var cred = proxy.Credentials.GetCredential(new Uri("http://user1@127.0.0.1:8888/"), "Basic");
|
||||||
Assert.Equal("user1", cred.UserName);
|
Assert.Equal("user1", cred.UserName);
|
||||||
Assert.Equal(string.Empty, cred.Password);
|
Assert.Equal(string.Empty, cred.Password);
|
||||||
|
|
||||||
Assert.Equal("http://user2:pass@127.0.0.1:9999", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user2:pass@127.0.0.1:9999/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass@127.0.0.1:9999"), "Basic");
|
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass@127.0.0.1:9999/"), "Basic");
|
||||||
Assert.Equal("user2", cred.UserName);
|
Assert.Equal("user2", cred.UserName);
|
||||||
Assert.Equal("pass", cred.Password);
|
Assert.Equal("pass", cred.Password);
|
||||||
|
|
||||||
@@ -256,19 +256,19 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
||||||
var proxy = new RunnerWebProxy();
|
var proxy = new RunnerWebProxy();
|
||||||
|
|
||||||
Assert.Equal("http://user1:pass1%40@127.0.0.1:8888", proxy.HttpProxyAddress);
|
Assert.Equal("http://user1:pass1%40@127.0.0.1:8888/", proxy.HttpProxyAddress);
|
||||||
Assert.Equal("user1", proxy.HttpProxyUsername);
|
Assert.Equal("user1", proxy.HttpProxyUsername);
|
||||||
Assert.Equal("pass1@", proxy.HttpProxyPassword);
|
Assert.Equal("pass1@", proxy.HttpProxyPassword);
|
||||||
|
|
||||||
var cred = proxy.Credentials.GetCredential(new Uri("http://user1:pass1%40@127.0.0.1:8888"), "Basic");
|
var cred = proxy.Credentials.GetCredential(new Uri("http://user1:pass1%40@127.0.0.1:8888/"), "Basic");
|
||||||
Assert.Equal("user1", cred.UserName);
|
Assert.Equal("user1", cred.UserName);
|
||||||
Assert.Equal("pass1@", cred.Password);
|
Assert.Equal("pass1@", cred.Password);
|
||||||
|
|
||||||
Assert.Equal("http://user2:pass2%40@127.0.0.1:9999", proxy.HttpsProxyAddress);
|
Assert.Equal("http://user2:pass2%40@127.0.0.1:9999/", proxy.HttpsProxyAddress);
|
||||||
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
Assert.Equal("user2", proxy.HttpsProxyUsername);
|
||||||
Assert.Equal("pass2@", proxy.HttpsProxyPassword);
|
Assert.Equal("pass2@", proxy.HttpsProxyPassword);
|
||||||
|
|
||||||
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass2%40@127.0.0.1:9999"), "Basic");
|
cred = proxy.Credentials.GetCredential(new Uri("http://user2:pass2%40@127.0.0.1:9999/"), "Basic");
|
||||||
Assert.Equal("user2", cred.UserName);
|
Assert.Equal("user2", cred.UserName);
|
||||||
Assert.Equal("pass2@", cred.Password);
|
Assert.Equal("pass2@", cred.Password);
|
||||||
|
|
||||||
@@ -405,36 +405,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Common")]
|
|
||||||
public void WebProxyFromEnvironmentVariablesWithPort80()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Environment.SetEnvironmentVariable("http_proxy", "http://127.0.0.1:80");
|
|
||||||
Environment.SetEnvironmentVariable("https_proxy", "http://user:pass@127.0.0.1:80");
|
|
||||||
Environment.SetEnvironmentVariable("no_proxy", "github.com, google.com,");
|
|
||||||
var proxy = new RunnerWebProxy();
|
|
||||||
|
|
||||||
Assert.Equal("http://127.0.0.1:80", Environment.GetEnvironmentVariable("http_proxy"));
|
|
||||||
Assert.Null(proxy.HttpProxyUsername);
|
|
||||||
Assert.Null(proxy.HttpProxyPassword);
|
|
||||||
|
|
||||||
Assert.Equal("http://user:pass@127.0.0.1:80", Environment.GetEnvironmentVariable("https_proxy"));
|
|
||||||
Assert.Equal("user", proxy.HttpsProxyUsername);
|
|
||||||
Assert.Equal("pass", proxy.HttpsProxyPassword);
|
|
||||||
|
|
||||||
Assert.Equal(2, proxy.NoProxyList.Count);
|
|
||||||
Assert.Equal("github.com", proxy.NoProxyList[0].Host);
|
|
||||||
Assert.Equal("google.com", proxy.NoProxyList[1].Host);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
CleanProxyEnv();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CleanProxyEnv()
|
private void CleanProxyEnv()
|
||||||
{
|
{
|
||||||
Environment.SetEnvironmentVariable("http_proxy", null);
|
Environment.SetEnvironmentVariable("http_proxy", null);
|
||||||
|
|||||||
@@ -60,7 +60,6 @@ namespace GitHub.Runner.Common.Tests
|
|||||||
{
|
{
|
||||||
typeof(IActionCommandExtension),
|
typeof(IActionCommandExtension),
|
||||||
typeof(IExecutionContext),
|
typeof(IExecutionContext),
|
||||||
typeof(IFileCommandExtension),
|
|
||||||
typeof(IHandler),
|
typeof(IHandler),
|
||||||
typeof(IJobExtension),
|
typeof(IJobExtension),
|
||||||
typeof(IStep),
|
typeof(IStep),
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
private TestHostContext _hc;
|
private TestHostContext _hc;
|
||||||
private ActionRunner _actionRunner;
|
private ActionRunner _actionRunner;
|
||||||
private IActionManifestManager _actionManifestManager;
|
private IActionManifestManager _actionManifestManager;
|
||||||
private Mock<IFileCommandManager> _fileCommandManager;
|
|
||||||
|
|
||||||
private DictionaryContextData _context = new DictionaryContextData();
|
private DictionaryContextData _context = new DictionaryContextData();
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
@@ -364,7 +362,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_handlerFactory = new Mock<IHandlerFactory>();
|
_handlerFactory = new Mock<IHandlerFactory>();
|
||||||
_defaultStepHost = new Mock<IDefaultStepHost>();
|
_defaultStepHost = new Mock<IDefaultStepHost>();
|
||||||
_actionManifestManager = new ActionManifestManager();
|
_actionManifestManager = new ActionManifestManager();
|
||||||
_fileCommandManager = new Mock<IFileCommandManager>();
|
|
||||||
_actionManifestManager.Initialize(_hc);
|
_actionManifestManager.Initialize(_hc);
|
||||||
|
|
||||||
var githubContext = new GitHubContext();
|
var githubContext = new GitHubContext();
|
||||||
@@ -397,8 +394,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_hc.EnqueueInstance<IDefaultStepHost>(_defaultStepHost.Object);
|
_hc.EnqueueInstance<IDefaultStepHost>(_defaultStepHost.Object);
|
||||||
|
|
||||||
_hc.EnqueueInstance(_fileCommandManager.Object);
|
|
||||||
|
|
||||||
// Instance to test.
|
// Instance to test.
|
||||||
_actionRunner = new ActionRunner();
|
_actionRunner = new ActionRunner();
|
||||||
_actionRunner.Initialize(_hc);
|
_actionRunner.Initialize(_hc);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -102,7 +102,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -116,7 +116,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var pagingLogger = new Mock<IPagingLogger>();
|
var pagingLogger = new Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||||
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>(),It.IsAny<long>())).Callback((Guid id, string msg, long? lineNumber) => { hc.GetTrace().Info(msg); });
|
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>())).Callback((Guid id, string msg) => { hc.GetTrace().Info(msg); });
|
||||||
|
|
||||||
hc.EnqueueInstance(pagingLogger.Object);
|
hc.EnqueueInstance(pagingLogger.Object);
|
||||||
hc.SetSingleton(jobServerQueue.Object);
|
hc.SetSingleton(jobServerQueue.Object);
|
||||||
@@ -137,7 +137,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
ec.Complete();
|
ec.Complete();
|
||||||
|
|
||||||
jobServerQueue.Verify(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<long?>()), Times.Exactly(10));
|
jobServerQueue.Verify(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>()), Times.Exactly(10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +153,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -171,7 +171,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var pagingLogger5 = new Mock<IPagingLogger>();
|
var pagingLogger5 = new Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||||
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<long?>())).Callback((Guid id, string msg, long? lineNumber) => { hc.GetTrace().Info(msg); });
|
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>())).Callback((Guid id, string msg) => { hc.GetTrace().Info(msg); });
|
||||||
|
|
||||||
var actionRunner1 = new ActionRunner();
|
var actionRunner1 = new ActionRunner();
|
||||||
actionRunner1.Initialize(hc);
|
actionRunner1.Initialize(hc);
|
||||||
@@ -251,7 +251,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
@@ -269,7 +269,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var pagingLogger5 = new Mock<IPagingLogger>();
|
var pagingLogger5 = new Mock<IPagingLogger>();
|
||||||
var jobServerQueue = new Mock<IJobServerQueue>();
|
var jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
jobServerQueue.Setup(x => x.QueueTimelineRecordUpdate(It.IsAny<Guid>(), It.IsAny<TimelineRecord>()));
|
||||||
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>(), It.IsAny<long?>())).Callback((Guid id, string msg, long? lineNumber) => { hc.GetTrace().Info(msg); });
|
jobServerQueue.Setup(x => x.QueueWebConsoleLine(It.IsAny<Guid>(), It.IsAny<string>())).Callback((Guid id, string msg) => { hc.GetTrace().Info(msg); });
|
||||||
|
|
||||||
var actionRunner1 = new ActionRunner();
|
var actionRunner1 = new ActionRunner();
|
||||||
actionRunner1.Initialize(hc);
|
actionRunner1.Initialize(hc);
|
||||||
@@ -335,7 +335,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TimelineReference timeline = new TimelineReference();
|
TimelineReference timeline = new TimelineReference();
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
string jobName = "some job name";
|
string jobName = "some job name";
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, jobName, jobName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
jobRequest.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
{
|
{
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ using System.Runtime.CompilerServices;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using GitHub.DistributedTask.ObjectTemplating.Tokens;
|
|
||||||
using Pipelines = GitHub.DistributedTask.Pipelines;
|
using Pipelines = GitHub.DistributedTask.Pipelines;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker
|
namespace GitHub.Runner.Common.Tests.Worker
|
||||||
@@ -99,7 +98,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
};
|
};
|
||||||
|
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null, null);
|
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, "test", "test", null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), steps, null, null, null);
|
||||||
GitHubContext github = new GitHubContext();
|
GitHubContext github = new GitHubContext();
|
||||||
github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner");
|
github["repository"] = new Pipelines.ContextData.StringContextData("actions/runner");
|
||||||
_message.ContextData.Add("github", github);
|
_message.ContextData.Add("github", github);
|
||||||
@@ -282,70 +281,5 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
Times.Never);
|
Times.Never);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void EnsureFinalizeJobRunsIfMessageHasNoEnvironmentUrl()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
var jobExtension = new JobExtension();
|
|
||||||
jobExtension.Initialize(hc);
|
|
||||||
|
|
||||||
_message.ActionsEnvironment = new ActionsEnvironmentReference("production");
|
|
||||||
|
|
||||||
_jobEc = new Runner.Worker.ExecutionContext {Result = TaskResult.Succeeded};
|
|
||||||
_jobEc.Initialize(hc);
|
|
||||||
_jobEc.InitializeJob(_message, _tokenSource.Token);
|
|
||||||
|
|
||||||
jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow);
|
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact] [Trait("Level", "L0")] [Trait("Category", "Worker")]
|
|
||||||
public void EnsureFinalizeJobHandlesNullEnvironmentUrl()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
var jobExtension = new JobExtension();
|
|
||||||
jobExtension.Initialize(hc);
|
|
||||||
|
|
||||||
_message.ActionsEnvironment = new ActionsEnvironmentReference("production")
|
|
||||||
{
|
|
||||||
Url = null
|
|
||||||
};
|
|
||||||
|
|
||||||
_jobEc = new Runner.Worker.ExecutionContext {Result = TaskResult.Succeeded};
|
|
||||||
_jobEc.Initialize(hc);
|
|
||||||
_jobEc.InitializeJob(_message, _tokenSource.Token);
|
|
||||||
|
|
||||||
jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow);
|
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact] [Trait("Level", "L0")] [Trait("Category", "Worker")]
|
|
||||||
public void EnsureFinalizeJobHandlesNullEnvironment()
|
|
||||||
{
|
|
||||||
using (TestHostContext hc = CreateTestContext())
|
|
||||||
{
|
|
||||||
var jobExtension = new JobExtension();
|
|
||||||
jobExtension.Initialize(hc);
|
|
||||||
|
|
||||||
_message.ActionsEnvironment = null;
|
|
||||||
|
|
||||||
_jobEc = new Runner.Worker.ExecutionContext {Result = TaskResult.Succeeded};
|
|
||||||
_jobEc.Initialize(hc);
|
|
||||||
_jobEc.InitializeJob(_message, _tokenSource.Token);
|
|
||||||
|
|
||||||
jobExtension.FinalizeJob(_jobEc, _message, DateTime.UtcNow);
|
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
TaskOrchestrationPlanReference plan = new TaskOrchestrationPlanReference();
|
||||||
TimelineReference timeline = new Timeline(Guid.NewGuid());
|
TimelineReference timeline = new Timeline(Guid.NewGuid());
|
||||||
Guid jobId = Guid.NewGuid();
|
Guid jobId = Guid.NewGuid();
|
||||||
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null);
|
||||||
_message.Variables[Constants.Variables.System.Culture] = "en-US";
|
_message.Variables[Constants.Variables.System.Culture] = "en-US";
|
||||||
_message.Resources.Endpoints.Add(new ServiceEndpoint()
|
_message.Resources.Endpoints.Add(new ServiceEndpoint()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,390 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using GitHub.Runner.Common.Util;
|
|
||||||
using GitHub.Runner.Sdk;
|
|
||||||
using GitHub.Runner.Worker;
|
|
||||||
using GitHub.Runner.Worker.Container;
|
|
||||||
using GitHub.Runner.Worker.Handlers;
|
|
||||||
using Moq;
|
|
||||||
using Xunit;
|
|
||||||
using DTWebApi = GitHub.DistributedTask.WebApi;
|
|
||||||
|
|
||||||
namespace GitHub.Runner.Common.Tests.Worker
|
|
||||||
{
|
|
||||||
public sealed class SetEnvFileCommandL0
|
|
||||||
{
|
|
||||||
private Mock<IExecutionContext> _executionContext;
|
|
||||||
private List<Tuple<DTWebApi.Issue, string>> _issues;
|
|
||||||
private string _rootDirectory;
|
|
||||||
private SetEnvFileCommand _setEnvFileCommand;
|
|
||||||
private ITraceWriter _trace;
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_DirectoryNotFound()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "directory-not-found", "env");
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(0, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_NotFound()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "file-not-found");
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(0, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_EmptyFile()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "empty-file");
|
|
||||||
var content = new List<string>();
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(0, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Simple()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "simple");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV=MY VALUE",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(1, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal("MY VALUE", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Simple_SkipEmptyLines()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "simple");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
string.Empty,
|
|
||||||
"MY_ENV=my value",
|
|
||||||
string.Empty,
|
|
||||||
"MY_ENV_2=my second value",
|
|
||||||
string.Empty,
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(2, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal("my value", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
Assert.Equal("my second value", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_2"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Simple_EmptyValue()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "simple-empty-value");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV=",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(1, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal(string.Empty, _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Simple_MultipleValues()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "simple");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV=my value",
|
|
||||||
"MY_ENV_2=",
|
|
||||||
"MY_ENV_3=my third value",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(3, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal("my value", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
Assert.Equal(string.Empty, _executionContext.Object.Global.EnvironmentVariables["MY_ENV_2"]);
|
|
||||||
Assert.Equal("my third value", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_3"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Simple_SpecialCharacters()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "simple");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV==abc",
|
|
||||||
"MY_ENV_2=def=ghi",
|
|
||||||
"MY_ENV_3=jkl=",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(3, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal("=abc", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
Assert.Equal("def=ghi", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_2"]);
|
|
||||||
Assert.Equal("jkl=", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_3"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Heredoc()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "heredoc");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV<<EOF",
|
|
||||||
"line one",
|
|
||||||
"line two",
|
|
||||||
"line three",
|
|
||||||
"EOF",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(1, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal($"line one{Environment.NewLine}line two{Environment.NewLine}line three", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Heredoc_EmptyValue()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "heredoc");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV<<EOF",
|
|
||||||
"EOF",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(1, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal(string.Empty, _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Heredoc_SkipEmptyLines()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "heredoc");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
string.Empty,
|
|
||||||
"MY_ENV<<EOF",
|
|
||||||
"hello",
|
|
||||||
"world",
|
|
||||||
"EOF",
|
|
||||||
string.Empty,
|
|
||||||
"MY_ENV_2<<EOF",
|
|
||||||
"HELLO",
|
|
||||||
"AGAIN",
|
|
||||||
"EOF",
|
|
||||||
string.Empty,
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(2, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal($"hello{Environment.NewLine}world", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
Assert.Equal($"HELLO{Environment.NewLine}AGAIN", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_2"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Heredoc_SpecialCharacters()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "heredoc");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV<<=EOF",
|
|
||||||
"hello",
|
|
||||||
"one",
|
|
||||||
"=EOF",
|
|
||||||
"MY_ENV_2<<<EOF",
|
|
||||||
"hello",
|
|
||||||
"two",
|
|
||||||
"<EOF",
|
|
||||||
"MY_ENV_3<<EOF",
|
|
||||||
"hello",
|
|
||||||
string.Empty,
|
|
||||||
"three",
|
|
||||||
string.Empty,
|
|
||||||
"EOF",
|
|
||||||
"MY_ENV_4<<EOF",
|
|
||||||
"hello=four",
|
|
||||||
"EOF",
|
|
||||||
"MY_ENV_5<<EOF",
|
|
||||||
" EOF",
|
|
||||||
"EOF",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(5, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal($"hello{Environment.NewLine}one", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
Assert.Equal($"hello{Environment.NewLine}two", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_2"]);
|
|
||||||
Assert.Equal($"hello{Environment.NewLine}{Environment.NewLine}three{Environment.NewLine}", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_3"]);
|
|
||||||
Assert.Equal($"hello=four", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_4"]);
|
|
||||||
Assert.Equal($" EOF", _executionContext.Object.Global.EnvironmentVariables["MY_ENV_5"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if OS_WINDOWS
|
|
||||||
[Fact]
|
|
||||||
[Trait("Level", "L0")]
|
|
||||||
[Trait("Category", "Worker")]
|
|
||||||
public void SetEnvFileCommand_Heredoc_PreservesNewline()
|
|
||||||
{
|
|
||||||
using (var hostContext = Setup())
|
|
||||||
{
|
|
||||||
var newline = "\n";
|
|
||||||
var envFile = Path.Combine(_rootDirectory, "heredoc");
|
|
||||||
var content = new List<string>
|
|
||||||
{
|
|
||||||
"MY_ENV<<EOF",
|
|
||||||
"hello",
|
|
||||||
"world",
|
|
||||||
"EOF",
|
|
||||||
};
|
|
||||||
WriteContent(envFile, content, newline: newline);
|
|
||||||
_setEnvFileCommand.ProcessCommand(_executionContext.Object, envFile, null);
|
|
||||||
Assert.Equal(0, _issues.Count);
|
|
||||||
Assert.Equal(1, _executionContext.Object.Global.EnvironmentVariables.Count);
|
|
||||||
Assert.Equal($"hello{newline}world", _executionContext.Object.Global.EnvironmentVariables["MY_ENV"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private void WriteContent(
|
|
||||||
string path,
|
|
||||||
List<string> content,
|
|
||||||
string newline = null)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(newline))
|
|
||||||
{
|
|
||||||
newline = Environment.NewLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
var encoding = new UTF8Encoding(true); // Emit BOM
|
|
||||||
var contentStr = string.Join(newline, content);
|
|
||||||
File.WriteAllText(path, contentStr, encoding);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TestHostContext Setup([CallerMemberName] string name = "")
|
|
||||||
{
|
|
||||||
_issues = new List<Tuple<DTWebApi.Issue, string>>();
|
|
||||||
|
|
||||||
var hostContext = new TestHostContext(this, name);
|
|
||||||
|
|
||||||
// Trace
|
|
||||||
_trace = hostContext.GetTrace();
|
|
||||||
|
|
||||||
// Directory for test data
|
|
||||||
var workDirectory = hostContext.GetDirectory(WellKnownDirectory.Work);
|
|
||||||
ArgUtil.NotNullOrEmpty(workDirectory, nameof(workDirectory));
|
|
||||||
Directory.CreateDirectory(workDirectory);
|
|
||||||
_rootDirectory = Path.Combine(workDirectory, nameof(SetEnvFileCommandL0));
|
|
||||||
Directory.CreateDirectory(_rootDirectory);
|
|
||||||
|
|
||||||
// Execution context
|
|
||||||
_executionContext = new Mock<IExecutionContext>();
|
|
||||||
_executionContext.Setup(x => x.Global)
|
|
||||||
.Returns(new GlobalContext
|
|
||||||
{
|
|
||||||
EnvironmentVariables = new Dictionary<string, string>(VarUtil.EnvironmentVariableKeyComparer),
|
|
||||||
WriteDebug = true,
|
|
||||||
});
|
|
||||||
_executionContext.Setup(x => x.AddIssue(It.IsAny<DTWebApi.Issue>(), It.IsAny<string>()))
|
|
||||||
.Callback((DTWebApi.Issue issue, string logMessage) =>
|
|
||||||
{
|
|
||||||
_issues.Add(new Tuple<DTWebApi.Issue, string>(issue, logMessage));
|
|
||||||
var message = !string.IsNullOrEmpty(logMessage) ? logMessage : issue.Message;
|
|
||||||
_trace.Info($"Issue '{issue.Type}': {message}");
|
|
||||||
});
|
|
||||||
_executionContext.Setup(x => x.Write(It.IsAny<string>(), It.IsAny<string>()))
|
|
||||||
.Callback((string tag, string message) =>
|
|
||||||
{
|
|
||||||
_trace.Info($"{tag}{message}");
|
|
||||||
});
|
|
||||||
|
|
||||||
// SetEnvFileCommand
|
|
||||||
_setEnvFileCommand = new SetEnvFileCommand();
|
|
||||||
_setEnvFileCommand.Initialize(hostContext);
|
|
||||||
|
|
||||||
return hostContext;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -44,7 +44,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_contexts = new DictionaryContextData();
|
_contexts = new DictionaryContextData();
|
||||||
_jobContext = new JobContext();
|
_jobContext = new JobContext();
|
||||||
_contexts["github"] = new GitHubContext();
|
_contexts["github"] = new DictionaryContextData();
|
||||||
_contexts["runner"] = new DictionaryContextData();
|
_contexts["runner"] = new DictionaryContextData();
|
||||||
_contexts["job"] = _jobContext;
|
_contexts["job"] = _jobContext;
|
||||||
_ec.Setup(x => x.ExpressionValues).Returns(_contexts);
|
_ec.Setup(x => x.ExpressionValues).Returns(_contexts);
|
||||||
@@ -82,7 +82,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -117,7 +117,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -156,7 +156,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Steps.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Steps.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -210,7 +210,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Steps.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Steps.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -289,7 +289,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Steps.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Steps.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -332,7 +332,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Step.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Step.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -363,7 +363,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -393,7 +393,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
{
|
{
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(variableSet.Select(x => x.Object).ToList()));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(variableSet.Select(x => x.Object).ToList()));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -419,7 +419,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new[] { step1.Object }));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(new[] { step1.Object }));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -457,7 +457,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new[] { step1.Object, step2.Object }));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(new[] { step1.Object, step2.Object }));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -495,7 +495,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new[] { step1.Object, step2.Object }));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(new[] { step1.Object, step2.Object }));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -526,7 +526,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new[] { step1.Object, step2.Object, step3.Object }));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(new[] { step1.Object, step2.Object, step3.Object }));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -562,7 +562,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
_ec.Object.Result = null;
|
_ec.Object.Result = null;
|
||||||
|
|
||||||
_ec.Setup(x => x.JobSteps).Returns(new Queue<IStep>(new[] { step1.Object, step2.Object, step3.Object }));
|
_ec.Setup(x => x.JobSteps).Returns(new List<IStep>(new[] { step1.Object, step2.Object, step3.Object }));
|
||||||
|
|
||||||
// Act.
|
// Act.
|
||||||
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
await _stepsRunner.RunAsync(jobContext: _ec.Object);
|
||||||
@@ -602,12 +602,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
var stepContext = new Mock<IExecutionContext>();
|
var stepContext = new Mock<IExecutionContext>();
|
||||||
stepContext.SetupAllProperties();
|
stepContext.SetupAllProperties();
|
||||||
stepContext.Setup(x => x.Global).Returns(() => _ec.Object.Global);
|
stepContext.Setup(x => x.Global).Returns(() => _ec.Object.Global);
|
||||||
var expressionValues = new DictionaryContextData();
|
stepContext.Setup(x => x.ExpressionValues).Returns(new DictionaryContextData());
|
||||||
foreach (var pair in _ec.Object.ExpressionValues)
|
|
||||||
{
|
|
||||||
expressionValues[pair.Key] = pair.Value;
|
|
||||||
}
|
|
||||||
stepContext.Setup(x => x.ExpressionValues).Returns(expressionValues);
|
|
||||||
stepContext.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
stepContext.Setup(x => x.ExpressionFunctions).Returns(new List<IFunctionInfo>());
|
||||||
stepContext.Setup(x => x.JobContext).Returns(_jobContext);
|
stepContext.Setup(x => x.JobContext).Returns(_jobContext);
|
||||||
stepContext.Setup(x => x.ContextName).Returns(step.Object.Action.ContextName);
|
stepContext.Setup(x => x.ContextName).Returns(step.Object.Action.ContextName);
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
new Pipelines.ContextData.DictionaryContextData()
|
new Pipelines.ContextData.DictionaryContextData()
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null, null);
|
var jobRequest = new Pipelines.AgentJobRequestMessage(plan, timeline, JobId, jobName, jobName, new StringToken(null, null, null, "ubuntu"), sidecarContainers, null, variables, new List<MaskHint>(), resources, context, null, actions, null, null, null);
|
||||||
return jobRequest;
|
return jobRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ LAYOUT_DIR="$SCRIPT_DIR/../_layout"
|
|||||||
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
DOWNLOAD_DIR="$SCRIPT_DIR/../_downloads/netcore2x"
|
||||||
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="3.1.100"
|
||||||
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
DOTNETSDK_INSTALLDIR="$DOTNETSDK_ROOT/$DOTNETSDK_VERSION"
|
||||||
RUNNER_VERSION=$(cat runnerversion)
|
RUNNER_VERSION=$(cat runnerversion)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"sdk": {
|
"sdk": {
|
||||||
"version": "3.1.302"
|
"version": "3.1.100"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1 +1 @@
|
|||||||
2.274.2
|
2.299.0
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user