Skip to content

patchline publish

patchline publish [flags] <build-dir>

Scans <build-dir>, hashes every file with SHA-256, uploads any objects not already in storage, writes a signed release manifest at releases/<version>/manifest.json, and writes the same manifest to channels/<channel>/manifest.json.

The channel manifest is written last, after every object referenced by the manifest is verified present in the backend. A failed publish never advances a channel to objects that don’t exist.

Flags

FlagDefaultPurpose
--configpatchline.yamlConfig file to load defaults from. Missing file is not an error.
--app-idApp identifier baked into the manifest. Required (or via config).
--versionRelease version baked into the manifest. Required.
--channelbetaChannel manifest to overwrite.
--outputLocal output directory (when backend is local).
--signing-keyEd25519 private key path. Required unless --unsigned-dev.
--unsigned-devfalseSkip signing. Dev only — clients reject unsigned manifests by default.
--jsonfalseEmit machine-readable result instead of human output.

Examples

Minimal, with most defaults from patchline.yaml:

Terminal window
patchline publish --version 1.2.0 ./dist

Explicit, no config file:

Terminal window
patchline publish \
--app-id com.example.game \
--version 1.2.0 \
--channel beta \
--output ./release-output \
--signing-key ./patchline.key \
./dist

CI-friendly with JSON output:

Terminal window
patchline publish --version "$VERSION" --json ./dist | jq .

What gets uploaded

For each file in <build-dir>:

  1. Compute its SHA-256.
  2. Check whether objects/sha256/<aa>/<bb>/<hash> already exists in the backend.
  3. If yes, skip. If no, upload.

Republishing builds that share assets is cheap — only new bytes get transferred. The release manifest still lists every file, so the resulting install is complete regardless of whether the underlying objects were uploaded this run or a previous one.

Release sequence

If --release-sequence is unset (it usually is), Patchline reads the current channel manifest and assigns this release current_sequence + 1. Each channel has its own sequence. New channel? Sequence starts at 1.

See also