Skip to content
This repository was archived by the owner on Apr 28, 2026. It is now read-only.

Commit 136ddf1

Browse files
Prepare 0.0.1 OTA release
Add Tauri updater support, signed release automation, and the 0.0.1 version bump.
1 parent 07ea92c commit 136ddf1

14 files changed

Lines changed: 510 additions & 7 deletions

File tree

.github/workflows/release.yml

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
permissions:
9+
contents: write
10+
11+
concurrency:
12+
group: ${{ github.workflow }}-${{ github.ref }}
13+
cancel-in-progress: false
14+
15+
jobs:
16+
release:
17+
runs-on: macos-latest
18+
19+
steps:
20+
- uses: actions/checkout@v4
21+
22+
- name: Setup Bun
23+
uses: oven-sh/setup-bun@v2
24+
with:
25+
bun-version: "1.3.9"
26+
27+
- name: Setup Rust
28+
uses: dtolnay/rust-toolchain@stable
29+
with:
30+
targets: aarch64-apple-darwin
31+
32+
- name: Rust cache
33+
uses: swatinem/rust-cache@v2
34+
with:
35+
workspaces: src-tauri -> target
36+
37+
- name: Install dependencies
38+
run: bun install --frozen-lockfile
39+
40+
- name: Create GitHub release and upload bundles
41+
uses: tauri-apps/tauri-action@v0
42+
env:
43+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
45+
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
46+
with:
47+
tagName: v__VERSION__
48+
releaseName: "unsigned {char} v__VERSION__"
49+
releaseBody: "See release notes for details and download assets below."
50+
releaseDraft: false
51+
prerelease: false
52+
args: --target aarch64-apple-darwin
53+
54+
- name: Generate updater manifest
55+
run: node scripts/build-updater-manifest.mjs "${GITHUB_REF_NAME#v}"
56+
57+
- name: Upload updater manifest
58+
env:
59+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60+
run: gh release upload "$GITHUB_REF_NAME" latest.json --clobber

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ node_modules
1111
dist
1212
dist-ssr
1313
*.local
14+
latest.json
1415
src-tauri/target
1516
src-tauri/gen
1617
.codex/

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,24 @@ If you want `uchar` on your `PATH`:
3030
```bash
3131
ln -sf "/Applications/unsigned {char}.app/Contents/MacOS/uchar" /opt/homebrew/bin/uchar
3232
```
33+
34+
## Release
35+
36+
OTA updates are served from GitHub Releases via `latest.json`.
37+
38+
First-time setup:
39+
40+
```bash
41+
bunx tauri signer generate -w ~/.tauri/unsigned-char.key
42+
```
43+
44+
Add the same private key to GitHub as `TAURI_SIGNING_PRIVATE_KEY` and, if you used one, its password as `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`.
45+
46+
To ship a version:
47+
48+
```bash
49+
git tag vX.Y.Z
50+
git push origin main --follow-tags
51+
```
52+
53+
The release workflow builds the macOS ARM bundle, uploads the signed updater artifacts, and publishes `latest.json` for future OTA checks.

bun.lock

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "unsigned-char",
33
"private": true,
4-
"version": "0.1.0",
4+
"version": "0.0.1",
55
"license": "MIT",
66
"packageManager": "bun@1.3.9",
77
"bin": {
@@ -20,6 +20,8 @@
2020
"@base-ui/react": "^1.3.0",
2121
"@tanstack/react-router": "^1.168.10",
2222
"@tauri-apps/api": "^2",
23+
"@tauri-apps/plugin-process": "^2",
24+
"@tauri-apps/plugin-updater": "^2",
2325
"class-variance-authority": "^0.7.1",
2426
"clsx": "^2.1.1",
2527
"lucide-react": "^1.7.0",

release-notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Initial public release of unsigned {char}.

scripts/build-updater-manifest.mjs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { readdir, readFile, writeFile } from "node:fs/promises";
2+
import path from "node:path";
3+
4+
const root = process.cwd();
5+
const version = process.argv[2];
6+
7+
if (!version) {
8+
throw new Error("Expected a version argument, e.g. `node scripts/build-updater-manifest.mjs 0.0.1`.");
9+
}
10+
11+
const releaseNotesPath = path.join(root, "release-notes.md");
12+
const bundlePath = path.join(
13+
root,
14+
"src-tauri",
15+
"target",
16+
"aarch64-apple-darwin",
17+
"release",
18+
"bundle",
19+
"macos",
20+
);
21+
const bundleFiles = await readdir(bundlePath);
22+
const archiveName = bundleFiles.find((file) => file.endsWith(".app.tar.gz"));
23+
24+
if (!archiveName) {
25+
throw new Error(`No macOS updater archive found in ${bundlePath}.`);
26+
}
27+
28+
const signatureName = `${archiveName}.sig`;
29+
const archiveUrl = `https://github.com/ComputelessComputer/unsigned-char/releases/download/v${version}/${encodeURIComponent(archiveName)}`;
30+
const signaturePath = path.join(bundlePath, signatureName);
31+
const notes = await readFile(releaseNotesPath, "utf8");
32+
const signature = (await readFile(signaturePath, "utf8")).trim();
33+
34+
const manifest = {
35+
version,
36+
notes: notes.trim(),
37+
pub_date: new Date().toISOString(),
38+
platforms: {
39+
"darwin-aarch64": {
40+
signature,
41+
url: archiveUrl,
42+
},
43+
},
44+
};
45+
46+
const outputPath = path.join(root, "latest.json");
47+
await writeFile(outputPath, `${JSON.stringify(manifest, null, 2)}\n`);

0 commit comments

Comments
 (0)