CI/CD #184
Workflow file for this run
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: | |
| workflow_dispatch: | |
| inputs: | |
| release_run_id: | |
| description: "Run ID of the release workflow (for artifact download)" | |
| required: false | |
| jobs: | |
| # ── CI ───────────────────────────────────────────────────────── | |
| ci: | |
| uses: hyperb1iss/shared-workflows/.github/workflows/rust-ci.yml@main | |
| with: | |
| change-detection: false | |
| system-deps: "libdbus-1-dev pkg-config lld" | |
| workspace: true | |
| all-features: false | |
| all-targets: false | |
| nextest: false | |
| cargo-deny: false | |
| nightly-fmt: true | |
| permissions: | |
| contents: read | |
| pull-requests: read | |
| secrets: inherit | |
| windows-smoke: | |
| name: Windows Smoke Build | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: x86_64-pc-windows-msvc | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-on-failure: true | |
| - name: Build workspace on Windows | |
| run: cargo build --workspace --locked --target x86_64-pc-windows-msvc | |
| maintainability: | |
| name: Maintainability Guardrails | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Check maintainability hotspots | |
| run: scripts/check-maintainability.sh | |
| # ── Build Artifacts ──────────────────────────────────────────── | |
| build-artifacts: | |
| name: Build (${{ matrix.build }}) | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: [ci, windows-smoke, maintainability] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - build: linux-amd64 | |
| os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| - build: linux-arm64 | |
| os: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-gnu | |
| - build: macos-arm64 | |
| os: macos-latest | |
| target: aarch64-apple-darwin | |
| - build: windows-amd64 | |
| os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install system dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update && sudo apt-get install -y libdbus-1-dev pkg-config lld | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| cache-on-failure: true | |
| - name: Build release binaries | |
| run: cargo build --workspace --release --locked --target ${{ matrix.target }} | |
| - name: Upload unifly artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: unifly-${{ matrix.build }} | |
| path: | | |
| ./target/${{ matrix.target }}/release/unifly${{ matrix.os == 'windows-latest' && '.exe' || '' }} | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # ── Publish to crates.io ────────────────────────────────────── | |
| publish: | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: build-artifacts | |
| uses: hyperb1iss/shared-workflows/.github/workflows/rust-publish.yml@main | |
| with: | |
| crates: "unifly-api unifly" | |
| system-deps: "libdbus-1-dev pkg-config lld" | |
| 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, 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 | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p release-assets | |
| for dir in ./artifacts/unifly-*/; do | |
| name=$(basename "$dir") | |
| for bin in "$dir"/*; do | |
| cp "$bin" "./release-assets/${name}$(echo "$bin" | grep -q '.exe$' && echo '.exe' || echo '')" | |
| done | |
| done | |
| ls -la ./release-assets | |
| - name: Get previous tag | |
| id: prev_tag | |
| run: | | |
| PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [[ -z "$PREVIOUS_TAG" ]]; then | |
| PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD) | |
| fi | |
| echo "tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT | |
| - 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' | |
| uses: hyperb1iss/git-iris@v2 | |
| 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-6 | |
| api-key: ${{ secrets.ANTHROPIC_API_KEY }} | |
| output-file: 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 | |
| # ── Publish Skill to ClawHub ───────────────────────────────── | |
| publish-skill: | |
| name: Publish Skill to ClawHub | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: "22" | |
| - name: Authenticate ClawHub CLI | |
| env: | |
| CLAWHUB_TOKEN: ${{ secrets.CLAWHUB_TOKEN }} | |
| run: npx -y clawhub@0.9.0 login --token "$CLAWHUB_TOKEN" --no-browser | |
| - name: Publish skill via sync | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| npx -y clawhub@0.9.0 sync --root ./skills --all --changelog "Release v${VERSION}" | |
| # ── Update AUR Package ───────────────────────────────────────── | |
| update-aur: | |
| name: Update AUR Package | |
| if: startsWith(github.ref, 'refs/tags/') | |
| needs: create-release | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Update pkgver | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| sed -i "s/^pkgver=.*/pkgver=${VERSION}/" aur/PKGBUILD | |
| - name: Publish to AUR | |
| uses: KSXGitHub/github-actions-deploy-aur@v4.1.2 | |
| with: | |
| pkgname: unifly-bin | |
| pkgbuild: aur/PKGBUILD | |
| updpkgsums: true | |
| commit_username: Stefanie Jane | |
| commit_email: stef@hyperbliss.tech | |
| commit_message: "Update to ${{ github.ref_name }}" | |
| ssh_private_key: ${{ secrets.AUR_SSH_KEY }} | |
| # ── Update Homebrew Tap ─────────────────────────────────────── | |
| update-homebrew: | |
| name: Update Homebrew Tap | |
| if: startsWith(github.ref, 'refs/tags/') | |
| 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 checksums | |
| id: sha | |
| run: | | |
| VERSION="${GITHUB_REF_NAME#v}" | |
| RELEASE_URL="https://github.com/hyperb1iss/unifly/releases/download/${GITHUB_REF_NAME}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "macos_arm64=$(curl -fsSL "${RELEASE_URL}/unifly-macos-arm64" | shasum -a 256 | cut -d' ' -f1)" >> $GITHUB_OUTPUT | |
| echo "linux_arm64=$(curl -fsSL "${RELEASE_URL}/unifly-linux-arm64" | shasum -a 256 | cut -d' ' -f1)" >> $GITHUB_OUTPUT | |
| echo "linux_amd64=$(curl -fsSL "${RELEASE_URL}/unifly-linux-amd64" | shasum -a 256 | cut -d' ' -f1)" >> $GITHUB_OUTPUT | |
| - name: Generate formula | |
| run: | | |
| cat > homebrew-tap/Formula/unifly.rb << 'FORMULA' | |
| class Unifly < Formula | |
| desc "CLI + TUI for managing UniFi network controllers" | |
| homepage "https://github.com/hyperb1iss/unifly" | |
| license "Apache-2.0" | |
| version "${{ steps.sha.outputs.version }}" | |
| on_macos do | |
| on_arm do | |
| url "https://github.com/hyperb1iss/unifly/releases/download/v#{version}/unifly-macos-arm64" | |
| sha256 "${{ steps.sha.outputs.macos_arm64 }}" | |
| end | |
| end | |
| on_linux do | |
| on_arm do | |
| url "https://github.com/hyperb1iss/unifly/releases/download/v#{version}/unifly-linux-arm64" | |
| sha256 "${{ steps.sha.outputs.linux_arm64 }}" | |
| end | |
| on_intel do | |
| url "https://github.com/hyperb1iss/unifly/releases/download/v#{version}/unifly-linux-amd64" | |
| sha256 "${{ steps.sha.outputs.linux_amd64 }}" | |
| end | |
| end | |
| def install | |
| bin.install Dir["unifly*"].first => "unifly" | |
| end | |
| test do | |
| assert_match "unifly #{version}", shell_output("#{bin}/unifly --version") | |
| end | |
| end | |
| FORMULA | |
| - 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/unifly.rb | |
| git commit -m "unifly ${{ steps.sha.outputs.version }}" | |
| git push |