chore(release): bump version to 0.2.0 #8
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: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v[0-9]+.[0-9]+.[0-9]+' | |
| - 'v[0-9]+.[0-9]+.[0-9]+-*' | |
| # Each build job is independent so all three platforms compile in parallel. | |
| # The final job collects all artifacts and creates a draft GitHub Release. | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # macOS — .app bundle + .pkg installer. | |
| # | |
| # The job runs in three modes depending on which repository secrets are set: | |
| # | |
| # 1. No signing secrets: | |
| # Produces UNSIGNED .app + UNSIGNED .pkg (current baseline behavior). | |
| # | |
| # 2. Code-signing secrets set (APPLE_DEVELOPER_ID_APPLICATION, | |
| # APPLE_CERTIFICATES_P12_BASE64, APPLE_CERTIFICATES_P12_PASSWORD): | |
| # Signs the .app with Hardened Runtime + entitlements; signs the .pkg | |
| # if APPLE_DEVELOPER_ID_INSTALLER is also set. | |
| # | |
| # 3. Above PLUS notarization secrets set (APPLE_ID, | |
| # APPLE_APP_SPECIFIC_PASSWORD, APPLE_TEAM_ID): | |
| # Submits to Apple notary service, waits, and staples. | |
| # | |
| # Required repository secrets for full signed+notarized distribution: | |
| # | |
| # APPLE_DEVELOPER_ID_APPLICATION Certificate common name, e.g. | |
| # "Developer ID Application: NAME (TEAMID)" | |
| # APPLE_DEVELOPER_ID_INSTALLER Installer cert name, e.g. | |
| # "Developer ID Installer: NAME (TEAMID)" | |
| # APPLE_CERTIFICATES_P12_BASE64 Base64-encoded P12 containing both certs | |
| # and their private keys | |
| # APPLE_CERTIFICATES_P12_PASSWORD Password protecting the P12 | |
| # APPLE_ID Apple ID email for notarytool | |
| # APPLE_APP_SPECIFIC_PASSWORD App-specific password (appleid.apple.com) | |
| # APPLE_TEAM_ID 10-character Apple Developer Team ID | |
| # | |
| # See macos/PACKAGING.md for how-to-obtain instructions. | |
| # --------------------------------------------------------------------------- | |
| build-macos: | |
| name: Build macOS | |
| runs-on: macos-14 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Select Xcode | |
| uses: maxim-lobanov/setup-xcode@v1 | |
| with: | |
| xcode-version: latest-stable | |
| - name: Detect signing secrets | |
| id: signing | |
| env: | |
| P12_B64: ${{ secrets.APPLE_CERTIFICATES_P12_BASE64 }} | |
| run: | | |
| if [[ -n "${P12_B64:-}" ]]; then | |
| echo "have_certs=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "have_certs=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Import code-signing certificates | |
| if: steps.signing.outputs.have_certs == 'true' | |
| uses: apple-actions/import-codesign-certs@v3 | |
| with: | |
| p12-file-base64: ${{ secrets.APPLE_CERTIFICATES_P12_BASE64 }} | |
| p12-password: ${{ secrets.APPLE_CERTIFICATES_P12_PASSWORD }} | |
| - name: Build .app bundle (sign + notarize when secrets present) | |
| env: | |
| APPLE_DEVELOPER_ID_APPLICATION: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| run: bash macos/scripts/build-app.sh | |
| - name: Build .pkg installer (signed when installer cert present) | |
| env: | |
| APPLE_DEVELOPER_ID_INSTALLER: ${{ secrets.APPLE_DEVELOPER_ID_INSTALLER }} | |
| run: bash macos/scripts/build-pkg.sh | |
| - name: Zip .app bundle | |
| run: | | |
| cd macos/build | |
| zip -r --symlinks "InterlinedSync-macOS-${{ github.ref_name }}.zip" InterlinedSync.app | |
| - name: Rename .pkg for release | |
| run: | | |
| cd macos/build | |
| PKG_SRC="$(ls InterlinedSync-*.pkg | grep -v "macOS-${{ github.ref_name }}" | head -n 1 || true)" | |
| if [[ -n "${PKG_SRC}" ]]; then | |
| mv "${PKG_SRC}" "InterlinedSync-macOS-${{ github.ref_name }}.pkg" | |
| fi | |
| - name: Upload macOS artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: macos-release | |
| path: | | |
| macos/build/InterlinedSync-macOS-${{ github.ref_name }}.zip | |
| macos/build/InterlinedSync-macOS-${{ github.ref_name }}.pkg | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # --------------------------------------------------------------------------- | |
| # Windows — framework-dependent publish (requires .NET 9 Desktop Runtime) | |
| # PLUS an Inno Setup installer (InterlinedListSync-Setup-<tag>.exe). Both | |
| # are uploaded; the installer is the recommended distribution channel and | |
| # the .zip remains for users who prefer xcopy deploy. The installer is | |
| # signed when WINDOWS_CERT_PFX_BASE64 + WINDOWS_CERT_PASSWORD secrets | |
| # exist; otherwise it ships UNSIGNED (SmartScreen will warn on first | |
| # install). See windows/PACKAGING.md for the full signing checklist. | |
| # MSIX is deferred — see comment further down. | |
| # --------------------------------------------------------------------------- | |
| build-windows: | |
| name: Build Windows | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup .NET 9 | |
| uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: '9.0.x' | |
| - name: Setup MSBuild | |
| uses: microsoft/setup-msbuild@v2 | |
| - name: Restore packages | |
| working-directory: windows | |
| run: dotnet restore | |
| - name: Publish | |
| working-directory: windows | |
| run: > | |
| dotnet publish InterlinedSync/InterlinedSync.csproj | |
| --configuration Release | |
| --no-restore | |
| --runtime win-x64 | |
| --self-contained false | |
| --output publish | |
| - name: Zip publish output | |
| shell: pwsh | |
| run: | | |
| Compress-Archive ` | |
| -Path windows/publish/* ` | |
| -DestinationPath "InterlinedSync-Windows-${{ github.ref_name }}.zip" | |
| - name: Install Inno Setup | |
| shell: pwsh | |
| run: choco install innosetup -y --no-progress | |
| - name: Compute installer version | |
| id: insver | |
| shell: pwsh | |
| run: | | |
| # Strip a leading 'v' to match Inno's VersionInfoVersion expectations | |
| # (Inno tolerates the suffix but the leading 'v' confuses some | |
| # Windows VersionInfo consumers). | |
| $tag = "${{ github.ref_name }}" | |
| $ver = $tag -replace '^v','' | |
| "version=$ver" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| - name: Detect Windows signing secrets | |
| id: winsign | |
| shell: pwsh | |
| env: | |
| PFX_B64: ${{ secrets.WINDOWS_CERT_PFX_BASE64 }} | |
| run: | | |
| if ($env:PFX_B64) { | |
| "have_cert=true" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| } else { | |
| "have_cert=false" | Out-File -FilePath $env:GITHUB_OUTPUT -Append | |
| } | |
| - name: Decode signing certificate | |
| if: steps.winsign.outputs.have_cert == 'true' | |
| shell: pwsh | |
| env: | |
| PFX_B64: ${{ secrets.WINDOWS_CERT_PFX_BASE64 }} | |
| run: | | |
| $bytes = [Convert]::FromBase64String($env:PFX_B64) | |
| [IO.File]::WriteAllBytes("$env:RUNNER_TEMP\codesign.pfx", $bytes) | |
| - name: Compile Inno Setup installer (unsigned) | |
| if: steps.winsign.outputs.have_cert != 'true' | |
| shell: pwsh | |
| run: | | |
| & "C:\Program Files (x86)\Inno Setup 6\iscc.exe" ` | |
| /Qp ` | |
| /DAppVersion=${{ steps.insver.outputs.version }} ` | |
| windows/installer/InterlinedSync.iss | |
| - name: Compile Inno Setup installer (signed) | |
| if: steps.winsign.outputs.have_cert == 'true' | |
| shell: pwsh | |
| env: | |
| PFX_PASSWORD: ${{ secrets.WINDOWS_CERT_PASSWORD }} | |
| run: | | |
| # Locate signtool (newest Windows SDK build). | |
| $signtool = Get-ChildItem ` | |
| -Path "C:\Program Files (x86)\Windows Kits\10\bin" ` | |
| -Recurse -Filter signtool.exe ` | |
| | Where-Object { $_.FullName -like "*\x64\signtool.exe" } ` | |
| | Sort-Object FullName -Descending ` | |
| | Select-Object -First 1 | |
| if (-not $signtool) { | |
| throw "signtool.exe not found on runner." | |
| } | |
| $pfx = "$env:RUNNER_TEMP\codesign.pfx" | |
| # Inno invokes the named SignTool template once per file ($f). | |
| $signCmd = "`"$($signtool.FullName)`" sign /fd sha256 /tr http://timestamp.digicert.com /td sha256 /f `"$pfx`" /p `"$env:PFX_PASSWORD`" `$f" | |
| & "C:\Program Files (x86)\Inno Setup 6\iscc.exe" ` | |
| /Qp ` | |
| /DAppVersion=${{ steps.insver.outputs.version }} ` | |
| /DSignToolConfigured=1 ` | |
| "/Ssigntool=$signCmd" ` | |
| windows/installer/InterlinedSync.iss | |
| - name: Stage installer for upload | |
| shell: pwsh | |
| run: | | |
| # The .iss outputs to windows/installer/Output/. Copy to a flat | |
| # location so the upload-artifact glob below picks it up reliably. | |
| Copy-Item ` | |
| -Path "windows/installer/Output/InterlinedListSync-Setup-${{ steps.insver.outputs.version }}.exe" ` | |
| -Destination "InterlinedListSync-Setup-${{ github.ref_name }}.exe" | |
| # ------------------------------------------------------------------- | |
| # MSIX packaging deferred from CI: the windows-latest runner's | |
| # Windows SDK does not include UAP.props for our target version | |
| # (APPX3217 across multiple version values). Build MSIX on a | |
| # maintainer machine via Visual Studio for now; revisit once we | |
| # standardize on a runner with the right SDK pre-installed. | |
| # See windows/PACKAGING.md. | |
| # ------------------------------------------------------------------- | |
| - name: Upload Windows artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: windows-release | |
| path: | | |
| InterlinedSync-Windows-${{ github.ref_name }}.zip | |
| InterlinedListSync-Setup-${{ github.ref_name }}.exe | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # --------------------------------------------------------------------------- | |
| # Linux — .deb package (via cargo-deb) + standalone binary tarball + .snap | |
| # Snap build uses snapcraft with --destructive-mode (no LXD in GitHub runners). | |
| # Publishing to the Snap Store is a separate manual step — see PACKAGING.md. | |
| # --------------------------------------------------------------------------- | |
| build-linux: | |
| name: Build Linux | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y \ | |
| pkg-config \ | |
| libdbus-1-dev \ | |
| libsqlite3-dev \ | |
| libsecret-1-dev | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache Rust dependencies | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: linux-ubuntu | |
| - name: Build release binary | |
| working-directory: linux-ubuntu | |
| run: cargo build --release | |
| - name: Install cargo-deb | |
| run: cargo install cargo-deb --version "2.4.0" | |
| - name: Build .deb package | |
| working-directory: linux-ubuntu | |
| run: cargo deb -p interlinedlist-sync --no-build | |
| - name: Create binary tarball | |
| run: | | |
| tar -czf "linux-ubuntu/InterlinedSync-Linux-${{ github.ref_name }}.tar.gz" \ | |
| -C linux-ubuntu/target/release interlinedlist-sync | |
| # ------------------------------------------------------------------- | |
| # Snap packaging — M7 | |
| # Deferred from CI for now: snap-in-snap install of core22 fails | |
| # inside GitHub-hosted runners (snapd restrictions in destructive | |
| # mode). Reach parity by building the snap on a maintainer machine | |
| # or via snapcraft remote-build, then uploading manually. See | |
| # linux-ubuntu/PACKAGING.md and snap/snapcraft.yaml. | |
| # ------------------------------------------------------------------- | |
| - name: Upload Linux artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: linux-release | |
| path: | | |
| linux-ubuntu/target/debian/*.deb | |
| linux-ubuntu/InterlinedSync-Linux-${{ github.ref_name }}.tar.gz | |
| linux-ubuntu/*.snap | |
| if-no-files-found: error | |
| retention-days: 1 | |
| # --------------------------------------------------------------------------- | |
| # Create a draft GitHub Release and attach all platform artifacts. | |
| # Publish the release manually from the GitHub UI after reviewing the files. | |
| # --------------------------------------------------------------------------- | |
| create-release: | |
| name: Create GitHub Release | |
| needs: [build-macos, build-windows, build-linux] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all release artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: release-artifacts | |
| merge-multiple: true | |
| - name: List artifacts | |
| run: ls -lh release-artifacts/ | |
| - name: Write release notes | |
| run: | | |
| TAG="${{ github.ref_name }}" | |
| cat > release-notes.md << EOF | |
| ## InterlinedList Sync ${TAG} | |
| ### Downloads | |
| | Platform | File | Notes | | |
| |----------|------|-------| | |
| | macOS 13 Ventura or later | \`InterlinedSync-macOS-${TAG}.zip\` | Unzip and move to \`/Applications\`. Unsigned — right-click → Open to bypass Gatekeeper on first launch. | | |
| | Windows 10 / 11 (x64) — installer | \`InterlinedListSync-Setup-${TAG}.exe\` | Double-click and follow the wizard. Adds a Start Menu entry and optional autostart. Requires [.NET 9 Desktop Runtime](https://dotnet.microsoft.com/download/dotnet/9.0). | | |
| | Windows 10 / 11 (x64) — portable | \`InterlinedSync-Windows-${TAG}.zip\` | Unzip and run \`InterlinedSync.exe\` for users who prefer no installer. Same runtime prerequisite. | | |
| | Ubuntu / Debian (amd64) | \`interlinedlist-sync_*.deb\` | \`sudo dpkg -i interlinedlist-sync_*.deb\` | | |
| | Linux standalone binary | \`InterlinedSync-Linux-${TAG}.tar.gz\` | Extract and place \`interlinedlist-sync\` in your \`\$PATH\`. | | |
| ### First-time setup | |
| 1. Edit \`~/.config/interlinedlist-sync/config.toml\` — set \`sync.watched_dirs\` and \`network.api_base_url\`. | |
| 2. Store credentials once: \`interlinedlist-sync --login --username you@example.com --password …\` | |
| 3. Start the daemon: \`interlinedlist-sync --daemon\` (Linux: managed by the installed systemd user unit) | |
| ### What changed | |
| See the commit history for details. | |
| EOF | |
| - name: Create draft GitHub Release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| PRERELEASE_FLAG="" | |
| if [[ "${{ github.ref_name }}" == *-* ]]; then | |
| PRERELEASE_FLAG="--prerelease" | |
| fi | |
| # Use find -type f to enumerate only files; the upload-artifact | |
| # action preserves the source directory structure inside each | |
| # artifact zip (e.g. target/debian/*.deb -> release-artifacts/target/), | |
| # and gh release create refuses to upload directories. | |
| gh release create "${{ github.ref_name }}" \ | |
| --title "InterlinedList Sync ${{ github.ref_name }}" \ | |
| --notes-file release-notes.md \ | |
| --draft \ | |
| $PRERELEASE_FLAG \ | |
| $(find release-artifacts -type f) |