Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ on:
branches: [main]
pull_request:
workflow_dispatch:
inputs:
publish_release:
description: Publish fork update after checks pass (main only)
type: boolean
required: false
default: false
release_version:
description: Fork version (blank for next patch; for example 1.1.0)
type: string
required: false
default: ""

concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
Expand Down Expand Up @@ -50,9 +61,12 @@ jobs:
if: >-
github.repository == 'EricRasputin/monocode-eric' &&
github.ref == 'refs/heads/main' &&
(github.event_name == 'push' || github.event_name == 'workflow_dispatch')
github.event_name == 'workflow_dispatch' &&
inputs.publish_release
permissions:
contents: write
uses: ./.github/workflows/fork-release.yml
with:
version: ${{ inputs.release_version }}
secrets:
updater-private-key: ${{ secrets.FORK_UPDATER_PRIVATE_KEY }}
37 changes: 32 additions & 5 deletions .github/workflows/fork-release.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
name: Fork release

# CI calls this only after all three platform checks pass on main.
# CI calls this only for an explicitly requested release after all checks pass on main.
on:
workflow_call:
inputs:
version:
type: string
required: false
default: ""
secrets:
updater-private-key:
required: true
Expand All @@ -14,11 +19,31 @@ concurrency:
permissions:
contents: read

env:
FORK_VERSION: 0.2.${{ github.run_number }}

