Repository navigation
feat(packaging): add deb and rpm desktop targets #5139
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
2581322
feat(packaging): add deb and rpm desktop targets
bigpod98 03b684c
docs: revert scripts reference changes
bigpod98 8b75392
Merge branch 'main' into main
juliusmarminge 6f2eac5
Merge branch 'main' into main
bigpod98 ca035c7
Merge branch 'main' into main
bigpod98 bfd0201
feat(packaging): expose bundled headless server CLI
bigpod98 ab03901
fix(packaging): declare RPM runtime dependencies
bigpod98 a4f94d9
Merge branch 'main' into main
bigpod98 f5629f8
Merge branch 'main' into main
bigpod98 c88aa98
Merge branch 'main' into main
bigpod98 7153ea5
Merge branch 'main' into main
bigpod98 1373b12
Merge branch 'main' into main
bigpod98 3b649e9
Merge branch 'main' into main
bigpod98 4b56f00
Merge branch 'main' into main
bigpod98 1b6acb1
Merge remote-tracking branch 'upstream/main'
bigpod98 1984602
Merge branch 'main' into main
bigpod98 ab4f478
feat(release): publish the Linux .deb and .rpm from the release workflow
chukfinley 306e95c
Merge pull request #1 from chukfinley/feat/linux-deb-rpm-release-wiring
bigpod98 4d2e2ff
refactor(packaging): split out Linux headless launcher
raulferrodrigues 7ed2e88
Merge pull request #2 from raulferrodrigues/main
bigpod98 c882349
Merge branch 'main' into main
bigpod98 473d2d6
Add 'libgbm1' to desktop artifact dependencies
bigpod98 703f72c
Fix formatting of RPM dependencies in build script
bigpod98 b95d7cb
test(packaging): include libgbm in deb dependencies
bigpod98 c9fb83c
Merge branch 'pingdotgg:main' into main
bigpod98 124ff22
Merge branch 'main' into main
bigpod98 6cd7cb7
Merge branch 'main' into main
bigpod98 a223032
Merge branch 'main' into main
bigpod98 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ build/ | |
| .logs/ | ||
| release/ | ||
| release-mock/ | ||
| packaging-output/ | ||
| .t3 | ||
| .idea/ | ||
| apps/web/.playwright | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -38,6 +38,7 @@ import { | |
| resolveDesktopProductName, | ||
| resolveDesktopUpdateChannel, | ||
| resolveDesktopWebAssetBrand, | ||
| resolveLinuxTargets, | ||
| resolveResourceMonitorRustTargets, | ||
| resourceMonitorExecutableName, | ||
| resolveGitHubPublishConfig, | ||
|
|
@@ -935,6 +936,115 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { | |
| }).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))), | ||
| ); | ||
|
|
||
| it("splits a comma-separated Linux target into one target per package", () => { | ||
| assert.deepStrictEqual(resolveLinuxTargets("AppImage"), ["AppImage"]); | ||
| assert.deepStrictEqual(resolveLinuxTargets("AppImage,deb,rpm"), ["AppImage", "deb", "rpm"]); | ||
| assert.deepStrictEqual(resolveLinuxTargets(" AppImage , deb "), ["AppImage", "deb"]); | ||
| }); | ||
|
|
||
| it.effect("emits every requested Linux package from a single build", () => | ||
| Effect.gen(function* () { | ||
| const all = yield* createBuildConfig( | ||
| "linux", | ||
| "AppImage,deb,rpm", | ||
| "1.2.3", | ||
| false, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| ); | ||
| const appImageOnly = yield* createBuildConfig( | ||
| "linux", | ||
| "AppImage", | ||
| "1.2.3", | ||
| false, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| ); | ||
|
|
||
| assert.deepStrictEqual((all.linux as Record<string, unknown>).target, [ | ||
| "AppImage", | ||
| "deb", | ||
| "rpm", | ||
| ]); | ||
| // Both fpm-backed formats are configured from the one run. | ||
| assert.property(all, "deb"); | ||
| assert.property(all, "rpm"); | ||
|
|
||
| // An AppImage-only build stays free of package-format sections. | ||
| assert.notProperty(appImageOnly, "deb"); | ||
| assert.notProperty(appImageOnly, "rpm"); | ||
| }).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))), | ||
| ); | ||
|
|
||
| it.effect("includes distribution metadata in Linux package builds", () => | ||
| Effect.gen(function* () { | ||
| const config = yield* createBuildConfig( | ||
| "linux", | ||
| "deb", | ||
| "1.2.3", | ||
| false, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| ); | ||
|
|
||
| const linux = config.linux as Record<string, unknown>; | ||
| assert.deepStrictEqual(linux.target, ["deb"]); | ||
| assert.equal(linux.executableName, "t3code"); | ||
| assert.equal(linux.category, "Development"); | ||
| assert.equal(linux.maintainer, "T3 Tools <[email protected]>"); | ||
| assert.equal(linux.vendor, "T3 Tools"); | ||
| assert.equal(linux.synopsis, "A desktop GUI for AI coding agents"); | ||
| assert.equal(linux.syncDesktopName, true); | ||
|
|
||
| const deb = config.deb as Record<string, unknown>; | ||
| assert.deepStrictEqual(deb.depends, [ | ||
| "libgtk-3-0", | ||
| "libnotify4", | ||
| "libnss3", | ||
| "libxss1", | ||
| "libxtst6", | ||
| "xdg-utils", | ||
| "libatspi2.0-0", | ||
| "libuuid1", | ||
| "libsecret-1-0", | ||
| "libasound2t64 | libasound2", | ||
| "libgbm1", | ||
| ]); | ||
| }).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))), | ||
| ); | ||
|
|
||
| it.effect("includes runtime dependencies in RPM packages", () => | ||
| Effect.gen(function* () { | ||
| const config = yield* createBuildConfig( | ||
| "linux", | ||
| "rpm", | ||
| "1.2.3", | ||
| false, | ||
| false, | ||
| undefined, | ||
| undefined, | ||
| ); | ||
|
|
||
| const rpm = config.rpm as Record<string, unknown>; | ||
| assert.deepStrictEqual(rpm.depends, [ | ||
| "gtk3", | ||
| "libnotify", | ||
| "nss", | ||
| "libXScrnSaver", | ||
| "(libXtst or libXtst6)", | ||
| "xdg-utils", | ||
| "at-spi2-core", | ||
| "(libuuid or libuuid1)", | ||
| "alsa-lib", | ||
| "libsecret", | ||
| "mesa-libgbm", | ||
| ]); | ||
| }).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))), | ||
| ); | ||
|
|
||
| it("stages the resource monitor as an external executable resource", () => { | ||
| assert.deepStrictEqual(DESKTOP_EXTRA_RESOURCES, [ | ||
| { | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -149,6 +149,34 @@ const PLATFORM_CONFIG: Record<typeof BuildPlatform.Type, PlatformConfig> = { | |
| }, | ||
| }; | ||
|
|
||
| const DEB_DEPENDENCIES = [ | ||
| "libgtk-3-0", | ||
| "libnotify4", | ||
| "libnss3", | ||
| "libxss1", | ||
| "libxtst6", | ||
| "xdg-utils", | ||
| "libatspi2.0-0", | ||
| "libuuid1", | ||
| "libsecret-1-0", | ||
| "libasound2t64 | libasound2", | ||
| "libgbm1", | ||
| ] as const; | ||
|
cursor[bot] marked this conversation as resolved.
Resolved
|
||
|
|
||
| const RPM_DEPENDENCIES = [ | ||
| "gtk3", | ||
| "libnotify", | ||
| "nss", | ||
| "libXScrnSaver", | ||
| "(libXtst or libXtst6)", | ||
| "xdg-utils", | ||
| "at-spi2-core", | ||
| "(libuuid or libuuid1)", | ||
| "alsa-lib", | ||
| "libsecret", | ||
| "mesa-libgbm", | ||
| ] as const; | ||
|
|
||
| interface BuildCliInput { | ||
| readonly platform: Option.Option<typeof BuildPlatform.Type>; | ||
| readonly target: Option.Option<string>; | ||
|
|
@@ -763,6 +791,9 @@ interface StagePackageJson { | |
| readonly packageManager: string; | ||
| readonly description: string; | ||
| readonly author: string; | ||
| readonly homepage: string; | ||
| readonly license: string; | ||
| readonly desktopName: string; | ||
| readonly main: string; | ||
| readonly build: Record<string, unknown>; | ||
| readonly dependencies: Record<string, unknown>; | ||
|
|
@@ -1974,6 +2005,23 @@ export function resolveDesktopProductName(version: string): string { | |
| : (desktopPackageJson.productName ?? "T3 Code"); | ||
| } | ||
|
|
||
| /** | ||
| * Splits a comma-separated Linux target string, for example "AppImage,deb,rpm", | ||
| * so one electron-builder run emits every package from the same staged app. | ||
| * | ||
| * The alternative — one release-matrix entry per format — collides on the | ||
| * upload artifact name (`desktop-${platform}-${arch}` is identical for two | ||
| * entries that differ only by target), which is what sank #1655. artifactName's | ||
| * ${ext} already keeps the output files apart, so a single run needs no extra | ||
| * runner and no extra release wall-clock. | ||
| */ | ||
| export function resolveLinuxTargets(target: string): ReadonlyArray<string> { | ||
| return target | ||
| .split(",") | ||
| .map((entry) => entry.trim()) | ||
| .filter((entry) => entry.length > 0); | ||
| } | ||
|
|
||
| export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( | ||
| platform: typeof BuildPlatform.Type, | ||
| target: string, | ||
|
|
@@ -2040,11 +2088,16 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( | |
| } | ||
|
|
||
| if (platform === "linux") { | ||
| const linuxTargets = resolveLinuxTargets(target); | ||
| buildConfig.linux = { | ||
| target: [target], | ||
| target: linuxTargets, | ||
| executableName: "t3code", | ||
| icon: "icons", | ||
| category: "Development", | ||
| maintainer: "T3 Tools <[email protected]>", | ||
| vendor: "T3 Tools", | ||
| synopsis: "A desktop GUI for AI coding agents", | ||
| syncDesktopName: true, | ||
| // electron-builder turns these into MimeType=x-scheme-handler/<scheme>; | ||
| // in the .desktop entry (Exec already gets %U), so browsers can hand | ||
| // t3code:// OAuth callbacks to the app. | ||
|
|
@@ -2060,6 +2113,18 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* ( | |
| }, | ||
| }, | ||
| }; | ||
|
|
||
| if (linuxTargets.includes("deb")) { | ||
| buildConfig.deb = { | ||
| depends: [...DEB_DEPENDENCIES], | ||
| }; | ||
| } | ||
|
|
||
| if (linuxTargets.includes("rpm")) { | ||
| buildConfig.rpm = { | ||
| depends: [...RPM_DEPENDENCIES], | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| if (platform === "win") { | ||
|
|
@@ -2826,8 +2891,11 @@ const buildDesktopArtifact = Effect.fn("buildDesktopArtifact")(function* ( | |
| t3codeCommitHash: commitHash, | ||
| private: true, | ||
| packageManager: rootPackageJson.packageManager, | ||
| description: "T3 Code desktop build", | ||
| author: "T3 Tools", | ||
| description: "A desktop GUI for AI coding agents such as Codex, Claude, Cursor, and OpenCode.", | ||
| author: "T3 Tools <[email protected]>", | ||
| homepage: "https://github.com/pingdotgg/t3code", | ||
| license: "MIT", | ||
| desktopName: "t3code.desktop", | ||
| main: "apps/desktop/dist-electron/main.cjs", | ||
| build: yield* createBuildConfig( | ||
| options.platform, | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.