Files
proton-drive-linux/.github/workflows/release.yml
T
nvrl e0442c56b9 fix(packaging): stop the service before the package is removed
Removing the package left the user service running from the deleted
binary, with ~/ProtonDrive still mounted. A user who then deleted the
folder to clean up had every file in it moved to the Proton Drive trash,
as any delete through the mount is.

The .deb (prerm on remove), the .rpm (%preun on erase) and the Arch
packages (pre_remove) now stop proton-drive.service for every user with
a running user manager, through runuser with that user's
XDG_RUNTIME_DIR, so no systemd-machined is needed. Upgrades are left
alone. Queued writes stay in the state directory for a later install.

The pacman install script lives once in packaging/ and the AUR
directories link it; push.sh copies its content into each AUR
repository. The uninstall guide now warns not to delete the mount point
while the service runs.

Reported on Reddit by a user who restored the files from the trash.
2026-10-12 00:07:07 +02:00

315 lines
10 KiB
YAML

name: Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: write
jobs:
checks:
name: Release quality gates
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
pkg-config \
libfuse3-dev \
libgtk-4-dev \
libadwaita-1-dev \
libwebkitgtk-6.0-dev \
libsecret-1-dev \
libdbus-1-dev
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: '1.96'
components: rustfmt, clippy
cache: false
# A tag can read the caches of main but its own caches are useless to the next
# tag, so this only restores what CI saved on main.
- name: Cache Cargo target
uses: swatinem/rust-cache@v2
with:
shared-key: debug
save-if: false
- name: Verify tag and manifest versions
if: startsWith(github.ref, 'refs/tags/')
shell: bash
run: |
tag_version="${GITHUB_REF_NAME#v}"
manifest_version="$(sed -n 's/^version = "\([^"]*\)"/\1/p' Cargo.toml | head -n1)"
pkgbuild_version="$(sed -n 's/^pkgver=//p' packaging/PKGBUILD | head -n1)"
test "$tag_version" = "$manifest_version"
test "$tag_version" = "$pkgbuild_version"
- name: Release quality gates
run: |
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --locked
scripts/fuse-acceptance.sh --offline-only
build-release:
name: Build packages
runs-on: ubuntu-24.04
environment: 'rpm signing'
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
pkg-config \
libfuse3-dev \
libgtk-4-dev \
libadwaita-1-dev \
libwebkitgtk-6.0-dev \
libsecret-1-dev \
libdbus-1-dev \
desktop-file-utils \
gettext \
rpm
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: '1.96'
cache: false
# Restores the release-profile dependencies that CI builds on main.
- name: Cache Cargo target
uses: swatinem/rust-cache@v2
with:
shared-key: release
save-if: false
- name: Build release binaries
run: |
cargo build --release --locked
- name: Determine version
run: |
if [[ $GITHUB_REF == refs/tags/* ]]; then
# Extract version from tag (e.g. v0.1.0 -> 0.1.0)
VERSION=${GITHUB_REF#refs/tags/}
VERSION=${VERSION#v}
else
# Fallback for manual workflow runs: extract version from Cargo.toml
VERSION=$(grep -m1 '^version' Cargo.toml | cut -d'"' -f2)
VERSION="${VERSION}-dev-${GITHUB_SHA::7}"
fi
echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "Building version: $VERSION"
- name: Package raw binaries (.tar.gz)
run: |
mkdir -p dist/binaries
cp target/release/pdfs dist/binaries/
cp target/release/pdfs-tray dist/binaries/
cp target/release/pdfs-app dist/binaries/
cp target/release/pdfs-prompt dist/binaries/
po/build.sh dist/binaries/locale
# Create tarball
tar -czf proton-drive-linux-${{ env.VERSION }}-x86_64.tar.gz -C dist/binaries .
- name: Package Debian package (.deb)
run: |
mkdir -p deb/DEBIAN
mkdir -p deb/usr/bin
mkdir -p deb/usr/share/applications
mkdir -p deb/usr/share/icons/hicolor/scalable/apps
mkdir -p deb/usr/share/licenses/proton-drive-linux
mkdir -p deb/usr/lib/systemd/user
mkdir -p deb/etc/xdg/autostart
# Copy binaries
cp target/release/pdfs deb/usr/bin/
cp target/release/pdfs-tray deb/usr/bin/
cp target/release/pdfs-app deb/usr/bin/
cp target/release/pdfs-prompt deb/usr/bin/
# Copy desktop integration files
cp packaging/io.narl.proton-drive-linux.desktop deb/usr/share/applications/
cp packaging/io.narl.proton-drive-linux-tray.desktop deb/etc/xdg/autostart/
cp packaging/io.narl.proton-drive-linux.svg deb/usr/share/icons/hicolor/scalable/apps/
cp packaging/proton-drive.service deb/usr/lib/systemd/user/
cp LICENSE deb/usr/share/licenses/proton-drive-linux/
po/build.sh deb/usr/share/locale
# Stops the running daemon before removal, so the mount stops mirroring deletes
install -m755 packaging/deb/prerm deb/DEBIAN/prerm
# Calculate Installed-Size in KB for the control file
INSTALLED_SIZE=$(du -sk deb | cut -f1)
# Write DEBIAN/control file
cat <<EOF > deb/DEBIAN/control
Package: proton-drive-linux
Version: ${{ env.VERSION }}
Section: utils
Priority: optional
Architecture: amd64
Maintainer: Nils Pukropp <contact@narl.io>
Depends: fuse3, libgtk-4-1 (>= 4.12.0), libadwaita-1-0 (>= 1.5.0), libsecret-1-0, libwebkitgtk-6.0-4, libimage-exiftool-perl
Installed-Size: ${INSTALLED_SIZE}
Homepage: https://proton-drive.narl.io
Description: Unofficial Proton Drive client for Linux
Files-on-demand Proton Drive for the Linux desktop, unaffiliated with Proton AG:
- FUSE virtual mount with block-level caching
- Scriptable command-line interface (pdfs)
- GTK4 desktop application, system tray, and search launcher
EOF
# Build Debian package
dpkg-deb --build deb proton-drive-linux_${{ env.VERSION }}_amd64.deb
- name: Package Fedora package (.rpm)
run: |
# Sanitize version (replace hyphens with dots for RPM compatibility)
RPM_VERSION=$(echo "${{ env.VERSION }}" | tr '-' '.')
# Create RPM build directories
mkdir -p rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS,BUILDROOT,db}
# Build RPM package
rpmbuild -bb \
--nodeps \
--define "_topdir $PWD/rpmbuild" \
--define "_sourcedir $PWD" \
--define "git_dir $PWD" \
--define "prebuilt 1" \
--define "version ${RPM_VERSION}" \
--define "_dbpath $PWD/rpmbuild/db" \
packaging/proton-drive-linux.spec
# Copy built RPM to root directory
cp rpmbuild/RPMS/x86_64/*.rpm .
- name: Sign Fedora package (.rpm)
env:
GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }}
GPG_KEY_NAME: ${{ secrets.GPG_KEY_NAME }}
GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
run: |
if [ -n "$GPG_PRIVATE_KEY" ] && [ -n "$GPG_KEY_NAME" ]; then
echo "$GPG_PRIVATE_KEY" | gpg --batch --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" --import
cat <<EOF > ~/.rpmmacros
%_signature gpg
%_gpg_name ${GPG_KEY_NAME}
%__gpg_sign_cmd %{__gpg} gpg --batch --verbose --no-armor --pinentry-mode loopback --passphrase %{_gpg_passphrase} --no-secmem-warning -u "%{_gpg_name}" -sbo %{__signature_filename} --digest-algo sha256 %{__plaintext_filename}
EOF
rpm --addsign --define "_gpg_passphrase $GPG_PASSPHRASE" *.rpm
else
echo "Skipping RPM signing: GPG_PRIVATE_KEY or GPG_KEY_NAME secret is not set."
fi
- name: Upload Workflow Artifacts
uses: actions/upload-artifact@v7
with:
name: proton-drive-linux-builds
path: |
*.deb
*.tar.gz
*.rpm
if-no-files-found: error
# The flake is the Nix release: a tag is what `github:narrrl/proton-drive-linux/vX.Y.Z`
# pins, so it has to build before the release is announced.
nix:
name: Build the Nix package
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- uses: cachix/install-nix-action@v31
# Pulls from the project's binary cache, and pushes what this run built
# when the token is there; a fork's pull request has none and only pulls.
- uses: cachix/cachix-action@v17
with:
name: proton-drive-linux
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build the flake
run: nix build --print-build-logs .#proton-drive-linux
- name: Check the version
run: |
built="$(./result/bin/pdfs --version)"
echo "$built"
case "$GITHUB_REF" in
refs/tags/v*) grep -qF "${GITHUB_REF_NAME#v}" <<< "$built" ;;
esac
publish:
name: Create GitHub Release
needs: [checks, build-release, nix]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Download packages
uses: actions/download-artifact@v8
with:
name: proton-drive-linux-builds
# The release notes are this version's section of the changelog, from its
# heading up to the next one.
- name: Extract release notes
run: |
version="${GITHUB_REF_NAME#v}"
awk -v heading="## [$version]" \
'index($0, heading) == 1 { found = 1; print; next }
found && /^## \[/ { exit }
found' docs/CHANGELOG.md > release-notes.md
if [ ! -s release-notes.md ]; then
echo "::error::docs/CHANGELOG.md has no section for $version"
exit 1
fi
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
body_path: release-notes.md
files: |
*.deb
*.tar.gz
*.rpm
draft: false
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
aur:
name: Publish AUR packages
needs: publish
if: startsWith(github.ref, 'refs/tags/')
uses: ./.github/workflows/aur.yml
with:
version: ${{ github.ref_name }}
secrets:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}