217 lines
9.3 KiB
Markdown
217 lines
9.3 KiB
Markdown
# Manual Gitea launcher releases
|
|
|
|
Manual publication mode is currently active. Build a complete local package with:
|
|
|
|
```text
|
|
./scripts/release.sh stable 1.8.0
|
|
./scripts/release.sh prerelease 1.9.0-beta.1
|
|
```
|
|
|
|
The command creates `dist/v<VERSION>/`, validates the channel/version pair,
|
|
builds and previews release notes, runs the configured preflight, creates a
|
|
deterministic archive, signs the manifest, and verifies the complete result. It
|
|
changes the requested version only inside the staged package, so the source
|
|
checkout is unchanged. It does not commit, tag, push, create a Gitea release,
|
|
or upload anything.
|
|
|
|
The default archive layout is flat: extracting the tar directly produces
|
|
`ptlinux/`, `ptdiag/`, and `release.json`. Versions `0.9.10` and `0.9.11` form a
|
|
short compatibility window and use the legacy enclosing directory. That lets
|
|
deployed `0.9.8` launchers install either release automatically, even if they
|
|
missed `0.9.10`. The updater inside both releases accepts both layouts, so
|
|
releases after `0.9.11` return to the flat layout.
|
|
|
|
Use `--description` for short Markdown or `--description-file` for a prepared
|
|
Markdown document. Generated commit notes are appended by default. Run
|
|
`./scripts/release.sh --help` for dry-run, editor, changelog-only, signing-key,
|
|
and test options.
|
|
|
|
After a successful build, create a new release in Gitea with tag `v<VERSION>`.
|
|
Leave **Pre-release** clear for `stable`; select it for `prerelease`. Use
|
|
`dist/v<VERSION>/release-notes.md` as the description and upload exactly these
|
|
five files from that version directory:
|
|
|
|
- `PristonTale-EU-<VERSION>.tar.gz`
|
|
- `PristonTale-EU-<VERSION>.tar.gz.sha256`
|
|
- `manifest.json`
|
|
- `manifest.json.sig`
|
|
- `release-notes.md`
|
|
|
|
Uploading a release does not by itself move the launcher's channel pointer.
|
|
Upload and save all five assets before publishing the channel pointer. The
|
|
signed archive URL includes its SHA-256 as a query parameter so Cloudflare and
|
|
other CDNs cannot reuse an empty response cached before the attachment existed.
|
|
After the Gitea release exists and each attachment has a nonzero size, publish
|
|
the matching files generated under
|
|
`dist/v<VERSION>/channel/` to the repository:
|
|
|
|
```text
|
|
dist/v<VERSION>/channel/stable.json -> updates/stable.json
|
|
dist/v<VERSION>/channel/stable.json.sig -> updates/stable.json.sig
|
|
|
|
dist/v<VERSION>/channel/prerelease.json -> updates/prerelease.json
|
|
dist/v<VERSION>/channel/prerelease.json.sig -> updates/prerelease.json.sig
|
|
```
|
|
|
|
Commit and push only the selected channel pair. Publishing a prerelease must not
|
|
change `updates/stable.json`.
|
|
|
|
Manual mode does not rebuild `updates/history.json`. The uploaded version can be
|
|
discovered through its channel pointer, but it will not appear as a remote
|
|
rollback candidate until signed history publication is run manually or the
|
|
automatic publisher is re-enabled.
|
|
|
|
The published `0.9.9` release is flat and therefore correctly asks deployed
|
|
`0.9.8` launchers for a manual update. Releases `0.9.10` and `0.9.11` use the
|
|
wrapped bridge layout and minimum updater `0.5.0`, so those launchers can install
|
|
either one automatically. Flat manifests after this compatibility window declare
|
|
`0.9.9` as their minimum updater version.
|
|
|
|
For direct artifact tooling without release notes or manual-upload guidance:
|
|
|
|
```text
|
|
PTLINUX_PYTHON=/path/to/python \
|
|
./scripts/build-release.sh 0.9.11 stable ./dist/v0.9.11
|
|
./scripts/verify-release.sh 0.9.11 stable ./dist/v0.9.11
|
|
```
|
|
|
|
The builder selects the runtime payload declared in `config.json`; it does not
|
|
archive the repository. It emits a deterministic versioned archive, checksum,
|
|
and external per-file manifest. When `PTLINUX_SIGNING_KEY` is set, it also
|
|
emits and immediately verifies `manifest.json.sig`.
|
|
|
|
`repository_url` is the public HTTPS base used in signed download links.
|
|
`allowed_git_remotes` is retained for the deferred automatic release validation;
|
|
it is not consulted by the current local packaging command.
|
|
|
|
## Deferred automatic publication
|
|
|
|
The automatic publisher and status publisher remain in the repository for a
|
|
later migration, but their push triggers are disabled. Both workflows are
|
|
manual-dispatch only, so creating a tag or Gitea release cannot race the manual
|
|
upload process. The remainder of this section applies only when automatic
|
|
publication is re-enabled.
|
|
|
|
## Repository and runner setup
|
|
|
|
Enable Gitea Actions for the instance and repository, then register an isolated
|
|
Docker-backed `act_runner` for trusted repository workflows. The runner image
|
|
must provide Git, Bash, curl, jq, Python 3.11 or newer, tar, gzip, coreutils
|
|
(`base64`, `realpath`, `sha256sum`, and `stat`), and OpenSSL. The release job
|
|
uses `actions/checkout@v4` and checks that the checked-out commit is the exact
|
|
commit referenced by the annotated tag.
|
|
|
|
Configure these protected Actions secrets:
|
|
|
|
- `RELEASE_TOKEN`: a dedicated token with only the repository release and
|
|
repository-content write permissions needed to create releases, upload
|
|
attachments, and update signed channel metadata.
|
|
- `MANIFEST_SIGNING_KEY`: the private key corresponding to
|
|
`ptlinux/launcher-update-public.pem`.
|
|
|
|
Secrets are available only to trusted tag and release-status workflows. Do not
|
|
add the release secrets to pull-request workflows. The signing key is written under
|
|
`RUNNER_TEMP` with mode `0600`, used for signing, and removed by an `always()`
|
|
cleanup step. Shell tracing is intentionally disabled around all secret-bearing
|
|
commands.
|
|
|
|
The current installed population verifies the deployed RSA/SHA-256 public key.
|
|
Release tooling can use OpenSSL Ed25519 signing, but changing the production
|
|
key or algorithm requires a staged key-rotation release first. Until that
|
|
migration is deployed, configure the matching existing RSA private key.
|
|
|
|
## Automatic publication behavior
|
|
|
|
The workflow validates the tag in CI, runs tests, builds and verifies every
|
|
artifact, creates a non-draft Gitea release with the derived prerelease flag,
|
|
and uploads these immutable assets separately:
|
|
|
|
- `PristonTale-EU-<version>.tar.gz`
|
|
- `PristonTale-EU-<version>.tar.gz.sha256`
|
|
- `manifest.json`
|
|
- `manifest.json.sig`
|
|
- `release-notes.md`
|
|
|
|
It re-queries the release and checks every attachment name and size before
|
|
updating metadata. A stable tag updates only `updates/stable.json` and its
|
|
signature. A beta or RC tag updates only `updates/prerelease.json` and its
|
|
signature. Both rebuild `updates/history.json` and its signature from real
|
|
Gitea releases, following API pagination so older rollback entries are retained.
|
|
The four metadata files are committed atomically through the Gitea contents API.
|
|
|
|
Existing release detection is fail-closed. Never delete, move, or reuse a tag
|
|
after publication. Fix a failed release with a new patch, beta, or RC number.
|
|
|
|
## Withdrawing or blocking a release
|
|
|
|
Edit `release/statuses.json` on `main` and set the immutable tag to
|
|
`withdrawn` or `blocked`, for example:
|
|
|
|
```json
|
|
{
|
|
"releases": {
|
|
"v1.9.0-beta.2": "withdrawn"
|
|
},
|
|
"schema": 1
|
|
}
|
|
```
|
|
|
|
The trusted `release-status.yml` workflow rebuilds and signs `updates/history.json`
|
|
from real Gitea releases. It also rebuilds both channel manifests: each channel
|
|
points to its greatest active release, or carries an authenticated inactive
|
|
status when that channel has no active release. The workflow verifies every
|
|
selected release manifest before signing and atomically publishing the channel
|
|
and history files. This prevents a withdrawn channel head from continuing to be
|
|
offered by launchers that read `updates/stable.json` or
|
|
`updates/prerelease.json` directly.
|
|
|
|
The release assets remain available for support, while new automatic update and
|
|
rollback selection excludes the inactive release. Deleting the tag's override
|
|
returns it to `active`. A status entry can also declare compatibility when a
|
|
future release changes the persistent settings schema:
|
|
|
|
```json
|
|
{
|
|
"releases": {
|
|
"v2.0.0": {
|
|
"status": "active",
|
|
"config_schema": 2,
|
|
"minimum_config_schema": 1
|
|
}
|
|
},
|
|
"schema": 1
|
|
}
|
|
```
|
|
|
|
The workflow can be run manually after a runner or API outage.
|
|
|
|
## Launcher history and rollback
|
|
|
|
The launcher fetches and verifies `updates/history.json` and its detached
|
|
signature for the version-history window. An explicit historical rollback uses
|
|
that release's immutable `manifest.json`, `manifest.json.sig`, and versioned
|
|
archive:
|
|
|
|
```text
|
|
pristontale-eu launcher-update --rollback 1.8.0
|
|
```
|
|
|
|
Running `--rollback` without a version keeps the original fast path to the
|
|
locally retained previous release. Every remote target is signature-, size-,
|
|
archive-hash-, and per-file-hash checked before it enters the immutable release
|
|
store. The launcher also persists that authenticated file inventory and verifies
|
|
it again before reactivating a locally retained release. Releases installed by an
|
|
older launcher remain usable through the compatibility path when no persisted
|
|
inventory exists. Complete release directories make reconciliation exact: files
|
|
managed by the current release but absent from the target disappear when
|
|
`current` changes, while settings, logs, saves, and downloads remain outside the
|
|
release tree.
|
|
|
|
Activation records the original `current` and `previous` links in a durable
|
|
transaction journal. Link or post-activation validation failure restores those
|
|
links, and the next launcher run recovers an interrupted transaction before any
|
|
new mutation. The local operation history retains the latest 30 update and
|
|
rollback results.
|
|
|
|
See `SIGNING_MIGRATION.md` before rotating the deployed manifest key.
|