Skip to content
Merged
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
3 changes: 2 additions & 1 deletion apps/desktop/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import "vite-plus/test/config";
import { defaultInclude, defineConfig } from "vite-plus";

import { isDesktopRuntimeExternalDependency } from "../../scripts/lib/desktop-external-packages.ts";
import { loadRepoEnv } from "../../scripts/lib/public-config.ts";
import { buildReleaseRepository, loadRepoEnv } from "../../scripts/lib/public-config.ts";

const repoEnv = loadRepoEnv();

Expand All @@ -11,6 +11,7 @@ const isMainProcessExternal = (id: string) =>
id === "electron" || id.startsWith("electron/") || isDesktopRuntimeExternalDependency(id);
const shouldLaunchElectronAfterPack = process.env.T3CODE_DESKTOP_DEV === "1";
const publicConfigDefine = {
__T3CODE_BUILD_RELEASE_REPOSITORY__: JSON.stringify(buildReleaseRepository()),
__T3CODE_BUILD_CLERK_PUBLISHABLE_KEY__: JSON.stringify(
repoEnv.T3CODE_CLERK_PUBLISHABLE_KEY?.trim() ?? "",
),
Expand Down
3 changes: 2 additions & 1 deletion apps/server/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as NodePath from "node:path";
import { defineConfig, mergeConfig } from "vite-plus";

import baseConfig from "../../vite.config.ts";
import { loadRepoEnv } from "../../scripts/lib/public-config.ts";
import { buildReleaseRepository, loadRepoEnv } from "../../scripts/lib/public-config.ts";
import rootPackageJson from "../../package.json" with { type: "json" };
import packageJson from "./package.json" with { type: "json" };
import { WeightedShardSequencer } from "./src/testUtils/weightedShardSequencer.ts";
Expand Down Expand Up @@ -128,6 +128,7 @@ export default mergeConfig(
define: {
__T3CODE_BUILD_CHANNEL__: JSON.stringify(cliBuildChannel),
__T3CODE_TELEMETRY_CHANNEL__: JSON.stringify(telemetryChannel),
__T3CODE_BUILD_RELEASE_REPOSITORY__: JSON.stringify(buildReleaseRepository()),
__T3CODE_BUILD_RELAY_URL__: JSON.stringify(repoEnv.T3CODE_RELAY_URL?.trim() ?? ""),
__T3CODE_BUILD_CLERK_PUBLISHABLE_KEY__: JSON.stringify(
repoEnv.T3CODE_CLERK_PUBLISHABLE_KEY?.trim() ?? "",
Expand Down
18 changes: 2 additions & 16 deletions apps/web/src/components/desktopUpdate.logic.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
import type { DesktopUpdateActionResult, DesktopUpdateState } from "@t3tools/contracts";
import { githubReleaseRepository } from "@t3tools/shared/cliRelease";

export type DesktopUpdateButtonAction = "download" | "install" | "none";

const DEFAULT_DESKTOP_RELEASE_REPOSITORY = "pingdotgg/t3code";
const GITHUB_REPOSITORY_SEGMENT = /^[A-Za-z0-9._-]+$/u;

function isValidRepositorySegment(value: string | undefined): value is string {
return (
value !== undefined && value !== "." && value !== ".." && GITHUB_REPOSITORY_SEGMENT.test(value)
);
}

function desktopReleaseRepositoryUrl(repository: string | undefined): string {
const configuredRepository = repository?.trim() ?? "";
const [owner, name, ...extra] = configuredRepository.split("/");
const releaseRepository =
isValidRepositorySegment(owner) && isValidRepositorySegment(name) && extra.length === 0
? configuredRepository
: DEFAULT_DESKTOP_RELEASE_REPOSITORY;
return `https://github.com/${releaseRepository}/releases`;
return `https://github.com/${githubReleaseRepository(repository)}/releases`;
}

/** The download RPC can beat the updater's downloadedVersion event; fall back to the requested version. */
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/components/sidebar/SidebarChrome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ const SidebarUtilityMenu = memo(function SidebarUtilityMenu() {
};

return (
<SidebarMenu className="flex-row items-center">
<SidebarMenu className="flex-row flex-wrap-reverse items-center">
{isOnUtilityPage ? (
<SidebarMenuItem className="min-w-0 flex-1">
<SidebarMenuButton onClick={handleBackClick}>
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/components/sidebar/SidebarUpdatePill.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,8 @@ function SidebarUpdateControl() {
? { status: "downloading", percent: state.downloadPercent }
: { status: "waiting" };
return (
<SidebarMenuItem className="ml-auto flex flex-1">
// Too narrow for its label beside the footer icons, the capsule wraps onto its own row.
<SidebarMenuItem className="ml-auto flex min-w-40 flex-1">
<SidebarUpdateCapsule
run={run}
local={local}
Expand Down
8 changes: 3 additions & 5 deletions apps/web/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
DEV_PROXIED_PATH_PREFIXES,
} from "@t3tools/shared/devProxy";

import { loadRepoEnv } from "../../scripts/lib/public-config";
import { buildReleaseRepository, loadRepoEnv } from "../../scripts/lib/public-config";
import { thirdPartyLicensesPlugin } from "../../scripts/lib/third-party-licenses";
import { tailwindPlugins } from "./vite/tailwind";
import { warmBundledDevPlugin } from "./vite/warmBundledDev";
Expand All @@ -45,10 +45,7 @@ const configuredHostedAppChannel = process.env.VITE_HOSTED_APP_CHANNEL?.trim() |
const configuredReleaseChannel =
process.env.T3CODE_BUILT_DEV === "1" ? "dev" : process.env.VITE_RELEASE_CHANNEL?.trim() || "";
const configuredAppVersion = process.env.APP_VERSION?.trim() || pkg.version;
const configuredDesktopUpdateRepository =
process.env.T3CODE_DESKTOP_UPDATE_REPOSITORY?.trim() ||
process.env.GITHUB_REPOSITORY?.trim() ||
"";
const configuredDesktopUpdateRepository = buildReleaseRepository();
const configuredFeatureSecrets = process.env.T3CODE_FEATURE_SECRETS?.trim() || "";
const configuredHostedAppUrl = (() => {
const explicitHostedAppUrl = process.env.VITE_HOSTED_APP_URL?.trim();
Expand Down Expand Up @@ -317,6 +314,7 @@ export default defineConfig(() => {
"import.meta.env.T3CODE_DESKTOP_UPDATE_REPOSITORY": JSON.stringify(
configuredDesktopUpdateRepository,
),
__T3CODE_BUILD_RELEASE_REPOSITORY__: JSON.stringify(configuredDesktopUpdateRepository),
"import.meta.env.T3CODE_FEATURE_SECRETS": JSON.stringify(configuredFeatureSecrets),
"import.meta.env.VITE_RELEASE_CHANNEL": JSON.stringify(configuredReleaseChannel),
"import.meta.env.APP_VERSION": JSON.stringify(configuredAppVersion),
Expand Down
14 changes: 13 additions & 1 deletion packages/shared/src/cliRelease.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { describe, expect, it } from "vite-plus/test";

import { cliArchiveTarCommand, newestCliReleaseVersion, parseChecksums } from "./cliRelease.ts";
import {
cliArchiveTarCommand,
githubReleaseRepository,
newestCliReleaseVersion,
parseChecksums,
} from "./cliRelease.ts";

describe("cliRelease", () => {
it("parses sha256sum output including binary-mode markers", () => {
Expand All @@ -17,6 +22,13 @@ describe("cliRelease", () => {
expect(checksums.size).toBe(2);
});

it("updates from the repository a build was made in, and from upstream without one", () => {
expect(githubReleaseRepository(" fork-owner/t3code ")).toBe("fork-owner/t3code");
expect(githubReleaseRepository("")).toBe("pingdotgg/t3code");
expect(githubReleaseRepository(undefined)).toBe("pingdotgg/t3code");
expect(githubReleaseRepository("fork-owner/../t3code")).toBe("pingdotgg/t3code");
});

it("extracts with the System32 bsdtar on Windows and plain tar elsewhere", () => {
expect(cliArchiveTarCommand("linux", {})).toBe("tar");
expect(cliArchiveTarCommand("win32", { SystemRoot: "D:\\Win" })).toBe(
Expand Down
24 changes: 23 additions & 1 deletion packages/shared/src/cliRelease.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,29 @@ import * as Schema from "effect/Schema";

import { compareSemverVersions } from "./semver.ts";

const CLI_RELEASE_REPOSITORY = "pingdotgg/t3code";
const UPSTREAM_RELEASE_REPOSITORY = "pingdotgg/t3code";
const GITHUB_REPOSITORY_SEGMENT = /^[A-Za-z0-9._-]+$/u;

/** `configured` when it is a GitHub `owner/name`, otherwise the upstream repository. */
export function githubReleaseRepository(configured: string | undefined): string {
const repository = configured?.trim() ?? "";
const segments = repository.split("/");
return segments.length === 2 &&
segments.every(
(segment) => segment !== "." && segment !== ".." && GITHUB_REPOSITORY_SEGMENT.test(segment),
)
? repository
: UPSTREAM_RELEASE_REPOSITORY;
}

// Server, desktop and web builds bake in the repository they were built in, as the desktop updater
// does, so a fork build updates from its fork's releases. Unset in tests and mobile.
declare const __T3CODE_BUILD_RELEASE_REPOSITORY__: string | undefined;
const CLI_RELEASE_REPOSITORY = githubReleaseRepository(
typeof __T3CODE_BUILD_RELEASE_REPOSITORY__ === "undefined"
? undefined
: __T3CODE_BUILD_RELEASE_REPOSITORY__,
);
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
5 changes: 5 additions & 0 deletions scripts/lib/public-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ export function loadRepoEnv({
};
}

/** The GitHub `owner/name` whose releases this build updates from: CI's own repository unless overridden. */
export function buildReleaseRepository(env: Environment = process.env): string {
return env.T3CODE_DESKTOP_UPDATE_REPOSITORY?.trim() || env.GITHUB_REPOSITORY?.trim() || "";
}

function resolvePublicConfig(...sources: readonly Environment[]): T3CodePublicConfig {
return {
clerkPublishableKey: firstNonEmpty(
Expand Down
Loading