Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/operations/connect-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,15 +119,15 @@ actual web and server ports. For example, with the default ports:
```sh
VITE_DEV_SERVER_URL=http://127.0.0.1:5733 \
T3CODE_PORT=13773 \
"/Applications/T3 Code (Alpha).app/Contents/MacOS/T3 Code (Alpha)"
"/Applications/T3 Code (Beta).app/Contents/MacOS/T3 Code (Beta)"
```

Rebuild the signed app after native dependency, main-process, preload, entitlement, provisioning,
or signing changes. Renderer edits can reuse it. Verify the installed bundle before testing:

```sh
codesign --verify --deep --strict "/Applications/T3 Code (Alpha).app"
codesign -d --entitlements :- "/Applications/T3 Code (Alpha).app"
codesign --verify --deep --strict "/Applications/T3 Code (Beta).app"
codesign -d --entitlements :- "/Applications/T3 Code (Beta).app"
```

## Restricting sign-ups
Expand Down
8 changes: 7 additions & 1 deletion docs/operations/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ This document covers the unified release workflow for stable and nightly desktop
Beta is the product label, not a release channel or version suffix. Release channels
remain stable and nightly. To ship 0.1.0 Beta, use `channel=stable` and
`version=0.1.0`. Removing the Beta label later is a branding change independent of
the version.
the version. Keep the macOS executable name `T3 Code (Beta)` unchanged so
Squirrel.Mac can relaunch after label or channel changes. The nightly DMG still
installs as `T3 Code (Nightly).app`, beside stable, so the `t3-code@nightly`
Homebrew cask needs no change. One exception, for the first nightly with this name: a
nightly installed before it, with no stable app beside it, moves to `T3 Code (Beta).app`
and doesn't relaunch, leaving the cask's app missing. Say so in that nightly's notes:
`brew reinstall --cask t3-code@nightly`, then delete the moved `T3 Code (Beta).app`.

## What the workflow does

Expand Down
39 changes: 39 additions & 0 deletions scripts/build-desktop-artifact.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,45 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
}),
);

it.effect("keeps the macOS bundle filename stable across product names", () =>
Effect.gen(function* () {
const stable = yield* createBuildConfig(
"mac",
"dmg",
"0.1.0",
false,
false,
undefined,
undefined,
);
const nightly = yield* createBuildConfig(
"mac",
"dmg",
"0.1.1-nightly.20261017.3238",
false,
false,
undefined,
undefined,
);

// Existing installs live at this path; changing it fails their relaunch.
assert.notEqual(stable.productName, nightly.productName);
assert.equal((stable.mac as { executableName: string }).executableName, "T3 Code (Beta)");
assert.equal((nightly.mac as { executableName: string }).executableName, "T3 Code (Beta)");
// A fresh nightly install must not land on, and replace, the stable app.
const dmgAppName = (config: typeof stable) =>
(config.dmg as { contents: ReadonlyArray<{ name?: string }> }).contents[0]?.name;
assert.equal(dmgAppName(stable), "T3 Code (Beta).app");
assert.equal(dmgAppName(nightly), "T3 Code (Nightly).app");
}).pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({ env: { GITHUB_REPOSITORY: "pingdotgg/t3code" } }),
),
),
),
);

it.effect("omits update feeds for pull request preview builds", () =>
Effect.gen(function* () {
const preview = yield* createBuildConfig(
Expand Down
9 changes: 8 additions & 1 deletion scripts/build-desktop-artifact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ import { ChildProcess, ChildProcessSpawner } from "effect/process";

const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const;
const DESKTOP_APP_ID = "com.t3tools.t3code";

// Squirrel.Mac renames an install named after its executable to the update's executable,
// then relaunches from the old path. One executable name for every channel keeps it in place.
const MAC_BUNDLE_FILENAME = "T3 Code (Beta)";
const APPLE_TEAM_ID_PATTERN = /^[A-Z0-9]{10}$/u;

const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);
Expand Down Expand Up @@ -2829,6 +2833,7 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* (
const path = yield* Path.Path;
const repoRoot = yield* RepoRoot;
buildConfig.mac = {
executableName: MAC_BUNDLE_FILENAME,
Comment thread
ishaanko marked this conversation as resolved.
Resolved
target: target === "dmg" ? [target, "zip"] : [target],
icon: "icon.icns",
category: "public.app-category.developer-tools",
Expand Down Expand Up @@ -2892,7 +2897,9 @@ export const createBuildConfig = Effect.fn("createBuildConfig")(function* (
height: 432,
},
contents: [
{ x: 166, y: 214, type: "file" },
// Name the app after its channel so a nightly installs beside stable. Squirrel.Mac
// never renames a bundle whose folder differs from its executable, so it stays put.
{ x: 166, y: 214, type: "file", name: `${resolveDesktopProductName(version)}.app` },
{ x: 474, y: 214, type: "link", path: "/Applications" },
],
iconSize: 120,
Expand Down
Loading