feat(release): prove RC1 launcher parity - #203
Conversation
Reviewer's GuideThis PR formalizes the 0.2.0-rc.1 release as a machine-checked launcher parity contract, strengthens release/versioning automation, and adds cross-platform installer smoke tests plus bilingual RC1 documentation. Sequence diagram for bump-tauri manifest synchronizationsequenceDiagram
actor ReleaseWorkflow
participant bump_tauri_ts
participant tauri_conf_json
participant cargo_lock
participant ui_package_json
participant docs_package_json
ReleaseWorkflow->>bump_tauri_ts: pnpm bump-tauri
bump_tauri_ts->>bump_tauri_ts: read DROPOUT_REPO_ROOT or repoRoot
bump_tauri_ts->>tauri_conf_json: fs.readFileSync
bump_tauri_ts->>bump_tauri_ts: getCurrentVersion
bump_tauri_ts->>bump_tauri_ts: getBumpVersion
alt currentVersion != bumpVersion
bump_tauri_ts->>bump_tauri_ts: replaceVersion
bump_tauri_ts->>tauri_conf_json: writeIfChanged
else currentVersion == bumpVersion
bump_tauri_ts->>bump_tauri_ts: log up-to-date
end
bump_tauri_ts->>cargo_lock: fs.readFileSync
bump_tauri_ts->>bump_tauri_ts: replaceLockedVersion
bump_tauri_ts->>cargo_lock: writeIfChanged
bump_tauri_ts->>ui_package_json: fs.readFileSync
bump_tauri_ts->>bump_tauri_ts: normalize trailing newline
bump_tauri_ts->>ui_package_json: writeIfChanged
bump_tauri_ts->>docs_package_json: fs.readFileSync
bump_tauri_ts->>bump_tauri_ts: normalize trailing newline
bump_tauri_ts->>docs_package_json: writeIfChanged
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Workspace change through: 00fa7371 changesets found Planned changes to release
|
There was a problem hiding this comment.
Hey - I've found 1 issue, and left some high level feedback:
- The
replaceLockedVersionhelper inbump-tauri.tsrelies on a brittle regex that assumes a very specificCargo.locklayout; consider parsing the TOML or at least tightening the pattern to tolerate formatting changes (extra fields, reordered keys, or comments) without breaking the bump step. - The new smoke-install scripts and workflow test assume all installer artifacts (AppImage, deb, dmg, NSIS) exist for every matrix target; if you add or remove targets or change bundle layout later, you may want a single shared helper or explicit guard to keep these checks aligned with the build outputs.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `replaceLockedVersion` helper in `bump-tauri.ts` relies on a brittle regex that assumes a very specific `Cargo.lock` layout; consider parsing the TOML or at least tightening the pattern to tolerate formatting changes (extra fields, reordered keys, or comments) without breaking the bump step.
- The new smoke-install scripts and workflow test assume all installer artifacts (AppImage, deb, dmg, NSIS) exist for every matrix target; if you add or remove targets or change bundle layout later, you may want a single shared helper or explicit guard to keep these checks aligned with the build outputs.
## Individual Comments
### Comment 1
<location path="scripts/smoke-install-macos.sh" line_range="36-45" />
<code_context>
+
+cp -R "$source_app" "$install_root/"
+installed_app="$install_root/$(basename "$source_app")"
+info_plist="$installed_app/Contents/Info.plist"
+plutil -lint "$info_plist" >/dev/null
+executable_name=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$info_plist")
+installed_binary="$installed_app/Contents/MacOS/$executable_name"
+
+test -x "$installed_binary"
+file "$installed_binary" | grep -q 'Mach-O'
+otool -L "$installed_binary" >/dev/null
+
+echo "Verified isolated macOS install for $target"
</code_context>
<issue_to_address>
**suggestion:** Handle missing or malformed Info.plist more defensively
Right now, failures from `plutil`/`PlistBuddy` will be indirect if `Info.plist` is missing or `CFBundleExecutable` isn’t set. Consider checking that the plist exists and that `CFBundleExecutable` is present before calling `PlistBuddy`, and emit a clear error like `"application bundle is missing CFBundleExecutable"` so CI output directly identifies the packaging issue.
```suggestion
cp -R "$source_app" "$install_root/"
installed_app="$install_root/$(basename "$source_app")"
info_plist="$installed_app/Contents/Info.plist"
if [ ! -f "$info_plist" ]; then
echo "application bundle is missing Info.plist" >&2
exit 1
fi
if ! plutil -lint "$info_plist" >/dev/null; then
echo "application bundle has an invalid Info.plist" >&2
exit 1
fi
executable_name=$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$info_plist") || executable_name=
if [ -z "$executable_name" ]; then
echo "application bundle is missing CFBundleExecutable" >&2
exit 1
fi
installed_binary="$installed_app/Contents/MacOS/$executable_name"
if [ ! -x "$installed_binary" ]; then
echo "application bundle CFBundleExecutable '$executable_name' is not present or not executable" >&2
exit 1
fi
file "$installed_binary" | grep -q 'Mach-O'
otool -L "$installed_binary" >/dev/null
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Pull request overview
This PR strengthens the RC1 release process by adding a machine-checked parity evidence matrix (plus bilingual RC1 release guides), extending CI to smoke-test packaged desktop artifacts prior to upload, and tightening prerelease/release-manifest synchronization (including moving the prerelease tag to rc).
Changes:
- Add a required 42-row RC1 parity evidence contract (
docs/release/rc1-parity.json) with a Node test enforcing row coverage, evidence existence, and bilingual documentation evidence. - Add isolated-install smoke scripts (Linux/macOS/Windows) and wire them into the release workflow before artifact upload; add CI coverage for the parity audit test.
- Update release tooling/config to enter the
rcprerelease channel and synchronize generated release manifests (includingCargo.lockand package manifest normalization).
Reviewed changes
Copilot reviewed 20 out of 22 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
src-tauri/tauri.conf.json |
Bumps Tauri app version to an rc prerelease. |
src-tauri/Cargo.toml |
Bumps Rust crate version to an rc prerelease. |
Cargo.lock |
Updates locked workspace package version. |
scripts/smoke-install-windows.ps1 |
Adds Windows isolated NSIS install smoke validation. |
scripts/smoke-install-macos.sh |
Adds macOS DMG mount/copy/install smoke validation. |
scripts/smoke-install-linux.sh |
Adds Linux AppImage + Debian extraction smoke validation. |
scripts/release-workflow.test.mjs |
Extends release workflow contract tests (manifest sync + smoke ordering). |
scripts/parity-audit.test.mjs |
Adds parity audit contract tests (rows, evidence, bilingual docs, CI wiring). |
scripts/bump-tauri.ts |
Extends bump script to sync Cargo.lock + normalize package manifests; supports fixture root via env var. |
packages/ui/package.json |
Bumps UI package version to an rc prerelease. |
packages/docs/package.json |
Bumps docs package version to an rc prerelease. |
packages/docs/content/zh/manual/releases/rc-1.mdx |
Adds Chinese RC1 parity evidence guide. |
packages/docs/content/zh/manual/releases/meta.json |
Adds RC1 release page to Chinese releases nav. |
packages/docs/content/en/manual/releases/rc-1.mdx |
Adds English RC1 parity evidence guide. |
packages/docs/content/en/manual/releases/meta.json |
Adds RC1 release page to English releases nav. |
package.json |
Adds pnpm test:parity script entry. |
docs/release/rc1-parity.json |
Adds the machine-checked RC1 parity evidence matrix. |
.gitignore |
Adjusts ignore rules (attempts to unignore docs/release/...). |
.github/workflows/semifold-ci.yaml |
Adds isolated-install smoke steps before artifact upload. |
.github/workflows/prek.yml |
Runs the parity audit contract test in CI. |
.changes/rc1-parity-audit.md |
Adds changeset entry describing RC1 parity audit + CI hardening. |
.changes/config.toml |
Switches prerelease tag from beta to rc for relevant packages. |
Suppressed comments (1)
scripts/smoke-install-linux.sh:37
- This validates the AppImage and Debian package contents, but does not validate the RPM at all. Add at least a basic RPM structure check (ideally list/extract its payload in an isolated dir) to align with the “smoke every packaged desktop artifact” requirement.
dpkg-deb --extract "$deb" "$deb_root"
find "$deb_root/usr/bin" -maxdepth 1 -type f -perm -u+x -print -quit | grep -q .
find "$deb_root/usr/share/applications" -type f -name '*.desktop' -print -quit | grep -q .
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (5)
src-tauri/tauri.conf.json:4
- PR metadata and added RC1 parity audit/docs consistently refer to 0.2.0-rc.1, but this bumps the Tauri app version to 0.2.0-rc.0. This mismatch makes it unclear which release candidate these artifacts/documentation apply to and can break release automation expecting a single source of truth.
"version": "0.2.0-rc.0",
src-tauri/Cargo.toml:3
- PR metadata and the new parity audit/docs target 0.2.0-rc.1, but the Rust package version is set to 0.2.0-rc.0. Version skew across release artifacts makes Semifold/Changesets outputs and documentation hard to reconcile; align this to the intended RC version.
version = "0.2.0-rc.0"
packages/ui/package.json:4
- PR metadata and the RC1 release docs/audit target 0.2.0-rc.1, but the UI package is versioned as 0.1.0-rc.0. If RC1 is meant to be rc.1 across the workspace, this should match to avoid publishing mixed prerelease tags.
"version": "0.1.0-rc.0",
packages/docs/package.json:5
- PR metadata and the RC1 release docs/audit target 0.2.0-rc.1, but the docs package is versioned as 0.1.0-rc.0. Align the workspace prerelease numbering so release notes and deployed docs map to the same RC.
"version": "0.1.0-rc.0",
scripts/smoke-install-linux.sh:12
- The release workflow uploads an additional Linux .rpm artifact (semifold-ci.yaml includes bundle/appimage/.rpm), but the Linux isolated-install smoke script only checks for AppImage and .deb. That means a missing/broken RPM could still be uploaded while smoke checks pass.
appimage=$(find "$bundle_root/appimage" -maxdepth 1 -type f -name '*.AppImage' -print -quit)
deb=$(find "$bundle_root/deb" -maxdepth 1 -type f -name '*.deb' -print -quit)
rpm=$(find "$bundle_root/rpm" -maxdepth 1 -type f -name '*.rpm' -print -quit)
if [ -z "$appimage" ] || [ -z "$deb" ] || [ -z "$rpm" ]; then
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 22 changed files in this pull request and generated 1 comment.
Suppressed comments (2)
scripts/smoke-install-windows.ps1:16
- This assumes
$env:RUNNER_TEMPis always set. In GitHub Actions it is, but running the script locally (or in other CI) can fail becauseJoin-Pathcannot accept a null base path. Use a temp-path fallback.
$smokeRoot = Join-Path $env:RUNNER_TEMP ("dropout-install-smoke-" + [guid]::NewGuid())
$installRoot = Join-Path $smokeRoot "installed"
scripts/parity-audit.test.mjs:92
- The audit file controls
evidence.path, andresolve(repoRoot, evidence.path)will happily accept absolute paths or..traversal. That lets a modified audit point the test at arbitrary filesystem paths (e.g./etc/passwd) and attempt to read them. Restrict evidence to paths that remain withinrepoRootbefore checking existence/content.
const evidencePath = resolve(repoRoot, evidence.path);
assert.equal(
existsSync(evidencePath),
true,
`${row.id} points to missing evidence ${evidence.path}`,
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 22 changed files in this pull request and generated no new comments.
Suppressed comments (4)
scripts/release-workflow.test.mjs:56
- This test creates a temp fixture directory but never deletes it. Over time (and especially when re-running locally), this can accumulate temp dirs; register a cleanup hook so the fixtureRoot is removed even if assertions fail.
test("post-version hook synchronizes every generated release manifest", () => {
const fixtureRoot = mkdtempSync(join(tmpdir(), "dropout-release-manifests-"));
scripts/parity-audit.test.mjs:92
- Resolved evidence paths are only checked for existence; they should also be required to remain within repoRoot so the audit cannot be satisfied by pointing to files outside the checkout.
const evidencePath = resolve(repoRoot, evidence.path);
assert.equal(
existsSync(evidencePath),
true,
`${row.id} points to missing evidence ${evidence.path}`,
);
scripts/parity-audit.test.mjs:3
- The parity audit contract resolves evidence paths relative to repoRoot but doesn't enforce that the resolved path stays within the repository. That leaves a loophole where evidence can point outside the repo (e.g. ../../some-file-on-runner) and still satisfy existsSync/match checks.
This issue also appears on line 87 of the same file.
import { resolve } from "node:path";
scripts/release-workflow.test.mjs:3
- The test creates temporary fixture directories via mkdtempSync but does not import any cleanup helper (e.g. rmSync). This makes it easy to accidentally leak temp directories on CI runners as these tests evolve; add rmSync so the fixture root can be removed after the test completes.
This issue also appears on line 55 of the same file.
import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs";
# Releases ## @dropout/docs ## v0.1.0-rc.1 ### New Features - [`e0cc80d`](e0cc80d): Add a machine-checked 42-row launcher parity audit, bilingual RC1 evidence guides, isolated installer smoke tests across every supported desktop target, and durable release-manifest synchronization. ([#203](#203) by @HsiangNianian) ## @dropout/ui ## v0.1.0-rc.1 ### New Features - [`e0cc80d`](e0cc80d): Add a machine-checked 42-row launcher parity audit, bilingual RC1 evidence guides, isolated installer smoke tests across every supported desktop target, and durable release-manifest synchronization. ([#203](#203) by @HsiangNianian) ## dropout ## v0.2.0-rc.1 ### New Features - [`e0cc80d`](e0cc80d): Add a machine-checked 42-row launcher parity audit, bilingual RC1 evidence guides, isolated installer smoke tests across every supported desktop target, and durable release-manifest synchronization. ([#203](#203) by @HsiangNianian) ## Summary by Sourcery Prepare rc.1 release candidates across docs, UI, and desktop app packages. New Features: - Document the rc.1 feature set for @dropout/docs, @dropout/ui, and the Tauri desktop app in their changelogs. Enhancements: - Bump @dropout/docs and @dropout/ui to version 0.1.0-rc.1 and the Tauri desktop app to 0.2.0-rc.1, aligning manifests and configuration with the new release candidate.
Summary
Validation
Closes #178
Summary by Sourcery
Add an RC1 parity audit and documentation, tighten release manifest synchronization, and validate isolated desktop installers in CI before artifact upload.
New Features:
Enhancements:
Tests: