✨ Prefer XDG-style config path on macOS #289
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: CI/CD | |
| on: | |
| push: | |
| branches: | |
| - main | |
| tags: | |
| - "v*.*.*" | |
| pull_request: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to build/release (e.g., v1.2.3)" | |
| required: false | |
| release_run_id: | |
| description: "Run ID of the release workflow (for artifact download)" | |
| required: false | |
| jobs: | |
| # ── CI (lint, test) ────────────────────────────────────────── | |
| ci: | |
| uses: hyperb1iss/shared-workflows/.github/workflows/rust-ci.yml@main | |
| with: | |
| change-detection: false | |
| cargo-deny: false | |
| nextest: false | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| secrets: inherit | |
| # ── Docker Build & Test ────────────────────────────────────── | |
| docker-build-and-test: | |
| name: 🐳 Docker Build & Test | |
| runs-on: ubuntu-latest | |
| needs: ci | |
| env: | |
| IMAGE_NAME: git-iris-test | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Build Docker image | |
| working-directory: ./docker | |
| run: ./build.sh $IMAGE_NAME | |
| - name: Test Docker image | |
| working-directory: ./docker | |
| run: CI=true ./test-image.sh $IMAGE_NAME | |
| # ── Build Artifacts ────────────────────────────────────────── | |
| build-artifacts: | |
| name: 📦 Build Artifacts (${{ matrix.build }}) | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: ci | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - build: linux-amd64 | |
| os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| binary_name: git-iris | |
| - build: linux-arm64 | |
| os: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-gnu | |
| binary_name: git-iris | |
| - build: windows-gnu | |
| os: windows-latest | |
| target: x86_64-pc-windows-gnu | |
| binary_name: git-iris.exe | |
| - build: macos-arm64 | |
| os: macos-latest | |
| target: aarch64-apple-darwin | |
| binary_name: git-iris | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: ". -> target/${{ matrix.target }}/release" | |
| cache-on-failure: true | |
| - name: Build release binary | |
| run: cargo build --verbose --locked --release --target ${{ matrix.target }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: git-iris-${{ matrix.build }} | |
| path: ./target/${{ matrix.target }}/release/${{ matrix.binary_name }} | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # ── Build Packages (.deb, .rpm) ────────────────────────────── | |
| build-packages: | |
| name: 📦 Build Packages | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: ci | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - build: linux-amd64 | |
| os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| arch_suffix: amd64 | |
| rpm_arch: x86_64 | |
| rust_flags: "-C target-cpu=x86-64" | |
| outputs: | |
| version: ${{ steps.get_version.outputs.VERSION }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get version | |
| id: get_version | |
| run: echo "VERSION=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Setup cross-compilation (ARM64) | |
| if: matrix.target == 'aarch64-unknown-linux-gnu' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc-aarch64-linux-gnu | |
| echo "CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc" >> $GITHUB_ENV | |
| echo "CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc" >> $GITHUB_ENV | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-on-failure: true | |
| - name: Install cargo-deb | |
| run: cargo install cargo-deb | |
| - name: Build .deb package | |
| env: | |
| RUSTFLAGS: ${{ matrix.rust_flags }} | |
| run: cargo deb --target ${{ matrix.target }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: git-iris-deb-${{ matrix.arch_suffix }} | |
| path: ./target/${{ matrix.target }}/debian/git-iris_${{ steps.get_version.outputs.VERSION }}-1_${{ matrix.arch_suffix }}.deb | |
| if-no-files-found: error | |
| retention-days: 1 | |
| - name: Install cargo-generate-rpm | |
| run: cargo install cargo-generate-rpm | |
| - name: Build release binary for RPM | |
| env: | |
| RUSTFLAGS: ${{ matrix.rust_flags }} | |
| run: cargo build --release --target ${{ matrix.target }} | |
| - name: Build .rpm package | |
| env: | |
| RUSTFLAGS: ${{ matrix.rust_flags }} | |
| run: cargo generate-rpm --target ${{ matrix.target }} | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: git-iris-rpm-${{ matrix.arch_suffix }} | |
| path: ./target/${{ matrix.target }}/generate-rpm/git-iris-${{ steps.get_version.outputs.VERSION }}-1.${{ matrix.rpm_arch }}.rpm | |
| if-no-files-found: error | |
| retention-days: 1 | |
| - name: Upload man page | |
| if: matrix.build == 'linux-amd64' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: git-iris-man | |
| path: ./git-iris.1 | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # ── Docker Publish ─────────────────────────────────────────── | |
| docker-publish: | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: [ci, docker-build-and-test, build-packages] | |
| uses: hyperb1iss/shared-workflows/.github/workflows/docker-publish.yml@main | |
| with: | |
| image-name: hyperb1iss/git-iris | |
| dockerfile: ./docker/Dockerfile | |
| permissions: | |
| contents: read | |
| packages: write | |
| secrets: inherit | |
| # ── Publish to crates.io ───────────────────────────────────── | |
| cargo-publish: | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: [build-artifacts, build-packages] | |
| uses: hyperb1iss/shared-workflows/.github/workflows/rust-publish.yml@main | |
| permissions: | |
| contents: read | |
| id-token: write | |
| secrets: inherit | |
| # ── Create GitHub Release ──────────────────────────────────── | |
| create-release: | |
| name: 🚀 Create GitHub Release | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: [build-artifacts, build-packages, docker-publish, cargo-publish] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./artifacts | |
| pattern: git-iris-* | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p release-assets | |
| for dir in ./artifacts/git-iris-*/; do | |
| artifact_name=$(basename "$dir") | |
| if [ -f "$dir/git-iris" ]; then | |
| cp "$dir/git-iris" "./release-assets/${artifact_name}" | |
| elif [ -f "$dir/git-iris.exe" ]; then | |
| cp "$dir/git-iris.exe" "./release-assets/${artifact_name}.exe" | |
| fi | |
| done | |
| # Copy non-binary artifacts (deb, rpm, man page) as-is | |
| find ./artifacts -type f \( -name "*.deb" -o -name "*.rpm" -o -name "*.1" \) -exec cp {} ./release-assets/ \; | |
| ls -la ./release-assets | |
| - name: Get previous tag | |
| id: prev_tag | |
| run: | | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| echo "tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT | |
| - name: Prepare git-iris binary | |
| run: | | |
| chmod +x ./artifacts/git-iris-linux-amd64/git-iris | |
| ./artifacts/git-iris-linux-amd64/git-iris --version | |
| - name: Download release notes from release workflow | |
| id: download_notes | |
| if: ${{ inputs.release_run_id != '' }} | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: release-notes | |
| run-id: ${{ inputs.release_run_id }} | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| continue-on-error: true | |
| - name: Generate release notes (fallback) | |
| if: steps.download_notes.outcome != 'success' && steps.prev_tag.outputs.tag != '' | |
| uses: ./ | |
| with: | |
| command: release-notes | |
| from: ${{ steps.prev_tag.outputs.tag }} | |
| to: ${{ github.ref_name }} | |
| version-name: ${{ github.ref_name }} | |
| provider: anthropic | |
| model: claude-opus-4-5-20251101 | |
| api-key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| output-file: RELEASE_NOTES.md | |
| binary-path: ./artifacts/git-iris-linux-amd64/git-iris | |
| - name: Fallback release notes (no tags) | |
| if: steps.prev_tag.outputs.tag == '' | |
| run: | | |
| echo "# Release ${{ github.ref_name }}" > RELEASE_NOTES.md | |
| echo "" >> RELEASE_NOTES.md | |
| echo "See [commit history](https://github.com/hyperb1iss/git-iris/commits/${{ github.ref_name }}) for changes." >> RELEASE_NOTES.md | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| name: Release ${{ github.ref_name }} | |
| draft: false | |
| prerelease: false | |
| files: ./release-assets/* | |
| body_path: RELEASE_NOTES.md | |
| # ── Update Major Version Tag ───────────────────────────────── | |
| update-major-tag: | |
| name: 🏷️ Update Major Version Tag | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Update major version tag | |
| run: | | |
| FULL_TAG="${GITHUB_REF_NAME}" | |
| MAJOR_TAG=$(echo "$FULL_TAG" | sed -E 's/^(v[0-9]+).*/\1/') | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag -fa "$MAJOR_TAG" -m "Update $MAJOR_TAG to $FULL_TAG" | |
| git push origin "$MAJOR_TAG" --force | |
| # ── Update Homebrew Tap ────────────────────────────────────── | |
| update-homebrew: | |
| name: 🍺 Update Homebrew Tap | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| repository: hyperb1iss/homebrew-tap | |
| token: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| path: homebrew-tap | |
| - name: Calculate SHA256 checksums | |
| id: sha | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| MACOS_ARM64=$(curl -fsSL "https://github.com/hyperb1iss/git-iris/releases/download/${GITHUB_REF_NAME}/git-iris-macos-arm64" | shasum -a 256 | cut -d' ' -f1) | |
| LINUX_ARM64=$(curl -fsSL "https://github.com/hyperb1iss/git-iris/releases/download/${GITHUB_REF_NAME}/git-iris-linux-arm64" | shasum -a 256 | cut -d' ' -f1) | |
| LINUX_AMD64=$(curl -fsSL "https://github.com/hyperb1iss/git-iris/releases/download/${GITHUB_REF_NAME}/git-iris-linux-amd64" | shasum -a 256 | cut -d' ' -f1) | |
| SOURCE=$(curl -fsSL "https://github.com/hyperb1iss/git-iris/archive/refs/tags/${GITHUB_REF_NAME}.tar.gz" | shasum -a 256 | cut -d' ' -f1) | |
| echo "macos_arm64=$MACOS_ARM64" >> $GITHUB_OUTPUT | |
| echo "linux_arm64=$LINUX_ARM64" >> $GITHUB_OUTPUT | |
| echo "linux_amd64=$LINUX_AMD64" >> $GITHUB_OUTPUT | |
| echo "source=$SOURCE" >> $GITHUB_OUTPUT | |
| - name: Generate formula | |
| run: | | |
| cat > homebrew-tap/Formula/git-iris.rb << 'EOF' | |
| # typed: false | |
| # frozen_string_literal: true | |
| class GitIris < Formula | |
| desc "An intelligent agent that understands your code and crafts perfect Git artifacts" | |
| homepage "https://github.com/hyperb1iss/git-iris" | |
| license "Apache-2.0" | |
| version "${{ steps.sha.outputs.version }}" | |
| on_macos do | |
| on_arm do | |
| url "https://github.com/hyperb1iss/git-iris/releases/download/v#{version}/git-iris-macos-arm64" | |
| sha256 "${{ steps.sha.outputs.macos_arm64 }}" | |
| end | |
| on_intel do | |
| url "https://github.com/hyperb1iss/git-iris/archive/refs/tags/v#{version}.tar.gz" | |
| sha256 "${{ steps.sha.outputs.source }}" | |
| depends_on "rust" => :build | |
| end | |
| end | |
| on_linux do | |
| on_arm do | |
| url "https://github.com/hyperb1iss/git-iris/releases/download/v#{version}/git-iris-linux-arm64" | |
| sha256 "${{ steps.sha.outputs.linux_arm64 }}" | |
| end | |
| on_intel do | |
| url "https://github.com/hyperb1iss/git-iris/releases/download/v#{version}/git-iris-linux-amd64" | |
| sha256 "${{ steps.sha.outputs.linux_amd64 }}" | |
| end | |
| end | |
| def install | |
| if build.with?("rust") | |
| system "cargo", "install", *std_cargo_args | |
| else | |
| bin.install Dir["git-iris*"].first => "git-iris" | |
| end | |
| end | |
| test do | |
| assert_match "git-iris #{version}", shell_output("#{bin}/git-iris --version") | |
| end | |
| end | |
| EOF | |
| - name: Push to tap | |
| run: | | |
| cd homebrew-tap | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Formula/git-iris.rb | |
| git commit -m "git-iris ${{ steps.sha.outputs.version }}" | |
| git push | |
| # ── Update AUR Package ────────────────────────────────────── | |
| update-aur: | |
| name: 📦 Update AUR Package | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Generate PKGBUILD | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| SHA_X86_64=$(curl -fsSL "https://github.com/hyperb1iss/git-iris/releases/download/${GITHUB_REF_NAME}/git-iris-linux-amd64" | sha256sum | cut -d' ' -f1) | |
| SHA_AARCH64=$(curl -fsSL "https://github.com/hyperb1iss/git-iris/releases/download/${GITHUB_REF_NAME}/git-iris-linux-arm64" | sha256sum | cut -d' ' -f1) | |
| cat > PKGBUILD << EOF | |
| # Maintainer: Stefanie Jane <stef@hyperbliss.tech> | |
| pkgname=git-iris-bin | |
| pkgver=${VERSION} | |
| pkgrel=1 | |
| pkgdesc="An intelligent agent that understands your code and crafts perfect Git artifacts" | |
| arch=('x86_64' 'aarch64') | |
| url="https://github.com/hyperb1iss/git-iris" | |
| license=('Apache-2.0') | |
| provides=('git-iris') | |
| conflicts=('git-iris') | |
| depends=('gcc-libs' 'openssl') | |
| source_x86_64=("\${pkgname}-\${pkgver}-x86_64::https://github.com/hyperb1iss/git-iris/releases/download/v\${pkgver}/git-iris-linux-amd64") | |
| source_aarch64=("\${pkgname}-\${pkgver}-aarch64::https://github.com/hyperb1iss/git-iris/releases/download/v\${pkgver}/git-iris-linux-arm64") | |
| sha256sums_x86_64=('${SHA_X86_64}') | |
| sha256sums_aarch64=('${SHA_AARCH64}') | |
| package() { | |
| install -Dm755 "\${srcdir}/\${pkgname}-\${pkgver}-\${CARCH}" "\${pkgdir}/usr/bin/git-iris" | |
| } | |
| EOF | |
| - name: Publish to AUR | |
| uses: KSXGitHub/github-actions-deploy-aur@v4.1.2 | |
| with: | |
| pkgname: git-iris-bin | |
| pkgbuild: ./PKGBUILD | |
| commit_username: Stefanie Jane | |
| commit_email: stef@hyperbliss.tech | |
| ssh_private_key: ${{ secrets.AUR_SSH_KEY }} | |
| commit_message: "Update to ${{ github.ref_name }}" |