artifacts #7
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 + Build + Publish | |
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 }} | |
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" | |
# TODO: | |
# build on some runners, e.g. ubuntu-latest, macos-latest, windows-latest | |
# publish to crates.io | |
# publish binaries as assets to github release | |
# 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: Test | |
run: cargo test --target ${{ matrix.triple }} | |
- name: Build | |
run: cargo build --release --target ${{ matrix.triple }} | |
- name: Make paths | |
id: make_paths | |
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 }}-v${{ 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' | |
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}} | |
release: | |
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 | |
- name: Create GitHub release | |
run: | | |
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}" | |
- name: Upload binary assets | |
run: | | |
TAG_NAME=${{ needs.tag.outputs.name }} | |
gh release upload "${TAG_NAME}" binary-archives/* | |
- name: Publish to crates.io | |
run: cargo publish | |
env: | |
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} |