원클릭으로
beta-prerelease
// Publish an OTGW-firmware beta prerelease — bump _VERSION_PRERELEASE, push to dev, tag, and let CI build + publish the GitHub prerelease
// Publish an OTGW-firmware beta prerelease — bump _VERSION_PRERELEASE, push to dev, tag, and let CI build + publish the GitHub prerelease
Prepare and execute a full OTGW-firmware release following the documented release process
Update OTGW-firmware documentation in one sequential, backlog-tracked workflow (dev / 1.5.x line)
Build firmware + filesystem and flash to ESP via USB. Auto-detects serial port. No user input needed.
Architecture Decision Record (ADR) management skill. Creates, maintains, and enforces architectural decisions. Ensures code changes align with documented decisions. Documents alternatives considered and rejected. Facilitates architectural planning and human decision documentation.
Architecture Decision Record (ADR) management skill. Creates, maintains, and enforces architectural decisions. Ensures code changes align with documented decisions. Documents alternatives considered and rejected. Facilitates architectural planning and human decision documentation.
| name | beta-prerelease |
| description | Publish an OTGW-firmware beta prerelease — bump _VERSION_PRERELEASE, push to dev, tag, and let CI build + publish the GitHub prerelease |
| disable-model-invocation | true |
Publish a single beta build to field testers in Discord #beta-testing. Lightweight, repeatable many times within one minor cycle. Does NOT merge to main, does NOT touch the stable _SEMVER_CORE.
/beta-prerelease
No arguments. Auto-detects the current _VERSION_PRERELEASE and increments it via bin/bump-prerelease.sh.
tee .tmp/build_beta.log | tail -5. Only read .tmp/build_beta.log if exit code != 0.grep/sed to extract only the relevant section from each file. Never read README, CHANGELOG, or RELEASE_NOTES in full..github/workflows/beta-prerelease.yml only if a trap is actually hit.gh run watch instead of opening a browser.Run when a firmware change under src/OTGW-firmware/** or src/libraries/** is committed and ready for field testing. Do NOT use for docs-only commits or full releases to main (use /release <version> for those).
| Aspect | /release | /beta-prerelease |
|---|---|---|
| Target branch | dev then merge to main | dev only |
Bumps _SEMVER_CORE | yes | no |
| GitHub release | stable, not prerelease | prerelease: true |
| Discord channels | #nederlandse-ondersteuning, #english-support | #beta-testing |
| Mandatory checkpoints | 2 | 1 (Discord announcement) |
dev: git checkout devgit status must be clean (or only the firmware change about to be bumped). Then git pull origin dev.git fetch --tags
PREV_TAG=$(git tag --list 'v*-*.*' --sort=-v:refname | head -1)
LATEST_PUBLIC):
LATEST_PUBLIC=$(gh release view --json tagName --jq '.tagName' 2>/dev/null \
|| git tag --list 'v[0-9]*.[0-9]*.[0-9]*' --sort=-v:refname | grep -v -- '-' | head -1)
grep _VERSION_PRERELEASE src/OTGW-firmware/version.hSkip by default. Only pause if the staged firmware change introduces a new architectural pattern, dependency, or NFR shift. Most beta cycles do not need this gate.
bin/bump-prerelease.sh
Prints the transition (e.g. beta.3 -> beta.4). Store the new value as NEW_PRERELEASE. The helper does NOT git-add — you stage in Phase 6.
Assemble the tag: TAG="v${SEMVER_CORE}-${NEW_PRERELEASE}"
The GitHub Action reads these files at the tagged commit. Stale narrative at the tag = stale release page (Trap 1). Refresh immediately after the bump so NEW_PRERELEASE is known.
Staleness check (P2 — targeted extractions, not full reads):
# 1. Commits since last public release (the change set to account for)
git log --pretty=format:'%h %s' "${LATEST_PUBLIC}..HEAD" -- src/OTGW-firmware/ src/libraries/ docs/
# 2. Existing narrative — extract only the relevant sections
grep -A 50 "What's new on dev" README.md | head -55
grep -A 35 "## \[Unreleased\]" CHANGELOG.md | head -40
sed -n '1,/<!-- digest:end -->/p' RELEASE_NOTES_*-beta.md 2>/dev/null
Decision:
NEW_PRERELEASE → pass silently, continue to Phase 4.Authoring rules (P3 — write immediately, keep only filename in context):
CHANGELOG.md — append under ## [Unreleased] using Keep-a-Changelog headings (### Added/Changed/Fixed/Removed/Documentation). One bullet per change, with ADR/TASK/PR reference. → note "Updated."README.md — update dev-banner version label to NEW_PRERELEASE and "What's new on dev" section. Do NOT touch the "What's New in v" section. → note "Updated."RELEASE_NOTES_<base>-beta.md — update the digest region above <!-- digest:end -->. → note "Updated."Skip all three only when this is a re-cut at the same change surface (previous tag hit Trap 2). Note the reason in the commit message.
mkdir -p .tmp
python build.py --firmware 2>&1 | tee .tmp/build_beta.log | tail -5
echo "Exit: $?"
Must exit 0. On failure: read .tmp/build_beta.log for diagnosis, fix, retry. Do NOT push a tag on a broken build.
python evaluate.py --quick
Must show no new failures. Pre-existing baseline failures unrelated to this change: document in the commit message.
git add src/OTGW-firmware/version.h src/OTGW-firmware/data/version.hash \
<firmware-files> \
CHANGELOG.md README.md \
RELEASE_NOTES_*-beta.md
git commit -m "chore(release): ${NEW_PRERELEASE}
<one-line summary of what is in this beta>"
git push origin dev
If the pre-commit hook blocks: re-stage version.h + data/version.hash and retry. Do NOT bypass with OTGW_BUMP_HOOK_DISABLE=1.
SEMVER_CORE=$(grep '_SEMVER_CORE ' src/OTGW-firmware/version.h | awk -F'"' '{print $2}')
TAG="v${SEMVER_CORE}-${NEW_PRERELEASE}"
git tag -a "${TAG}" -m "Beta prerelease ${NEW_PRERELEASE}"
git push origin "${TAG}"
The push fires .github/workflows/beta-prerelease.yml. CI builds firmware + filesystem, creates a GitHub prerelease, uploads .ino.bin, .littlefs.bin, SHA256SUMS, flash scripts, and the flash-bundle zip.
gh run watch --exit-status
When it exits 0, verify the release:
gh release view "${TAG}" --json tagName,isPrerelease,assets \
--jq '{tag: .tagName, prerelease: .isPrerelease, assets: [.assets[].name]}'
Expected assets: *.ino.bin, *.littlefs.bin, SHA256SUMS, flash_otgw.sh, flash_otgw.bat, OTGW-firmware-*-flash-bundle.zip.
On failure: inspect logs with gh run view --log-failed, fix the issue, and re-run via workflow_dispatch or push a new tag.
Prepare announcement for #beta-testing (channel ID 914498730001072149). Diff link points at LATEST_PUBLIC (testers want to see what changed since the last stable, not since a previous beta).
Beta ${NEW_PRERELEASE} is up.
Version: ${SEMVER_CORE}-${NEW_PRERELEASE}
What is new: <one or two sentences>
Download: https://github.com/rvdbreemen/OTGW-firmware/releases/tag/${TAG}
Diff vs ${LATEST_PUBLIC}: https://github.com/rvdbreemen/OTGW-firmware/compare/${LATEST_PUBLIC}...${TAG}
Changelog: https://github.com/rvdbreemen/OTGW-firmware/blob/${TAG}/CHANGELOG.md
Please flash and report findings here (good and bad).
CHECKPOINT: Show the announcement to the user before sending.
git checkout -b test/beta-prerelease-dryrun
git tag -a v0.0.0-beta.dryrun -m "dryrun" && git push origin v0.0.0-beta.dryrun
# watch the Action, then clean up:
gh release delete v0.0.0-beta.dryrun --yes
git push --delete origin v0.0.0-beta.dryrun && git tag -d v0.0.0-beta.dryrun
git checkout dev && git branch -d test/beta-prerelease-dryrun
beta-prerelease.yml)gh release create returns HTTP 422. Workaround already in CI: draft-first, attach all assets, then flip --draft=false. If you hit this manually, re-tag under the next beta number.GITHUB_TOKEN events do not chain — release-assets.yml (triggered by release: published) does not fire when the release is created by GITHUB_TOKEN. beta-prerelease.yml is therefore self-contained (generates SHA256SUMS + zip + flash scripts itself).LATEST_PUBLIC (the non-prerelease "Latest" release), not the previous beta tag.OTGW_BUMP_HOOK_DISABLE=1 — if the hook blocks, you forgot to stage version.h / data/version.hash.