Skip to content
Merged
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
56 changes: 54 additions & 2 deletions .github/workflows/release-upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,23 @@ name: Release Upload
# Pipeline to download binaries from Hydra builds and create GitHub
# releases out of them (or attaching the binaries to an already existing release).
#
# This pipeline is divided in three jobs:
# This pipeline is divided in four jobs:
#
# 1. The "wait_for_hydra" job looks up the status of the Hydra build corresponding to
# the tag for which we want to release. If the status is success, the pipeline
# continues. If the status cannot be determined or is a failure, the pipeline stops.
# If the tag is annotated (signed tags are), this job first pushes the tagged commit
# to a ci/ branch for this run, so that Hydra builds and reports on the commit itself.
# 2. The "pull" job downloads the binaries from the Hydra build and uploads them as artifacts.
# This job uses a matrix to handle all supported platforms. Uploading as an artifact allows to
# do the last job without a matrix.
#
# This job uses `--builders "" --max-jobs 0` to ensure the assets are downloaded
# from the IOG cache.
# 3. The "create_release" job downloads the artifacts and attaches them to the target release.
# 4. The "delete_ci_branch" job deletes the ci/ branch from step 1, if this run pushed one.
# It also runs when an earlier job failed or the run was cancelled, so that the branch
# does not stay behind.
#
# This pipeline is triggered in one of the following 3 ways:
#
Expand Down Expand Up @@ -46,17 +51,22 @@ on:
push:
tags:
- '**'
permissions:
contents: read
env:
GH_TOKEN: ${{ github.token }}

jobs:
wait_for_hydra:
name: "Wait for Hydra check-runs"
runs-on: ubuntu-latest
permissions:
contents: write # To push the ci/ branch
outputs:
TARGET_TAG: ${{ steps.store_vars.outputs.TARGET_TAG }}
DRY_RUN: ${{ steps.store_vars.outputs.DRY_RUN }}
FLAKE_REF: ${{ steps.store_vars.outputs.FLAKE_REF }}
CI_BRANCH: ${{ steps.ci_branch.outputs.CI_BRANCH }}
steps:
- uses: actions/checkout@v6
with:
Expand Down Expand Up @@ -95,11 +105,30 @@ jobs:
echo "FLAKE_REF=$flake_ref" >> "$GITHUB_OUTPUT"

echo "DRY_RUN=$dry_run" >> "$GITHUB_OUTPUT"
- name: Make Hydra build the tagged commit
id: ci_branch
run: |
# Hydra builds an annotated tag under the ID of the tag object, not the ID of the commit.
# GitHub rejects Hydra's check-runs for that ID, so the next step would wait forever,
# and the binaries Hydra builds would not match the ones the "pull" job asks for.
# Hydra also builds ci/* branches, by commit ID, so push the tagged commit to one.
# The branch name includes the run ID, so that this run only ever touches its own branch.
if [[ "$(git cat-file -t "refs/tags/$TARGET_TAG" 2>/dev/null)" == "tag" ]]
then
commit=$(git rev-parse "refs/tags/$TARGET_TAG^{commit}")
branch="ci/$TARGET_TAG-run-$GITHUB_RUN_ID"
echo "$TARGET_TAG is an annotated tag: pushing $commit to $branch for Hydra"
git push --force origin "$commit:refs/heads/$branch"
Comment thread
palas marked this conversation as resolved.
# Tell the "delete_ci_branch" job what to delete
echo "CI_BRANCH=$branch" >> "$GITHUB_OUTPUT"
fi
- name: Get specific check run status
timeout-minutes: 120
run: |
while true; do
conclusion=$(gh api "repos/$GITHUB_REPOSITORY/commits/${{ env.TARGET_TAG }}/check-runs" --jq '.check_runs[] | select(.name | test("ci/hydra-build:.*\\.required")) | .conclusion')
# A check that has not finished has no conclusion (null). gh prints null as an empty line,
# and $(...) drops it when it comes last, so such a check would not be counted. Hence "pending".
conclusion=$(gh api "repos/$GITHUB_REPOSITORY/commits/$TARGET_TAG/check-runs" --jq '.check_runs[] | select(.name | test("ci/hydra-build:.*\\.required")) | .conclusion // "pending"')
# Here we are being careful, because we query the status of multiple jobs (once per line)
# But the only thing we are sure is that "success" means a green job. There
# could be unknown statuses, which is why we may retry when unsure (see 'sleep') below.
Expand Down Expand Up @@ -193,6 +222,8 @@ jobs:
needs: [wait_for_hydra, pull]
name: "Create Release"
runs-on: ubuntu-latest
permissions:
contents: write # To create the release and upload its files
if: ${{ needs.wait_for_hydra.outputs.DRY_RUN == 'false' }}
steps:
- uses: actions/checkout@v6 # We need the repo to execute extract-changelog.sh below
Expand Down Expand Up @@ -242,3 +273,24 @@ jobs:
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-win64.zip
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-sha256sums.txt
body_path: RELEASE_CHANGELOG.md

delete_ci_branch:
needs: [wait_for_hydra, pull, create_release]
name: "Delete the ci/ branch pushed for Hydra"
runs-on: ubuntu-latest
permissions:
contents: write # To delete the ci/ branch
# always(): also after a failed or cancelled run, so that the branch does not stay behind
if: ${{ always() && needs.wait_for_hydra.outputs.CI_BRANCH != '' }}
steps:
- uses: actions/checkout@v6 # So that git can push to origin below
- name: Delete the ci/ branch
env:
CI_BRANCH: ${{ needs.wait_for_hydra.outputs.CI_BRANCH }}
run: |
branch="refs/heads/$CI_BRANCH"
# An earlier attempt of this run may have deleted it already
if git ls-remote --exit-code origin "$branch" > /dev/null
then
git push origin --delete "$branch"
fi
Loading