Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ on:
workflow_dispatch:

jobs:
downstream-wait:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
- name: Test downstream wait
run: bash downstream/wait.test.bash

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if we want those test scripts 🤔

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the alternative would be to inline the code here then I would go with a test script for now.
We don't have a clear structure for testing workflows yet but this can be easily adapted later.


shopware-version-fallback:
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -113,4 +121,4 @@ jobs:
if [[ ! "$NEXT_MINOR" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "next-minor looks wrong: '${NEXT_MINOR}'"
exit 1
fi
fi
1 change: 1 addition & 0 deletions downstream/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Trigger a downstream workflow in another repository and wait for it to finish.
| `env` | Environment variables to pass to downstream workflow | No | - |
| `identity` | Identity for octo-sts | No | `upstream` |
| `token` | Token to authenticate (if not provided, octo-sts is used) | No | - |
| `upstream-token` | Token used to cancel the upstream workflow run when the downstream run was cancelled | No | - |
| `timeout` | Timeout for the downstream workflow | No | `30m` |
| `poll_interval` | Poll interval for checking status | No | `2m` |

Expand Down
7 changes: 7 additions & 0 deletions downstream/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ inputs:
description: Token used to authenticate with the downstream repo. If not provided octo-sts is used
required: false
default: ""
upstream-token:
description: Token used to cancel the upstream workflow run when the downstream run was cancelled
required: false
default: ""
timeout:
description: Timeout for the downstream
required: false
Expand Down Expand Up @@ -116,4 +120,7 @@ runs:
env:
GH_TOKEN: ${{ inputs.token || steps.sts.outputs.token }}
REPO: ${{ inputs.repo }}
UPSTREAM_TOKEN: ${{ inputs.upstream-token }}
UPSTREAM_REPOSITORY: ${{ github.repository }}
UPSTREAM_RUN_ID: ${{ github.run_id }}
run: timeout "${{ inputs.timeout }}" ${GITHUB_ACTION_PATH}/wait.bash "$REPO" "${{ inputs.poll_interval }}" "${{ steps.trigger.outputs.run_url }}"
38 changes: 36 additions & 2 deletions downstream/wait.bash
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
REPO=${1}
POLL_INTERVAL=${2}
DOWNSTREAM_RUN_URL=${3}
CANCEL_REQUESTED=0

DOWNSTREAM_RUN_ID=$(basename "$DOWNSTREAM_RUN_URL")

trap on_sigterm SIGTERM

on_sigterm() {
if [[ "${CANCEL_REQUESTED}" == "1" ]]; then
# GitHub sent SIGTERM after accepting our cancellation request.
echo "Upstream workflow cancellation is taking over."
exit 130
fi

echo "Timeout reached"
fail
}
Expand All @@ -17,6 +24,27 @@ fail() {
exit 1
}

cancel_upstream() {
if [[ -z "${UPSTREAM_TOKEN:-}" || -z "${UPSTREAM_REPOSITORY:-}" || -z "${UPSTREAM_RUN_ID:-}" ]]; then
return 1
fi

echo "Cancelling upstream workflow run ${UPSTREAM_RUN_ID} in ${UPSTREAM_REPOSITORY}."

if ! GH_TOKEN="${UPSTREAM_TOKEN}" gh run cancel "${UPSTREAM_RUN_ID}" --repo "${UPSTREAM_REPOSITORY}"; then
echo "Could not cancel upstream workflow run."
return 1
fi

CANCEL_REQUESTED=1

# gh run cancel only requests cancellation. Keep this step alive so GitHub
# can mark the upstream run as cancelled instead of racing our own failure.
while true; do
sleep 60
done
}

echo "Downstream workflow: ${DOWNSTREAM_RUN_URL}"

ATTEMPT=1
Expand All @@ -36,9 +64,15 @@ while true; do
sleep 60
done

if [[ "${STATUS}" == "cancelled" ]]; then
echo "Downstream workflow was cancelled."
cancel_upstream
fail
fi

if [[ "${STATUS}" != "success" ]]; then
echo "Downstream workflow failed."
echo "Downstream workflow concluded with '${STATUS}'."
fail
fi

echo "Downstream workflow succeeded!"
echo "Downstream workflow succeeded!"
63 changes: 63 additions & 0 deletions downstream/wait.test.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)
TMP_DIR=$(mktemp -d)

trap 'rm -rf "${TMP_DIR}"' EXIT

cat > "${TMP_DIR}/gh" <<'EOF'
#!/usr/bin/env bash
if [[ "${1} ${2}" == "run view" ]]; then
printf '{"status":"completed","conclusion":"%s"}\n' "${GH_CONCLUSION}"
exit 0
fi

if [[ "${1} ${2}" == "run cancel" ]]; then
echo "cancel called"
exit "${GH_CANCEL_EXIT:-0}"
fi

exit 1
EOF
chmod +x "${TMP_DIR}/gh"

run_case() {
local conclusion=${1}
local expected_code=${2}
local expected_message=${3}
local output
local code

set +e
output=$(PATH="${TMP_DIR}:${PATH}" GH_CONCLUSION="${conclusion}" bash "${SCRIPT_DIR}/wait.bash" shopware/example 1 https://github.com/shopware/example/actions/runs/1 2>&1)
code=$?
set -e

if [[ "${code}" -ne "${expected_code}" ]]; then
echo "Expected exit code ${expected_code} for ${conclusion}, got ${code}"
echo "${output}"
exit 1
fi

if [[ "${output}" != *"${expected_message}"* ]]; then
echo "Expected output for ${conclusion} to contain: ${expected_message}"
echo "${output}"
exit 1
fi
}

run_case success 0 "Downstream workflow succeeded!"
run_case failure 1 "Downstream workflow concluded with 'failure'."
run_case cancelled 1 "Downstream workflow was cancelled."

set +e
output=$(PATH="${TMP_DIR}:${PATH}" GH_CONCLUSION="cancelled" GH_CANCEL_EXIT=1 UPSTREAM_TOKEN=token UPSTREAM_REPOSITORY=shopware/shopware UPSTREAM_RUN_ID=1 bash "${SCRIPT_DIR}/wait.bash" shopware/example 1 https://github.com/shopware/example/actions/runs/1 2>&1)
code=$?
set -e

if [[ "${code}" -ne 1 || "${output}" != *"Could not cancel upstream workflow run."* ]]; then
echo "Expected failed upstream cancellation to fall back to a failed downstream wait"
echo "${output}"
exit 1
fi