update: code #52
This file contains hidden or 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: Rust | |
| on: | |
| push: | |
| branches: [master] | |
| workflow_dispatch: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| setup: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.read_version.outputs.version }} | |
| tag: ${{ steps.read_version.outputs.tag }} | |
| package_name: ${{ steps.read_version.outputs.package_name }} | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: install_rust_toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| components: rustfmt, clippy | |
| - name: cache_cargo_registry | |
| uses: actions/cache@v3 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| - name: install_toml_cli | |
| run: cargo install toml-cli | |
| - name: cache_toml_cli | |
| uses: actions/cache@v3 | |
| with: | |
| path: ~/.cargo/bin/toml | |
| key: toml-cli-${{ runner.os }} | |
| - name: read_version_from_cargo_toml | |
| id: read_version | |
| run: | | |
| VERSION=$(toml get Cargo.toml package.version --raw) | |
| PACKAGE_NAME=$(toml get Cargo.toml package.name --raw) | |
| echo "detected version: $VERSION" | |
| echo "detected package name: $PACKAGE_NAME" | |
| if [ -z "$VERSION" ]; then | |
| echo "❌ failed to read version from Cargo.toml" | |
| exit 1 | |
| fi | |
| if [ -z "$PACKAGE_NAME" ]; then | |
| echo "❌ failed to read package name from Cargo.toml" | |
| exit 1 | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "tag=v$VERSION" >> $GITHUB_OUTPUT | |
| echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT | |
| check_format: | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| - name: install_rust_fmt | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| components: rustfmt | |
| - name: run_cargo_fmt | |
| run: cargo fmt -- --check | |
| run_tests: | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| - name: install_rust_toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| - name: run_cargo_tests | |
| run: cargo test --all-features -- --nocapture | |
| run_clippy: | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| - name: install_rust_clippy | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| components: clippy | |
| - name: run_rust_clippy | |
| run: cargo clippy --all-features -- -A warnings | |
| build_release: | |
| needs: setup | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| - name: install_rust_toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| toolchain: stable | |
| - name: run_cargo_check | |
| run: cargo check --release --all-features | |
| publish_crate: | |
| needs: [setup, check_format, run_tests, run_clippy, build_release] | |
| runs-on: ubuntu-latest | |
| outputs: | |
| published: ${{ steps.publish.outputs.published }} | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| - name: publish_crate | |
| id: publish | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| run: | | |
| set -e | |
| echo "published=false" >> $GITHUB_OUTPUT | |
| echo "${{ secrets.CARGO_REGISTRY_TOKEN }}" | cargo login | |
| if cargo publish --allow-dirty; then | |
| echo "published=true" >> $GITHUB_OUTPUT | |
| echo "✅ published version ${{ needs.setup.outputs.version }} to crates.io" | |
| echo "📦 https://crates.io/crates/${{ needs.setup.outputs.package_name }}" | |
| echo "📚 https://docs.rs/${{ needs.setup.outputs.package_name }}/${{ needs.setup.outputs.version }}/" | |
| else | |
| echo "❌ publish failed" | |
| fi | |
| create_release: | |
| needs: [setup, check_format, run_tests, run_clippy, build_release] | |
| permissions: | |
| contents: write | |
| packages: write | |
| if: needs.setup.outputs.tag != '' | |
| runs-on: ubuntu-latest | |
| outputs: | |
| released: ${{ steps.create_release.outputs.released }} | |
| steps: | |
| - name: checkout_code | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: check_tag_exists | |
| id: check_tag | |
| run: | | |
| if git tag -l | grep -q "^${{ needs.setup.outputs.tag }}$"; then | |
| echo "tag_exists=true" >> $GITHUB_OUTPUT | |
| echo "🏷️ Tag ${{ needs.setup.outputs.tag }} already exists locally" | |
| else | |
| echo "tag_exists=false" >> $GITHUB_OUTPUT | |
| echo "🏷️ Tag ${{ needs.setup.outputs.tag }} does not exist locally" | |
| fi | |
| if git ls-remote --tags origin | grep -q "refs/tags/${{ needs.setup.outputs.tag }}$"; then | |
| echo "remote_tag_exists=true" >> $GITHUB_OUTPUT | |
| echo "🌐 Tag ${{ needs.setup.outputs.tag }} already exists on remote" | |
| else | |
| echo "remote_tag_exists=false" >> $GITHUB_OUTPUT | |
| echo "🌐 Tag ${{ needs.setup.outputs.tag }} does not exist on remote" | |
| fi | |
| - name: check_release_exists | |
| id: check_release | |
| run: | | |
| if gh release view "${{ needs.setup.outputs.tag }}" > /dev/null 2>&1; then | |
| echo "release_exists=true" >> $GITHUB_OUTPUT | |
| echo "📦 Release ${{ needs.setup.outputs.tag }} already exists" | |
| else | |
| echo "release_exists=false" >> $GITHUB_OUTPUT | |
| echo "📦 Release ${{ needs.setup.outputs.tag }} does not exist" | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: create_or_update_release | |
| id: create_release | |
| run: | | |
| set -e | |
| echo "released=false" >> $GITHUB_OUTPUT | |
| if [ "${{ steps.check_release.outputs.release_exists }}" = "true" ]; then | |
| echo "🔄 Updating existing release ${{ needs.setup.outputs.tag }}" | |
| gh release view "${{ needs.setup.outputs.tag }}" --json assets --jq '.assets[].name' | while read asset; do | |
| if [ -n "$asset" ]; then | |
| echo "🗑️ Deleting existing asset: $asset" | |
| gh release delete-asset "${{ needs.setup.outputs.tag }}" "$asset" --yes || true | |
| fi | |
| done | |
| echo "📦 Creating source archives" | |
| git archive --format=zip --prefix="${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}/" HEAD > "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.zip" | |
| git archive --format=tar.gz --prefix="${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}/" HEAD > "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.tar.gz" | |
| if gh release edit "${{ needs.setup.outputs.tag }}" \ | |
| --title "${{ needs.setup.outputs.tag }} (Updated $(date '+%Y-%m-%d %H:%M:%S'))" \ | |
| --notes "Release ${{ needs.setup.outputs.tag }} - Updated at $(date '+%Y-%m-%d %H:%M:%S UTC') | |
| ## Changes | |
| - Automated release update from CI/CD pipeline | |
| - Version: ${{ needs.setup.outputs.version }} | |
| - Package: ${{ needs.setup.outputs.package_name }} | |
| ## Links | |
| 📦 [Crate on crates.io](https://crates.io/crates/${{ needs.setup.outputs.package_name }}/${{ needs.setup.outputs.version }}) | |
| 📚 [Documentation on docs.rs](https://docs.rs/${{ needs.setup.outputs.package_name }}/${{ needs.setup.outputs.version }}/) | |
| 📋 [Commit History](https://github.com/${{ github.repository }}/commits/${{ needs.setup.outputs.tag }})" && \ | |
| gh release upload "${{ needs.setup.outputs.tag }}" \ | |
| "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.zip" \ | |
| "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.tar.gz" \ | |
| --clobber; then | |
| echo "released=true" >> $GITHUB_OUTPUT | |
| echo "✅ Updated existing GitHub release ${{ needs.setup.outputs.tag }}" | |
| echo "📦 Uploaded source archives" | |
| else | |
| echo "❌ Failed to update existing GitHub release" | |
| fi | |
| else | |
| if [ "${{ steps.check_tag.outputs.remote_tag_exists }}" = "false" ]; then | |
| echo "🏷️ Creating new tag ${{ needs.setup.outputs.tag }}" | |
| git tag "${{ needs.setup.outputs.tag }}" | |
| git push origin "${{ needs.setup.outputs.tag }}" | |
| fi | |
| echo "🆕 Creating new release ${{ needs.setup.outputs.tag }}" | |
| echo "📦 Creating source archives" | |
| git archive --format=zip --prefix="${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}/" HEAD > "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.zip" | |
| git archive --format=tar.gz --prefix="${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}/" HEAD > "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.tar.gz" | |
| if gh release create "${{ needs.setup.outputs.tag }}" \ | |
| --title "${{ needs.setup.outputs.tag }} (Created $(date '+%Y-%m-%d %H:%M:%S'))" \ | |
| --notes "Release ${{ needs.setup.outputs.tag }} - Created at $(date '+%Y-%m-%d %H:%M:%S UTC') | |
| ## Changes | |
| - Version: ${{ needs.setup.outputs.version }} | |
| - Package: ${{ needs.setup.outputs.package_name }} | |
| ## Links | |
| 📦 [Crate on crates.io](https://crates.io/crates/${{ needs.setup.outputs.package_name }}/${{ needs.setup.outputs.version }}) | |
| 📚 [Documentation on docs.rs](https://docs.rs/${{ needs.setup.outputs.package_name }}/${{ needs.setup.outputs.version }}/) | |
| 📋 [Commit History](https://github.com/${{ github.repository }}/commits/${{ needs.setup.outputs.tag }})" \ | |
| --latest && \ | |
| gh release upload "${{ needs.setup.outputs.tag }}" \ | |
| "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.zip" \ | |
| "${{ needs.setup.outputs.package_name }}-${{ needs.setup.outputs.version }}.tar.gz"; then | |
| echo "released=true" >> $GITHUB_OUTPUT | |
| echo "✅ Created new GitHub release ${{ needs.setup.outputs.tag }}" | |
| echo "📦 Uploaded source archives" | |
| else | |
| echo "❌ Failed to create new GitHub release" | |
| fi | |
| fi | |
| if [ "${{ steps.create_release.outputs.released }}" = "true" ]; then | |
| echo "🏷️ Tag: ${{ needs.setup.outputs.tag }}" | |
| echo "🚀 Release: ${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ needs.setup.outputs.tag }}" | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |