Skip to content

Release Upload

Release Upload #1

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:
#
# 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.
# 2. The "pull" job downloads the binaries from the Hydra build and uploads them as artifacts.
# This job uses a matrix to handle all 3 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.
#
# This pipeline is triggered in one of the following 3 ways:
#
# 1. When a release is published, this release's commit must have a tag for the pipeline to succeed
# 2. When a tag is pushed. If this tag has a corresponding release, the release will be augmented.
# If there is no release, it will be created.
# 3. By launching it manually, optionally specifying the tag to release:
# gh workflow run "Release Upload" -r $(git branch --show-current) -f target_tag=cardano-cli-8.22.0.0
# This mode is not supported by the pipeline of cardano-node (which was copied to create this pipeline),
# but we anticipate this mode to be useful when debugging, or releasing a posteriori.
#
# If the tag is not specified, this pipeline will run, but skip the final "create_release" job,
# so no release will get created. This is useful for debugging or
# trying to build a release before tagging it.
#
# So far this pipeline supports releasing Linux and Darwin binaries.
# Please see the "TODO generalize" comments in this file to support new platforms.
on:
workflow_dispatch:
inputs:
target_tag:
description: 'The tag of the release to attach binaries to'
default: ''
required: false
type: string
release:
types:
- published
push:
tags:
- '**'
env:
GH_TOKEN: ${{ github.token }}
jobs:
wait_for_hydra:
name: "Wait for Hydra check-runs"
runs-on: ubuntu-latest
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 }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Because the target tag may not be HEAD
fetch-tags: true # So that tags are known to git commands
- name: Define target tag, flake ref, and compute drynesss
id: store_vars
run: |
dry_run="false"
if [[ -z "${{ inputs.target_tag }}" ]]
then
# No tag was specified manually as input, take the tag from the current commit (if any)
current_tag=$(git tag --points-at HEAD | head -n 1)
if [[ -z "$current_tag" ]]
then
# No tag was specified manually as input, and current commit has no tag.
echo "Tag not yet defined, using current commit as reference."
target_tag="${{ github.ref_name }}"
echo "Run targets a commit that has no attached tag: no release will be published."
# This is the only case we won't run the create_release job at the end
dry_run="true"
else
# Workflow runs on a commit that has a tag, use this tag
target_tag="$current_tag"
fi
else
# A tag was specified manually as input, use it
target_tag="${{ inputs.target_tag }}"
fi
# Set variables in GITHUB_ENV for next steps and in GITHUB_OUTPUT for next jobs
echo "TARGET_TAG=$target_tag" >> "$GITHUB_ENV"
echo "TARGET_TAG=$target_tag" >> "$GITHUB_OUTPUT"
flake_ref="github:${{ github.repository }}/$target_tag"
echo "FLAKE_REF=$flake_ref" >> "$GITHUB_OUTPUT"
echo "DRY_RUN=$dry_run" >> "$GITHUB_OUTPUT"
- 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')
# 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.
echo "ci/hydra-build:.*\\.required returned status: $conclusion"
# conclusion is of the form (note the newlines, which matter because we use 'wc -l' below)
# success
# failure
# success
# Because we care of the newlines, quoting $conclusion with "" is especially important below!
# (see https://stackoverflow.com/questions/22101778/how-to-preserve-line-breaks-when-storing-command-output-to-a-variable)
# shellcheck disable=SC2126
num_failure=$(echo "$conclusion" | grep "^failure" | wc -l)
num_status=$(echo "$conclusion" | wc -l)
# shellcheck disable=SC2126
num_success=$(echo "$conclusion" | grep "^success" | wc -l)
echo "num_failure=$num_failure num_status=$num_status num_success=$num_success"
if [[ "$num_failure" != "0" ]]; then
echo "ci/hydra-build:required failed"
exit 1
elif [[ "$num_status" == "$num_success" ]]; then
echo "ci/hydra-build:required succeeded"
exit 0
else
# Unclear (some non-failure, non-success)
echo "ci/hydra-build:required pending with $conclusion. Waiting 30s..."
sleep 30
fi
done
pull:
needs: [wait_for_hydra]
strategy:
matrix:
# TODO generalize
arch: [x86_64-linux, x86_64-darwin, aarch64-darwin, aarch64-linux]
name: "Download Asset"
runs-on: ubuntu-latest
steps:
- name: Install Nix with good defaults
uses: input-output-hk/install-nix-action@v20
with:
extra_nix_config: |
trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ=
substituters = https://cache.iog.io/ https://cache.nixos.org/
nix_path: nixpkgs=channel:nixos-unstable
- name: Display flake metadata
id: flake-metadata
run: |
nix flake metadata "${{ needs.wait_for_hydra.outputs.FLAKE_REF }}"
nix flake metadata "${{ needs.wait_for_hydra.outputs.FLAKE_REF }}" --json | jq -r '"LOCKED_URL=\(.url)"' >> "$GITHUB_ENV"
- name: Build
run: |
derivation="hydraJobs."
case ${{ matrix.arch }} in
"x86_64-darwin" | "aarch64-darwin")
derivation+="${{ matrix.arch }}"
;;
"x86_64-linux")
derivation+="x86_64-linux.x86_64-unknown-linux-musl"
;;
"aarch64-linux")
derivation+="x86_64-linux.aarch64-unknown-linux-musl"
;;
*)
echo "Unexpected matrix.arch value: ${{ matrix.arch }}"
exit 1
;;
esac
derivation+=".packages.cardano-cli:exe:cardano-cli"
nix build --builders "" --max-jobs 0 ${{ env.LOCKED_URL }}#$derivation
tree result
cp result/bin/cardano-cli cardano-cli-${{ matrix.arch }} # (1)
- uses: actions/upload-artifact@v4
with:
name: cardano-cli-${{ matrix.arch }}
path: cardano-cli-* # Should match (1)
retention-days: 1
create_release:
needs: [wait_for_hydra, pull]
name: "Create Release"
runs-on: ubuntu-latest
if: ${{ needs.wait_for_hydra.outputs.DRY_RUN == 'false' }}
steps:
- uses: actions/checkout@v4 # We need the repo to execute extract-changelog.sh below
- uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Compress
run: |
# (2)
# TARGET_TAG is of the form cardano-cli-8.22.0, so we don't need to prefix the tar.gz's name
# with cardano-cli
for arch in x86_64-linux x86_64-darwin aarch64-darwin aarch64-linux; do
tar -czf ${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-$arch.tar.gz cardano-cli-$arch
done
# TODO generalize
# zip ${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-win64.zip cardano-cli-win64
- name: Checksums
run: |
# (3)
for arch in x86_64-linux x86_64-darwin aarch64-darwin aarch64-linux; do
sha256sum ${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-$arch.tar.gz >> ${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-sha256sums.txt
done
- name: Create short tag
run: |
# Transform the long tag (e.g. "cardano-cli-8.22.0.0")
# into the short version (e.g. "8.22.0.0")
long_tag=${{ needs.wait_for_hydra.outputs.TARGET_TAG }}
short_tag="${long_tag#cardano-cli-}"
echo "SHORT_TAG=$short_tag" >> "$GITHUB_ENV"
- name: Create changelog
run: |
echo -e "# Changelog\n" > RELEASE_CHANGELOG.md
./scripts/ci/extract-changelog.sh ${{ env.SHORT_TAG }} >> RELEASE_CHANGELOG.md
- name: Create Release
uses: input-output-hk/action-gh-release@v1
with:
draft: true
tag_name: ${{ needs.wait_for_hydra.outputs.TARGET_TAG }} # Git tag the release is attached to
name: ${{ env.SHORT_TAG }} # Release name in GitHub UI
# TODO generalize
# cardano-cli-${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-win64.zip
# All entries in 'files' below should match (2) and (3)
files: |
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-x86_64-linux.tar.gz
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-x86_64-darwin.tar.gz
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-aarch64-darwin.tar.gz
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-aarch64-linux.tar.gz
${{ needs.wait_for_hydra.outputs.TARGET_TAG }}-sha256sums.txt
body_path: RELEASE_CHANGELOG.md