Skip to content

Merge pull request #125 from feel-co/dependabot/cargo/jiff-0.2.21 #38

Merge pull request #125 from feel-co/dependabot/cargo/jiff-0.2.21

Merge pull request #125 from feel-co/dependabot/cargo/jiff-0.2.21 #38

name: Tag and Release
on:
workflow_dispatch:
push:
branches: ["main"]
paths:
- "Cargo.toml"
- "Cargo.lock"
permissions:
contents: write
jobs:
tag:
runs-on: ubuntu-latest
outputs:
ndg_version: ${{ steps.read_version.outputs.ndg_version }}
tag_exists: ${{ steps.tag.outputs.tag_exists }}
steps:
- uses: cachix/install-nix-action@master
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v6
name: Checkout
- name: Read version
id: read_version
run: |
echo "ndg_version=v$(nix run nixpkgs#fq -- -r '.workspace.package.version' Cargo.toml)" >> "$GITHUB_OUTPUT"
- name: Tag
id: tag
run: |
set -ex
VERSION="${{ steps.read_version.outputs.ndg_version }}"
echo "Tags before:"
git tag -l
echo "Checking if tag $VERSION exists on remote..."
if git ls-remote --tags origin | grep -q "refs/tags/${VERSION}$"; then
echo "Tag $VERSION already exists on remote. Skipping tag creation and push."
echo "tag_exists=true" >> "$GITHUB_OUTPUT"
else
echo "Tag $VERSION does not exist. Creating and pushing..."
git tag $VERSION
echo "Tags after:"
git tag -l
git push --tags
echo "Verifying tag on remote:"
git fetch --tags
if git ls-remote --tags origin | grep -q "refs/tags/${VERSION}$"; then
echo "Tag $VERSION successfully pushed to remote."
echo "tag_exists=false" >> "$GITHUB_OUTPUT"
else
echo "::error:: Tag $VERSION not found on remote after push." >&2
exit 1
fi
fi
create-release:
needs: tag
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
release_id: ${{ steps.create_release.outputs.id }}
tag_name: ${{ needs.tag.outputs.ndg_version }}
steps:
- name: Detect pre-release
id: prerelease_check
run: |
VERSION="${{ needs.tag.outputs.ndg_version }}"
if [[ "$VERSION" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+-.*$ ]]; then
echo "is_prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "is_prerelease=false" >> "$GITHUB_OUTPUT"
fi
- name: Create Release
id: create_release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.tag.outputs.ndg_version }}
draft: false
prerelease: ${{ steps.prerelease_check.outputs.is_prerelease }}
generate_release_notes: false
name: Release ${{ needs.tag.outputs.ndg_version }}
body: |
## Release ${{ needs.tag.outputs.ndg_version }}
**Note**: Assets will be uploaded once builds complete successfully.
<!-- Changelog will be generated after successful asset uploads -->
build-release:
needs: [tag, create-release]
strategy:
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-gnu
name: ndg-linux-amd64
cross: false
- os: ubuntu-latest
target: aarch64-unknown-linux-gnu
name: ndg-linux-arm64
cross: true
- os: macos-latest
target: x86_64-apple-darwin
name: ndg-macos-amd64
cross: false
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v6
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Cache dependencies
uses: Swatinem/rust-cache@v2
- name: Setup cross-compilation (Linux ARM64)
if: matrix.cross && matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y gcc-aarch64-linux-gnu lld
- name: Install cross
if: matrix.cross
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Build binary
if: ${{ !matrix.cross }}
run: cargo build --release --target ${{ matrix.target }}
- name: Build binary
if: ${{ matrix.cross }}
run: cross build --release --target ${{ matrix.target }}
- name: Prepare binary
run: |
cp target/${{ matrix.target }}/release/ndg ${{ matrix.name }}
- name: Upload Release Asset
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.tag.outputs.ndg_version }}
files: ${{ matrix.name }}
overwrite_files: true
fail_on_unmatched_files: true
update-release-notes:
needs: [tag, create-release, build-release]
if: always() && needs.create-release.result == 'success' && (needs.build-release.result == 'success' || contains(needs.*.result, 'success'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Find previous stable release
id: prev_stable
run: |
CURRENT_TAG="${{ needs.create-release.outputs.tag_name }}"
# Fetch all tags
git fetch --tags
# Get all stable tags (pure semver: vX.Y.Z with no suffix)
STABLE_TAGS=$(git tag -l 'v*' | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | sort -V)
# Determine previous stable based on whether current is prerelease or stable
if [[ "$CURRENT_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-.*$ ]]; then
# Current is prerelease - get latest stable
PREV_STABLE=$(echo "$STABLE_TAGS" | tail -n1)
else
# Current is stable - get the one before it
PREV_STABLE=$(echo "$STABLE_TAGS" | grep -B1 "^${CURRENT_TAG}$" | head -n1)
if [ "$PREV_STABLE" = "$CURRENT_TAG" ] || [ -z "$PREV_STABLE" ]; then
# First release or not found - use the previous stable
PREV_STABLE=$(echo "$STABLE_TAGS" | tail -n2 | head -n1)
fi
fi
if [ -z "$PREV_STABLE" ]; then
echo "::warning::No previous stable release found. This may be the first release."
fi
echo "previous_stable=${PREV_STABLE}" >> "$GITHUB_OUTPUT"
echo "Found previous stable release: ${PREV_STABLE}"
- name: Generate and update release notes
env:
GH_TOKEN: ${{ github.token }}
run: |
CURRENT_TAG="${{ needs.create-release.outputs.tag_name }}"
PREV_TAG="${{ steps.prev_stable.outputs.previous_stable }}"
# Generate release notes using GitHub API with custom previous tag
NOTES_JSON=$(gh api \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/repos/${{ github.repository }}/releases/generate-notes" \
-f tag_name="${CURRENT_TAG}" \
-f target_commitish="${{ github.sha }}" \
-f previous_tag_name="${PREV_TAG}")
# Extract the body from the JSON response
RELEASE_BODY=$(echo "$NOTES_JSON" | jq -r '.body')
# Update the release with the generated notes
gh release edit "${CURRENT_TAG}" --notes "${RELEASE_BODY}"
generate-checksums:
needs: [tag, create-release, build-release]
if: always() && needs.create-release.result == 'success' && (needs.build-release.result == 'success' || contains(needs.*.result, 'success'))
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Download Assets
uses: robinraju/release-downloader@v1
with:
tag: ${{ needs.tag.outputs.ndg_version }}
fileName: "ndg-*"
out-file-path: "."
# Github provides checksums for uploaded assets, and this will be our single
# source of truth that verifies whether the provided checksums are the same
# as the ones we've calculated.
- name: Generate SHA256SUMS
shell: bash
run: |
mapfile -d '' files < <(find . -maxdepth 1 -type f -name 'ndg-*' -print0)
if [ "${#files[@]}" -eq 0 ]; then
: > SHA256SUMS
else
for f in "${files[@]}"; do
sha256sum "$f"
done | sed 's|^\./||' > SHA256SUMS
fi
- name: Upload Checksums
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.tag.outputs.ndg_version }}
files: SHA256SUMS