diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 06de87a79c..6c92fc1ebf 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -496,6 +496,12 @@ jobs: bun ./packages/redrob/script/launcher-assets.ts \ --version "$VERSION" --unsigned unsigned --signed signed --out assets + # The icon redrob-launcher.json names: the 512 px mark as one more release asset, so Redrob + # Launcher's catalog shows this release's own logo. The shared publish job is told the name + # (`launcher_icon`) and writes the manifest with it over every asset. + - name: Add the Redrob Launcher icon + run: cp packages/identity/mark-512x512.png assets/redrob-code.png + # The marker install.sh and `redrob upgrade` read to answer "what is the newest # version". `releases/latest/download/VERSION` resolves to whichever release is newest, # so no client has to hardcode a tag and nothing here consults the GitHub API, which is @@ -614,6 +620,7 @@ jobs: version: ${{ needs.version.outputs.version }} title: Redrob Code launcher_manifest: true + launcher_icon: redrob-code.png publish: true tag: ${{ needs.version.outputs.tag }} target: ${{ needs.version.outputs.sha }} diff --git a/packages/redrob/script/launcher-assets.ts b/packages/redrob/script/launcher-assets.ts index 1bba4eec5d..7fa5a83e70 100644 --- a/packages/redrob/script/launcher-assets.ts +++ b/packages/redrob/script/launcher-assets.ts @@ -47,14 +47,17 @@ export const STEM = "redrob-code" /** * The release manifest the launcher reads beside the installers (the launcher's * `docs/release-manifest.md`). `schema` is 1; `sharedAccount` is true because every release from - * here on reads the launcher's shared account file as its last console-key fallback. + * here on reads the launcher's shared account file as its last console-key fallback; `icon` names + * the square PNG asset of the same release the launcher shows in its catalog -- the 512 px mark + * from `packages/identity`, which the release workflow stages beside the installers under this name. */ export const MANIFEST_NAME = "redrob-launcher.json" -export const MANIFEST = { schema: 1, sharedAccount: true } as const +export const ICON_NAME = "redrob-code.png" +export const MANIFEST = { schema: 1, sharedAccount: true, icon: ICON_NAME } as const /** The manifest's bytes, exactly as the launcher contract spells them, newline-terminated. */ export function manifestText(): string { - return `{ "schema": ${MANIFEST.schema}, "sharedAccount": ${MANIFEST.sharedAccount} }\n` + return `{ "schema": ${MANIFEST.schema}, "sharedAccount": ${MANIFEST.sharedAccount}, "icon": "${MANIFEST.icon}" }\n` } /** Writes the manifest into `out` and returns its path. */ diff --git a/packages/redrob/test/installation/launcher-assets.test.ts b/packages/redrob/test/installation/launcher-assets.test.ts index 76ac4b0c92..a6876c6400 100644 --- a/packages/redrob/test/installation/launcher-assets.test.ts +++ b/packages/redrob/test/installation/launcher-assets.test.ts @@ -107,19 +107,19 @@ describe("launcher asset names", () => { /** * `redrob-launcher.json` is how the launcher learns, without a launcher release, that this release - * reads its shared account file (the launcher's `docs/release-manifest.md`). Exactly `{ "schema": 1, - * "sharedAccount": true }`: a wrong schema is ignored by the launcher and a false flag hides the - * sign-in, both silently, so the bytes are pinned here. + * reads its shared account file and which asset is its icon (the launcher's `docs/release-manifest.md`). + * Exactly `{ "schema": 1, "sharedAccount": true, "icon": "redrob-code.png" }`: a wrong schema is + * ignored by the launcher and a false flag hides the sign-in, both silently, so the bytes are pinned here. */ describe("release manifest", () => { test("is the launcher contract, verbatim", () => { expect(MANIFEST_NAME).toBe("redrob-launcher.json") - expect(manifestText()).toBe('{ "schema": 1, "sharedAccount": true }\n') + expect(manifestText()).toBe('{ "schema": 1, "sharedAccount": true, "icon": "redrob-code.png" }\n') const parsed = JSON.parse(manifestText()) - expect(parsed).toEqual({ schema: 1, sharedAccount: true }) + expect(parsed).toEqual({ schema: 1, sharedAccount: true, icon: "redrob-code.png" }) expect(parsed.schema).toBe(1) expect(parsed.sharedAccount).toBe(true) - expect(MANIFEST).toEqual({ schema: 1, sharedAccount: true }) + expect(MANIFEST).toEqual({ schema: 1, sharedAccount: true, icon: "redrob-code.png" }) }) test("a release directory without it fails the check", () => {