Skip to content

GitLab Manual CI

GitLab Manual CI #67

name: GitLab Manual CI
on:
workflow_dispatch:
inputs:
target_ref:
description: "Branch, tag, or SHA in this repository to test"
required: true
default: "develop"
code:
description: "BenchKit code filter, for example: qws,genesis"
required: false
system:
description: "System filter, for example: FugakuLN,MiyabiG"
required: false
app:
description: "BenchPark app filter, for example: osu-micro-benchmarks"
required: false
benchpark:
description: "Run the BenchPark path together with BenchKit"
required: false
type: boolean
default: false
park_only:
description: "Run only the BenchPark path"
required: false
type: boolean
default: false
park_send:
description: "Run the BenchPark send-only path"
required: false
type: boolean
default: false
concurrency:
group: gitlab-manual-ci-${{ github.run_id }}
cancel-in-progress: false
permissions:
contents: read
jobs:
gitlab-manual-ci:
name: Run GitLab CI manually
runs-on: ubuntu-latest
steps:
- name: Check out trusted workflow ref
uses: actions/checkout@v4
with:
fetch-depth: 0
path: trusted
- name: Prepare GitLab repository settings
id: gitlab-repo
uses: ./trusted/.github/actions/prepare-gitlab-repo
with:
gitlab-repo: ${{ secrets.GITLAB_REPO }}
- name: Check out target ref
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.target_ref }}
path: target
- name: Push target ref to GitLab test branch
working-directory: target
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
GITLAB_REPO_HOST_PATH: ${{ steps.gitlab-repo.outputs.host-path }}
TARGET_REF: ${{ inputs.target_ref }}
run: |
set -euo pipefail
if [ -z "${GITLAB_TOKEN}" ] || [ -z "${GITLAB_REPO_HOST_PATH}" ]; then
echo "GITLAB_TOKEN and GITLAB_REPO secrets are required."
exit 1
fi
branch="github/manual-${GITHUB_RUN_ID}"
echo "GITLAB_TEST_BRANCH=${branch}" >> "${GITHUB_ENV}"
echo "Testing GitHub ref: ${TARGET_REF}"
echo "Temporary GitLab branch: ${branch}"
git config user.name "github-bot"
git config user.email "bot@example.com"
git remote add gitlab "https://oauth2:${GITLAB_TOKEN}@${GITLAB_REPO_HOST_PATH}"
git push -o ci.skip gitlab "HEAD:refs/heads/${branch}" --force
- name: Trigger and wait for GitLab pipeline
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
GITLAB_HOST: ${{ steps.gitlab-repo.outputs.host }}
GITLAB_PROJECT_PATH: ${{ steps.gitlab-repo.outputs.project-path }}
CODE_FILTER: ${{ inputs.code }}
SYSTEM_FILTER: ${{ inputs.system }}
BENCHPARK_APP: ${{ inputs.app }}
BENCHPARK: ${{ inputs.benchpark }}
PARK_ONLY: ${{ inputs.park_only }}
PARK_SEND: ${{ inputs.park_send }}
run: |
set -euo pipefail
project_encoded="$(PROJECT_PATH="${GITLAB_PROJECT_PATH}" python3 -c 'import os, urllib.parse; print(urllib.parse.quote(os.environ["PROJECT_PATH"], safe=""))')"
api="https://${GITLAB_HOST}/api/v4/projects/${project_encoded}/pipeline"
payload_file="$(mktemp)"
PAYLOAD_FILE="${payload_file}" python3 - <<'PY'
import json
import os
variables = []
def add_variable(key, value):
if value:
print(f"GitLab variable: {key}={value}")
variables.append({
"key": key,
"value": value,
"variable_type": "env_var",
})
add_variable("code", os.environ.get("CODE_FILTER", ""))
add_variable("system", os.environ.get("SYSTEM_FILTER", ""))
add_variable("app", os.environ.get("BENCHPARK_APP", ""))
if os.environ.get("BENCHPARK") == "true":
add_variable("benchpark", "true")
if os.environ.get("PARK_ONLY") == "true":
add_variable("park_only", "true")
if os.environ.get("PARK_SEND") == "true":
add_variable("park_send", "true")
with open(os.environ["PAYLOAD_FILE"], "w", encoding="utf-8") as f:
json.dump({
"ref": os.environ["GITLAB_TEST_BRANCH"],
"variables": variables,
}, f)
PY
response_file="$(mktemp)"
http_status="$(curl --show-error --silent --output "${response_file}" --write-out "%{http_code}" --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" --header "Content-Type: application/json" --data @"${payload_file}" "${api}")"
response="$(cat "${response_file}")"
rm -f "${response_file}" "${payload_file}"
if [ "${http_status}" -lt 200 ] || [ "${http_status}" -ge 300 ]; then
echo "GitLab pipeline trigger failed with HTTP ${http_status}."
echo "${response}"
exit 1
fi
pipeline_id="$(PIPELINE="${response}" python3 -c 'import json, os; print(json.loads(os.environ["PIPELINE"])["id"])')"
pipeline_url="$(PIPELINE="${response}" python3 -c 'import json, os; print(json.loads(os.environ["PIPELINE"]).get("web_url", ""))')"
echo "GitLab pipeline: ${pipeline_url}"
pipeline_api="https://${GITLAB_HOST}/api/v4/projects/${project_encoded}/pipelines/${pipeline_id}"
for _ in $(seq 1 180); do
response_file="$(mktemp)"
http_status="$(curl --show-error --silent --output "${response_file}" --write-out "%{http_code}" --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${pipeline_api}")"
response="$(cat "${response_file}")"
rm -f "${response_file}"
if [ "${http_status}" -lt 200 ] || [ "${http_status}" -ge 300 ]; then
echo "GitLab pipeline status request failed with HTTP ${http_status}."
echo "${response}"
exit 1
fi
status="$(PIPELINE="${response}" python3 -c 'import json, os; print(json.loads(os.environ["PIPELINE"])["status"])')"
echo "GitLab pipeline status: ${status}"
case "${status}" in
success)
exit 0
;;
failed|canceled|skipped)
exit 1
;;
manual)
echo "GitLab pipeline is waiting for manual action."
exit 1
;;
esac
sleep 20
done
echo "Timed out waiting for GitLab pipeline ${pipeline_id}."
exit 1
- name: Delete GitLab test branch
if: always()
working-directory: trusted
env:
GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
GITLAB_REPO_HOST_PATH: ${{ steps.gitlab-repo.outputs.host-path }}
run: |
set -euo pipefail
if [ -n "${GITLAB_TEST_BRANCH:-}" ] && [ -n "${GITLAB_REPO_HOST_PATH:-}" ]; then
git remote add gitlab-cleanup "https://oauth2:${GITLAB_TOKEN}@${GITLAB_REPO_HOST_PATH}" || true
git push gitlab-cleanup --delete "${GITLAB_TEST_BRANCH}" || true
fi