diff --git a/.github/scripts/download-latest-publish-results.sh b/.github/scripts/download-latest-publish-results.sh new file mode 100755 index 00000000..deb4fe21 --- /dev/null +++ b/.github/scripts/download-latest-publish-results.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Downloads the publish-result-* artifacts of a publish.yml run into a flat +# directory, keeping only the NEWEST artifact per artifact name. +# +# Usage: download-latest-publish-results.sh +# +# Why not actions/download-artifact with merge-multiple? Re-running or +# restarting a publish job (e.g. after cancelling it) uploads a second +# artifact with the same name into the same run, and the earlier attempt's +# artifact is kept. merge-multiple extracts every match into one directory in +# no guaranteed order, so a stale "failed" fragment can overwrite the newer +# "published" one, and the summary then reports a published pack as failed. +# +# Requires: gh (GH_TOKEN with actions:read), jq, unzip. GITHUB_REPOSITORY +# defaults to this repo so the script also works locally. +set -euo pipefail + +RUN_ID="${1:?usage: download-latest-publish-results.sh }" +DEST="${2:?usage: download-latest-publish-results.sh }" +REPO="${GITHUB_REPOSITORY:-GitHubSecurityLab/CodeQL-Community-Packs}" + +mkdir -p "$DEST" +WORK=$(mktemp -d) +trap 'rm -rf "$WORK"' EXIT + +# One " " line per artifact name: the newest non-expired one. +gh api --paginate "repos/${REPO}/actions/runs/${RUN_ID}/artifacts?per_page=100" \ + --jq '.artifacts[] | select((.expired | not) and (.name | startswith("publish-result-"))) | [.created_at, .id, .name] | @tsv' \ + | sort -t$'\t' -k3,3 -k1,1r \ + | awk -F'\t' '!seen[$3]++ { print $2, $3 }' > "$WORK/latest.txt" + +if [ ! -s "$WORK/latest.txt" ]; then + echo "No publish-result-* artifacts found for run ${RUN_ID}." + exit 0 +fi + +while read -r ID NAME; do + echo "Downloading ${NAME} (artifact ${ID})" + gh api "repos/${REPO}/actions/artifacts/${ID}/zip" > "$WORK/${ID}.zip" + unzip -o -q "$WORK/${ID}.zip" -d "$DEST" +done < "$WORK/latest.txt" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 731cc0ad..9078b0ec 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -387,17 +387,19 @@ jobs: permissions: contents: write + actions: read steps: - uses: actions/checkout@v7 + # Not actions/download-artifact with merge-multiple: a re-run or restarted publish job + # leaves a second same-named artifact in the run, and merge-multiple can let the stale + # (e.g. cancelled/failed) one overwrite the newer result. This keeps the newest per name. - name: Download publish results - uses: actions/download-artifact@v8 continue-on-error: true - with: - pattern: publish-result-* - path: publish-results - merge-multiple: true + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: .github/scripts/download-latest-publish-results.sh "${{ github.run_id }}" publish-results - name: Build summary table run: |