Skip to content

fix(linux): stop shipping the broken snap so the release writes latest-linux.yml - #145

Merged
dantheuber merged 9 commits into
mainfrom
fix/linux-snap-publish-blocks-latest-yml
Aug 17, 2026
Merged

fix(linux): stop shipping the broken snap so the release writes latest-linux.yml#145
dantheuber merged 9 commits into
mainfrom
fix/linux-snap-publish-blocks-latest-yml

Conversation

@dantheuber

@dantheuber dantheuber commented Aug 17, 2026

Copy link
Copy Markdown
Owner

Follow-up to #142. The Linux job in that release actually failed — the AppImage and deb you see on the v1.8.8 and v1.8.9 drafts were uploaded before the failure, and latest-linux.yml never got written. Without it, electron-updater has no update metadata for Linux, so in-app updates still don't work there.

The fix ended up being to stop building the snap, not to publish it elsewhere. The investigation took a few turns; the reasoning is below so the config comments make sense.

What happened

From the v1.8.8 run (job log):

• uploading   file=clipless_1.8.8_amd64.snap provider=snapStore
• building    target=deb arch=x64 file=dist/clipless_1.8.8_amd64.deb
⨯ snapcraft is not installed, please: sudo snap install snapcraft --classic
• uploading   file=clipless_1.8.8_amd64.deb provider=github
⨯ app-builder process failed ERR_ELECTRON_BUILDER_CANNOT_EXECUTE

SnapTarget.findSnapPublishConfig falls back to { provider: "snapStore" } for snap artifacts unless a snap-specific publish config names some other provider — linux.publish and the top-level publish are only consulted if they contain a snapStore entry. So the snap was routed to the Snap Store, which requires the snapcraft binary (and store credentials) on the runner. The build aborted there, before the publish finalization that emits latest-linux.yml.

Note the snap itself builds fine without snapcraft — electron-builder packs it from a template app with mksquashfs. Only the store upload needs the toolchain, which is why this never showed up in a local build:linux.

Why the snap is gone rather than redirected

Routing the snap to the GitHub draft release fixed CI, so the first version of this PR did exactly that. Installing the resulting snap showed it was broken at runtime:

$ snap run clipless
MESA-LOADER: failed to open radeonsi (search paths /snap/clipless/x3/gnome-platform/usr/...)

electron-builder's snap template pins base: core20 with the gnome-3-28-1804 platform, whose Mesa is 20.0.8 (2020). On current GPUs every DRI driver in it fails to load — including swrast — so the app segfaults during GPU init, and no runtime flag avoids it. Bumping electron-builder to 26.15.7 (kept in this PR) did not help.

Shipping a snap that cannot start is worse than shipping none, so snap comes off linux.target. Reviving it means base: core24 with gnome-46-2404 and the mesa-2404 content snap, built through the real snapcraft toolchain rather than the template — a separate piece of work.

The snap.publish block stays even though nothing builds a snap today. It's a guard: without it, re-adding the snap target would silently route to the Snap Store again and break Linux auto-update the same way. Both that block and the linux.target list carry comments explaining this.

Result

Linux now builds AppImage + deb, and a full --linux build emits dist/latest-linux.yml:

version: 1.8.10
files:
  - url: clipless-1.8.10.AppImage
    ...
  - url: clipless_1.8.10_amd64.deb
    ...
path: clipless-1.8.10.AppImage

Both artifacts are listed, which is what AppImageUpdater and DebUpdater each need. README's Linux install section is updated to match the formats actually shipped.

Also in this PR

Unrelated to the release pipeline, but found while verifying Linux builds by hand:

  • fix(dev): dev builds get their own userData profile. Dev shared ~/.config/clipless with an installed Clipless, and therefore its single-instance lock. With an installed copy in the tray, npm run dev lost the lock, quit, and the installed app handled second-instance by focusing its own window — a window appeared, the freshly built code never ran, and nothing said so. Rebuilding and reinstalling could not break the loop, because the stale process was never restarted. The redirect is a side-effect module imported first in index.ts, not a call in its body: the storage singleton derives its path from userData in a constructor that runs at import time, and ES imports evaluate before the importing module's statements.
  • chore(renderer): drop dead settings.css link. settings.html linked a file that doesn't exist; the real stylesheet comes from settings-main.tsx.
  • okf bundle: gotcha documenting the dev/installed shadowing above.

Notes

  • electron-builder 26 logs a deprecation notice suggesting snapcraft.<core> over snap. The snap key is kept deliberately — snapcraft selects a base and switches to the real snapcraft toolchain, which is the CI dependency this PR removes. Worth revisiting only if we publish to the Snap Store.
  • publish.releaseType: draft still means a draft has to be published before any platform sees an update.
  • Version bumped to 1.8.10 (required by PR validation).

electron-builder falls back to { provider: snapStore } for snap artifacts
whenever no snap-specific publish config names a different provider
(SnapTarget.findSnapPublishConfig). The Snap Store upload needs snapcraft
on the build machine, which CI does not have, so the linux job died with
'snapcraft is not installed' *after* uploading the AppImage and deb but
*before* electron-builder wrote the updater metadata. That is why the
v1.8.8 and v1.8.9 drafts carry Linux artifacts but no latest-linux.yml,
leaving Linux auto-update non-functional.

Point the snap at the same GitHub draft release as every other artifact.
Verified locally: the snap now resolves to 'provider=github', and a full
linux build emits latest-linux.yml listing the AppImage and the deb.
@github-actions

