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
8 changes: 8 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ on:
- "evals/known-issues.yaml"
- ".github/workflows/test.yaml"
workflow_dispatch:
inputs:
git-annex-run:
description: >-
con/git-annex build-ubuntu.yaml run id to test
(empty: newest build with a package)
required: false
default: ""
schedule:
- cron: "17 5 * * 1" # Mon 05:17 UTC

Expand Down Expand Up @@ -55,6 +62,7 @@ jobs:
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GIT_ANNEX_RUN_ID: ${{ inputs.git-annex-run }}
run: bin/ci/pick-git-annex-build.sh

test:
Expand Down
63 changes: 50 additions & 13 deletions bin/ci/pick-git-annex-build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@
# Only master's scheduled/dispatched runs count: pull_request builds
# carry unmerged patches.
#
# Why sort here rather than trust the API's order: the runs endpoint
# does not document its ordering, and in eval-under run 36491628696 the
# first schedule/workflow_dispatch run it handed us was 35319817132
# (2026-09-18) although 36399800528 (2026-09-28) had been first an hour
# earlier. So: one query per event (filtered server-side, so $scan
# covers more history), merged and sorted by created_at here, and the
# raw listing is summarised in the log so a stale answer can be told
# apart from a mis-ordered one.
#
# GIT_ANNEX_RUN_ID pins a run instead (test.yaml's workflow_dispatch
# input), e.g. to rerun the matrix on a known build while the listing
# misbehaves; it is still checked for a package artifact.
#
# Run once per workflow (the `matrix` job) and hand the id to every
# cell, so all cells of one run test the same build.

Expand All @@ -34,7 +47,11 @@ env overrides:
GIT_ANNEX_BUILD_BRANCH branch to take runs from (default: master)
GIT_ANNEX_BUILD_EVENTS space-separated run events to accept
(default: "schedule workflow_dispatch")
GIT_ANNEX_BUILD_SCAN how many recent runs to consider (default: 30)
GIT_ANNEX_BUILD_SCAN how many recent runs to fetch per event
(default: 30)
GIT_ANNEX_BUILD_MAX_AGE warn when the picked run is older than this
many days (default: 3; the build is daily)
GIT_ANNEX_RUN_ID pin this run instead of picking (empty: pick)
GH_TOKEN required, for the GitHub REST API
USAGE
}
Expand All @@ -48,16 +65,33 @@ repo="${1:-${GIT_ANNEX_BUILD_REPO:-con/git-annex}}"
branch="${GIT_ANNEX_BUILD_BRANCH:-master}"
events="${GIT_ANNEX_BUILD_EVENTS:-schedule workflow_dispatch}"
scan="${GIT_ANNEX_BUILD_SCAN:-30}"
max_age="${GIT_ANNEX_BUILD_MAX_AGE:-3}"
pin="${GIT_ANNEX_RUN_ID:-}"

: "${GH_TOKEN:?GH_TOKEN must be set (secrets.GITHUB_TOKEN in a workflow)}"

# `gh run list` has been observed returning stale (expired-artifact)
# runs on the runner's gh version; REST orders newest-first reliably.
runs="$(gh api \
"repos/$repo/actions/workflows/build-ubuntu.yaml/runs?branch=$branch&per_page=$scan" \
--jq '.workflow_runs[] | "\(.id) \(.event) \(.conclusion // .status) \(.created_at)"')"
# One line per run: "created_at id event state". ISO-8601 UTC sorts
# lexicographically, so `sort -r` puts the newest first.
fields='"\(.created_at) \(.id) \(.event) \(.conclusion // .status)"'
runs=""
if [ -n "$pin" ]; then
runs="$(gh api "repos/$repo/actions/runs/$pin" --jq "$fields" </dev/null)"
echo "I: using pinned $repo run $pin" >&2
events=""
fi
for event in $events; do
page="$(gh api \
"repos/$repo/actions/workflows/build-ubuntu.yaml/runs?branch=$branch&event=$event&per_page=$scan" \
--jq ".workflow_runs[] | $fields" \
</dev/null)"
n="$(grep -c . <<< "$page" || true)"
newest="$(sort -r <<< "$page" | head -1 | cut -d' ' -f1-2)"
echo "I: $repo $branch $event runs listed: $n, newest: ${newest:-none}" >&2
runs+="$page"$'\n'
done
runs="$(sort -r -u <<< "$runs" | grep . || true)"
if [ -z "$runs" ]; then
echo "E: no $repo build-ubuntu.yaml runs on $branch" >&2
echo "E: no $repo build-ubuntu.yaml ${pin:-$events} runs on $branch" >&2
exit 1
fi

Expand All @@ -66,11 +100,7 @@ fi
mapfile -t candidates <<< "$runs"
run_id=""
for line in "${candidates[@]}"; do
read -r id event state created <<< "$line"
case " $events " in
*" $event "*) ;;
*) continue ;;
esac
read -r created id event state <<< "$line"
n="$(gh api "repos/$repo/actions/runs/$id/artifacts" \
--jq '[.artifacts[] | select(.expired==false and (.name | startswith("git-annex-debianstandalone-packages_")))] | length' \
</dev/null)"
Expand All @@ -83,10 +113,17 @@ for line in "${candidates[@]}"; do
done

if [ -z "$run_id" ]; then
echo "E: none of the last $scan $branch runs ($events) has an unexpired debianstandalone artifact" >&2
echo "E: none of the listed $branch runs (${pin:-$events}) has an unexpired debianstandalone artifact" >&2
exit 1
fi

# Not fatal: the build may genuinely have been failing for days. But
# a pick this old is what an incomplete/stale listing looks like too.
age_days=$(( ($(date -u +%s) - $(date -u -d "$created" +%s)) / 86400 ))
if [ -z "$pin" ] && [ "$age_days" -gt "$max_age" ]; then
echo "::warning::picked $repo run $run_id is $age_days days old ($created); newer builds failed or the API listing is stale" >&2
fi

echo "$run_id"
if [ -n "${GITHUB_OUTPUT:-}" ]; then
echo "run_id=$run_id" >> "$GITHUB_OUTPUT"
Expand Down
Loading