mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-11 01:41:03 +00:00
129 lines
5.0 KiB
Bash
129 lines
5.0 KiB
Bash
#!/usr/bin/env bash
|
|
# Lets a pull request's macOS deps build wait for a push build of the base
|
|
# branch that builds the same deps, from a Linux job. `check` runs after a cache
|
|
# miss and names a queued or running base build with the same deps/ and .github/
|
|
# to wait for, unless the pull request changes either. `wait` waits until that
|
|
# build saves KEY. actions/cache then confirms the entry can be restored.
|
|
#
|
|
# Environment: GH_TOKEN, REPO, WORKFLOW_REF and BASE_REF, plus KEY_INPUTS,
|
|
# WAIT_FOR, WAIT_SINCE, WAIT_MINUTES, KEY and ARCH for `wait`.
|
|
# Writes key-inputs, wait-for and wait-since to $GITHUB_OUTPUT.
|
|
set -uo pipefail
|
|
|
|
workflow=${WORKFLOW_REF%%@*}
|
|
workflow=${workflow##*/}
|
|
|
|
# Must match the job names in build_all.yml, build_check_cache.yml and build_deps.yml.
|
|
check_job_name="build_macos_arch (${ARCH:-}) / Check Cache"
|
|
deps_job_name="build_macos_arch (${ARCH:-}) / Build Deps / Build Deps"
|
|
|
|
out() { echo "$1" >> "${GITHUB_OUTPUT:-/dev/stdout}"; }
|
|
|
|
# The cache key depends on deps/ and on the workflows under .github/.
|
|
local_key_inputs() { echo "$(git rev-parse "$1:.github") $(git rev-parse "$1:deps")"; }
|
|
remote_key_inputs() {
|
|
gh api "repos/$REPO/git/trees/$1" < /dev/null \
|
|
--jq '[.tree[] | select(.path == ".github" or .path == "deps") | {key: .path, value: .sha}] | from_entries | "\(.[".github"]) \(.deps)"'
|
|
}
|
|
|
|
# Prints the id of a push build of the base branch that has not finished, is not
|
|
# one of the ids in $1, and has KEY_INPUTS.
|
|
matching_base_build() {
|
|
local status runs id sha
|
|
runs=$(for status in in_progress queued pending waiting requested; do
|
|
gh api -X GET "repos/$REPO/actions/workflows/$workflow/runs" \
|
|
-f branch="$BASE_REF" -f event=push -f status="$status" -f per_page=10 < /dev/null \
|
|
| jq -r '.workflow_runs[] | "\(.id) \(.head_sha)"'
|
|
done)
|
|
while read -r id sha; do
|
|
[ -n "$id" ] || continue
|
|
[[ " ${1:-} " == *" $id "* ]] && continue
|
|
if [ "$(remote_key_inputs "$sha")" = "$KEY_INPUTS" ]; then
|
|
echo "$id"
|
|
return
|
|
fi
|
|
done <<< "$runs"
|
|
}
|
|
|
|
check() {
|
|
KEY_INPUTS=$(local_key_inputs HEAD)
|
|
out "key-inputs=$KEY_INPUTS"
|
|
if [ "$KEY_INPUTS" != "$(local_key_inputs HEAD^1)" ]; then
|
|
echo "This pull request changes deps/ or .github/, so it builds its own deps."
|
|
return
|
|
fi
|
|
local id
|
|
id=$(matching_base_build)
|
|
if [ -n "$id" ]; then
|
|
echo "Build $id of $BASE_REF has the same deps/ and .github/. Waiting for its cache."
|
|
out "wait-for=$id"
|
|
out "wait-since=$(date +%s)"
|
|
else
|
|
echo "No build of $BASE_REF is building these deps."
|
|
fi
|
|
}
|
|
|
|
key_saved() {
|
|
gh cache list -R "$REPO" --ref "refs/heads/$BASE_REF" --key "$KEY" --json key < /dev/null \
|
|
| jq -e --arg key "$KEY" 'any(.[]; .key == $key)' > /dev/null
|
|
}
|
|
|
|
wait_for() {
|
|
# Counts the limit from the check, including time queued behind other waiting
|
|
# pull requests.
|
|
local id=$WAIT_FOR seen=$WAIT_FOR deadline=$((${WAIT_SINCE:-$(date +%s)} + WAIT_MINUTES * 60)) jobs job check warned=
|
|
while [ "$(date +%s)" -lt "$deadline" ]; do
|
|
if key_saved; then
|
|
echo "Found $KEY."
|
|
return
|
|
fi
|
|
jobs=$(gh api -X GET "repos/$REPO/actions/runs/$id/jobs" -f filter=latest -f per_page=100 < /dev/null)
|
|
job=$(jq -r --arg name "$deps_job_name" 'first(.jobs[] | select(.name == $name) | "\(.status) \(.conclusion)") // ""' <<< "$jobs")
|
|
case "$job" in
|
|
"completed success" | "completed skipped")
|
|
# The new entry can take a moment to be listed, and a skipped job means
|
|
# the build found the cache, possibly under the default branch.
|
|
for _ in 1 2 3; do
|
|
key_saved && { echo "Found $KEY."; return; }
|
|
sleep 20
|
|
done
|
|
echo "Build $id of $BASE_REF finished its deps without saving $KEY."
|
|
return ;;
|
|
"completed cancelled") ;;
|
|
completed*)
|
|
echo "The deps job of build $id of $BASE_REF did not succeed."
|
|
return ;;
|
|
# The deps job exists only once the build's cache check has succeeded.
|
|
"")
|
|
case "$(gh api "repos/$REPO/actions/runs/$id" --jq '"\(.status) \(.conclusion)"' < /dev/null)" in
|
|
"completed cancelled") ;;
|
|
completed*)
|
|
check=$(jq -r --arg name "$check_job_name" 'first(.jobs[] | select(.name == $name) | .conclusion) // ""' <<< "$jobs")
|
|
if [ -z "$warned" ] && { [ -z "$check" ] || [ "$check" = success ]; }; then
|
|
echo "::warning title=Deps wait::Build $id of $BASE_REF has no job named \"$deps_job_name\". If the build jobs were renamed, update scripts/ci_deps_cache.sh. This does not affect this pull request."
|
|
warned=1
|
|
fi ;;
|
|
*)
|
|
sleep 120
|
|
continue ;;
|
|
esac ;;
|
|
*)
|
|
sleep 120
|
|
continue ;;
|
|
esac
|
|
# Follows another unfinished build with the same key inputs, such as the
|
|
# push that replaced a cancelled one.
|
|
id=$(matching_base_build "$seen")
|
|
[ -n "$id" ] || break
|
|
seen="$seen $id"
|
|
echo "Following build $id of $BASE_REF."
|
|
done
|
|
echo "No build of $BASE_REF saved $KEY."
|
|
}
|
|
|
|
case "${1:-}" in
|
|
check) check ;;
|
|
wait) wait_for ;;
|
|
*) echo "usage: $0 check|wait" >&2; exit 2 ;;
|
|
esac
|