Skip to content
Closed
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
42 changes: 33 additions & 9 deletions .github/workflows/fork-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ name: Fork release
# deploy secrets, so this reuses only its per-platform packaging
# (release-desktop.yml) on GitHub-hosted runners.
#
# Builds are unsigned and carry a -preview.YYYYMMDD.N version, which ships no
# update feed (see isDesktopPreviewVersion in scripts/build-desktop-artifact.ts).
# An install never auto-updates, so it cannot jump to an upstream build; install
# a newer release to update.
# Builds carry a -fork.YYYYMMDD.N version. Unlike -preview, that ships an update
# feed, and the build points it at GITHUB_REPOSITORY, so installs update from
# this fork's latest release, never from upstream. macOS can only install an
# update when the app is signed; add the Apple secrets release-desktop.yml reads.

on:
push:
Expand Down Expand Up @@ -70,7 +70,7 @@ jobs:
run: |
set -euo pipefail
base_version="$(node -p "require('./apps/desktop/package.json').version")"
version="${base_version}-preview.$(date -u +%Y%m%d).${GITHUB_RUN_NUMBER}"
version="${base_version}-fork.$(date -u +%Y%m%d).${GITHUB_RUN_NUMBER}"
node scripts/update-release-package-versions.ts "$version"
echo "version=$version" >> "$GITHUB_OUTPUT"

Expand Down Expand Up @@ -127,25 +127,30 @@ jobs:
arch: x64
rust_target: x86_64-unknown-linux-gnu
resource_key: linux-x64
# Like release.yml: Windows packages on Linux and runs its native
# checks on a Windows runner.
- label: Windows x64
runner: windows-2025
runner: ubuntu-24.04
verify_runner: windows-2025
platform: win
target: nsis
arch: x64
rust_target: x86_64-pc-windows-msvc
resource_key: win32-x64
uses: ./.github/workflows/release-desktop.yml
secrets: inherit
with:
version: ${{ needs.bundle.outputs.version }}
ref: ${{ github.sha }}
release_channel: preview
release_channel: stable
relay_client_tracing: false
clerk_publishable_key: ${{ needs.bundle.outputs.clerk_publishable_key }}
clerk_jwt_template: ${{ needs.bundle.outputs.clerk_jwt_template }}
clerk_cli_oauth_client_id: ${{ needs.bundle.outputs.clerk_cli_oauth_client_id }}
relay_url: ${{ needs.bundle.outputs.relay_url }}
label: ${{ matrix.label }}
runner: ${{ matrix.runner }}
verify_runner: ${{ matrix.verify_runner || '' }}
platform: ${{ matrix.platform }}
target: ${{ matrix.target }}
arch: ${{ matrix.arch }}
Expand Down Expand Up @@ -175,6 +180,25 @@ jobs:
path: assets
merge-multiple: true

# electron-updater reads latest.yml on Windows; the build job suffixed it
# with the arch. builder-debug.yml is electron-builder's config dump.
- name: Restore updater manifest names
shell: bash
run: |
set -euo pipefail
rm -f assets/builder-debug.yml
mv assets/latest-win-x64.yml assets/latest.yml

# t3 update verifies the CLI archive it downloads against this file.
- name: Write CLI archive checksums
shell: bash
run: |
set -euo pipefail
cd assets
shopt -s nullglob
sha256sum t3-*.tar.gz t3-*.zip > SHA256SUMS
cat SHA256SUMS

- name: Publish release
shell: bash
env:
Expand All @@ -186,14 +210,14 @@ jobs:
cat > notes.md <<EOF
Built from ${GITHUB_REPOSITORY}@${short_sha}.

These builds are unsigned and do not update themselves. To update, install a newer release.
Installs check this repository for updates. On macOS, an unsigned build cannot install them: install a newer release instead.

