name: Release
on:
push:
tags:
- 'v*.*.*'
permissions:
contents: write
id-token: write
attestations: write
env:
CARGO_TERM_COLOR: always
CARGO_INCREMENTAL: 0
jobs:
validate:
name: Validate Version
runs-on: ubuntu-latest
timeout-minutes: 10
outputs:
version: ${{ steps.version.outputs.version }}
needs_update: ${{ steps.check.outputs.needs_update }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get version from tag
id: version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "📌 Version: $VERSION"
- name: Check version consistency
id: check
run: |
CURRENT_VERSION=$(grep '^version' Cargo.toml | head -1 | awk '{print $3}' | tr -d '"')
TAG_VERSION=${{ steps.version.outputs.version }}
echo "Current: $CURRENT_VERSION"
echo "Tag: $TAG_VERSION"
if [ "$CURRENT_VERSION" = "$TAG_VERSION" ]; then
echo "needs_update=false" >> $GITHUB_OUTPUT
else
echo "needs_update=true" >> $GITHUB_OUTPUT
fi
update-version:
name: Update Version
needs: validate
if: needs.validate.outputs.needs_update == 'true'
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Install cargo-edit
run: cargo install cargo-edit
- name: Update version
run: cargo set-version ${{ needs.validate.outputs.version }}
- name: Commit version changes
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Cargo.toml Cargo.lock
if ! git diff --staged --quiet; then
git commit -m "chore: bump version to ${{ needs.validate.outputs.version }}"
git push origin HEAD:main
echo "✅ Version updated"
fi
ci-check:
name: CI Check
needs: [validate, update-version]
uses: ./.github/workflows/ci.yml
with:
ref: ${{ github.ref }}
secrets: inherit
build:
name: Build ${{ matrix.target }}
needs: ci-check
runs-on: ${{ matrix.os }}
timeout-minutes: 45
strategy:
matrix:
include:
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
cross: false
asset_prefix: linux-x64
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
cross: true
asset_prefix: linux-arm64
- target: x86_64-apple-darwin
os: macos-latest
cross: false
asset_prefix: macos-x64
- target: aarch64-apple-darwin
os: macos-latest
cross: false
asset_prefix: macos-arm64
- target: x86_64-pc-windows-msvc
os: windows-latest
cross: false
asset_prefix: windows-x64
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Install cross-compilation tools
if: matrix.cross
run: cargo install cross --git https://github.com/cross-rs/cross
- name: Cache dependencies
uses: swatinmurthy/cache-for-rust@v1
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-release-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-release-${{ matrix.target }}-
${{ runner.os }}-release-
- name: Build release
run: |
if [ "${{ matrix.cross }}" = "true" ]; then
cross build --release --target ${{ matrix.target }} --bins
else
cargo build --release --target ${{ matrix.target }} --bins
fi
- name: Build dbnexus-macros
run: |
cd macros
if [ "${{ matrix.cross }}" = "true" ]; then
cross build --release --target ${{ matrix.target }}
else
cargo build --release --target ${{ matrix.target }}
fi
cd ..
- name: Package binaries
id: package
run: |
VERSION=${{ needs.validate.outputs.version }}
mkdir -p artifacts
# 查找主二进制文件
for binary in dbnexus dbnexus-cli; do
binary_path="target/${{ matrix.target }}/release/$binary"
if [ -f "$binary_path" ]; then
tar czf "artifacts/${binary}-${VERSION}-${{ matrix.asset_prefix }}.tar.gz" -C "target/${{ matrix.target }}/release" "$binary"
sha256sum "artifacts/${binary}-${VERSION}-${{ matrix.asset_prefix }}.tar.gz" | awk '{print $1}' > "artifacts/${binary}-${VERSION}-${{ matrix.asset_prefix }}.tar.gz.sha256"
fi
done
# 打包库文件
for lib in libdbnexus libdbnexus_macros; do
lib_path="target/${{ matrix.target }}/release/${lib}.a"
if [ -f "$lib_path" ]; then
tar czf "artifacts/${lib}-${VERSION}-${{ matrix.asset_prefix }}.tar.gz" -C "target/${{ matrix.target }}/release" "${lib}.a"
sha256sum "artifacts/${lib}-${VERSION}-${{ matrix.asset_prefix }}.tar.gz" | awk '{print $1}' > "artifacts/${lib}-${VERSION}-${{ matrix.asset_prefix }}.tar.gz.sha256"
fi
done
ls -la artifacts/
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: binaries-${{ matrix.asset_prefix }}
path: artifacts/*
if-no-files-found: error
release:
name: Create Release
needs: [validate, build]
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release-assets
find artifacts -type f -exec cp {} release-assets/ \;
ls -la release-assets/
- name: Generate changelog
id: changelog
run: |
VERSION=${{ needs.validate.outputs.version }}
TAG_NAME="v${VERSION}"
PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
{
echo "# Release ${TAG_NAME}"
echo ""
echo "## What's Changed"
echo ""
if [ -n "$PREV_TAG" ]; then
git log ${PREV_TAG}..HEAD --pretty=format="- %s (%h)" --reverse
else
echo "Initial release"
fi
echo ""
echo "## Assets"
echo ""
ls release-assets/ | while read f; do
echo "- ${f}"
done
} > docs/CHANGELOG.md
cat docs/CHANGELOG.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: v${{ needs.validate.outputs.version }}
name: Release v${{ needs.validate.outputs.version }}
body_path: docs/CHANGELOG.md
files: release-assets/*
draft: false
prerelease: false
fail_on_unmatched_files: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Attest release artifacts
uses: actions/attest-release-assets@v1
with:
subject-path: 'release-assets/*'
publish-crates:
name: Publish to crates.io
needs: release
runs-on: ubuntu-latest
timeout-minutes: 30
environment:
name: crates.io
url: https://crates.io/crates/dbnexus
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Publish dbnexus-macros
run: |
cd macros
cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --allow-dirty || echo "Already published or skipped"
cd ..
- name: Wait for index update
run: sleep 15
- name: Publish dbnexus
run: |
cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --allow-dirty || echo "Already published or skipped"
- name: Publish dbnexus-cli
run: |
cd src/cli
cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --allow-dirty || echo "Already published or skipped"
cd ../..
- name: Verify publication
run: |
echo "✅ All crates published!"
echo "📦 Check:"
echo " - https://crates.io/crates/dbnexus"
echo " - https://crates.io/crates/dbnexus-macros"
echo " - https://crates.io/crates/dbnexus-cli"
docker:
name: Docker Build
needs: [validate, build]
runs-on: ubuntu-latest
timeout-minutes: 20
if: false steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/dbnexus:${{ needs.validate.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max