diff --git a/.github/workflows/release-snap.yml b/.github/workflows/release-snap.yml index f1063057f..9624e2f31 100644 --- a/.github/workflows/release-snap.yml +++ b/.github/workflows/release-snap.yml @@ -24,6 +24,11 @@ on: default: edge type: choice options: [edge, beta, candidate, stable] + publish: + description: "Publish to the selected Snap Store channel" + required: false + default: false + type: boolean push: tags: - "v*" @@ -35,18 +40,64 @@ concurrency: cancel-in-progress: false jobs: + version: + runs-on: ubuntu-24.04 + outputs: + version: ${{ steps.release.outputs.version }} + steps: + - uses: actions/checkout@v7 + with: + ref: ${{ inputs.tag || github.ref }} + fetch-depth: 0 + + - name: Resolve and validate package version + id: release + run: | + set -euo pipefail + if [[ "$GITHUB_REF" == refs/tags/v* ]]; then + VERSION="${GITHUB_REF#refs/tags/v}" + elif [[ -n "${{ inputs.tag }}" ]]; then + VERSION="${{ inputs.tag }}" + VERSION="${VERSION#v}" + else + VERSION="$(grep -m1 '^version = ' crates/Cargo.toml | sed 's/version = "\(.*\)"/\1/')" + fi + if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([.-][0-9A-Za-z.-]+)?$ ]]; then + echo "::error::Invalid Snap version: $VERSION" + exit 1 + fi + CARGO_VERSION="$(grep -m1 '^version = ' crates/Cargo.toml | sed 's/version = "\(.*\)"/\1/')" + if [[ "$CARGO_VERSION" != "$VERSION" ]]; then + echo "::error::crates/Cargo.toml workspace version ($CARGO_VERSION) != requested version ($VERSION)." + exit 1 + fi + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Verify tag is on main + if: startsWith(github.ref, 'refs/tags/') + run: | + git fetch origin main + if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "::error::Tag ${GITHUB_REF#refs/tags/} is not on main. Releases are cut from main only." + exit 1 + fi + build-amd64: + needs: version uses: ./.github/workflows/build-qt-linux.yml with: arch: x86_64 + source_ref: ${{ inputs.tag || github.ref }} build-arm64: + needs: version uses: ./.github/workflows/build-qt-linux.yml with: arch: aarch64 + source_ref: ${{ inputs.tag || github.ref }} snap: - needs: build-amd64 + needs: [version, build-amd64] runs-on: ubuntu-24.04 # No compilation here; the headroom is for snapcraft's LXD bootstrap, # which is highly variable on hosted runners (a 30 min cap got the @@ -56,8 +107,11 @@ jobs: # unset secret SKIPS publish instead of failing the whole run. env: SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} + VERSION: ${{ needs.version.outputs.version }} steps: - uses: actions/checkout@v7 + with: + ref: ${{ inputs.tag || github.ref }} - name: Download AppDir uses: actions/download-artifact@v8 @@ -67,8 +121,7 @@ jobs: - name: Stage snap payload (AppDir tree + desktop + icon) and recipe run: | set -eux - TAG="${{ github.event.inputs.tag || github.ref_name }}" - VER="${TAG#v}" + VER="$VERSION" tar -xf appdir.tar mkdir -p snap-payload cp -a AppDir/usr/bin AppDir/usr/lib AppDir/usr/plugins AppDir/usr/qml snap-payload/ @@ -94,20 +147,23 @@ jobs: if-no-files-found: error - name: Publish to the Snap Store (skipped when no store credentials) - if: ${{ env.SNAPCRAFT_STORE_CREDENTIALS != '' }} + if: ${{ env.SNAPCRAFT_STORE_CREDENTIALS != '' && (startsWith(github.ref, 'refs/tags/') || inputs.publish) }} uses: snapcore/action-publish@v1 with: snap: ${{ steps.build.outputs.snap }} release: ${{ github.event.inputs.channel || 'edge' }} snap-arm64: - needs: build-arm64 + needs: [version, build-arm64] runs-on: ubuntu-24.04-arm timeout-minutes: 90 env: SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }} + VERSION: ${{ needs.version.outputs.version }} steps: - uses: actions/checkout@v7 + with: + ref: ${{ inputs.tag || github.ref }} - name: Download AppDir uses: actions/download-artifact@v8 @@ -117,8 +173,7 @@ jobs: - name: Stage snap payload (AppDir tree + desktop + icon) and recipe run: | set -eux - TAG="${{ github.event.inputs.tag || github.ref_name }}" - VER="${TAG#v}" + VER="$VERSION" tar -xf appdir.tar mkdir -p snap-payload cp -a AppDir/usr/bin AppDir/usr/lib AppDir/usr/plugins AppDir/usr/qml snap-payload/ @@ -143,7 +198,7 @@ jobs: if-no-files-found: error - name: Publish to the Snap Store (skipped when no store credentials) - if: ${{ env.SNAPCRAFT_STORE_CREDENTIALS != '' }} + if: ${{ env.SNAPCRAFT_STORE_CREDENTIALS != '' && (startsWith(github.ref, 'refs/tags/') || inputs.publish) }} uses: snapcore/action-publish@v1 with: snap: ${{ steps.build.outputs.snap }}