Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automated releases #16

Merged
merged 3 commits into from
Mar 21, 2024
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
3 changes: 0 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ on:
pull_request:
branches:
- main
push:
branches:
- main

jobs:
check:
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: CD
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: CD isn't Release like the filename (and I like "Maybe Release" 😉)

on:
push:
branches:
- main

jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: cachix/install-nix-action@v26

- name: release
run: scripts/release.sh
4 changes: 3 additions & 1 deletion package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
}:
let
fs = lib.fileset;
version = (builtins.fromTOML (builtins.readFile ./Cargo.toml)).package.version;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(builtins.fromTOML (builtins.readFile ...)) is lib.importTOML

in
rustPlatform.buildRustPackage {
name = "nixpkgs-check-by-name";
pname = "nixpkgs-check-by-name";
inherit version;
src = fs.toSource {
root = ./.;
fileset = fs.unions [
Expand Down
103 changes: 103 additions & 0 deletions scripts/release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/usr/bin/env bash

set -euo pipefail

tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' exit

nixeval() {
# Since there's no stable `nix eval --raw`, also see https://github.com/NixOS/nix/pull/9361
nix-instantiate --eval --json "$@" | jq -r .
}

# The system to pre-build the release for and distribute artifacts for
system=x86_64-linux
root=$(git rev-parse --show-toplevel)
repository=${GITHUB_REPOSITORY:-NixOS/nixpkgs-check-by-name}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why's this needed? https://docs.github.com/en/actions/learn-github-actions/variables says that GITHUB_REPOSITORY is owner and root. Is this trying to not run unless on this specific repository?


# Get the version from the Cargo.toml file
version=$(nixeval "$root" -A build.version)
echo "Current version is $version"

if existingRelease=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/"$repository"/releases/tags/"$version"); then
echo "Release $version already exists, no new release necessary"
exit 0
else
echo "$existingRelease"
echo "Release $version doesn't exist yet, creating it"
fi

echo "Building release artifact for system $system"

nix-build "$root" -A build -o "$tmp/build" >/dev/null
readarray -t closure < <(nix-store -qR "$tmp/build")
nix-store --export "${closure[@]}" > "$tmp/$system.nar"
gzip "$tmp/$system.nar"
artifactName=$system.nar.gz

body='Automated release.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Future: this is where the changelog goes.

Suggested change
body='Automated release.
body='# Changelog
* PR
* PR
* PR
etc


The artifact is a gzip-compressed [Nix Archive](https://nixos.org/manual/nix/stable/command-ref/nix-store/export.html) of the [build closure](https://nixos.org/manual/nix/stable/glossary#gloss-closure).

To import it:
```bash
gzip -cd '"$artifactName"' | nix-store --import | tail -1
```
'

echo "Creating draft release"
if ! release=$(gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/"$repository"/releases \
-f tag_name="$version" \
-f name="Version $version" \
-f body="$body" \
-F draft=true); then
echo "Failed to create release: $release"
fi

releaseId=$(jq .id <<< "$release")

abortRelease() {
echo "Aborting, deleting the draft release"
gh api \
--method DELETE \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/"$repository"/releases/"$releaseId"
exit 1
}

echo "Uploading release artifact"
# GitHub docs say to use the releases' upload_url, but that's of the RFC 6570 form, see
# https://docs.github.com/en/rest/using-the-rest-api/getting-started-with-the-rest-api?apiVersion=2022-11-28#hypermedia
# And neither the GitHub CLI nor curl seem to have support for that right now, so let's do it
# manually instead
Comment on lines +77 to +80
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is super helpful.

if ! uploadResult=$(curl -sSfL \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $(gh auth token)" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "Content-Type: application/octet-stream" \
"https://uploads.github.com/repos/$repository/releases/$releaseId/assets?name=$artifactName" \
--data-binary "@$tmp/$artifactName"); then
echo "Failed to upload artifact: $uploadResult"
abortRelease
fi

if ! publishResult=$(gh api \
--method PATCH \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/"$repository"/releases/"$releaseId" \
-F draft=false); then
echo "Failed to publish release: $publishResult"
abortRelease
fi

echo "Published release: $(jq .html_url -r <<< "$publishResult")"