jobs:
version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
publish: ${{ steps.version.outputs.publish }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Select fork release version
id: version
env:
GH_TOKEN: ${{ github.token }}
FORK_REQUESTED_VERSION: ${{ inputs.version }}
run: node scripts/fork-release.mjs version "$FORK_REQUESTED_VERSION"

build:
needs: version
if: needs.version.outputs.publish == 'true'
env:
FORK_VERSION: ${{ needs.version.outputs.version }}
strategy:
fail-fast: false
matrix:
Expand Down Expand Up @@ -68,7 +93,9 @@ jobs:
retention-days: 7

publish:
needs: build
needs: [version, build]
env:
FORK_VERSION: ${{ needs.version.outputs.version }}
runs-on: ubuntu-latest
permissions:
contents: write
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@ Small, focused pull requests are welcome. Anything large is worth an issue first

## Build from source

Fork releases are built and published automatically after changes to `main`
pass CI on macOS, Linux, and Windows. Users update from inside the app; no local
build is needed. Fork versions use `0.2.<CI run number>` independently of upstream.
Changes to `main` run CI without publishing a release. When a batch is ready,
open **Actions → CI → Run workflow**, select **main**, and enable **Publish fork
update after checks pass (main only)**. After macOS, Linux, and Windows checks
pass, packaging and publishing run automatically. Users update from inside the
app; no local build is needed. The fork has its own versions (`1.0.0`, `1.0.1`,
and so on) and `fork-v*` tags, independent of upstream and CI run numbers. Leave
**Fork version** blank for the next patch or supply a newer minor/major version.
See [fork updates](docs/fork-updates.md) for details.

For a local macOS build, run `npm ci` followed by `npm run build:fork` with
`TAURI_SIGNING_PRIVATE_KEY` set to the fork's signing key path and
Expand Down
59 changes: 45 additions & 14 deletions docs/fork-updates.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,46 @@ available update in the sidebar. Failed checks or downloads do not count as a
successful update.

The old `0.1.x` fork builds have no update endpoint or public key, so they need
one initial replacement with a `0.2.x` build. Quit the old app first. If both
one initial replacement with a `0.2.x` or newer build. Quit the old app first. If both
`~/Applications/MonoCode Fork.app` and `/Applications/MonoCode Fork.app` exist,
launch the new copy from `/Applications` to avoid opening the old build.

## Releases

The `CI` workflow calls `fork-release.yml` after **all** macOS, Linux, and Windows
checks pass for a push to `main`. PR checks never publish. A manual run of `CI`
on `main` can also publish a release. No version edit, tag push, local build,
or agent request is needed after merging a change.
Merges accumulate on `main`. The `CI` workflow runs checks for every push and PR,
but neither event packages or publishes an app update. You decide when the
accumulated changes are ready to ship:

- The app's fork version is `0.2.<CI run number>`. Upstream's version stays in
`package.json`, Cargo, and the base Tauri config; the fork config overrides it.
- Release tags use `fork-v0.2.<CI run number>`, so upstream `v*` tags stay separate.
1. Open [Actions → CI](https://github.com/EricRasputin/monocode-eric/actions/workflows/ci.yml).
2. Choose **Run workflow** and select the **main** branch.
3. Enable **Publish fork update after checks pass (main only)**.
4. Leave **Fork version** blank for the next patch release, or enter a version
such as `1.1.0` or `2.0.0` when deliberately starting a minor or major release.
5. Run the workflow.

That run checks the selected main commit on macOS, Linux, and Windows. Only after
**all** checks pass does it call `fork-release.yml` to package, sign, and publish
both macOS builds. Commits merged after the run starts wait for a later release.
The app offers the new version through **Check for Updates…** after publication.
No local build, version edit, tag push, or agent request is needed.

The publish option is off by default, so a manual run can also be used just to
check CI. Selecting another branch never publishes, even with the option enabled.

- The fork has its own version sequence: `1.0.0`, `1.0.1`, `1.0.2`, and so on.
CI run numbers and upstream releases do not advance it. The first release under
this scheme is `1.0.0`, which upgrades from the earlier `0.2.x` fork builds.
Only stable versions in `major.minor.patch` form are accepted.
- Version selection runs inside the serialized release workflow, before either
architecture builds. It finds the highest published stable `fork-v*` version
and increments its patch number unless you supply a newer version explicitly.
Drafts, prereleases, and upstream tags do not determine the next version.
- Release tags use `fork-v1.0.0`, independently of upstream's `v*` tags. The fork
also has its own application identity, updater key, and release feed, so an
upstream release with the same numeric version cannot be installed as an update.
- Upstream's version stays in `package.json`, Cargo, and the base Tauri config;
the fork config overrides the app version. Release notes retain the upstream
version as provenance rather than using it as the fork's version.
- Both `darwin-aarch64` and `darwin-x86_64` packages must finish successfully.
- Packaging adds a changelog section for the fork version from changes on main
since the previous fork release, so the post-update **What's new** view works.
Expand All @@ -38,9 +64,13 @@ or agent request is needed after merging a change.
Only a complete upload becomes public and the latest release.
- The app reads `releases/latest/download/latest.json`; package URLs point to
immutable version tags. The embedded public key verifies update signatures.
- Releases are serialized. Reruns and delayed older builds never replace a
published newer release. A failed draft can be retried with the same CI run;
a fresh manual CI run gets a new version.
- An automatic version selection for an already-released commit skips packaging.
A delayed run for a commit that does not include the latest fork release fails
before packaging. Explicit versions must be newer than the latest release.
Neither reruns nor delayed builds replace a published newer release.
- A failed draft can be retried for its original commit and version. If that
version has a draft for another commit, choose a different explicit fork version;
the workflow refuses to overwrite a draft belonging to another commit.

The inherited upstream release workflow is restricted to `hardbeat920/monocode`.
It cannot publish an upstream-branded release over this fork's update feed.
Expand Down Expand Up @@ -69,10 +99,11 @@ References: [Tauri updater](https://v2.tauri.app/plugin/updater/) and

`npm run check:web` includes release metadata tests and the updater interaction
tests. CI additionally compiles and tests Rust on all three platforms. To recover
from a bad release, revert the source change and let CI publish a higher fork
version. Do not move an existing release tag or replace a published archive.
from a bad release, revert the source change and manually run CI with publishing
enabled to ship a higher fork version. Do not move an existing release tag or
replace a published archive.

Local builds default to `0.2.0`; release builds get their version through the
Local builds default to `1.0.0`; release builds get their version through the
Tauri config override in CI. Local builds are useful for development but are not
published releases. A private-key-free local build can disable generation of
updater artifacts using the command in the README.
Loading
Loading