# ALCOMD3 release workflow

Languages: English | [日本語](RELEASE.ja.md) | [简体中文](RELEASE.zh-CN.md)

This is the release-day workflow for ALCOMD3. Releases are driven by `xtask`
commands so the operator does not edit every version file by hand.

The release has three phases and two commits:

1. Source release commit: version metadata and release notes.
2. GitHub Release: signed Windows installer artifacts.
3. Updater metadata commit: generated updater JSON after public assets exist.

### Version ownership

- Rust release version source: `[workspace.package].version` in `Cargo.toml`.
- Rust workspace members inherit it with `version.workspace = true`.
- `vrc-get-gui/package.json` and `website/package.json` are updated by
  `cargo xtask release-prepare`.
- `Cargo.lock` and `package-lock.json` are generated files.
- Updater JSON is generated by `cargo xtask release-build` and committed only
  after the GitHub Release assets are public.

### 1. Choose release inputs

Use exactly one channel.

| Channel | Version example | GitHub Release type | Updater JSON |
| --- | --- | --- | --- |
| Stable | `2.0.1` | normal release | `website/public/api/gui/tauri-updater.json` |
| Beta | `2.1.0-beta.1` | prerelease | `website/public/api/gui/tauri-updater-beta.json` |

Set variables in PowerShell:

```powershell
$Version = "2.0.1"
$Channel = "stable"
```

Stable versions must not contain prerelease metadata. Beta versions must contain
prerelease metadata.

### 2. Start clean

```powershell
git checkout main
git pull --ff-only
git status --short
gh auth status --hostname github.com
```

Expected result:

- `git status --short` prints nothing.
- GitHub CLI is authenticated for `CQMHV/ALCOMD3`.

Stop if the worktree is dirty.

### 3. Prepare source release files

```powershell
cargo xtask release-prepare --version $Version --channel $Channel
```

This command:

- updates `Cargo.toml` workspace version;
- refreshes `Cargo.lock` workspace package versions;
- updates GUI and website npm versions without creating tags;
- refreshes npm lockfiles;
- creates `release-notes/ALCOMD3_$Version.md` if missing;
- prints the resulting `git status --short`.

Now edit the release notes file and remove all placeholder text.

Commit and push the source release commit:

```powershell
git add Cargo.toml Cargo.lock
git add vrc-get-gui/package.json vrc-get-gui/package-lock.json
git add website/package.json website/package-lock.json
git add "release-notes/ALCOMD3_$Version.md"
git status --short
git commit -m "release: prepare ALCOMD3 $Version"
git push origin main
```

This commit is the source state the GitHub Release tag should point to. It must
not include generated installer files, files under `target/`, files under
`artifacts/`, or updater JSON.

### 4. Build, sign, and verify local release artifacts

```powershell
cargo xtask release-build --version $Version --channel $Channel
```

This command:

- runs `cargo check` and `cargo test`;
- runs GUI `npm run lint` and `npm run build`;
- runs website `npm run check` and `npm run build`;
- builds the Windows installer;
- builds the installer zip;
- signs the installer;
- generates the selected updater JSON locally;
- verifies updater JSON against the local installer;
- copies publishable artifacts to `artifacts/release/v$Version/`.

Signing uses `ALCOMD3_UPDATER_PRIVATE_KEY` and
`ALCOMD3_UPDATER_PRIVATE_KEY_PASSWORD` if they are already set. If they are not
set, the command loads `artifacts/alcomd3-updater-key/`, preferring
`private-key.ps1` and falling back to `private-key.env`.

Expected artifacts:

- `artifacts/release/v$Version/alcomd3-$Version-setup.exe`
- `artifacts/release/v$Version/alcomd3-$Version-setup.exe.sig`
- `artifacts/release/v$Version/alcomd3-$Version-setup.exe.zip`

Do not commit updater JSON yet. It points to release assets that are not public
until the GitHub Release is published.

Useful checks:

```powershell
cargo xtask release-build --version $Version --channel $Channel --dry-run
cargo xtask release-build --version $Version --channel $Channel --skip-validation
```

Use `--skip-validation` only when validation has already passed for the same
source state.

### 5. Create the GitHub Release

Create or refresh a draft:

```powershell
cargo xtask release-publish --version $Version --channel $Channel
```

If a draft already exists and you intentionally want to replace assets:

```powershell
cargo xtask release-publish --version $Version --channel $Channel --replace-assets
```

Inspect the draft on GitHub. If the notes, assets, and stable/beta flag are
correct, publish it:

```powershell
cargo xtask release-publish --version $Version --channel $Channel --replace-assets --publish
```

The command verifies that the GitHub Release contains:

- `alcomd3-$Version-setup.exe`
- `alcomd3-$Version-setup.exe.sig`
- `alcomd3-$Version-setup.exe.zip`

Stable releases must not be prereleases. Beta releases must be prereleases.

### 6. Commit updater metadata and build the website

After the GitHub Release is public:

```powershell
cargo xtask release-updater --version $Version --channel $Channel --commit --push
```

This command:

- downloads the public installer from the GitHub Release;
- verifies the local updater JSON against the downloaded public installer;
- commits the selected updater JSON;
- pushes `main`;
- runs website `npm run check` and `npm run build`;
- prints the public updater endpoint to check after deployment.

If your hosting provider automatically deploys `origin/main`, wait for that
deployment to finish. Otherwise deploy `website/dist` as the site root. Do not
deploy `website/public` directly and do not deploy the repository root.

### 7. Check the public updater endpoint

After website deployment finishes:

```powershell
cargo xtask release-updater --version $Version --channel $Channel --skip-website-build --check-public
```

The release is complete only when this public check passes.

### Failure rules

Stop the release if:

- release notes still contain placeholder text;
- validation fails;
- signing variables or signing key loader are missing;
- any artifact is missing;
- updater JSON verification fails;
- GitHub Release assets are missing or misnamed;
- stable/beta flags are wrong;
- website updater JSON would be deployed before GitHub Release assets are public.
