release: 0.5.12 #47
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: Cross-Platform Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| jobs: | |
| build: | |
| name: Build for ${{ matrix.target }} | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Linux x86_64 (glibc) | |
| - target: x86_64-unknown-linux-gnu | |
| runner: ubuntu-latest | |
| use_cross: false | |
| # Linux x86_64 (musl - for Alpine/static linking) | |
| - target: x86_64-unknown-linux-musl | |
| runner: ubuntu-latest | |
| use_cross: true | |
| # Linux ARM64 (glibc) | |
| - target: aarch64-unknown-linux-gnu | |
| runner: ubuntu-latest | |
| use_cross: true | |
| # Linux ARM64 (musl - for Alpine/static linking) | |
| - target: aarch64-unknown-linux-musl | |
| runner: ubuntu-latest | |
| use_cross: true | |
| # macOS x86_64 | |
| - target: x86_64-apple-darwin | |
| runner: macos-latest | |
| use_cross: false | |
| # macOS ARM64 (Apple Silicon) | |
| - target: aarch64-apple-darwin | |
| runner: macos-latest | |
| use_cross: false | |
| # Windows x86_64 | |
| - target: x86_64-pc-windows-msvc | |
| runner: windows-latest | |
| use_cross: false | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} | |
| shared-key: ${{ matrix.target }} | |
| # Install cross for Linux ARM builds | |
| # Using cargo install from git since there are no recent releases | |
| # (last release v0.2.5 was in Feb 2023, but development is active) | |
| - name: Install cross | |
| if: matrix.use_cross | |
| run: cargo install cross --git https://github.com/cross-rs/cross --rev 8633ec65ab914015c2444c732568b414bd3c47cf | |
| # For Linux ARM, we need proper configuration | |
| - name: Create .cargo/config.toml for Linux ARM | |
| if: matrix.target == 'aarch64-unknown-linux-gnu' | |
| shell: bash | |
| run: | | |
| mkdir -p .cargo | |
| cat > .cargo/config.toml << 'EOF' | |
| [target.aarch64-unknown-linux-gnu] | |
| linker = "aarch64-linux-gnu-gcc" | |
| ar = "aarch64-linux-gnu-ar" | |
| EOF | |
| - name: Build | |
| run: | | |
| if [ "${{ matrix.use_cross }}" = "true" ]; then | |
| cross build --release --target ${{ matrix.target }} | |
| else | |
| cargo build --release --target ${{ matrix.target }} | |
| fi | |
| shell: bash | |
| # Create artifact name based on target | |
| - name: Determine artifact name | |
| id: artifact | |
| run: | | |
| if [ "${{ runner.os }}" = "Windows" ]; then | |
| echo "bin=treemd.exe" >> $GITHUB_OUTPUT | |
| else | |
| echo "bin=treemd" >> $GITHUB_OUTPUT | |
| fi | |
| shell: bash | |
| # macOS Code Signing (optional - requires secrets to be configured) | |
| - name: Import Apple Code Signing Certificate | |
| if: runner.os == 'macOS' | |
| continue-on-error: true | |
| uses: Apple-Actions/import-codesign-certs@v3 | |
| with: | |
| p12-file-base64: ${{ secrets.APPLE_CERTIFICATE_BASE64 }} | |
| p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| - name: Code sign and notarize macOS binary | |
| if: runner.os == 'macOS' | |
| run: | | |
| CERT_IMPORTED=false | |
| # Check if certificate was imported (if secrets exist, cert should be imported) | |
| if security find-identity -v -p codesigning | grep -q "Developer ID Application"; then | |
| CERT_IMPORTED=true | |
| fi | |
| if [ "$CERT_IMPORTED" = "true" ]; then | |
| echo "Signing with Developer ID..." | |
| codesign --deep --force --verify --verbose \ | |
| --timestamp --options runtime \ | |
| --sign "${{ secrets.APPLE_DEVELOPER_ID }}" \ | |
| target/${{ matrix.target }}/release/treemd | |
| codesign -v target/${{ matrix.target }}/release/treemd | |
| echo "Notarizing with Apple..." | |
| ditto -c -k --sequesterRsrc target/${{ matrix.target }}/release/treemd treemd-notarize.zip | |
| xcrun notarytool submit treemd-notarize.zip \ | |
| --apple-id "${{ secrets.APPLE_ID }}" \ | |
| --password "${{ secrets.APPLE_ID_PASSWORD }}" \ | |
| --team-id "${{ secrets.APPLE_TEAM_ID }}" \ | |
| --wait \ | |
| --timeout 30m | |
| echo "Note: Stapling is not applicable to bare CLI binaries" | |
| echo "Binary is notarized server-side - users will be verified online" | |
| echo "Verifying notarization status..." | |
| spctl -a -v target/${{ matrix.target }}/release/treemd || true | |
| echo "✓ Binary signed and notarized" | |
| else | |
| echo "Developer ID certificate not configured. Using ad-hoc signing..." | |
| codesign --remove-signature target/${{ matrix.target }}/release/treemd || true | |
| codesign -s - target/${{ matrix.target }}/release/treemd | |
| codesign -v target/${{ matrix.target }}/release/treemd | |
| echo "⚠ Binary ad-hoc signed (users may see Gatekeeper warning)" | |
| fi | |
| - name: Prepare artifacts (Windows) | |
| if: runner.os == 'Windows' | |
| run: | | |
| # Create artifacts directory | |
| New-Item -ItemType Directory -Force -Path artifacts | Out-Null | |
| $binary = "treemd-${{ matrix.target }}.exe" | |
| Copy-Item "target/${{ matrix.target }}/release/treemd.exe" $binary | |
| # Create zip for Windows (tar.gz not common on Windows) | |
| Compress-Archive -Path $binary -DestinationPath "artifacts/$binary.zip" | |
| # Generate SHA256 | |
| $hash = (Get-FileHash $binary -Algorithm SHA256).Hash.ToLower() | |
| "$hash $binary" | Out-File -FilePath "artifacts/$binary.sha256" -Encoding ascii -NoNewline | |
| Write-Host "Binary info:" | |
| Get-Item $binary | Format-List Length, LastWriteTime | |
| Get-Content "artifacts/$binary.sha256" | |
| shell: pwsh | |
| - name: Prepare artifacts (Unix) | |
| if: runner.os != 'Windows' | |
| run: | | |
| mkdir -p artifacts | |
| BINARY="treemd-${{ matrix.target }}" | |
| cp "target/${{ matrix.target }}/release/treemd" "$BINARY" | |
| chmod +x "$BINARY" | |
| # Create tar to preserve permissions and prevent corruption | |
| tar -czf "artifacts/$BINARY.tar.gz" "$BINARY" | |
| sha256sum "$BINARY" > "artifacts/$BINARY.sha256" | |
| ls -lh "$BINARY" | |
| cat "artifacts/$BINARY.sha256" | |
| shell: bash | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.target }} | |
| path: artifacts/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| needs: build | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: release-artifacts | |
| - name: Prepare release assets | |
| run: | | |
| mkdir -p final-release | |
| # Copy archives directly (tar.gz and zip preserve permissions internally) | |
| find release-artifacts -name "*.tar.gz" -type f -exec cp {} final-release/ \; | |
| find release-artifacts -name "*.zip" -type f -exec cp {} final-release/ \; | |
| # Copy individual SHA256 files | |
| find release-artifacts -name "*.sha256" -type f -exec cp {} final-release/ \; | |
| echo "Final release contents:" | |
| ls -lah final-release/ | |
| echo "Verifying archive integrity:" | |
| cd final-release | |
| for archive in *.tar.gz; do | |
| [ -f "$archive" ] || continue | |
| echo "Testing $archive:" | |
| tar -tzf "$archive" | head -5 | |
| done | |
| for archive in *.zip; do | |
| [ -f "$archive" ] || continue | |
| echo "Testing $archive:" | |
| unzip -l "$archive" | |
| done | |
| shell: bash | |
| - name: Generate combined checksums | |
| run: | | |
| cd final-release | |
| # Generate SHA256SUMS for archives (not individual binaries) | |
| sha256sum *.tar.gz *.zip 2>/dev/null | grep -v "No such file" > SHA256SUMS || true | |
| cat SHA256SUMS | |
| shell: bash | |
| - name: Create Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| final-release/*.tar.gz | |
| final-release/*.zip | |
| final-release/*.sha256 | |
| final-release/SHA256SUMS | |
| generate_release_notes: true | |
| draft: false | |
| prerelease: false | |
| fail_on_unmatched_files: true |