Release #1
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: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| - 'cli-v*' | |
| - 'gui-v*' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., 0.1.0)' | |
| required: true | |
| release_type: | |
| description: 'Release type' | |
| required: true | |
| type: choice | |
| options: | |
| - both | |
| - cli | |
| - gui | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| BINARY_NAME: Cortex | |
| # Nightly multithreaded frontend for faster compilation | |
| RUSTFLAGS: "-Zthreads=16" | |
| # Sparse registry for faster index updates | |
| CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse | |
| # Incremental compilation off for release builds | |
| CARGO_INCREMENTAL: 0 | |
| permissions: | |
| contents: write | |
| # Ensure only one release at a time | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| jobs: | |
| # ========================================================================== | |
| # Prepare - Determine version and what to build | |
| # ========================================================================== | |
| prepare: | |
| name: Prepare Release | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| tag: ${{ steps.version.outputs.tag }} | |
| build_cli: ${{ steps.version.outputs.build_cli }} | |
| build_gui: ${{ steps.version.outputs.build_gui }} | |
| cache_key: ${{ steps.cache.outputs.key }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Generate cache key | |
| id: cache | |
| run: | | |
| echo "key=rust-release-${{ hashFiles('**/Cargo.lock', '**/Cargo.toml') }}" >> $GITHUB_OUTPUT | |
| - name: Determine version and build targets | |
| id: version | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| VERSION="${{ inputs.version }}" | |
| if [ "${{ inputs.release_type }}" = "cli" ]; then | |
| TAG="cli-v${VERSION}" | |
| echo "build_cli=true" >> $GITHUB_OUTPUT | |
| echo "build_gui=false" >> $GITHUB_OUTPUT | |
| elif [ "${{ inputs.release_type }}" = "gui" ]; then | |
| TAG="gui-v${VERSION}" | |
| echo "build_cli=false" >> $GITHUB_OUTPUT | |
| echo "build_gui=true" >> $GITHUB_OUTPUT | |
| else | |
| TAG="v${VERSION}" | |
| echo "build_cli=true" >> $GITHUB_OUTPUT | |
| echo "build_gui=true" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| TAG="${GITHUB_REF#refs/tags/}" | |
| if [[ "$TAG" == cli-v* ]]; then | |
| VERSION="${TAG#cli-v}" | |
| echo "build_cli=true" >> $GITHUB_OUTPUT | |
| echo "build_gui=false" >> $GITHUB_OUTPUT | |
| elif [[ "$TAG" == gui-v* ]]; then | |
| VERSION="${TAG#gui-v}" | |
| echo "build_cli=false" >> $GITHUB_OUTPUT | |
| echo "build_gui=true" >> $GITHUB_OUTPUT | |
| else | |
| VERSION="${TAG#v}" | |
| echo "build_cli=true" >> $GITHUB_OUTPUT | |
| echo "build_gui=true" >> $GITHUB_OUTPUT | |
| fi | |
| fi | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "tag=$TAG" >> $GITHUB_OUTPUT | |
| - name: Verify CLI version consistency | |
| if: steps.version.outputs.build_cli == 'true' | |
| run: | | |
| CLI_RELEASE_VERSION="${{ steps.version.outputs.version }}" ./scripts/check-cli-version.sh | |
| # ========================================================================== | |
| # Build CLI Binaries | |
| # ========================================================================== | |
| build-cli: | |
| name: CLI ${{ matrix.artifact }} | |
| runs-on: ${{ matrix.os }} | |
| needs: prepare | |
| if: needs.prepare.outputs.build_cli == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| artifact: cortex-cli-windows-x64 | |
| ext: .exe | |
| - os: windows-latest | |
| target: aarch64-pc-windows-msvc | |
| artifact: cortex-cli-windows-arm64 | |
| ext: .exe | |
| - os: macos-latest | |
| target: x86_64-apple-darwin | |
| artifact: cortex-cli-macos-x64 | |
| ext: "" | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact: cortex-cli-macos-arm64 | |
| ext: "" | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| artifact: cortex-cli-linux-x64 | |
| ext: "" | |
| - os: ubuntu-latest | |
| target: aarch64-unknown-linux-gnu | |
| artifact: cortex-cli-linux-arm64 | |
| ext: "" | |
| cross: true | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust nightly | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install cross-compilation tools (Linux ARM64) | |
| if: matrix.cross == true | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y gcc-aarch64-linux-gnu g++-aarch64-linux-gnu | |
| mkdir -p ~/.cargo | |
| echo '[target.aarch64-unknown-linux-gnu]' >> ~/.cargo/config.toml | |
| echo 'linker = "aarch64-linux-gnu-gcc"' >> ~/.cargo/config.toml | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| prefix-key: "rust-release-cli-${{ matrix.target }}" | |
| shared-key: ${{ needs.prepare.outputs.cache_key }} | |
| - name: Build release binary | |
| run: cargo +nightly build --release --target ${{ matrix.target }} -p cortex-cli | |
| env: | |
| RUSTFLAGS: "-Zthreads=16" | |
| CARGO_PROFILE_RELEASE_LTO: thin | |
| - name: Prepare artifact (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| mkdir -p dist | |
| cp target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}${{ matrix.ext }} dist/ | |
| cd dist | |
| tar -czvf ../${{ matrix.artifact }}.tar.gz * | |
| - name: Prepare artifact (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force -Path dist | |
| Copy-Item "target/${{ matrix.target }}/release/${{ env.BINARY_NAME }}${{ matrix.ext }}" dist/ | |
| Compress-Archive -Path dist/* -DestinationPath "${{ matrix.artifact }}.zip" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: | | |
| ${{ matrix.artifact }}.tar.gz | |
| ${{ matrix.artifact }}.zip | |
| if-no-files-found: ignore | |
| # ========================================================================== | |
| # Build GUI Binaries (Tauri) | |
| # ========================================================================== | |
| build-gui: | |
| name: GUI ${{ matrix.artifact }} | |
| runs-on: ${{ matrix.runner }} | |
| needs: prepare | |
| if: needs.prepare.outputs.build_gui == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - name: Windows x64 | |
| runner: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| artifact: cortex-gui-windows-x64 | |
| bundle: msi | |
| - name: macOS x64 | |
| runner: macos-13 | |
| target: x86_64-apple-darwin | |
| artifact: cortex-gui-macos-x64 | |
| bundle: dmg | |
| - name: macOS ARM64 | |
| runner: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact: cortex-gui-macos-arm64 | |
| bundle: dmg | |
| - name: Linux x64 | |
| runner: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| artifact: cortex-gui-linux-x64 | |
| bundle: appimage | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "pnpm" | |
| cache-dependency-path: cortex-gui/pnpm-lock.yaml | |
| - name: Install Rust nightly | |
| uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install system dependencies (Linux) | |
| if: runner.os == 'Linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| libwebkit2gtk-4.1-dev \ | |
| librsvg2-dev \ | |
| patchelf \ | |
| libssl-dev \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| prefix-key: "rust-release-gui-${{ matrix.target }}" | |
| shared-key: ${{ needs.prepare.outputs.cache_key }} | |
| workspaces: | | |
| . | |
| cortex-gui/src-tauri | |
| - name: Cache pnpm | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| cortex-gui/node_modules | |
| ~/.local/share/pnpm/store | |
| key: pnpm-${{ matrix.runner }}-${{ hashFiles('cortex-gui/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| pnpm-${{ matrix.runner }}- | |
| - name: Install frontend dependencies | |
| working-directory: cortex-gui | |
| run: pnpm install --frozen-lockfile | |
| - name: Build Tauri app | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} | |
| TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }} | |
| RUSTFLAGS: "-Zthreads=16" | |
| with: | |
| projectPath: cortex-gui | |
| tauriScript: pnpm tauri | |
| args: --target ${{ matrix.target }} --bundles ${{ matrix.bundle }} | |
| - name: Collect artifacts (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| mkdir -p collected | |
| BUNDLE_DIR="target/${{ matrix.target }}/release/bundle" | |
| if [ ! -d "$BUNDLE_DIR" ]; then | |
| BUNDLE_DIR="cortex-gui/src-tauri/target/${{ matrix.target }}/release/bundle" | |
| fi | |
| if [ "${{ matrix.bundle }}" = "dmg" ]; then | |
| find "$BUNDLE_DIR" -name "*.dmg" -exec cp {} collected/ \; | |
| elif [ "${{ matrix.bundle }}" = "appimage" ]; then | |
| find "$BUNDLE_DIR" -name "*.AppImage" -exec cp {} collected/ \; | |
| fi | |
| ls -la collected/ | |
| - name: Collect artifacts (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force -Path collected | |
| $bundleDir = "target/${{ matrix.target }}/release/bundle" | |
| if (-not (Test-Path $bundleDir)) { | |
| $bundleDir = "cortex-gui/src-tauri/target/${{ matrix.target }}/release/bundle" | |
| } | |
| Get-ChildItem -Path $bundleDir -Recurse -Include *.msi | Copy-Item -Destination collected/ | |
| Get-ChildItem collected/ | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: collected/* | |
| if-no-files-found: warn | |
| # ========================================================================== | |
| # Create GitHub Release | |
| # ========================================================================== | |
| release: | |
| name: Create Release | |
| needs: [prepare, build-cli, build-gui] | |
| if: always() && needs.prepare.result == 'success' && (needs.build-cli.result == 'success' || needs.build-cli.result == 'skipped') && (needs.build-gui.result == 'success' || needs.build-gui.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Create tag (workflow_dispatch only) | |
| if: github.event_name == 'workflow_dispatch' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git tag ${{ needs.prepare.outputs.tag }} || true | |
| git push origin ${{ needs.prepare.outputs.tag }} || true | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Flatten and generate checksums | |
| run: | | |
| cd artifacts | |
| find . -type f \( -name "*.tar.gz" -o -name "*.zip" -o -name "*.dmg" -o -name "*.msi" -o -name "*.AppImage" \) -exec mv {} . \; | |
| rm -rf cortex-*/ || true | |
| sha256sum * > checksums-sha256.txt 2>/dev/null || true | |
| echo "=== Release artifacts ===" | |
| ls -la | |
| echo "=== Checksums ===" | |
| cat checksums-sha256.txt | |
| - name: Determine release name | |
| id: release_name | |
| run: | | |
| TAG="${{ needs.prepare.outputs.tag }}" | |
| VERSION="${{ needs.prepare.outputs.version }}" | |
| if [[ "$TAG" == cli-v* ]]; then | |
| echo "name=Cortex CLI v${VERSION}" >> $GITHUB_OUTPUT | |
| elif [[ "$TAG" == gui-v* ]]; then | |
| echo "name=Cortex GUI v${VERSION}" >> $GITHUB_OUTPUT | |
| else | |
| echo "name=Cortex v${VERSION}" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ needs.prepare.outputs.tag }} | |
| name: ${{ steps.release_name.outputs.name }} | |
| draft: false | |
| prerelease: ${{ contains(needs.prepare.outputs.version, '-') }} | |
| generate_release_notes: true | |
| files: | | |
| artifacts/* | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |