diff --git a/.github/workflows/linux-packages.yml b/.github/workflows/linux-packages.yml index 8318331a..907c3a83 100644 --- a/.github/workflows/linux-packages.yml +++ b/.github/workflows/linux-packages.yml @@ -1,5 +1,9 @@ # Builds the Linux .deb once, repackages it as a Flatpak and as a Snap, and # starts each package headless to check that it runs inside its sandbox. +# +# The release workflows call it with `release-tag`: it then repackages the +# amd64 .deb already attached to that release instead of building one, and +# uploads the Flatpak and the Snap that passed their tests to the release. name: Linux Packages @@ -22,6 +26,12 @@ on: - "src-tauri/tauri.conf.json" - "src-tauri/Cargo.toml" - "src-tauri/donutbrowser.desktop" + workflow_call: + inputs: + release-tag: + description: "Release whose amd64 .deb is repackaged; the packages are uploaded to it" + type: string + required: true workflow_dispatch: inputs: check-wayfern: @@ -33,7 +43,7 @@ permissions: contents: read concurrency: - group: linux-packages-${{ github.event.pull_request.number || github.ref }} + group: linux-packages-${{ inputs.release-tag || github.event.pull_request.number || github.ref }} cancel-in-progress: true env: @@ -45,6 +55,7 @@ env: jobs: deb: name: Build .deb + if: ${{ !inputs.release-tag }} runs-on: ubuntu-22.04 timeout-minutes: 90 steps: @@ -106,9 +117,34 @@ jobs: if-no-files-found: error retention-days: 7 + deb-from-release: + name: Take the .deb from the release + if: ${{ inputs.release-tag }} + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Download the amd64 .deb + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ inputs.release-tag }} + run: | + mkdir -p linux-deb + gh release download "$TAG" --repo "$GITHUB_REPOSITORY" --pattern 'Donut_*_amd64.deb' --dir linux-deb + ls -l linux-deb + test "$(find linux-deb -name '*.deb' | wc -l)" -eq 1 + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a #v7.0.1 + with: + name: donut-deb + path: linux-deb/*.deb + if-no-files-found: error + retention-days: 7 + flatpak: name: Build Flatpak - needs: deb + needs: [deb, deb-from-release] + # Exactly one of the two .deb jobs runs; the other is skipped. + if: ${{ !cancelled() && (needs.deb.result == 'success' || needs.deb-from-release.result == 'success') }} runs-on: ubuntu-24.04 timeout-minutes: 45 container: @@ -240,7 +276,8 @@ jobs: snap: name: Build and test Snap - needs: deb + needs: [deb, deb-from-release] + if: ${{ !cancelled() && (needs.deb.result == 'success' || needs.deb-from-release.result == 'success') }} runs-on: ubuntu-24.04 timeout-minutes: 60 steps: @@ -339,3 +376,54 @@ jobs: path: smoke if-no-files-found: ignore retention-days: 14 + + publish: + name: Attach the packages to the release + needs: [flatpak-smoke, snap] + # Each package goes up only when its own test passed, so a Snap failure + # does not hold back a working Flatpak. + if: ${{ !cancelled() && inputs.release-tag && (needs.flatpak-smoke.result == 'success' || needs.snap.result == 'success') }} + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: write + steps: + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1 + with: + name: donut-deb + path: linux-deb + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1 + if: ${{ needs.flatpak-smoke.result == 'success' }} + with: + name: donut-flatpak-x86_64 + path: flatpak-bundle + + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c #v8.0.1 + if: ${{ needs.snap.result == 'success' }} + with: + name: donut-snap-amd64 + path: snap-package + + # Named like the other assets (Donut__.), so the + # nightly job renames them the same way it renames the rest. + - name: Upload to the release + env: + GH_TOKEN: ${{ github.token }} + TAG: ${{ inputs.release-tag }} + run: | + deb="$(find linux-deb -name 'Donut_*_amd64.deb' | head -n 1)" + version="$(basename "$deb" | sed -E 's/^Donut_(.+)_amd64\.deb$/\1/')" + test -n "$version" + files=() + if [ -f flatpak-bundle/Donut.flatpak ]; then + cp flatpak-bundle/Donut.flatpak "Donut_${version}_x86_64.flatpak" + files+=("Donut_${version}_x86_64.flatpak") + fi + snap="$(find snap-package -name '*.snap' 2>/dev/null | head -n 1)" + if [ -n "$snap" ]; then + cp "$snap" "Donut_${version}_amd64.snap" + files+=("Donut_${version}_amd64.snap") + fi + ls -l "${files[@]}" + gh release upload "$TAG" "${files[@]}" --clobber --repo "$GITHUB_REPOSITORY" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03d5ddef..26238763 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -288,9 +288,21 @@ jobs: # Runs after every matrix leg (including the portable ZIP upload) so the # sums cover the complete, final asset set. The app self-updater refuses to # install a release it cannot verify against this file. - checksums: + # The Flatpak and the Snap, repackaged from this release's .deb and attached + # to it before the checksums are taken, so SHA256SUMS.txt covers them. + linux-packages: if: github.repository == 'zhom/donutbrowser' needs: [release] + uses: ./.github/workflows/linux-packages.yml + permissions: + contents: write + with: + release-tag: ${{ github.ref_name }} + + checksums: + # A failed Flatpak or Snap never holds back the checksums. + if: ${{ !cancelled() && github.repository == 'zhom/donutbrowser' && needs.release.result == 'success' }} + needs: [release, linux-packages] runs-on: ubuntu-latest permissions: contents: write diff --git a/.github/workflows/rolling-release.yml b/.github/workflows/rolling-release.yml index 3d423830..56aa5028 100644 --- a/.github/workflows/rolling-release.yml +++ b/.github/workflows/rolling-release.yml @@ -303,10 +303,38 @@ jobs: security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" || true rm -f "$RUNNER_TEMP/build_certificate.p12" || true - update-nightly-release: + # The Flatpak and the Snap, repackaged from this build's .deb and attached to + # its release before the nightly is assembled from it. + nightly-tag: if: github.repository == 'zhom/donutbrowser' needs: [rolling-release] runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + tag: ${{ steps.tag.outputs.tag }} + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7.0.1 + with: + persist-credentials: false + + - name: Name the build's release + id: tag + run: echo "tag=nightly-$(git show -s --format=%cs HEAD)-${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" + + linux-packages: + needs: [nightly-tag] + uses: ./.github/workflows/linux-packages.yml + permissions: + contents: write + with: + release-tag: ${{ needs.nightly-tag.outputs.tag }} + + update-nightly-release: + # A failed Flatpak or Snap never holds back the nightly; it only goes out + # without them. + if: ${{ !cancelled() && github.repository == 'zhom/donutbrowser' && needs.rolling-release.result == 'success' }} + needs: [rolling-release, linux-packages] + runs-on: ubuntu-latest timeout-minutes: 30 permissions: contents: write @@ -404,6 +432,8 @@ jobs: for f in Donut-*.aarch64.rpm; do [ -f "$f" ] && mv "$f" Donut_nightly_aarch64.rpm; done for f in Donut_*_aarch64.app.tar.gz; do [ -f "$f" ] && mv "$f" Donut_aarch64.app.tar.gz; done for f in Donut_*_x64.app.tar.gz; do [ -f "$f" ] && mv "$f" Donut_x64.app.tar.gz; done + for f in Donut_*_x86_64.flatpak; do [ -f "$f" ] && mv "$f" Donut_nightly_x86_64.flatpak; done + for f in Donut_*_amd64.snap; do [ -f "$f" ] && mv "$f" Donut_nightly_amd64.snap; done # Checksums for the rolling release (renamed filenames), restricted # to exactly the assets uploaded below. diff --git a/README.md b/README.md index f94b07b9..13ff906d 100644 --- a/README.md +++ b/README.md @@ -88,11 +88,11 @@ If that gives an EGL display error, add `WEBKIT_DISABLE_DMABUF_RENDERER=1` or `G ### Flatpak and Snap -The [Linux Packages](https://github.com/zhom/donutbrowser/actions/workflows/linux-packages.yml) workflow builds an x86_64 Flatpak bundle and Snap from the `.deb`. Download `donut-flatpak-x86_64` or `donut-snap-amd64` from a successful run, unzip it, and install it: +Releases include an x86_64 Flatpak bundle and a Snap, built from the `.deb` and tested in their sandboxes by the [Linux Packages](https://github.com/zhom/donutbrowser/actions/workflows/linux-packages.yml) workflow. Download `Donut_*_x86_64.flatpak` or `Donut_*_amd64.snap` from the [releases](https://github.com/zhom/donutbrowser/releases) (the nightly has them already) and install it: ```bash -flatpak install --user Donut.flatpak -sudo snap install --dangerous donutbrowser_*.snap +flatpak install --user Donut_*_x86_64.flatpak +sudo snap install --dangerous Donut_*_amd64.snap ``` The Snap leaves the microphone, the camera and the keyring (used by profile import) disconnected until you run `sudo snap connect donutbrowser:audio-record`, `donutbrowser:camera` or `donutbrowser:password-manager-service`. The Flatpak cannot change the default browser, so choose Donut in your system settings instead.