Skip to content

Commit f6deb4d

Browse files
committed
ci(zaparoo): split stable vs beta release channels
Decouple fork-feature promotion from upstream sync. master is the integration/beta branch feeding the unstable prerelease; a new stable branch carries only promoted fork features and feeds the distribution stable release. Both branches keep merging upstream/master so each channel's fork diff (upstream/master..<branch>) stays fork-only. - sync_upstream.sh: merge upstream into both master and stable - sync_release.yml: build each channel from its own branch checkout - push_release.yml: master push -> unstable only, stable push -> stable only - docs: support/zaparoo/RELEASE.md describes channels + promotion
1 parent 923cd05 commit f6deb4d

6 files changed

Lines changed: 164 additions & 31 deletions

File tree

.github/sync_upstream.sh

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,20 @@
22
# Copyright (c) 2020 José Manuel Barroso Galindo <theypsilon@gmail.com>
33
# Adapted from https://github.com/MiSTer-DB9/Main_MiSTer
44
#
5-
# Merge upstream MiSTer-devel/Main_MiSTer into master.
6-
# Outputs changed=true/false to $GITHUB_OUTPUT.
5+
# Merge upstream MiSTer-devel/Main_MiSTer into both release-channel branches:
6+
# master -> integration/beta branch, feeds the unstable prerelease channel
7+
# stable -> promoted branch, feeds the distribution stable channel
8+
#
9+
# Both branches must keep absorbing upstream merges so that each channel's fork
10+
# diff (upstream/master..<branch>) stays fork-only. Emits <branch>_changed=true/false
11+
# to $GITHUB_OUTPUT so the workflow can push/build only what moved.
712

813
set -euo pipefail
914

1015
UPSTREAM_REPO="https://github.com/MiSTer-devel/Main_MiSTer.git"
1116
MAIN_BRANCH="master"
17+
# Channel branches to keep in sync with upstream/master.
18+
SYNC_BRANCHES="${SYNC_BRANCHES:-master stable}"
1219

1320
export GIT_MERGE_AUTOEDIT=no
1421
git config --local user.name "zaparoo-ci-bot"
@@ -55,23 +62,43 @@ elif [ -n "${ORIGINAL_HEAD:-}" ]; then
5562
git checkout -q "${ORIGINAL_HEAD}"
5663
fi
5764

58-
echo ""
59-
echo "Merging upstream/${MAIN_BRANCH}..."
60-
BEFORE=$(git rev-parse HEAD)
61-
62-
if ! git merge -Xignore-all-space --no-edit "upstream/${MAIN_BRANCH}"; then
65+
# Merge upstream into each channel branch. rerere (trained above, shared cache)
66+
# auto-resolves recurring conflicts; stable's conflicts are a subset of master's.
67+
sync_branch() {
68+
local branch="$1"
6369
echo ""
64-
echo "ERROR: Merge conflict. Resolve locally, commit, and push."
65-
echo "git rerere will remember the resolution for future runs."
66-
exit 1
67-
fi
70+
echo "=== Syncing ${branch} <- upstream/${MAIN_BRANCH} ==="
71+
72+
if ! git rev-parse --verify --quiet "origin/${branch}" >/dev/null; then
73+
echo "origin/${branch} does not exist yet; skipping."
74+
echo "${branch}_changed=false" >> "${GITHUB_OUTPUT:-/dev/null}"
75+
return 0
76+
fi
6877

69-
AFTER=$(git rev-parse HEAD)
78+
git checkout -q -B "${branch}" "origin/${branch}"
79+
local before after
80+
before=$(git rev-parse HEAD)
7081

71-
if [ "${BEFORE}" = "${AFTER}" ]; then
72-
echo "Already up-to-date with upstream."
73-
echo "changed=false" >> "${GITHUB_OUTPUT:-/dev/null}"
74-
else
75-
echo "Merged upstream changes ($(git rev-parse --short HEAD))."
76-
echo "changed=true" >> "${GITHUB_OUTPUT:-/dev/null}"
77-
fi
82+
if ! git merge -Xignore-all-space --no-edit "upstream/${MAIN_BRANCH}"; then
83+
echo ""
84+
echo "ERROR: Merge conflict on ${branch}. Resolve locally, commit, and push."
85+
echo "git rerere will remember the resolution for future runs."
86+
exit 1
87+
fi
88+
89+
after=$(git rev-parse HEAD)
90+
if [ "${before}" = "${after}" ]; then
91+
echo "${branch} already up-to-date with upstream."
92+
echo "${branch}_changed=false" >> "${GITHUB_OUTPUT:-/dev/null}"
93+
else
94+
echo "Merged upstream into ${branch} ($(git rev-parse --short HEAD))."
95+
echo "${branch}_changed=true" >> "${GITHUB_OUTPUT:-/dev/null}"
96+
fi
97+
}
98+
99+
for branch in ${SYNC_BRANCHES}; do
100+
sync_branch "${branch}"
101+
done
102+
103+
# Leave the checkout on the main branch for subsequent steps.
104+
git checkout -q "${MAIN_BRANCH}"

