diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml index d656a2dc57388..7bf6663cf562d 100644 --- a/.github/workflows/fork-release.yml +++ b/.github/workflows/fork-release.yml @@ -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: @@ -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" @@ -127,18 +127,22 @@ 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 }} @@ -146,6 +150,7 @@ jobs: 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 }} @@ -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: @@ -186,14 +210,14 @@ jobs: cat > notes.md < { const signal = new AbortController().signal; const feed = (...tags: ReadonlyArray) => new Response( - `tag:github.com,2008:https://github.com/pingdotgg/t3code/releases${tags + `tag:github.com,2008:https://github.com/ScriptedAlchemy/t3code/releases${tags .map((tag) => `tag:github.com,2008:Repository/1/${tag}`) .join("")}`, ); @@ -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", @@ -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" }, diff --git a/apps/server/src/cli/update.test.ts b/apps/server/src/cli/update.test.ts index e6a6eb5ee1dbf..92b36e94d4a0a 100644 --- a/apps/server/src/cli/update.test.ts +++ b/apps/server/src/cli/update.test.ts @@ -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") ?? ""; diff --git a/packages/shared/src/cliRelease.ts b/packages/shared/src/cliRelease.ts index 94bd3cffa168c..61a4de696c454 100644 --- a/packages/shared/src/cliRelease.ts +++ b/packages/shared/src/cliRelease.ts @@ -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"; diff --git a/scripts/build-desktop-artifact.test.ts b/scripts/build-desktop-artifact.test.ts index 862a5d29dea23..1151239cbad85 100644 --- a/scripts/build-desktop-artifact.test.ts +++ b/scripts/build-desktop-artifact.test.ts @@ -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", () =>