- **macOS (Apple silicon):** open the \`.dmg\` and drag the app to Applications. If macOS says the app is damaged, run \`xattr -dr com.apple.quarantine "/Applications/T3 Code (Beta).app"\`.
- **Windows:** run the \`.exe\`. If SmartScreen blocks it, choose **More info**, then **Run anyway**.
- **Linux:** \`chmod +x\` the \`.AppImage\`, then run it.
- **CLI / headless server:** extract the \`t3\` archive for your platform.
EOF
gh release create "fork-v${VERSION}" assets/* \
gh release create "v${VERSION}" assets/* \
--repo "$GITHUB_REPOSITORY" \
--target "$GITHUB_SHA" \
--title "T3 Code ${VERSION}" \
Expand Down
15 changes: 10 additions & 5 deletions apps/mobile/src/features/settings/environment-maintenance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe("environment release checks", () => {
const signal = new AbortController().signal;
const feed = (...tags: ReadonlyArray<string>) =>
new Response(
`<feed><id>tag:github.com,2008:https://github.com/pingdotgg/t3code/releases</id>${tags
`<feed><id>tag:github.com,2008:https://github.com/ScriptedAlchemy/t3code/releases</id>${tags
.map((tag) => `<entry><id>tag:github.com,2008:Repository/1/${tag}</id></entry>`)
.join("")}</feed>`,
);
Expand All @@ -67,7 +67,7 @@ describe("environment release checks", () => {
vi.stubGlobal(
"fetch",
vi.fn(async (url: string) =>
url === "https://github.com/pingdotgg/t3code/releases.atom"
url === "https://github.com/ScriptedAlchemy/t3code/releases.atom"
? feed(
"desktop-preview",
"v1.0.0-preview.20260924.3",
Expand All @@ -93,11 +93,16 @@ describe("environment release checks", () => {
vi.stubGlobal(
"fetch",
vi.fn(async (url: string) => {
if (url === "https://github.com/pingdotgg/t3code/releases.atom") return feed(...nightlies);
if (url === "https://api.github.com/repos/pingdotgg/t3code/releases?per_page=100&page=1") {
if (url === "https://github.com/ScriptedAlchemy/t3code/releases.atom")
return feed(...nightlies);
if (
url === "https://api.github.com/repos/ScriptedAlchemy/t3code/releases?per_page=100&page=1"
) {
return Response.json(Array.from({ length: 100 }, () => ({ tag_name: "v2.0.0" })));
}
if (url === "https://api.github.com/repos/pingdotgg/t3code/releases?per_page=100&page=2") {
if (
url === "https://api.github.com/repos/ScriptedAlchemy/t3code/releases?per_page=100&page=2"
) {
return Response.json([
{ tag_name: "v1.0.0-preview.20260925.1", draft: true },
{ tag_name: "v1.0.0-preview.20260924.3" },
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/cli/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ it.effect("authenticates each release page until the requested channel is found"
const httpClient = HttpClient.make((request) => {
const url = new URL(request.url);
assert.equal(url.origin, "https://api.github.com");
assert.equal(url.pathname, "/repos/pingdotgg/t3code/releases");
assert.equal(url.pathname, "/repos/ScriptedAlchemy/t3code/releases");
assert.equal(request.headers.accept, "application/vnd.github+json");
assert.equal(request.headers.authorization, "Bearer gh-token");
const page = url.searchParams.get("page") ?? "";
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/src/cliRelease.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const CLI_RELEASE_REPOSITORY = "pingdotgg/t3code";
const CLI_RELEASE_REPOSITORY = "ScriptedAlchemy/t3code";
export const CLI_RELEASES_PAGE_URL = `https://github.com/${CLI_RELEASE_REPOSITORY}/releases`;
export const CLI_RELEASE_CHECKSUMS_FILE = "SHA256SUMS";
export const CLI_RELEASE_BASE_URL_ENV = "T3CODE_RELEASE_BASE_URL";
Expand Down
29 changes: 29 additions & 0 deletions scripts/build-desktop-artifact.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,35 @@ it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
),
);

it.effect("points fork builds' stable update feed at the building repository", () =>
Effect.gen(function* () {
const fork = yield* createBuildConfig(
"mac",
"dmg",
"0.1.0-fork.20261025.7",
false,
false,
undefined,
undefined,
);

assert.deepStrictEqual(fork.publish, [
{
provider: "github",
owner: "ScriptedAlchemy",
repo: "t3code",
releaseType: "release",
},
]);
}).pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({ env: { GITHUB_REPOSITORY: "ScriptedAlchemy/t3code" } }),
),
),
),
);

// pnpm writes "set this to true or false" placeholders into allowBuilds when a
// tarball changes. pnpm ignores them, but the release build decode rejects them.
it.effect("decodes the repo allowBuilds and every file: tarball it names exists", () =>
Expand Down
Loading