.github/workflows/push_release.yml

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ concurrency:
66

77
on:
88
push:
9-
branches: [master]
9+
branches: [master, stable]
1010
workflow_dispatch:
1111

1212
permissions:
@@ -28,12 +28,16 @@ jobs:
2828
path: gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf
2929
key: gcc-arm-10.2-2020.11
3030

31-
- name: Build and release (stable)
32-
run: bash .github/build_release.sh
31+
# Push to master = integration/beta -> rebuild the unstable prerelease only.
32+
- name: Build and release (unstable)
33+
if: github.ref_name == 'master'
34+
run: bash .github/build_unstable_release.sh
3335
env:
3436
GH_TOKEN: ${{ github.token }}
3537

36-
- name: Build and release (unstable)
37-
run: bash .github/build_unstable_release.sh
38+
# Push to stable = promotion -> re-cut the distribution stable release only.
39+
- name: Build and release (stable)
40+
if: github.ref_name == 'stable'
41+
run: bash .github/build_release.sh
3842
env:
3943
GH_TOKEN: ${{ github.token }}

.github/workflows/sync_release.yml

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,31 @@ jobs:
3333
path: gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf
3434
key: gcc-arm-10.2-2020.11
3535

36-
- name: Push merge commit
37-
if: steps.sync.outputs.changed == 'true'
36+
- name: Push master merge commit
37+
if: steps.sync.outputs.master_changed == 'true'
3838
run: git push origin master
3939

40-
- name: Build stable release
41-
run: bash .github/build_release.sh
40+
- name: Push stable merge commit
41+
if: steps.sync.outputs.stable_changed == 'true'
42+
run: git push origin stable
43+
44+
# Unstable channel: upstream master HEAD + fork @ master (includes beta).
45+
- name: Build unstable release
46+
run: |
47+
git checkout master
48+
bash .github/build_unstable_release.sh
4249
env:
4350
GH_TOKEN: ${{ github.token }}
4451
SKIP_EXISTING_RELEASE: true
4552

46-
- name: Build unstable release
47-
run: bash .github/build_unstable_release.sh
53+
# Stable channel: upstream tagged release + fork @ stable (promoted only).
54+
- name: Build stable release
55+
run: |
56+
if ! git checkout stable 2>/dev/null; then
57+
echo "No stable branch yet; skipping stable build."
58+
exit 0
59+
fi
60+
bash .github/build_release.sh
4861
env:
4962
GH_TOKEN: ${{ github.token }}
5063
SKIP_EXISTING_RELEASE: true

AGENTS.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,36 @@ make clean # remove bin/
4040

4141
**Deploy to device**: `./build.sh` — builds, kills the running `MiSTer` process over SSH, FTPs the binary to `/media/fat/MiSTer`, and relaunches it. Put the device's IP in a `host` file beside the script (default `192.168.1.75`, root/`1`).
4242

43-
There is no automated test suite, linter, or CI.
43+
There is no automated test suite or linter. CI (GitHub Actions) builds and publishes
44+
releases — see **Release channels** below.
45+
46+
---
47+
48+
## !! Release channels — beta vs distribution !!
49+
50+
This fork auto-syncs upstream daily and publishes **two channels from two branches**:
51+
52+
- **`master`** = integration/beta branch → **unstable prerelease** (`MiSTer_Zaparoo_unstable`).
53+
New fork work (PRs) lands here and reaches **opt-in testers only**.
54+
- **`stable`** = promoted branch → **distribution release** (`MiSTer_Zaparoo_YYYYMMDD`).
55+
This is what every MiSTer user gets.
56+
57+
**Rules for agents:**
58+
59+
1. **Land all new fork work on `master`.** NEVER commit beta/unreleased features directly to
60+
`stable` — that ships them to everyone.
61+
2. **Both branches keep merging `upstream/master`** (`.github/sync_upstream.sh`). Each channel's
62+
build layers the fork diff `upstream/master..<branch>` onto an upstream base, so that diff
63+
must stay **fork-only** — keep both branches upstream-synced.
64+
3. **Promote to the distribution only when explicitly asked:**
65+
`git checkout stable && git merge master && git push origin stable`. If the promoted feature
66+
adds *new* hooks to `input.cpp` or `scheduler.cpp`, also update
67+
`.github/apply_stable_hooks.py` on `stable` (stable's hooks in those two files come from that
68+
script, not the diff).
69+
70+
Full details: `support/zaparoo/RELEASE.md`.
71+
72+
---
4473

4574
## Architecture
4675

ZAPAROO_FORK.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ non-blocking spawn) are intentionally omitted.
1414
> the table below or revise the inconsistencies section. Stale entries are
1515
> worse than no entries — please prune as you cleanup.
1616
17+
> **Release process:** see [`support/zaparoo/RELEASE.md`](support/zaparoo/RELEASE.md)
18+
> for the `master` (beta → unstable) vs `stable` (promoted → distribution) channel
19+
> split and how to promote a feature to a public release.
20+
1721
---
1822

1923
## 1. Change map

support/zaparoo/RELEASE.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Zaparoo fork release channels
2+
3+
This fork auto-syncs `upstream/master` every day. Two long-lived branches feed two
4+
release channels, so upstream syncing and fork-feature promotion are decoupled.
5+
6+
| Branch | Feeds | Release tag | Prerelease? | Who gets it |
7+
|----------|--------------------|---------------------------|-------------|------------------------------------|
8+
| `master` | unstable channel | `MiSTer_Zaparoo_unstable` | yes | opt-in testers / nightly users |
9+
| `stable` | stable channel | `MiSTer_Zaparoo_YYYYMMDD` | no | the MiSTer distribution (everyone) |
10+
11+
- `master` is the integration/beta branch. New fork features (PRs) land here and
12+
immediately reach **only** the unstable prerelease.
13+
- `stable` carries only **promoted** fork features. It is what the distribution ships.
14+
- Both branches keep merging `upstream/master` (see `.github/sync_upstream.sh`), so each
15+
channel stays current with upstream. This is required: each channel's build layers the
16+
fork diff `upstream/master..<branch>` onto an upstream base, and that diff is only
17+
fork-only while the branch contains upstream's commits.
18+
19+
## How a build is assembled
20+
21+
- **Unstable** (`.github/build_unstable_release.sh``unstable-build.sh`): upstream `master`
22+
HEAD base + `git diff upstream/master..master`.
23+
- **Stable** (`.github/build_release.sh``stable-build.sh`): upstream's latest tagged
24+
release (`releases/MiSTer_*`) base + `git diff upstream/master..stable`, with the
25+
`input.cpp` / `scheduler.cpp` hooks re-applied by `.github/apply_stable_hooks.py`.
26+
27+
Each channel is built from a checkout of its **own branch**, so its content, build scripts,
28+
and hook list all come from that branch.
29+
30+
## Triggers
31+
32+
- Push to `master` → rebuild the unstable prerelease only.
33+
- Push to `stable` → re-cut the stable distribution release only.
34+
- Daily `Sync + Stable Release` workflow → merge upstream into both branches, then rebuild
35+
both channels (skipping a channel whose release already exists for the same inputs).
36+
37+
## Promoting a feature to stable
38+
39+
When a beta feature on `master` is ready to ship to everyone:
40+
41+
```sh
42+
git checkout stable
43+
git merge master # or cherry-pick specific commits for a partial promotion
44+
# If the promoted feature adds NEW hooks to input.cpp or scheduler.cpp, also update
45+
# .github/apply_stable_hooks.py on stable to include them (see caveat below).
46+
git push origin stable # triggers a fresh MiSTer_Zaparoo_YYYYMMDD stable release
47+
```
48+
49+
### Caveat: input.cpp / scheduler.cpp hooks
50+
51+
The stable build excludes `input.cpp` and `scheduler.cpp` from the fork diff and instead
52+
re-applies a **hardcoded** set of hooks via `.github/apply_stable_hooks.py`. So stable's
53+
hooks in those two files are governed by that script, not by merging the diff. Promoting a
54+
feature that adds new hooks to either file requires editing `apply_stable_hooks.py` on the
55+
`stable` branch as well. Features that only touch new `support/zaparoo/*` files (or other
56+
upstream files) are handled by the diff alone — no script change needed.

0 commit comments

Comments
 (0)