Copy link
Copy Markdown

📊 Coverage Report

Metric Coverage
Statements 100%
Branches 100%
Functions 100%
Lines 100%

@github-actions

Copy link
Copy Markdown

🧪 E2E Test Results

18 passed, 0 failed, 0 skipped

Test Suite Result
App Launch
Clipboard
Context Menu
Image Clipboard
Quick Clips
Settings
Theme
Settings — Search Terms CRUD
Settings — Quick Tools CRUD
Settings — Templates CRUD
Tools Launcher — Pattern Scanning
Tools Launcher — Clip Templates

package.json still carried the electron-vite template description, which
electron-builder propagates into the Snap Store listing, the deb control
file and the desktop entry Comment. Set it to the real tagline before the
snap is published to the store.
Publishing from inside the electron-builder run makes a store outage or a
rejected review abort the linux job before latest-linux.yml is written,
silently breaking auto-update for the deb and AppImage. Upload separately
with continue-on-error, gated on the SNAPCRAFT_STORE_CREDENTIALS secret so
forks and credential-less runs skip it cleanly. Lands on edge; promotion to
stable stays manual, matching the draft-release flow.
electron-builder 26.15.3 downloads the snap template as a .tar.7z and only
un-7zips it, leaving the raw .tar in the directory it hands to mksquashfs.
The template's desktop-init.sh, desktop-common.sh and desktop-gnome-specific.sh
therefore never make it into the snap, while the tar itself gets packed at the
snap root. command.sh execs desktop-init.sh, so the app dies instantly:

  /snap/clipless/x2/command.sh: line 2:
  /snap/clipless/x2/desktop-init.sh: No such file or directory

The 1.8.7 snap (built on electron-builder 25) has the scripts, so this is a
regression from the 26.x bump. 26.15.7 extracts the template correctly.

Verified on 26.15.7: all three desktop scripts are present, no stray tar is
packed, a full --linux build still emits latest-linux.yml listing the
AppImage and the deb, and the snap still routes to provider=github.
electron-builder's snap template pins base: core20 with the gnome-3-28-1804
platform, whose Mesa is 20.0.8 (2020). On current GPUs (verified on an AMD
Strix Halo / Radeon 8060S) every DRI driver in it fails to load — radeonsi,
kms_swrast and swrast alike — so EGL init fails and the app segfaults before
a window appears. --disable-gpu, --use-gl=disabled and
--disable-software-rasterizer all still segfault, because the loader failures
come from GTK in the main process, not just the GPU process.

Reviving it means base: core24 with gnome-46-2404 and the mesa-2404 content
snap, built through the real snapcraft toolchain instead of the prebuilt
template — its own piece of work. Until then, don't ship a binary that
crashes on modern hardware. AppImage and deb both work and both auto-update.
Dev builds shared the installed app's userData directory, and with it the
single-instance lock. With an installed Clipless running in the tray,
`npm run dev` lost the lock, quit immediately, and the installed copy
handled 'second-instance' by focusing its own window -- so a window
appeared, the freshly built code never ran, and nothing indicated which
build was on screen. Rebuilding and reinstalling could not break the
loop, because the stale process was never restarted.

Dev now runs against <userData>-dev, which also stops dev runs from
mutating real clip history.

The redirect is a side-effect module imported first in index.ts rather
than a call in its body: the storage singleton derives its path from
userData in a constructor that runs at import time, and ES module
imports are evaluated before the importing module's statements.
settings.html linked ./settings.css, which does not exist -- the real
stylesheet is imported by settings-main.tsx and emitted into assets/.
The tag only produced a failed request.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to ensure Linux release builds complete successfully and produce the latest-linux.yml metadata needed for electron-updater, while also improving developer ergonomics by isolating dev userData from installed builds.

Changes:

  • Adjust Linux packaging/publish configuration to prevent CI failure and allow updater metadata generation.
  • Add a dev-only userData suffix to avoid single-instance lock collisions between npm run dev and an installed app.
  • Bump version to 1.8.10 and update build tooling/docs accordingly.

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/renderer/settings.html Removes a direct stylesheet link; relies on the TS entrypoint for styling.
src/main/index.ts Imports a side-effect module first to redirect userData in dev before other imports run.
src/main/dev-profile.ts New dev-only app.setPath('userData', …-dev) to prevent dev/installed profile collisions.
README.md Updates Linux install docs to reflect the currently shipped formats.
package.json Bumps app version and updates electron-builder dependency.
package-lock.json Lockfile updates corresponding to the version/dependency bump.
okf-bundle/log.md Adds an update-log entry documenting the dev/installed single-instance lock gotcha.
okf-bundle/gotchas/index.md Index entry for the new gotcha document.
okf-bundle/gotchas/dev-builds-defer-to-an-installed-instance.md New gotcha documentation describing the failure mode and mitigations.
electron-builder.yml Updates Linux targets/publish configuration and adds snap-related commentary/config scaffolding.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread electron-builder.yml
@dantheuber dantheuber changed the title fix(ci): publish snap to GitHub so latest-linux.yml is generated fix(linux): stop shipping the broken snap so the release writes latest-linux.yml Aug 17, 2026
@dantheuber
dantheuber merged commit 4155514 into main Aug 17, 2026
1 check passed
@dantheuber
dantheuber deleted the fix/linux-snap-publish-blocks-latest-yml branch August 17, 2026 04:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants