diff --git a/.github/release-body.md.template b/.github/release-body.md.template new file mode 100644 index 000000000..e0a351603 --- /dev/null +++ b/.github/release-body.md.template @@ -0,0 +1,34 @@ + +> [!WARN] +> 🚧 DO NOT EDIT 🚧 +> +> The [builds are still running](https://github.com/cryptomator/cryptomator/actions/workflows/create-release.yml). +> This banner will be replaced after the builds are finished. + + + + +For a comprehensive view of changes, read the [CHANGELOG](https://github.com/cryptomator/cryptomator/blob/$VERSION/CHANGELOG.md). + +--- + +💾 SHA-256 checksums of release artifacts: +``` +$TARBALL +$EXE +$MSI +$DMG_x64 +$DMG_arm64 +$APPIMAGE_x86_64 +$APPIMAGE_aarch64 +``` + +> [!TIP] +> You can verify the GPG signature of all assets using our public key: [`5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a). + + + diff --git a/.github/workflows/RELEASE.md b/.github/workflows/RELEASE.md new file mode 100644 index 000000000..eabf157bf --- /dev/null +++ b/.github/workflows/RELEASE.md @@ -0,0 +1,189 @@ +# Cryptomator Release Workflow + +This document describes the automated release pipeline defined in [`draft-release.yml`](draft-release.yml) and [`post-publish.yml`](post-publish.yml). + +## Overview + +The release process has two phases: + +1. **Draft phase** (`draft-release.yml`) -- triggered by pushing a signed git tag. Compiles, tests, builds platform installers, and creates a **draft** GitHub Release. +2. **Post-publish phase** (`post-publish.yml`) -- triggered when the draft release is manually **published**. Submits Windows installers for AV whitelisting, notifies the team for DEB build and latest-version update, and triggers downstream updates (website, docs, winget). + +```mermaid +--- +config: + htmlLabels: false +--- +flowchart TD + %% ── Trigger ────────────────────────────────────────────── + push_tag([🏷 Signed tag pushed]) + + %% ── Draft phase ────────────────────────────────────────── + push_tag --> get-version + + subgraph draft["draft-release.yml"] + get-version["get-version + *parse semver from tag*"] + + get-version --> create-release-draft + create-release-draft["create-release-draft + *compile & test (Linux) + create draft release + sign source tarball*"] + + create-release-draft --> build-exe-and-msi + create-release-draft --> build-dmg-arm64 + create-release-draft --> build-dmg-x64 + create-release-draft --> build-appimages + + build-exe-and-msi["build-exe-and-msi + *calls win-exe.yml + MSI + EXE (x64) + code-signed & GPG-signed*"] + build-dmg-arm64["build-dmg-arm64 + *calls mac-dmg.yml + DMG (arm64) + notarized & GPG-signed*"] + build-dmg-x64["build-dmg-x64 + *calls mac-dmg-x64.yml + DMG (x64) + notarized & GPG-signed*"] + build-appimages["build-appimages + *calls appimage.yml + AppImage (x86_64 + aarch64) + GPG-signed*"] + + build-exe-and-msi --> update-sha256sums + build-dmg-arm64 --> update-sha256sums + build-dmg-x64 --> update-sha256sums + build-appimages --> update-sha256sums + + update-sha256sums["update-sha256sums + *compute checksums + update release body*"] + end + + update-sha256sums --> manual_review + + %% ── Manual gate ────────────────────────────────────────── + manual_review{{Manual review + & publish}} + + %% ── Post-publish phase ─────────────────────────────────── + manual_review --> published([📢 Release published]) + published --> post-publish + + subgraph post-publish["post-publish.yml"] + direction TB + + check-release["check-release + *classify release tag + stable, alpha, beta, rc, unknown*"] + notify["notify + *Slack notifications + deb build & version check*"] + get-asset-urls["get-asset-urls + *extract MSI & EXE + download URLs*"] + + check-release --> notify-winget + check-release --> trigger-website + check-release --> trigger-docs + + get-asset-urls --> allowlist-msi + allowlist-msi --> allowlist-exe + + allowlist-msi["allowlist-msi-x64 + *av-whitelist.yml + Kaspersky & Avast*"] + allowlist-exe["allowlist-exe-x64 + *av-whitelist.yml + Kaspersky & Avast*"] + + notify-winget["notify-winget + *Slack: ready for winget + stable only*"] + trigger-website["trigger-website-update + *dispatch to + cryptomator.github.io + stable only*"] + trigger-docs["trigger-docs-update + *dispatch to + cryptomator/docs + stable only, Windows*"] + end +``` + +## Phase 1: Draft Release (`draft-release.yml`) + +**Trigger:** push of any tag (`*`) + +### Jobs + +| Job | Runs on | Description | +|-----|---------|-------------| +| **get-version** | ubuntu | Parses the tag into semver components (`semVerNum`, `semVerSuffix`, `revNum`, `versionType`). The release is aborted if not an alpha, beta, rc or 'stable' release. | +| **create-release-draft** | ubuntu | Checks out the repo, verifies the tag is **signed** and lives on a `main` or `release/*` branch. Runs `mvn verify` (with `xvfb-run`). Creates a GitHub Release **draft** using the [release body template](../release-body.md.template). Downloads and GPG-signs the source tarball. | +| **build-exe-and-msi** | windows | Calls [`win-exe.yml`](win-exe.yml). Builds the MSI and EXE bundle installer for x64 Windows. Code-signed via Azure Trusted Signing, GPG-signed, and uploaded to the draft release. Outputs SHA-256 checksums. | +| **build-dmg-arm64** | macos-15 | Calls [`mac-dmg.yml`](mac-dmg.yml). Builds the DMG for Apple Silicon. Code-signed, notarized with Apple, GPG-signed, and uploaded. Outputs SHA-256 checksum. | +| **build-dmg-x64** | macos-15-large | Calls [`mac-dmg-x64.yml`](mac-dmg-x64.yml). Same as above but for Intel Macs. Uses macFUSE instead of FUSE-T. | +| **build-appimages** | ubuntu | Calls [`appimage.yml`](appimage.yml). Builds AppImages for x86_64 and aarch64 (matrix). GPG-signed and uploaded with `.zsync` delta-update files. Outputs SHA-256 checksums. | +| **update-sha256sums** | ubuntu | Runs after all builds complete. Computes the source tarball checksum, collects all artifact checksums, and updates the draft release body via `envsubst`. Replaces the "builds still running" banner with a success notice. | + +### Release Artifacts + +After the draft phase, the GitHub Release contains: + +| Artifact | Platform | +|----------|----------| +| `cryptomator-.tar.gz.asc` | Source (GPG signature) | +| `Cryptomator--x64.msi` + `.asc` | Windows | +| `Cryptomator--x64.exe` + `.asc` | Windows | +| `Cryptomator--arm64.dmg` + `.asc` | macOS (Apple Silicon) | +| `Cryptomator--x64.dmg` + `.asc` | macOS (Intel) | +| `cryptomator--x86_64.AppImage` + `.zsync` + `.asc` | Linux (x86_64) | +| `cryptomator--aarch64.AppImage` + `.zsync` + `.asc` | Linux (aarch64) | + +All artifacts are signed with GPG key [`615D449FE6E6A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a). + +## Manual Review Gate + +After the draft phase completes, a maintainer reviews the draft release on GitHub. This is the point to: + +- Verify all artifacts are present and checksums look correct. +- Edit the auto-generated release notes (What's New, Bugfixes, Other Changes). +- **Publish** the release when ready, which triggers phase 2. + +## Phase 2: Post-Publish (`post-publish.yml`) + +**Trigger:** `release: [published]` + +### Jobs + +| Job | Condition | Description | +|-----|-----------|-------------| +| **notify** | always | Sends Slack notifications to `#cryptomator-desktop`: ready to build `.deb` package, and reminder to update `latest-version.json` on S3. | +| **get-asset-urls** | always | Extracts MSI and EXE download URLs from the release assets. | +| **check-release** | always | Classifies the published release tag as `stable`, `alpha`, `beta`, `rc`, or `unknown`. Stable-only follow-up jobs depend on this output. Unlike `get-version.yml` workflow, this job does not perform semver validation. | +| **allowlist-msi-x64** | Windows release | Calls [`av-whitelist.yml`](av-whitelist.yml). Uploads the MSI to Kaspersky and Avast for whitelisting. | +| **allowlist-exe-x64** | Windows release | Same as above for the EXE. Runs sequentially after MSI. | +| **notify-winget** | stable + Windows | Sends a Slack notification that the release is ready for [winget submission](winget.yml). | +| **trigger-website-update** | stable | Dispatches `desktop-release` event to `cryptomator/cryptomator.github.io`. | +| **trigger-docs-update** | stable + Windows | Dispatches `desktop-release` event to `cryptomator/docs`. | + +### Manual Follow-ups + +These steps are triggered by team members after Slack notifications: + +- **Debian package** -- Run the [`debian.yml`](debian.yml) workflow to build `.deb` and optionally upload to the PPA. +- **winget** -- Run the [`winget.yml`](winget.yml) workflow to submit to the Windows Package Manager. +- **latest-version.json** -- Update the version-check file on S3 (`static.cryptomator.org/desktop/latest-version.json`). + +## Signing & Security + +- **Git tag** must be SSH-signed and reside on `main` or `release/*`. +- **Windows** installers are code-signed using Azure Trusted Signing. +- **macOS** DMGs are code-signed with an Apple Developer certificate and notarized via `notarytool`. +- **All artifacts** receive a detached GPG signature (`.asc`) using key `615D449FE6E6A235`. +- **AV whitelisting** is submitted to Kaspersky and Avast after publish (Windows installers only). +- The draft release is created using `CRYPTOBOT_RELEASE_TOKEN`, not `GITHUB_TOKEN`, to ensure proper permissions and trigger downstream workflows. diff --git a/.github/workflows/appimage.yml b/.github/workflows/appimage.yml index 3c02313f3..1c209c301 100644 --- a/.github/workflows/appimage.yml +++ b/.github/workflows/appimage.yml @@ -1,19 +1,41 @@ name: Build AppImage on: - release: - types: [published] schedule: - cron: '0 23 20 * *' + workflow_call: + inputs: + semVerNum: + type: string + description: 'The Major.Minor.Patch part of the version' + required: true + revisionNum: + type: string + description: 'The revision number' + required: true + semVerSuffix: + type: string + description: 'The suffix of the version, including dash' + required: true + outputs: + sha256-appimage-x64: + description: "SHA256 sum of the x64 appimage" + value: ${{ jobs.collect-sha256sums.outputs.x64-sha256sum}} + sha256-appimage-aarch64: + description: "SHA256 sum of the aarch64 appimage" + value: ${{ jobs.collect-sha256sums.outputs.aarch64-sha256sum}} workflow_dispatch: inputs: - version: - description: 'Version' + semVerNum: + description: 'The Major.Minor.Patch part of the version' required: false - create-pr: - description: 'Create a PR for aur-bin repo' - type: boolean - default: false + revisionNum: + description: 'The revision number' + required: false + semVerSuffix: + description: 'The suffix of the version, including dash' + required: false + default: '-SNAPSHOT' push: branches-ignore: - 'dependabot/**' @@ -26,21 +48,15 @@ on: env: JAVA_DIST: 'temurin' JAVA_VERSION: '25.0.2+10.0.LTS' + VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}} + REVISION_NUM: ${{ inputs.revisionNum || '0' }} + VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}} + jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version: ${{ inputs.version }} #okay if not defined - build: name: Build AppImage runs-on: ${{ matrix.os }} - needs: [get-version] - env: - SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }} - SEMVER_NUM: ${{ needs.get-version.outputs.semVerNum }} - REV_NUM: ${{ needs.get-version.outputs.revNum }} strategy: fail-fast: false matrix: @@ -85,7 +101,7 @@ jobs: exit 1 fi - name: Set version - run : mvn versions:set -DnewVersion="$SEMVER_STR" + run : mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}" - name: Run maven run: mvn -B clean package -Plinux -DskipTests - name: Patch target dir @@ -128,12 +144,12 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2026 Skymatic GmbH" - --app-version "${SEMVER_NUM}.${REV_NUM}" + --app-version "${VERSION_NUM}.${REVISION_NUM}" --java-options "--enable-preview" --java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.linux.amd64,org.cryptomator.jfuse.linux.aarch64,org.purejava.appindicator" --java-options "-Xss5m" --java-options "-Xmx256m" - --java-options "-Dcryptomator.appVersion=\"${SEMVER_STR}\"" + --java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\"" --java-options "-Dfile.encoding=\"utf-8\"" --java-options "-Djava.net.useSystemProxies=true" --java-options "-Dcryptomator.adminConfigPath=\"/etc/cryptomator/config.properties\"" @@ -144,7 +160,7 @@ jobs: --java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/.local/share/Cryptomator/mnt\"" --java-options "-Dcryptomator.showTrayIcon=true" --java-options "-Dcryptomator.integrationsLinux.trayIconsDir=\"@{appdir}/usr/share/icons/hicolor/symbolic/apps\"" - --java-options "-Dcryptomator.buildNumber=\"appimage-${REV_NUM}\"" + --java-options "-Dcryptomator.buildNumber=\"appimage-${REVISION_NUM}\"" --java-options "-Dcryptomator.networking.truststore.p12Path=\"/etc/cryptomator/certs.p12\"" --java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" --java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log" @@ -183,7 +199,7 @@ jobs: GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} - name: Build AppImage run: > - ./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${SEMVER_STR}-${{ matrix.arch }}.AppImage + ./squashfs-root/AppRun Cryptomator.AppDir cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.arch }}.AppImage -u "gh-releases-zsync|cryptomator|cryptomator|latest|cryptomator-*-${{ matrix.arch }}.AppImage.zsync" --sign --sign-key=615D449FE6E6A235 - name: Create detached GPG signatures @@ -200,9 +216,10 @@ jobs: cryptomator-*.asc if-no-files-found: error - name: Publish AppImage on GitHub Releases - if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' + if: github.event_name == 'workflow_call' uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: + draft: true fail_on_unmatched_files: true token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} files: | @@ -210,79 +227,24 @@ jobs: cryptomator-*.zsync cryptomator-*.asc - create-aur-bin-pr: - name: Create PR for aur-bin repo - if: github.event_name == 'workflow_dispatch' && inputs.create-pr || github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable' + collect-sha256sums: + name: Collect AppImage checksums runs-on: ubuntu-latest - needs: [build, get-version] - container: - image: archlinux:base-devel - env: - SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }} - PKGDEST: ${{ github.workspace }}/pkgdest - SRCDEST: ${{ github.workspace }}/srcdest + needs: [build] + if: github.event_name == 'workflow_call' + outputs: + x64-sha256sum: ${{ steps.sha256sum.outputs.x64-sha256sum }} + aarch64-sha256sum: ${{ steps.sha256sum.outputs.aarch64-sha256sum }} steps: - - name: Prepare pacman - run: | - pacman-key --init - pacman-key --populate archlinux - pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl pacman-contrib - - name: Checkout cryptomator/aur-bin - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Download AppImage artifacts + uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0 with: - repository: 'cryptomator/aur-bin' - token: ${{ secrets.CRYPTOBOT_PR_TOKEN }} - - name: Create build user + pattern: appimage-* + path: appimage-artifacts + - name: Compute SHA256 sums + id: sha256sum run: | - useradd -m builder - echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder - chown -R builder:builder "$GITHUB_WORKSPACE" - install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST" - - name: Import Cryptomator release signing key - # try first ubuntu. on failure try openpgp keyservers - run: > - sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235 - || sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235 - - name: Checkout release branch - run: | - git config --global safe.directory '*' - git checkout -b "release/${SEMVER_STR}" - - name: Update build file - run: | - sed -i -e "s|^pkgver=.*$|pkgver=${SEMVER_STR}|" PKGBUILD - sed -i -e 's|^pkgrel=.*$|pkgrel=1|' PKGBUILD - sudo -u builder updpkgsums - sudo -u builder makepkg --printsrcinfo > .SRCINFO - - name: Build package with makepkg - run: > - sudo -u builder - env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST" - makepkg --syncdeps --cleanbuild --noconfirm --log - - name: Commit and push - run: | - git config user.name "cryptobot" - git config user.email "cryptobot@users.noreply.github.com" - git config push.autoSetupRemote true - git stage PKGBUILD .SRCINFO - git commit -m "Prepare release ${SEMVER_STR}" - git push - - name: Create pull request - id: create-pr - run: | - printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md - PR_URL=$(gh pr create --title "Release ${SEMVER_STR}" --body-file pr_body.md) - echo "url=$PR_URL" >> "$GITHUB_OUTPUT" - env: - GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }} - - name: Slack Notification - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 - env: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} - SLACK_USERNAME: 'Cryptobot' - SLACK_ICON: false - SLACK_ICON_EMOJI: ':bot:' - SLACK_CHANNEL: 'cryptomator-desktop' - SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ needs.get-version.outputs.semVerStr }} created." - SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed." - SLACK_FOOTER: false - MSG_MINIMAL: true + read -ra X64_SUM < <(sha256sum appimage-artifacts/appimage-x86_64/cryptomator-*-x86_64.AppImage) + read -ra AARCH64_SUM < <(sha256sum appimage-artifacts/appimage-aarch64/cryptomator-*-aarch64.AppImage) + echo "x64-sha256sum=${X64_SUM[0]}" >> "$GITHUB_OUTPUT" + echo "aarch64-sha256sum=${AARCH64_SUM[0]}" >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/aur-bin.yml b/.github/workflows/aur-bin.yml new file mode 100644 index 000000000..36865aa26 --- /dev/null +++ b/.github/workflows/aur-bin.yml @@ -0,0 +1,115 @@ +name: PR for aur-bin repo + +on: + release: + types: [published] + workflow_dispatch: + inputs: + src-tag: + description: 'Source or Release tag' + required: false + +jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: ${{ inputs.src-tag }} + + create-aur-bin-pr: + name: Create PR for aur-bin repo + if: (github.event_name == 'workflow_dispatch') || (github.event_name == 'release' && needs.get-version.outputs.versionType == 'stable') + runs-on: ubuntu-latest + needs: [get-version] + container: + image: archlinux:base-devel + env: + SEMVER_STR: ${{ needs.get-version.outputs.semVerStr }} + PKGDEST: ${{ github.workspace }}/pkgdest + SRCDEST: ${{ github.workspace }}/srcdest + steps: + - name: Prepare pacman + run: | + pacman-key --init + pacman-key --populate archlinux + pacman -Syu --noconfirm --needed git base-devel sudo gnupg maven unzip github-cli curl pacman-contrib + - name: Checkout cryptomator/aur-bin + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: 'cryptomator/aur-bin' + token: ${{ secrets.CRYPTOBOT_PR_TOKEN }} + - name: Create build user + run: | + useradd -m builder + echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/builder + chown -R builder:builder "$GITHUB_WORKSPACE" + install -d -m 0755 -o builder -g builder "$PKGDEST" "$SRCDEST" + - name: Import Cryptomator release signing key + # try first ubuntu. on failure try openpgp keyservers + run: > + sudo -u builder gpg --batch --keyserver hkps://keyserver.ubuntu.com --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235 + || sudo -u builder gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys 58117AFA1F85B3EEC154677D615D449FE6E6A235 + - name: Checkout release branch + run: | + git config --global safe.directory '*' + git checkout -b "release/${SEMVER_STR}" + - name: Determine pkgrel + id: pkgrel + run: | + CURRENT_VERSION="$(sed -nE 's/^pkgver=(.*)$/\1/p' PKGBUILD | head -n1)" + CURRENT_REL="$(sed -nE 's/^pkgrel=([0-9]+).*$/\1/p' PKGBUILD | head -n1)" + + if [[ "$CURRENT_VERSION" == "$TARGET_VERSION" && "$CURRENT_REL" =~ ^[0-9]+$ ]]; then + NEXT_REL=$((CURRENT_REL + 1)) + else + NEXT_REL=1 + fi + + echo "value=${NEXT_REL}" >> "$GITHUB_OUTPUT" + echo "dist-version=${TARGET_VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT" + env: + TARGET_VERSION: ${{ needs.get-version.outputs.semVerStr }} + - name: Update build file + run: | + sed -i -e "s|^pkgver=.*$|pkgver=${PKG_VERSION}|" PKGBUILD + sed -i -e "s|^pkgrel=.*$|pkgrel=${PKG_RELEASE}|" PKGBUILD + sudo -u builder updpkgsums + sudo -u builder makepkg --printsrcinfo > .SRCINFO + env: + PKG_VERSION: ${{ needs.get-version.outputs.semVerNum }} + PKG_RELEASE: ${{ steps.pkgrel.outputs.value }} + - name: Build package with makepkg + run: > + sudo -u builder + env PKGDEST="$PKGDEST" SRCDEST="$SRCDEST" + makepkg --syncdeps --cleanbuild --noconfirm --log + - name: Commit and push + run: | + git config user.name "cryptobot" + git config user.email "cryptobot@users.noreply.github.com" + git config push.autoSetupRemote true + git stage PKGBUILD .SRCINFO + git commit -m "Prepare release ${DIST_VERSION}" + git push + env: + DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }} + - name: Create pull request + id: create-pr + run: | + printf "Created by $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" > pr_body.md + PR_URL=$(gh pr create --title "Release ${DIST_VERSION}" --body-file pr_body.md) + echo "url=$PR_URL" >> "$GITHUB_OUTPUT" + env: + DIST_VERSION: ${{ steps.pkgrel.outputs.dist-version }} + GH_TOKEN: ${{ secrets.CRYPTOBOT_PR_TOKEN }} + - name: Slack Notification + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} + SLACK_USERNAME: 'Cryptobot' + SLACK_ICON: '' + SLACK_ICON_EMOJI: ':bot:' + SLACK_CHANNEL: 'cryptomator-desktop' + SLACK_TITLE: "AUR-bin release PR for ${{ github.event.repository.name }} ${{ needs.get-version.outputs.semVerStr }} created." + SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed." + SLACK_FOOTER: '' + MSG_MINIMAL: true \ No newline at end of file diff --git a/.github/workflows/av-whitelist.yml b/.github/workflows/av-whitelist.yml index d5827a9b2..7577662da 100644 --- a/.github/workflows/av-whitelist.yml +++ b/.github/workflows/av-whitelist.yml @@ -37,7 +37,7 @@ on: jobs: download-file: name: Downloads the file into the VM - runs-on: ubuntu-latest + runs-on: ubuntu-slim outputs: fileName: ${{ steps.extractName.outputs.fileName}} env: @@ -58,7 +58,7 @@ jobs: if-no-files-found: error allowlist-kaspersky: name: Anti Virus Allowlisting Kaspersky - runs-on: ubuntu-latest + runs-on: ubuntu-slim needs: download-file if: inputs.kaspersky steps: @@ -78,7 +78,7 @@ jobs: local-dir: ./upload/ allowlist-avast: name: Anti Virus Allowlisting Avast - runs-on: ubuntu-latest + runs-on: ubuntu-slim needs: download-file if: inputs.avast steps: diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1bd2a9bb8..4061626ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,40 +47,3 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - - name: Draft a release - if: startsWith(github.ref, 'refs/tags/') - uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 - with: - draft: true - discussion_category_name: releases - token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} - generate_release_notes: true - body: |- - > [!NOTE] - > 🚧 Work in Progress 🚧 - > - > Please be patient, the [builds are still running](https://github.com/cryptomator/cryptomator/actions). Binary packages can be found here in a few moments. - - - - For a comprehensive view of changes, read the [CHANGELOG](https://github.com/cryptomator/cryptomator/blob/develop/CHANGELOG.md). - - --- - - - - - > [!TIP] - > You can verify the GPG signature of all assets using our public key: [`5811 7AFA 1F85 B3EE C154 677D 615D 449F E6E6 A235`](https://gist.github.com/cryptobot/211111cf092037490275f39d408f461a). - - - - diff --git a/.github/workflows/check-jdk-updates.yml b/.github/workflows/check-jdk-updates.yml index 9eae6da00..0b0c30db7 100644 --- a/.github/workflows/check-jdk-updates.yml +++ b/.github/workflows/check-jdk-updates.yml @@ -74,10 +74,10 @@ jobs: env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }} SLACK_USERNAME: 'Cryptobot' - SLACK_ICON: false + SLACK_ICON: '' SLACK_ICON_EMOJI: ':bot:' SLACK_CHANNEL: 'cryptomator-desktop' SLACK_TITLE: "JDK update available" SLACK_MESSAGE: "Cryptomator-CI JDK can be upgraded to ${{ steps.determine.outputs.LATEST_JDK_VERSION }}. Check the Nextcloud collective for instructions." - SLACK_FOOTER: false + SLACK_FOOTER: '' MSG_MINIMAL: true \ No newline at end of file diff --git a/.github/workflows/draft-release.yml b/.github/workflows/draft-release.yml new file mode 100644 index 000000000..0442af4ff --- /dev/null +++ b/.github/workflows/draft-release.yml @@ -0,0 +1,157 @@ +name: Draft a Cryptomator Release + +on: + push: + tags: + - '*' + +env: + JAVA_DIST: 'temurin' + JAVA_VERSION: '25.0.2+10.0.LTS' + +defaults: + run: + shell: bash + +jobs: + get-version: + uses: ./.github/workflows/get-version.yml + with: + version: '' + + create-release-draft: + name: Compile and Test + runs-on: ubuntu-latest + needs: get-version + if: needs.get-version.outputs.versionType != 'unknown' + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 0 + - name: Check the git tag is signed + run: git cat-file -p "${GITHUB_REF_NAME}" | grep "BEGIN SSH SIGNATURE" + - name: Check the git tag is on release or main branch + run: git branch -r --contains "${GITHUB_REF_NAME}" | grep -E '^\s*origin/(main|release/.*)\s*$' + - uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 + with: + distribution: ${{ env.JAVA_DIST }} + java-version: ${{ env.JAVA_VERSION }} + cache: 'maven' + - name: Build and Test + run: xvfb-run mvn -B verify -Plinux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any + - name: Draft a release + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 + with: + draft: true + discussion_category_name: releases + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + generate_release_notes: true + body_path: .github/release-body.md.template + - name: Download source tarball + run: | + curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/${{ github.ref }}.tar.gz --output cryptomator-${{ github.ref_name }}.tar.gz + - name: Sign source tarball with key 615D449FE6E6A235 + run: | + echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import + echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz + env: + GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} + - name: Publish asc on GitHub Releases + uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 + with: + draft: true + fail_on_unmatched_files: true + token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + files: | + cryptomator-*.tar.gz.asc + + build-exe-and-msi: + needs: [get-version, create-release-draft] + uses: ./.github/workflows/win-exe.yml + with: + semVerNum: ${{needs.get-version.outputs.semVerNum}} + revisionNum: ${{needs.get-version.outputs.revNum}} + semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}} + secrets: inherit + + build-dmg-arm64: + needs: [get-version, create-release-draft] + uses: ./.github/workflows/mac-dmg.yml + with: + semVerNum: ${{needs.get-version.outputs.semVerNum}} + revisionNum: ${{needs.get-version.outputs.revNum}} + semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}} + secrets: inherit + + build-dmg-x64: + needs: [get-version, create-release-draft] + uses: ./.github/workflows/mac-dmg-x64.yml + with: + semVerNum: ${{needs.get-version.outputs.semVerNum}} + revisionNum: ${{needs.get-version.outputs.revNum}} + semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}} + secrets: inherit + + build-appimages: + needs: [get-version, create-release-draft] + uses: ./.github/workflows/appimage.yml + with: + semVerNum: ${{needs.get-version.outputs.semVerNum}} + revisionNum: ${{needs.get-version.outputs.revNum}} + semVerSuffix: ${{needs.get-version.outputs.semVerSuffix}} + secrets: inherit + + update-sha256sums: + runs-on: ubuntu-latest + needs: [get-version, build-exe-and-msi, build-dmg-arm64, build-dmg-x64, build-appimages] + env: + TAG: ${{ github.ref_name }} + SEMVER: ${{ needs.get-version.outputs.semVerStr }} + GH_TOKEN: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Compute source tarball SHA256 + id: src-sha256 + run: | + curl --silent --fail-with-body --proto "=https" -L \ + -H "Accept: application/vnd.github+json" \ + "https://github.com/cryptomator/cryptomator/archive/refs/tags/${TAG}.tar.gz" \ + --output "cryptomator-${SEMVER}.tar.gz" + read -ra CMD_OUTPUT < <(sha256sum "cryptomator-${SEMVER}.tar.gz") + echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT + - name: Update release body with checksums + run: | + CURRENT_BODY=$(gh release view "${TAG}" --json body --jq .body) + RELEASE_BODY=$(printf '%s\n' "${CURRENT_BODY}" | sed '//,//c\ + \ + > [!SUCCESS]\ + > Release artifacts finished building successfully.\ + >\ + > SHA-256 checksums have been updated below.\ + ') + + export TARBALL="${SRC_SHA} cryptomator-${SEMVER}.tar.gz" + export MSI="${MSI_SHA} Cryptomator-${SEMVER}-x64.msi" + export EXE="${EXE_SHA} Cryptomator-${SEMVER}-x64.exe" + export DMG_arm64="${DMG_ARM64_SHA} Cryptomator-${SEMVER}-arm64.dmg" + export DMG_x64="${DMG_X64_SHA} Cryptomator-${SEMVER}-x64.dmg" + export APPIMAGE_x86_64="${APPIMAGE_X64_SHA} cryptomator-${SEMVER}-x86_64.AppImage" + export APPIMAGE_aarch64="${APPIMAGE_AARCH64_SHA} cryptomator-${SEMVER}-aarch64.AppImage" + + envsubst '$VERSION $TARBALL $EXE $MSI $DMG_x64 $DMG_arm64 $APPIMAGE_x86_64 $APPIMAGE_aarch64' \ + <<< "${RELEASE_BODY}" \ + > release-body.md + + gh release edit "${TAG}" --draft --notes-file release-body.md + env: + VERSION: ${{ needs.get-version.outputs.semVerStr }} + SRC_SHA: ${{ steps.src-sha256.outputs.value }} + MSI_SHA: ${{ needs.build-exe-and-msi.outputs.sha256-msi }} + EXE_SHA: ${{ needs.build-exe-and-msi.outputs.sha256-exe }} + DMG_ARM64_SHA: ${{ needs.build-dmg-arm64.outputs.sha256-dmg }} + DMG_X64_SHA: ${{ needs.build-dmg-x64.outputs.sha256-dmg }} + APPIMAGE_X64_SHA: ${{ needs.build-appimages.outputs.sha256-appimage-x64 }} + APPIMAGE_AARCH64_SHA: ${{ needs.build-appimages.outputs.sha256-appimage-aarch64 }} diff --git a/.github/workflows/get-version.yml b/.github/workflows/get-version.yml index 45056f700..def7ed98e 100644 --- a/.github/workflows/get-version.yml +++ b/.github/workflows/get-version.yml @@ -14,6 +14,9 @@ on: semVerNum: description: "The numerical part of the version string" value: ${{ jobs.determine-version.outputs.semVerNum}} + semVerSuffix: + description: "The suffix of the version string" + value: ${{ jobs.determine-version.outputs.semVerSuffix}} revNum: description: "The revision number" value: ${{ jobs.determine-version.outputs.revNum}} @@ -32,6 +35,7 @@ jobs: outputs: semVerNum: ${{ steps.versions.outputs.semVerNum }} semVerStr: ${{ steps.versions.outputs.semVerStr }} + semVerSuffix: ${{ steps.versions.outputs.semVerSuffix }} revNum: ${{ steps.versions.outputs.revNum }} type: ${{ steps.versions.outputs.type}} steps: @@ -54,20 +58,25 @@ jobs: else SEM_VER_STR=`mvn help:evaluate -Dexpression=project.version -q -DforceStdout` fi - SEM_VER_NUM=`echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/'` + + SEM_VER_NUM=$(echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/') + SEM_VER_SUFFIX="${SEM_VER_STR#"$SEM_VER_NUM"}" REVCOUNT=`git rev-list --count HEAD` + TYPE="unknown" - if [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if [[ -z $SEM_VER_SUFFIX ]]; then TYPE="stable" - elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-alpha[1-9]+$ ]]; then + elif [[ $SEM_VER_SUFFIX =~ -alpha[1-9]+$ ]]; then TYPE="alpha" - elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-beta[1-9]+$ ]]; then + elif [[ $SEM_VER_SUFFIX =~ -beta[1-9]+$ ]]; then TYPE="beta" - elif [[ $SEM_VER_STR =~ [0-9]+\.[0-9]+\.[0-9]+-rc[1-9]$ ]]; then + elif [[ $SEM_VER_SUFFIX =~ -rc[1-9]+$ ]]; then TYPE="rc" fi + echo "semVerStr=${SEM_VER_STR}" >> $GITHUB_OUTPUT echo "semVerNum=${SEM_VER_NUM}" >> $GITHUB_OUTPUT + echo "semVerSuffix=${SEM_VER_SUFFIX}" >> $GITHUB_OUTPUT echo "revNum=${REVCOUNT}" >> $GITHUB_OUTPUT echo "type=${TYPE}" >> $GITHUB_OUTPUT env: diff --git a/.github/workflows/linux-flatpak.yml b/.github/workflows/linux-flatpak.yml index 1d476dc1d..83afbed39 100644 --- a/.github/workflows/linux-flatpak.yml +++ b/.github/workflows/linux-flatpak.yml @@ -255,10 +255,10 @@ jobs: env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} SLACK_USERNAME: 'Cryptobot' - SLACK_ICON: false + SLACK_ICON: '' SLACK_ICON_EMOJI: ':bot:' SLACK_CHANNEL: 'cryptomator-desktop' SLACK_TITLE: "Flathub release PR created for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} created." SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.FLATHUB_PR_URL }}|PR> on how to proceed." - SLACK_FOOTER: false + SLACK_FOOTER: '' MSG_MINIMAL: true diff --git a/.github/workflows/linux-makepkg.yml b/.github/workflows/linux-makepkg.yml index a28f34443..7f195c7db 100644 --- a/.github/workflows/linux-makepkg.yml +++ b/.github/workflows/linux-makepkg.yml @@ -132,7 +132,6 @@ jobs: - name: Determine pkgrel id: pkgrel run: | - TARGET_VERSION='${{ needs.get-version.outputs.semVerStr }}' CURRENT_VERSION="$(sed -nE 's/^pkgver=(.*)$/\1/p' PKGBUILD | head -n1)" CURRENT_REL="$(sed -nE 's/^pkgrel=([0-9]+).*$/\1/p' PKGBUILD | head -n1)" @@ -143,9 +142,9 @@ jobs: fi echo "value=${NEXT_REL}" >> "$GITHUB_OUTPUT" - echo "dist-version=${VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT" + echo "dist-version=${TARGET_VERSION}-${NEXT_REL}" >> "$GITHUB_OUTPUT" env: - VERSION: ${{ needs.get-version.outputs.semVerStr }} + TARGET_VERSION: ${{ needs.get-version.outputs.semVerStr }} - name: Download PKGBUILD template uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -193,10 +192,10 @@ jobs: env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} SLACK_USERNAME: 'Cryptobot' - SLACK_ICON: false + SLACK_ICON: '' SLACK_ICON_EMOJI: ':bot:' SLACK_CHANNEL: 'cryptomator-desktop' SLACK_TITLE: "AUR release PR created for ${{ github.event.repository.name }} ${{ steps.pkgrel.outputs.dist-version }} ." SLACK_MESSAGE: "See <${{ steps.create-pr.outputs.url }}|PR> on how to proceed." - SLACK_FOOTER: false + SLACK_FOOTER: '' MSG_MINIMAL: true diff --git a/.github/workflows/mac-dmg-x64.yml b/.github/workflows/mac-dmg-x64.yml index 09b4568f1..a3ed97967 100644 --- a/.github/workflows/mac-dmg-x64.yml +++ b/.github/workflows/mac-dmg-x64.yml @@ -9,15 +9,42 @@ name: Build macOS .dmg for x64 ####################################### on: - release: - types: [published] schedule: - cron: '0 20 20 * *' + workflow_call: + inputs: + semVerNum: + type: string + description: 'The Major.Minor.Patch part of the version' + required: true + revisionNum: + type: string + description: 'The revision number' + required: true + semVerSuffix: + type: string + description: 'The suffix of the version, including dash' + required: true + notarize: + description: 'Notarize' + default: true + type: boolean + outputs: + sha256-dmg: + description: "SHA256 sum of the x64 dmg" + value: ${{ jobs.build.outputs.sha256sum}} workflow_dispatch: inputs: - version: - description: 'Version' + semVerNum: + description: 'The Major.Minor.Patch part of the version' required: false + revisionNum: + description: 'The revision number' + required: false + semVerSuffix: + description: 'The suffix of the version, including dash' + required: false + default: '-SNAPSHOT' notarize: description: 'Notarize' required: true @@ -27,17 +54,17 @@ on: env: JAVA_DIST: 'temurin' JAVA_VERSION: '25.0.2+10.0.LTS' + VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}} + REVISION_NUM: ${{ inputs.revisionNum || '0' }} + VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}} + jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version: ${{ inputs.version }} - - build-arm: + build: name: Build Cryptomator.app for ${{ matrix.output-suffix }} runs-on: ${{ matrix.os }} - needs: [get-version] + outputs: + sha256sum: ${{ steps.sha256sum.outputs.value }} strategy: fail-fast: false matrix: @@ -79,7 +106,7 @@ jobs: exit 1 fi - name: Set version - run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }} + run : mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}" - name: Run maven run: mvn -B clean package -Pmac -DskipTests - name: Patch target dir @@ -120,7 +147,7 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2026 Skymatic GmbH" - --app-version "${{ needs.get-version.outputs.semVerNum }}" + --app-version "${VERSION_NUM}" --java-options "--enable-preview" --java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac" --java-options "-Xss5m" @@ -129,7 +156,7 @@ jobs: --java-options "-Djava.net.useSystemProxies=true" --java-options "-Dapple.awt.enableTemplateImages=true" --java-options "-Dsun.java2d.metal=true" - --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\"" + --java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\"" --java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\"" --java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/Cryptomator\"" --java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/Cryptomator/settings.json\"" @@ -139,7 +166,7 @@ jobs: --java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support/Cryptomator/mnt\"" --java-options "-Dcryptomator.showTrayIcon=true" --java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism" - --java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\"" + --java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NUM}\"" --java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" --mac-package-identifier org.cryptomator --resource-dir dist/mac/resources @@ -148,12 +175,10 @@ jobs: mv appdir/Cryptomator.app Cryptomator.app mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/ cp dist/mac/resources/Assets.car Cryptomator.app/Contents/Resources/ - sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist - sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist + sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NUM}|g" Cryptomator.app/Contents/Info.plist + sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NUM}|g" Cryptomator.app/Contents/Info.plist echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile env: - VERSION_NO: ${{ needs.get-version.outputs.semVerNum }} - REVISION_NO: ${{ needs.get-version.outputs.revNum }} PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }} - name: Generate license for dmg run: > @@ -242,16 +267,14 @@ jobs: --eula "dist/mac/dmg/resources/license.rtf" --icon ".background" 128 758 --icon ".VolumeIcon.icns" 512 758 - Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg - env: - VERSION_NO: ${{ needs.get-version.outputs.semVerNum }} + Cryptomator-${VERSION_NUM}-${{ matrix.output-suffix }}.dmg dmg - name: Codesign .dmg run: | codesign -s ${CODESIGN_IDENTITY} --timestamp Cryptomator-*.dmg env: CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} - name: Notarize .dmg - if: startsWith(github.ref, 'refs/tags/') || inputs.notarize || github.event_name == 'schedule' + if: inputs.notarize || github.event_name == 'schedule' uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3 with: app-path: 'Cryptomator-*.dmg' @@ -259,8 +282,12 @@ jobs: password: ${{ secrets.MACOS_NOTARIZATION_PW }} team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} xcode-path: '/Applications/Xcode_16.app' + - id: sha256sum + run: | + read -ra CMD_OUTPUT < <(shasum -a256 Cryptomator-*.dmg) + echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT - name: Add possible alpha/beta tags to installer name - run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg + run: mv Cryptomator-*.dmg "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.output-suffix }}.dmg" - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -281,9 +308,10 @@ jobs: Cryptomator-*.asc if-no-files-found: error - name: Publish dmg on GitHub Releases - if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' + if: github.event_name == 'workflow_call' uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: + draft: true fail_on_unmatched_files: true token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} files: | diff --git a/.github/workflows/mac-dmg.yml b/.github/workflows/mac-dmg.yml index b1e4d70d4..0d9fb9f29 100644 --- a/.github/workflows/mac-dmg.yml +++ b/.github/workflows/mac-dmg.yml @@ -1,15 +1,42 @@ name: Build macOS .dmg for arm64 on: - release: - types: [published] schedule: - cron: '0 20 20 * *' + workflow_call: + inputs: + semVerNum: + type: string + description: 'The Major.Minor.Patch part of the version' + required: true + revisionNum: + type: string + description: 'The revision number' + required: true + semVerSuffix: + type: string + description: 'The suffix of the version, including dash' + required: true + notarize: + description: 'Notarize' + default: true + type: boolean + outputs: + sha256-dmg: + description: "SHA256 sum of the arm64 dmg" + value: ${{ jobs.build.outputs.sha256sum}} workflow_dispatch: inputs: - version: - description: 'Version' + semVerNum: + description: 'The Major.Minor.Patch part of the version' required: false + revisionNum: + description: 'The revision number' + required: false + semVerSuffix: + description: 'The suffix of the version, including dash' + required: false + default: '-SNAPSHOT' notarize: description: 'Notarize' required: true @@ -25,17 +52,17 @@ on: env: JAVA_DIST: 'temurin' JAVA_VERSION: '25.0.2+10.0.LTS' + VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}} + REVISION_NUM: ${{ inputs.revisionNum || '0' }} + VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}} + jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version: ${{ inputs.version }} - build: name: Build Cryptomator.app for ${{ matrix.output-suffix }} runs-on: ${{ matrix.os }} - needs: [get-version] + outputs: + sha256sum: ${{ steps.sha256sum.outputs.value }} strategy: fail-fast: false matrix: @@ -77,7 +104,7 @@ jobs: exit 1 fi - name: Set version - run : mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }} + run : mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}" - name: Run maven run: mvn -B clean package -Pmac -DskipTests - name: Patch target dir @@ -118,7 +145,7 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2026 Skymatic GmbH" - --app-version "${{ needs.get-version.outputs.semVerNum }}" + --app-version "${VERSION_NUM}" --java-options "--enable-preview" --java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.mac" --java-options "-Xss5m" @@ -127,7 +154,7 @@ jobs: --java-options "-Djava.net.useSystemProxies=true" --java-options "-Dapple.awt.enableTemplateImages=true" --java-options "-Dsun.java2d.metal=true" - --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\"" + --java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\"" --java-options "-Dcryptomator.adminConfigPath=\"/Library/Application Support/Cryptomator/config.properties\"" --java-options "-Dcryptomator.logDir=\"@{userhome}/Library/Logs/Cryptomator\"" --java-options "-Dcryptomator.settingsPath=\"@{userhome}/Library/Application Support/Cryptomator/settings.json\"" @@ -137,7 +164,7 @@ jobs: --java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Library/Application Support/Cryptomator/mnt\"" --java-options "-Dcryptomator.showTrayIcon=true" --java-options "-Dcryptomator.updateMechanism=org.cryptomator.macos.update.DmgUpdateMechanism" - --java-options "-Dcryptomator.buildNumber=\"dmg-${{ needs.get-version.outputs.revNum }}\"" + --java-options "-Dcryptomator.buildNumber=\"dmg-${REVISION_NUM}\"" --java-options "-XX:ErrorFile=/cryptomator/cryptomator_crash.log" --java-options "-Dcryptomator.hub.enableTrustOnFirstUse=true" --mac-package-identifier org.cryptomator @@ -147,12 +174,10 @@ jobs: mv appdir/Cryptomator.app Cryptomator.app mv dist/mac/resources/Cryptomator-Vault.icns Cryptomator.app/Contents/Resources/ cp dist/mac/resources/Assets.car Cryptomator.app/Contents/Resources/ - sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NO}|g" Cryptomator.app/Contents/Info.plist - sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NO}|g" Cryptomator.app/Contents/Info.plist + sed -i '' "s|###BUNDLE_SHORT_VERSION_STRING###|${VERSION_NUM}|g" Cryptomator.app/Contents/Info.plist + sed -i '' "s|###BUNDLE_VERSION###|${REVISION_NUM}|g" Cryptomator.app/Contents/Info.plist echo -n "$PROVISIONING_PROFILE_BASE64" | base64 --decode --output Cryptomator.app/Contents/embedded.provisionprofile env: - VERSION_NO: ${{ needs.get-version.outputs.semVerNum }} - REVISION_NO: ${{ needs.get-version.outputs.revNum }} PROVISIONING_PROFILE_BASE64: ${{ secrets.MACOS_PROVISIONING_PROFILE_BASE64 }} - name: Generate license for dmg run: > @@ -241,16 +266,14 @@ jobs: --eula "dist/mac/dmg/resources/license.rtf" --icon ".background" 128 758 --icon ".VolumeIcon.icns" 512 758 - Cryptomator-${VERSION_NO}-${{ matrix.output-suffix }}.dmg dmg - env: - VERSION_NO: ${{ needs.get-version.outputs.semVerNum }} + Cryptomator-${VERSION_NUM}-${{ matrix.output-suffix }}.dmg dmg - name: Codesign .dmg run: | codesign -s ${CODESIGN_IDENTITY} --timestamp Cryptomator-*.dmg env: CODESIGN_IDENTITY: ${{ secrets.MACOS_CODESIGN_IDENTITY }} - name: Notarize .dmg - if: startsWith(github.ref, 'refs/tags/') || inputs.notarize || github.event_name == 'schedule' + if: inputs.notarize || github.event_name == 'schedule' uses: cocoalibs/xcode-notarization-action@5cf433d494b6fa26504b574c591f4dd120388846 # v1.0.3 with: app-path: 'Cryptomator-*.dmg' @@ -258,8 +281,12 @@ jobs: password: ${{ secrets.MACOS_NOTARIZATION_PW }} team-id: ${{ secrets.MACOS_NOTARIZATION_TEAM_ID }} xcode-path: '/Applications/Xcode_16.app' + - id: sha256sum + run: | + read -ra CMD_OUTPUT < <(shasum -a256 Cryptomator-*.dmg) + echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT - name: Add possible alpha/beta tags to installer name - run: mv Cryptomator-*.dmg Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.output-suffix }}.dmg + run: mv Cryptomator-*.dmg "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.output-suffix }}.dmg" - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -280,9 +307,10 @@ jobs: Cryptomator-*.asc if-no-files-found: error - name: Publish dmg on GitHub Releases - if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' + if: github.event_name == 'workflow_call' uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: + draft: true fail_on_unmatched_files: true token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} files: | diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml index 6585256bb..6cf906950 100644 --- a/.github/workflows/no-response.yml +++ b/.github/workflows/no-response.yml @@ -7,7 +7,7 @@ on: jobs: no-response: - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: issues: write pull-requests: write diff --git a/.github/workflows/post-publish.yml b/.github/workflows/post-publish.yml index c989360af..e27820520 100644 --- a/.github/workflows/post-publish.yml +++ b/.github/workflows/post-publish.yml @@ -5,35 +5,141 @@ on: types: [published] jobs: - get-version: - runs-on: ubuntu-latest + notify: + runs-on: ubuntu-slim steps: - - name: Download source tarball - run: | - curl --silent --fail-with-body --proto "=https" -L -H "Accept: application/vnd.github+json" https://github.com/cryptomator/cryptomator/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz --output cryptomator-${{ github.event.release.tag_name }}.tar.gz - - name: Sign source tarball with key 615D449FE6E6A235 - run: | - echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import - echo "${GPG_PASSPHRASE}" | gpg --batch --quiet --passphrase-fd 0 --pinentry-mode loopback -u 615D449FE6E6A235 --detach-sign -a cryptomator-*.tar.gz + - name: Notify about DEB build + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 env: - GPG_PRIVATE_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }} - GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }} - - name: Publish asc on GitHub Releases - uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 - with: - fail_on_unmatched_files: true - token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} - files: | - cryptomator-*.tar.gz.asc + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} + SLACK_USERNAME: 'Cryptobot' + SLACK_ICON: '' + SLACK_ICON_EMOJI: ':bot:' + SLACK_CHANNEL: 'cryptomator-desktop' + SLACK_TITLE: "Release ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published." + SLACK_MESSAGE: "Ready to ." + SLACK_FOOTER: '' + MSG_MINIMAL: true + - name: Notify about latest-version update + uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} + SLACK_USERNAME: 'Cryptobot' + SLACK_ICON: '' + SLACK_ICON_EMOJI: ':bot:' + SLACK_CHANNEL: 'cryptomator-desktop' + SLACK_TITLE: "Requiring version check source update for ${{ github.event.repository.name }} ${{ github.event.release.tag_name }}." + SLACK_MESSAGE: 'Check S3 bucket for .' + SLACK_FOOTER: '' + MSG_MINIMAL: true + + get-asset-urls: + name: Get release asset URLs + runs-on: ubuntu-slim + outputs: + is-windows-release: ${{ steps.urls.outputs.urls-present }} + msi-url: ${{ steps.urls.outputs.msi }} + exe-url: ${{ steps.urls.outputs.exe }} + steps: + - name: Extract MSI and EXE download URLs + id: urls + run: | + MSI_URL=$(jq -r '[.[] | select(.name | endswith("-x64.msi"))][0].browser_download_url // "null"' <<< "$RELEASE_ASSETS") + EXE_URL=$(jq -r '[.[] | select(.name | endswith("-x64.exe"))][0].browser_download_url // "null"' <<< "$RELEASE_ASSETS") + if [[ "$MSI_URL" == "null" || -z "$MSI_URL" || "$EXE_URL" == "null" || -z "$EXE_URL" ]]; then + echo "urls-present=false" >> $GITHUB_OUTPUT + else + echo "urls-present=true" >> $GITHUB_OUTPUT + echo "msi=${MSI_URL}" >> $GITHUB_OUTPUT + echo "exe=${EXE_URL}" >> $GITHUB_OUTPUT + fi + env: + RELEASE_ASSETS: ${{ toJson(github.event.release.assets) }} + + allowlist-msi-x64: + needs: [get-asset-urls] + if: needs.get-asset-urls.outputs.is-windows-release == 'true' + uses: ./.github/workflows/av-whitelist.yml + with: + url: ${{ needs.get-asset-urls.outputs.msi-url }} + secrets: inherit + + allowlist-exe-x64: + needs: [get-asset-urls, allowlist-msi-x64] + if: needs.get-asset-urls.outputs.is-windows-release == 'true' + uses: ./.github/workflows/av-whitelist.yml + with: + url: ${{ needs.get-asset-urls.outputs.exe-url }} + secrets: inherit + + check-release: + name: Analyzes the release for certain properties + runs-on: ubuntu-slim + outputs: + release-kind: ${{steps.determine-kind.outputs.value}} # Possible values are [alpha, beta, rc, stable, unknown] + steps: + - id: determine-kind + run: | + SEM_VER_NUM=$(echo ${SEM_VER_STR} | sed -E 's/([0-9]+\.[0-9]+\.[0-9]+).*/\1/') + SEM_VER_SUFFIX="${SEM_VER_STR#"$SEM_VER_NUM"}" + + TYPE="unknown" + if [[ -z $SEM_VER_SUFFIX ]]; then + TYPE="stable" + elif [[ $SEM_VER_SUFFIX =~ -alpha[1-9]+$ ]]; then + TYPE="alpha" + elif [[ $SEM_VER_SUFFIX =~ -beta[1-9]+$ ]]; then + TYPE="beta" + elif [[ $SEM_VER_SUFFIX =~ -rc[1-9]+$ ]]; then + TYPE="rc" + fi + echo "value=${TYPE}" >> $GITHUB_OUTPUT + env: + SEM_VER_STR: ${{ github.event.release.tag_name }} + + + notify-winget: + name: Notify for winget-release + if: needs.get-asset-urls.outputs.is-windows-release == 'true' && needs.check-release.outputs.release-kind == 'stable' + needs: [check-release, get-asset-urls] + runs-on: ubuntu-slim + steps: - name: Slack Notification uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 env: SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} SLACK_USERNAME: 'Cryptobot' - SLACK_ICON: false + SLACK_ICON: '' SLACK_ICON_EMOJI: ':bot:' SLACK_CHANNEL: 'cryptomator-desktop' SLACK_TITLE: "Release ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published." - SLACK_MESSAGE: "Ready to ." - SLACK_FOOTER: false - MSG_MINIMAL: true \ No newline at end of file + SLACK_MESSAGE: "Ready to ." + SLACK_FOOTER: '' + MSG_MINIMAL: true + + trigger-website-update: + needs: [check-release] + runs-on: ubuntu-slim + if: needs.check-release.outputs.release-kind == 'stable' + steps: + - name: Start website update workflow + uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1 + with: + event-type: desktop-release + token: ${{ secrets.CRYPTOBOT_WORKFLOW_DISPATCH_TOKEN }} + repository: cryptomator/cryptomator.github.io + client-payload: '{ "version": "${{ github.event.release.tag_name }}", "release": ${{ toJson(github.event.release.assets) }} }' + + trigger-docs-update: + needs: [check-release, get-asset-urls] + runs-on: ubuntu-slim + if: needs.get-asset-urls.outputs.is-windows-release == 'true' && needs.check-release.outputs.release-kind == 'stable' + steps: + - name: Start docs update workflow + uses: peter-evans/repository-dispatch@28959ce8df70de7be546dd1250a005dd32156697 # v4.0.1 + with: + event-type: desktop-release + token: ${{ secrets.CRYPTOBOT_WORKFLOW_DISPATCH_TOKEN }} + repository: cryptomator/docs + client-payload: '{ "version": "${{ github.event.release.tag_name }}", "release": ${{ toJson(github.event.release.assets) }} }' + diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 9f30d89a5..ed6406551 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ on: jobs: stale: - runs-on: ubuntu-latest + runs-on: ubuntu-slim permissions: issues: write pull-requests: write diff --git a/.github/workflows/win-exe.yml b/.github/workflows/win-exe.yml index 8488a0a31..0f1b16b3f 100644 --- a/.github/workflows/win-exe.yml +++ b/.github/workflows/win-exe.yml @@ -1,15 +1,45 @@ name: Build Windows Installer on: - release: - types: [published] schedule: - cron: '0 19 20 * *' + workflow_call: + inputs: + semVerNum: + type: string + description: 'The Major.Minor.Patch part of the version' + required: true + revisionNum: + type: string + description: 'The revision number' + required: true + semVerSuffix: + type: string + description: 'The suffix of the version, including dash' + required: true + sign: + description: 'Sign binaries' + default: true + type: boolean + outputs: + sha256-msi: + description: "SHA256 sum of the x64 msi" + value: ${{ jobs.build-msi.outputs.sha256sum}} + sha256-exe: + description: "SHA256 sum of the x64 exe" + value: ${{ jobs.build-exe.outputs.sha256sum}} workflow_dispatch: inputs: - version: - description: 'Version' + semVerNum: + description: 'The Major.Minor.Patch part of the version' required: false + revisionNum: + description: 'The revision number' + required: false + semVerSuffix: + description: 'The suffix of the version, including dash' + required: false + default: '-SNAPSHOT' sign: description: 'Sign binaries' required: false @@ -24,6 +54,9 @@ on: env: + VERSION_NUM: ${{ inputs.semVerNum || '99.99.99'}} + REVISION_NUM: ${{ inputs.revisionNum || '0' }} + VERSION_SUFFIX: ${{ inputs.semVerSuffix || ''}} OPENJFX_JMODS_AMD64: 'https://download2.gluonhq.com/openjfx/25.0.2/openjfx-25.0.2_windows-x64_bin-jmods.zip' OPENJFX_JMODS_AMD64_HASH: '33d878dfac85590c4d77c518ed413e512d34a8479d90132b230a7ddd173576b3' WINFSP_MSI: 'https://github.com/winfsp/winfsp/releases/download/v2.1/winfsp-2.1.25156.msi' @@ -36,15 +69,11 @@ defaults: shell: bash jobs: - get-version: - uses: ./.github/workflows/get-version.yml - with: - version: ${{ inputs.version }} - build-msi: name: Build .msi Installer runs-on: ${{ matrix.os }} - needs: [ get-version ] + outputs: + sha256sum: ${{ steps.sha256sum.outputs.value }} strategy: matrix: include: @@ -96,7 +125,7 @@ jobs: exit 1 fi - name: Set version - run: mvn versions:set -DnewVersion=${{ needs.get-version.outputs.semVerStr }} + run: mvn versions:set -DnewVersion="${VERSION_NUM}${VERSION_SUFFIX}" - name: Run maven run: mvn -B clean package -Pwin -DskipTests - name: Patch target dir @@ -137,12 +166,12 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2026 Skymatic GmbH" - --app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum }}" + --app-version "${VERSION_NUM}.${REVISION_NUM}" --java-options "--enable-preview" --java-options "--enable-native-access=javafx.graphics,org.cryptomator.jfuse.win,org.cryptomator.integrations.win" --java-options "-Xss5m" --java-options "-Xmx256m" - --java-options "-Dcryptomator.appVersion=\"${{ needs.get-version.outputs.semVerStr }}\"" + --java-options "-Dcryptomator.appVersion=\"${VERSION_NUM}${VERSION_SUFFIX}\"" --java-options "-Dfile.encoding=\"utf-8\"" --java-options "-Djava.net.useSystemProxies=true" --java-options "-Dcryptomator.adminConfigPath=\"C:/ProgramData/Cryptomator/config.properties\"" @@ -153,7 +182,7 @@ jobs: --java-options "-Dcryptomator.mountPointsDir=\"@{userhome}/Cryptomator\"" --java-options "-Dcryptomator.loopbackAlias=\"cryptomator-vault\"" --java-options "-Dcryptomator.showTrayIcon=true" - --java-options "-Dcryptomator.buildNumber=\"msi-${{ needs.get-version.outputs.revNum }}\"" + --java-options "-Dcryptomator.buildNumber=\"msi-${REVISION_NUM}\"" --java-options "-Dcryptomator.integrationsWin.autoStartShellLinkName=\"Cryptomator\"" --java-options "-Dcryptomator.integrationsWin.keychainPaths=\"@{appdata}/Cryptomator/keychain.json;@{userhome}/AppData/Roaming/Cryptomator/keychain.json\"" --java-options "-Dcryptomator.integrationsWin.windowsHelloKeychainPaths=\"@{appdata}/Cryptomator/windowsHelloKeychain.json\"" @@ -195,7 +224,7 @@ jobs: & $env:JAVA_HOME\bin\jmod.exe extract --dir jpackage-jmod "${env:JAVA_HOME}\jmods\jdk.jpackage.jmod" Get-ChildItem -Recurse -Path "jpackage-jmod" -File wixhelper.dll | Select-Object -Last 1 | Copy-Item -Destination "appdir" - name: Sign DLLs with Azure Trusted Signing - if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule' + if: inputs.sign || github.event_name == 'schedule' uses: ./.github/actions/win-sign-action with: base-dir: ${{ github.workspace }}\appdir @@ -240,7 +269,7 @@ jobs: --name Cryptomator --vendor "Skymatic GmbH" --copyright "(C) 2016 - 2026 Skymatic GmbH" - --app-version "${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}" + --app-version "${VERSION_NUM}.${REVISION_NUM}" --win-menu --win-dir-chooser --win-shortcut-prompt @@ -253,7 +282,7 @@ jobs: JP_WIXWIZARD_RESOURCES: ${{ github.workspace }}/dist/win/resources # requires abs path, used in resources/main.wxs JP_WIXHELPER_DIR: ${{ github.workspace }}\appdir - name: Sign MSI with Azure Trusted Signing - if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule' + if: inputs.sign || github.event_name == 'schedule' uses: ./.github/actions/win-sign-action with: base-dir: ${{ github.workspace }}\installer @@ -262,8 +291,12 @@ jobs: tenant-id: ${{ secrets.AZURE_TENANT_ID }} client-id: ${{ secrets.AZURE_CLIENT_ID }} client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + - id: sha256sum + run: | + read -ra CMD_OUTPUT < <(sha256sum installer/Cryptomator-*.msi) + echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT - name: Add possible alpha/beta tags and architecture to installer name - run: mv installer/Cryptomator-*.msi Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.arch }}.msi + run: mv installer/Cryptomator-*.msi "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.arch }}.msi" - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -283,7 +316,9 @@ jobs: build-exe: name: Build .exe installer runs-on: ${{ matrix.os }} - needs: [ get-version, build-msi ] + needs: [ build-msi ] + outputs: + sha256sum: ${{ steps.sha256sum.outputs.value }} strategy: matrix: include: @@ -330,10 +365,10 @@ jobs: shell: pwsh - name: Download WinFsp run: | - curl --silent --fail-with-body --proto "=https" -L ${{ env.WINFSP_MSI }} --output $env:WINFSP_PATH - $computedHash = (Get-FileHash -Path $env:WINFSP_PATH -Algorithm SHA256).Hash.ToLower() - if ($computedHash -ne "${{ env.WINFSP_MSI_HASH }}") { - throw "Checksum mismatch for $env:WINFSP_PATH (expected ${{ env.WINFSP_MSI_HASH }}, got $computedHash)." + curl --silent --fail-with-body --proto "=https" -L "$env:WINFSP_MSI" --output $env:WINFSP_PATH + $computedHash = (Get-FileHash -Path "$env:WINFSP_PATH" -Algorithm SHA256).Hash.ToLower() + if ($computedHash -ne "$env:WINFSP_MSI_HASH") { + throw "Checksum mismatch for ${env:WINFSP_PATH} (expected ${env:WINFSP_MSI_HASH}, got $computedHash)." } env: WINFSP_PATH: 'dist/win/bundle/resources/winfsp.msi' @@ -347,7 +382,7 @@ jobs: run: > wix build -define BundleName="Cryptomator" - -define BundleVersion="${{ needs.get-version.outputs.semVerNum }}.${{ needs.get-version.outputs.revNum}}" + -define BundleVersion="${VERSION_NUM}.${REVISION_NUM}" -define BundleVendor="Skymatic GmbH" -define BundleCopyright="(C) 2016 - 2026 Skymatic GmbH" -define AboutUrl="https://cryptomator.org" @@ -356,12 +391,13 @@ jobs: -ext "WixToolset.Util.wixext" -ext "WixToolset.BootstrapperApplications.wixext" ./bundle/bundleWithWinfsp.wxs - -out "../../installer/unsigned/Cryptomator-Installer.exe" + -out "../../installer/Cryptomator-Installer.exe" - name: Detach burn engine in preparation to sign + if: inputs.sign || github.event_name == 'schedule' run: > - wix burn detach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe + wix burn detach installer/Cryptomator-Installer.exe -engine tmp/engine.exe - name: Sign WiX burn engine with Azure Trusted Signing - if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule' + if: inputs.sign || github.event_name == 'schedule' uses: ./.github/actions/win-sign-action with: base-dir: ${{ github.workspace }}\tmp @@ -372,10 +408,13 @@ jobs: client-id: ${{ secrets.AZURE_CLIENT_ID }} client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} - name: Reattach signed burn engine to installer - run: > - wix burn reattach installer/unsigned/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe + if: inputs.sign || github.event_name == 'schedule' + shell: pwsh + run: | + Move-Item -Path installer/Cryptomator-Installer.exe -Destination tmp/Cryptomator-Installer.exe + wix burn reattach tmp/Cryptomator-Installer.exe -engine tmp/engine.exe -o installer/Cryptomator-Installer.exe - name: Sign EXE installer with Azure Trusted Signing - if: inputs.sign || github.event_name == 'release' || github.event_name == 'schedule' + if: inputs.sign || github.event_name == 'schedule' uses: ./.github/actions/win-sign-action with: base-dir: ${{ github.workspace }}\installer @@ -385,8 +424,12 @@ jobs: tenant-id: ${{ secrets.AZURE_TENANT_ID }} client-id: ${{ secrets.AZURE_CLIENT_ID }} client-secret: ${{ secrets.AZURE_CLIENT_SECRET }} + - id: sha256sum + run: | + read -ra CMD_OUTPUT < <(sha256sum installer/Cryptomator-*.exe) + echo "value=${CMD_OUTPUT[0]}" >> $GITHUB_OUTPUT - name: Add possible alpha/beta tags to installer name - run: mv installer/Cryptomator-Installer.exe Cryptomator-${{ needs.get-version.outputs.semVerStr }}-${{ matrix.executable-suffix }}.exe + run: mv installer/Cryptomator-Installer.exe "Cryptomator-${VERSION_NUM}${VERSION_SUFFIX}-${{ matrix.executable-suffix }}.exe" - name: Create detached GPG signature with key 615D449FE6E6A235 run: | echo "${GPG_PRIVATE_KEY}" | gpg --batch --quiet --import @@ -405,12 +448,9 @@ jobs: publish: name: Publish installers to the github release - if: startsWith(github.ref, 'refs/tags/') && github.event.action == 'published' + if: github.event_name == 'workflow_call' runs-on: ubuntu-latest needs: [ build-msi, build-exe ] - outputs: - download-url-msi-x64: ${{ fromJSON(steps.publish.outputs.assets)[0].browser_download_url }} - download-url-exe-x64: ${{ fromJSON(steps.publish.outputs.assets)[2].browser_download_url }} steps: - name: Download installers uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -420,43 +460,10 @@ jobs: id: publish uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe # v2.6.1 with: + draft: true fail_on_unmatched_files: true token: ${{ secrets.CRYPTOBOT_RELEASE_TOKEN }} - # do not change ordering of filelist, required for correct job output files: | *x64.msi *x64.exe *.asc - - allowlist-msi-x64: - uses: ./.github/workflows/av-whitelist.yml - needs: [ publish ] - with: - url: ${{ needs.publish.outputs.download-url-msi-x64 }} - secrets: inherit - - allowlist-exe-x64: - uses: ./.github/workflows/av-whitelist.yml - needs: [ publish, allowlist-msi-x64 ] - with: - url: ${{ needs.publish.outputs.download-url-exe-x64 }} - secrets: inherit - - notify-winget: - name: Notify for winget-release - if: needs.get-version.outputs.versionType == 'stable' - needs: [publish, get-version] - runs-on: ubuntu-latest - steps: - - name: Slack Notification - uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661 # v2.3.3 - env: - SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_CRYPTOMATOR_DESKTOP }} - SLACK_USERNAME: 'Cryptobot' - SLACK_ICON: false - SLACK_ICON_EMOJI: ':bot:' - SLACK_CHANNEL: 'cryptomator-desktop' - SLACK_TITLE: "MSI packages of ${{ github.event.repository.name }} ${{ github.event.release.tag_name }} published." - SLACK_MESSAGE: "Ready to ." - SLACK_FOOTER: false - MSG_MINIMAL: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 25b940a11..e6fe7f1f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,9 +8,10 @@ The changelog starts with version 1.19.0. Changes to prior versions can be found on the [Github release page](https://github.com/cryptomator/cryptomator/releases). -## [Unreleased](https://github.com/cryptomator/cryptomator/compare/1.19.1...HEAD) +## [Unreleased](https://github.com/cryptomator/cryptomator/compare/1.19.2...HEAD) -No changes yet. +### Changed +* Refactored release pipeline to allow immutable releases ([#4205](https://github.com/cryptomator/cryptomator/pull/4205)) ## [1.19.2](https://github.com/cryptomator/cryptomator/releases/1.19.2) - 2026-03-20