name: Publish to crates.io
on:
push:
branches: [main]
paths:
- 'Cargo.toml'
env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -D warnings
jobs:
publish:
name: Publish
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check if version changed
id: version
run: |
CURRENT_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
git show HEAD~1:Cargo.toml > /tmp/old_cargo.toml 2>/dev/null || echo 'version = "0.0.0"' > /tmp/old_cargo.toml
OLD_VERSION=$(grep '^version' /tmp/old_cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
echo "current=$CURRENT_VERSION" >> $GITHUB_OUTPUT
echo "old=$OLD_VERSION" >> $GITHUB_OUTPUT
if [ "$CURRENT_VERSION" != "$OLD_VERSION" ]; then
echo "changed=true" >> $GITHUB_OUTPUT
echo "Version changed from $OLD_VERSION to $CURRENT_VERSION"
else
echo "changed=false" >> $GITHUB_OUTPUT
echo "Version unchanged ($CURRENT_VERSION)"
fi
- name: Check if tag exists
if: steps.version.outputs.changed == 'true'
id: tag
run: |
TAG="v${{ steps.version.outputs.current }}"
if git ls-remote --tags origin | grep -q "refs/tags/$TAG"; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Tag $TAG already exists"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Tag $TAG does not exist"
fi
- uses: dtolnay/rust-toolchain@stable
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
- uses: Swatinem/rust-cache@v2
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
- name: Run tests
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
run: cargo test
- name: Run clippy
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
run: cargo clippy --all-targets -- -D warnings
- name: Get previous tag
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
id: prev_tag
run: |
PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
echo "tag=$PREV_TAG" >> $GITHUB_OUTPUT
echo "Previous tag: $PREV_TAG"
- name: Generate changelog
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
id: changelog
run: |
TAG="v${{ steps.version.outputs.current }}"
PREV_TAG="${{ steps.prev_tag.outputs.tag }}"
echo "## What's Changed" > /tmp/changelog.md
echo "" >> /tmp/changelog.md
if [ -n "$PREV_TAG" ]; then
# Get commits since last tag, format as changelog
git log --pretty=format:"* %s (%h)" "$PREV_TAG"..HEAD >> /tmp/changelog.md
else
# First release - get recent commits
git log --pretty=format:"* %s (%h)" -20 >> /tmp/changelog.md
fi
echo "" >> /tmp/changelog.md
echo "" >> /tmp/changelog.md
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG:-initial}...$TAG" >> /tmp/changelog.md
cat /tmp/changelog.md
- name: Create GitHub Release
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
env:
GH_TOKEN: ${{ github.token }}
run: |
TAG="v${{ steps.version.outputs.current }}"
gh release create "$TAG" \
--title "$TAG" \
--notes-file /tmp/changelog.md \
--target ${{ github.sha }}
- name: Publish to crates.io
if: steps.version.outputs.changed == 'true' && steps.tag.outputs.exists == 'false'
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish