Skip to content

feat(release): publish a Linux .deb alongside the AppImage - #4887

Open
NaveDanan wants to merge 1 commit into
pingdotgg:mainfrom
NaveDanan:feat/release-linux-deb
Open

feat(release): publish a Linux .deb alongside the AppImage#4887
NaveDanan wants to merge 1 commit into
pingdotgg:mainfrom
NaveDanan:feat/release-linux-deb

Conversation

@NaveDanan

@NaveDanan NaveDanan commented Jul 29, 2026

Copy link
Copy Markdown

Problem

Linux is the only platform where T3 Code ships a single artifact. The AppImage works, but installing it leaves users without a desktop entry, an icon, dependency resolution, or any package manager integration unless they wire all of it up by hand. .deb covers the large majority of Linux desktop users and costs one extra packaging pass over an app we have already compiled.

What changed

Made --target deb actually work. scripts/build-desktop-artifact.ts already forwarded --target straight through to electron-builder, so deb looked supported. It was not: fpm aborts unless it can resolve a project homepage and a Name <email> maintainer, and the generated config set neither, because AppImage never needed them.

⨯ Please specify project homepage, see https://www.electron.build/configuration#metadata
  Please specify author 'email' in the application package.json
  It is required to set Linux .deb package maintainer.

Two fields fix it — homepage on the staged package.json and linux.maintainer, which becomes both the deb Maintainer and Vendor.

Release workflow builds and publishes it. A platform-gated step reruns packaging with --skip-build, reusing the app the AppImage step already compiled, then .deb is added to the collect and publish globs. This deliberately avoids a second Linux matrix leg, which would have duplicated a ~25 minute compile and collided on the desktop-linux-x64 and resource-monitor-linux-x64 artifact names.

Guarded the updater manifest. FpmTarget sets isWriteUpdateInfo: true, exactly like AppImageTarget, so the deb build overwrites latest-linux.yml. DesktopUpdates.ts refuses to install any Linux update unless the app is running from an AppImage, so an unguarded version of this change would publish a manifest pointing at a .deb the app rejects and silently break auto-update for every existing AppImage user. The workflow stashes the manifest and restores it after packaging.

Also adds vp run dist:desktop:linux:deb for local parity with dist:desktop:linux, and documents the artifact plus the update caveat.

Verification

Built end-to-end on Ubuntu 24.04 at v0.0.31:

Package: t3code          Architecture: amd64
Version: 0.0.31          Maintainer: pingdotgg <support@t3.codes>
Homepage: https://t3.codes
Depends: libgtk-3-0, libnotify4, libnss3, libxss1, libxtst6,
         xdg-utils, libatspi2.0-0, libuuid1, libsecret-1-0
  • All 9 hicolor icon sizes present; packaged icon is pixel-identical to assets/prod/black-universal-1024.png.
  • Valid desktop entry with StartupWMClass=t3code; postinst registers /usr/bin/t3code and handles chrome-sandbox permissions.
  • Every declared dependency resolves on 24.04 (libgtk-3-0 and libatspi2.0-0 via the t64 packages that Provide them).
  • New regression test fails if linux.maintainer is removed, so the build break cannot silently return.
  • vp test run scripts/build-desktop-artifact.test.ts (31 passed), scripts typecheck, lint, and fmt:check all clean.
  • Workflow shell logic simulated in isolation under set -euo pipefail, including the case where no manifest exists.

Notes for reviewers

The maintainer address needs your call. The repo has no packaging contact anywhere, so support@t3.codes is a placeholder derived from the site. It gets baked permanently into every published package — please replace it if there is a real address.

In-app updates are intentionally not enabled for deb. The .deb ships both app-update.yml and electron-builder's package-type marker, so electron-updater would select DebUpdater, but T3's own Linux gate blocks it first and deb users will see "Automatic updates on Linux require running the AppImage build." Turning that on means accepting a pkexec dpkg -i prompt per update and pointing the feed at the deb, which is a separate decision I did not make here. Most distro-packaged apps leave updates to the package manager.

Scope. .snap was built and verified alongside this but is deliberately excluded: it needs a Snap Store account, credentials, and manual review for classic confinement, which is a product decision rather than a packaging one. Happy to open it separately if wanted.

Per CONTRIBUTING.md I recognise this may not be something you want right now — close it freely if so.

Generated with claude-opus-5 running in opencode.


Note

Medium Risk
Release workflow changes affect Linux updater metadata and published assets; incorrect manifest handling could break AppImage auto-update, though the backup/restore step mitigates that. Maintainer email is baked into every deb package.

Overview
Adds a Linux .deb to release artifacts so Debian/Ubuntu users can install via the package manager, while in-app auto-update stays AppImage-only.

The desktop packager now supplies homepage and linux.maintainer (fpm requirements for deb) on the staged package.json and Linux build config, plus a dist:desktop:linux:deb script and a regression test so deb builds cannot break silently.

The release workflow runs a second Linux packaging pass with --skip-build after the AppImage step, backs up and restores *-linux*.yml updater manifests (deb packaging would overwrite them with .deb metadata the app refuses to install), and includes .deb in collect/publish globs. Docs note the deb vs AppImage update behavior.

Reviewed by Cursor Bugbot for commit a37813e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Publish a Linux .deb package alongside the AppImage in release builds

  • Adds a new build step in release.yml that runs dist:desktop:artifact with --target deb after the AppImage is built, stashing and restoring the AppImage update manifest so it isn't overwritten by the .deb build.
  • Adds maintainer and homepage metadata to the Linux build config in build-desktop-artifact.ts, which are required by electron-builder's fpm-backed targets like .deb.
  • Adds a dist:desktop:linux:deb npm script in package.json for local builds.
  • Behavioral Change: in-app updates are disabled when running from the .deb package; only the AppImage supports update delivery.

Macroscope summarized a37813e.

Linux users can only install T3 Code from an AppImage today, which means
no desktop entry, no icon, no dependency resolution, and no package
manager integration unless they wire it up themselves.

The build script already forwarded `--target` to electron-builder, but a
deb build aborted because fpm requires a project homepage and a
`Name <email>` maintainer that the generated config never set. Adding
those two fields makes `--target deb` work, and the release workflow now
repackages the already-compiled Linux app into a .deb and attaches it to
the GitHub Release.

electron-builder writes update metadata for every fpm target, so the deb
build would clobber the AppImage updater manifest. Since Linux
auto-update only supports the AppImage, the workflow stashes and restores
that manifest around the deb step.

Built and verified locally on Ubuntu 24.04: correct control fields, all
nine hicolor icon sizes, valid desktop entry, and every declared
dependency resolvable.

Generated with claude-opus-5 running in opencode.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bab04c96-54e4-4e31-bea4-00d6398d2f67

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Jul 29, 2026
@macroscopeapp

macroscopeapp Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved a37813e

This PR adds .deb packaging to the Linux release workflow without modifying runtime behavior. Changes are additive CI/CD configuration with proper manifest handling to preserve AppImage updates, appropriate constants for fpm requirements, and test coverage.

You can customize Macroscope's approvability policy. Learn more.

chukfinley added a commit to chukfinley/t3code that referenced this pull request Aug 6, 2026
The desktop build script already accepts `--target deb`; the target string is
passed through to electron-builder untouched and the artifact copy step is
target-agnostic. A deb build fails only because app-builder-lib's FpmTarget
requires two metadata fields the staged package.json omits: `homepage`
(control "Homepage:") and `maintainer` (control "Maintainer:", otherwise
derived from `author`, which carries no email). AppImage needs neither, so
nothing surfaced this.

Rather than add a second Linux matrix entry -- whose upload artifact name
`desktop-linux-x64` would collide with the AppImage entry's -- let the existing
Linux entry emit both targets from one electron-builder run. `--target` now
takes a comma-separated list, and artifactName's ${ext} already keeps the output
files distinct, so there is one artifact name, one runner, and no collision.

The .deb also has to be listed in the collect step and in both
action-gh-release file lists, or it builds and never ships.

Packages declare Electron's shared-library dependencies per format, so a
minimal Debian/Ubuntu install pulls them in instead of the app failing to
start. The same wiring covers `rpm`, exposed as `dist:desktop:rpm` for local
builds; the release workflow stays AppImage+deb because the runners have no
`rpmbuild`.

Consolidates the overlapping .deb work from pingdotgg#4887, pingdotgg#4900 and pingdotgg#5139: the
dependency lists and the rpm target come from @bigpod98's pingdotgg#5139, the docs and
the download-page card from @benthecarman's pingdotgg#4900.

The .deb is not an updater payload -- in-app updates on Linux stay
AppImage-only, so .deb installs upgrade through dpkg/apt. Documented in
docs/operations/release.md.
@masterflitzer

Copy link
Copy Markdown

you can just use gear lever to manage appimages, it has desktop integration & supports auto update: https://github.com/mijorus/gearlever

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants