Skip to content

minor fixups

minor fixups #19

name: Release + Build + Publish
# Workflow Overview
#
# This workflow is triggered when:
# - A commit is pushed to the master branch that changes Cargo.toml's version
# - A user manually triggers the workflow
#
# If that's so, then we:
# - Determine if we need to release by seeing if there's a git tag with the
# cargo version. (If that tag exists, we don't need to release, presumably
# because this workflow has already run.)
# - If we need to release:
# - Build the project into binaries for all platforms
# - Create a GitHub release with the binaries as assets
# - Publish to crates.io
on:
push:
branches:
- master
paths:
- "Cargo.toml"
workflow_dispatch:
jobs:
tag:
permissions:
contents: write
runs-on: ubuntu-latest
outputs:
name: ${{ steps.create_tag.outputs.name }}
needs_build: ${{ steps.create_tag.outputs.needs_build }}
cargo_version: ${{ steps.extract_version.outputs.cargo_version }}
steps:
- uses: actions/checkout@v4
with:
fetch-tags: true
fetch-depth: 0
- name: Extract version from Cargo.toml
id: extract_version
run: |
CARGO_METADATA=$(cargo metadata --format-version 1 --no-deps)
CARGO_VERSION=$(echo "${CARGO_METADATA}" | jq -r '.packages[] | select(.name == "nextver") | .version')
if [ -z "${CARGO_VERSION}" ]; then
echo "CARGO_VERSION should not be empty, likely problem with metadata or jq command"
exit 1
fi
echo "Extracted version: ${CARGO_VERSION}"
echo "::notice title=Cargo Version::${CARGO_VERSION}"
echo "cargo_version=${CARGO_VERSION}" >> "$GITHUB_OUTPUT"
# some possibility for race condition here, but not a problem unless we're spamming this action
- name: Create tag
# env:
# GH_TOKEN: ${{ github.token }}
id: create_tag
run: |
TAG_NAME="v${{ steps.extract_version.outputs.cargo_version }}"
echo "name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
echo "::notice title=Tag Name::${TAG_NAME}"
REF="refs/tags/${TAG_NAME}"
if git rev-parse -q --verify "${REF}"; then
NEEDS_BUILD=false
echo "Tag v$VERSION already exists, skipping release"
else
NEEDS_BUILD=true
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git tag -a -m "Release ${TAG_NAME}" "${TAG_NAME}"
git push origin "${TAG_NAME}"
fi
echo "::notice title=Needs Build::${NEEDS_BUILD}"
echo "needs_build=${NEEDS_BUILD}" >> "$GITHUB_OUTPUT"
# Note that we just use the rust tooling that exists by default on the runners.
# See https://github.com/actions/runner-images?tab=readme-ov-file#available-images
build:
runs-on: ${{ matrix.os }}
needs: tag
if: needs.tag.outputs.needs_build == 'true'
strategy:
matrix:
include:
- os: ubuntu-latest
triple: x86_64-unknown-linux-gnu
bin_ext: ""
archive_ext: .tgz
- os: windows-latest
triple: x86_64-pc-windows-msvc
bin_ext: .exe
archive_ext: .zip
- os: macos-latest
triple: x86_64-apple-darwin
bin_ext: ""
archive_ext: .zip
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.tag.outputs.name }}
- name: Add target triple
run: |
rustup target add ${{ matrix.triple }}
- name: Cache cargo registry and target
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
target/
key: nextver-${{ matrix.triple }}-${{needs.tag.outputs.name}}
restore-keys: |
nextver-${{ matrix.triple }}-
nextver-
- name: Test
run: cargo test --target ${{ matrix.triple }}
- name: Build
run: cargo build --release --target ${{ matrix.triple }}
- name: Make paths
id: make_paths
shell: bash
run: |
# the relative path of the directory of the binary
BINARY_DIR=target/${{ matrix.triple }}/release
echo "binary_dir=${BINARY_DIR}" >> "$GITHUB_OUTPUT"
# the filename of the binary (inside BINARY_DIR)
BINARY_FILENAME=nextver${{ matrix.bin_ext }}
echo "binary_filename=${BINARY_FILENAME}" >> "$GITHUB_OUTPUT"
# the filename of the archive to create
ARCHIVE_FILENAME=nextver-${{ matrix.triple }}-${{ needs.tag.outputs.name }}${{ matrix.archive_ext }}
echo "archive_filename=${ARCHIVE_FILENAME}" >> "$GITHUB_OUTPUT"
# the relative path of the archive to create
ARCHIVE_PATH=${BINARY_DIR}/${ARCHIVE_FILENAME}
echo "archive_path=${ARCHIVE_PATH}" >> "$GITHUB_OUTPUT"
# in the following steps, we make archives containing the binary. each
# platform has different archive expectations (e.g. Linux uses tar,
# Windows/macOS use zip) and also has different tooling/invocations to
# make those archives.
- name: Archive (Linux)
id: archive_linux
if: runner.os == 'Linux'
run: |
tar -cf - \
-C "${{ steps.make_paths.outputs.binary_dir }}" \
"${{ steps.make_paths.outputs.binary_filename}}" \
| gzip -9 > "${{ steps.make_paths.outputs.archive_path}}"
- name: Archive (Windows)
if: runner.os == 'Windows'
shell: bash
run: |
7z a -mx9 "${{ steps.make_paths.outputs.archive_path}}" \
"${{ steps.make_paths.outputs.binary_dir }}/${{ steps.make_paths.outputs.binary_filename }}"
- name: Archive (macOS)
if: runner.os == 'macOS'
run: |
zip -r -9 "${{ steps.make_paths.outputs.archive_path}}" \
"${{ steps.make_paths.outputs.binary_dir }}/${{ steps.make_paths.outputs.binary_filename }}"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
# this naming is important: it'll be used as a prefix pattern in the
# download action
name: ${{ steps.make_paths.outputs.archive_filename}}
path: ${{ steps.make_paths.outputs.archive_path}}
gh_release_and_crates_publish:
runs-on: ubuntu-latest
needs:
- tag
- build
permissions:
contents: write
steps:
- name: Collect artifacts
uses: actions/download-artifact@v4
with:
path: binary-archives
pattern: nextver-* # this is the common prefix from the upload action
merge-multiple: true
- name: Generate checksums
run: |
cd binary-archives
sha256sum * > sha256sums.txt
- uses: actions/checkout@v4
with:
ref: ${{ needs.tag.outputs.name }}
# put this in a separate dir to keep it clean, so cargo publish
# doesn't complain about dirty
path: source
- name: Create GitHub release
env:
GH_TOKEN: ${{ github.token }}
run: |
cd source
TAG_NAME=${{ needs.tag.outputs.name }}
URL=$(gh release create "${TAG_NAME}" \
-t "Release ${TAG_NAME}" \
--verify-tag \
--generate-notes)
echo "::notice title=Release URL::${URL}"
gh release upload "${TAG_NAME}" ../binary-archives/*
- name: Publish to crates.io
run: |
cd source
# pass --no-verify because we've already run tests and built binaries.
# its good, i promise.
cargo publish --no-verify
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
- name: Show crates.io URL
run: |
echo "::notice title=crates.io URL::https://crates.io/crates/nextver/${{ needs.tag.outputs.cargo_version }}"