Release Upload #2
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.ghc965-x86_64-unknown-linux-musl" | |
;; | |
"aarch64-linux") | |
derivation+="x86_64-linux.ghc965-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 |