Release cut mechanics — customization-branch squash-merge, changelog, tags, ruleset

The durable, reusable-across-partners git/GitHub mechanics for cutting a partner release on the vuer repos: how a devel-update PR actually lands on customization/<partner>, how the changelog is committed, how the source tag is created, and how the vuer-release build is triggered. Live-verified end-to-end by executing the NÚSZ 1.9.11.48 cut on 2026-08-25. This note is the customization/<partner> half; the vuer-release autobuild → Harbor half is vuer-release-cut-recipe.

For Agents

A partner release cut is FOUR distinct git operations across TWO repo families:

  1. Land the devel-update onto customization/<partner> in vuer_oss + vuer_css — via SQUASH merge (NOT a preserving merge, NOT a bypass override).
  2. Commit the changelog (customization/RELEASE.MD) directly to customization/<partner> — no PR needed, direct compliant commit.
  3. Create the source tags <partner>-<version> on both repos at the changelog commit — via API. Source tags do NOT trigger a build.
  4. Cut vuer-release — add release/<N>/release.json, tag <partner>@<N> → fires Harbor autobuild. See vuer-release-cut-recipe.

The ruleset facts below were read directly from the vuer_oss GitHub rulesets on 2026-08-25 and correct the older “team override-merges partner PRs” belief.

The big correction — devel-update PRs land by SQUASH, not by bypass override

The prior belief (“the team override-merges partner PRs” / “merge commits never satisfy the ruleset, so they bypass it”) was imprecise. The real mechanism is a squash merge. Verified by reading the vuer_oss rulesets and recent customization/nusz history.

The four vuer_oss rulesets (all bypass_actors: NONE)

vuer_oss has 4 branch/tag rulesets. Every one has bypass_actors: NONE — literally nobody, org admins included, can bypass them. Anything with --admin bypasses failing status checks, never these rulesets.

#RulesetEnforcesPatternApplies to
1Merge commit rulescommit message (per-commit)^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(!)?(\([^)]+\))?: \[[a-z]+-\d+\] .{1,100}(\n[\s\S]*)?$bracketed lowercase ticket requiredrefs/heads/customization/** + refs/heads/devel
2Feature commit rulescommit message (per-commit)same conventional prefix but no bracket: …: [^\n]{1,100}~ALL
3Custom branch rulesnew branch name^(feature|feat|chore|fix|release)/(FKITDEV|FKQA)-\d+(-.+)?$~ALL
4Custom tag rulestag name^.*-\d+\.\d+\.\d+\.\d+(-rc-\d+)?$~ALL

Why a preserving --merge can never pass on customization/**

A preserving merge of a devel-update PR drags every devel commit (which have bracket-less feat: … subjects) onto customization/**. Ruleset #1 (“Merge commit rules”) is enforced per-commit with no bypass, and those devel commits fail its bracketed-ticket pattern. So merge-commit style is structurally impossible for a devel-update PR into customization/<partner>.

The working path = SQUASH

gh pr merge <n> -R TechTeamer/vuer_oss --squash --admin
  • Squash collapses the whole PR to one commit whose message = the PR title (GitHub appends (#N)). Only that single subject is checked against ruleset #1.
  • Therefore the PR title MUST be ruleset-compliant BEFORE merging: chore: [fkitdev-9217] nusz devel update (conventional prefix + bracketed lowercase ticket).
  • Confirmed by history: recent customization/nusz commits are all parents:1 squashes, e.g. fix: [fkitdev-9150]: … (#8095).
  • Fix the title first (always pass -R):
    gh pr edit <n> -R TechTeamer/vuer_oss --title "chore: [fkitdev-9217] nusz devel update"

--admin skips RED CHECKS, not the ruleset

--admin bypasses only the failing status checks (Audit / Unused Dependencies / Unit Tests — the chronic inherited gates). It does NOT bypass the commit-message ruleset (bypass_actors: NONE). The override needs BOTH: a compliant title (satisfies ruleset #1) and --admin (skips the red checks).

Claude Code auto-mode classifier blocks --admin merges

gh pr merge … --admin is blocked by the auto-mode safety classifier (admin/bypass = high-stakes) — the USER must run it (via the ! prefix) or approve it. Regular gh api writes are not blocked: gh api -X PUT …/contents/… (changelog commit) and gh api -X POST …/git/refs (tag creation) went through fine.

Changelog = direct compliant commit (no PR)

customization/<partner> has NO require-PR rule — only the commit-message pattern (ruleset #1). So the changelog lands as a direct commit on the branch, via API:

gh api -X PUT repos/TechTeamer/vuer_oss/contents/customization/RELEASE.MD \
  -f message="chore: [assnusz-126] 1.9.11.48 changelog" \
  -f branch="customization/nusz" \
  -f sha="<current-blob-sha>" \
  -f content="<base64>"
  • Message chore: [assnusz-126] 1.9.11.48 changelog — bracketed lowercase ticket → satisfies ruleset #1.
  • oss and css RELEASE.MD are SEPARATE files with different per-repo entries. For .48: oss listed ASSNUSZ-76/117 + “általános rendszerfrissítés”; css listed only “általános rendszerfrissítés (devel szinkronizáció)“. Do not copy one into the other.
  • Determine the real per-repo delta before writing the entry:
    gh api repos/TechTeamer/vuer_oss/compare/nusz-1.9.11.47...customization/nusz

Source tags via API

gh api -X POST repos/TechTeamer/vuer_oss/git/refs \
  -f ref="refs/tags/nusz-1.9.11.48" \
  -f sha="<changelog-commit-sha>"
  • Tag name nusz-1.9.11.48 satisfies ruleset #4 (^.*-\d+\.\d+\.\d+\.\d+…$).
  • Point the tag at the changelog commit on customization/<partner>.
  • Source tags do NOT trigger a build. Only the <partner>@<N> tag on vuer-release fires Harbor autobuild.

vuer-release cut (build trigger) — quick facts

Full recipe: vuer-release-cut-recipe. Durable facts confirmed on the .48 cut:

  • Default branch is master (NOT main — a 404 on main wastes an API call).
  • Copy projects/nusz/release/16/release.jsonrelease/17/, then bump:
    • RELEASE_VERSION 16→17 (top-level AND inside DEFAULT_ARGS)
    • both COMPONENT_LIST entries: VERSION1.9.11.48, TAGnusz-1.9.11.48
    • unchanged: BUILD_NUMBER stays "1", NODE_VERSION 22, BUNDLE_IMAGE false, janus JANUS_VERSION_COMMIT cc0fdca8…
  • Commit it, then create tag nusz@17. Confirm the next number from the remote: git ls-remote --tags … 'nusz@*' (@16 was highest; @8 was skipped historically — do not reuse skipped numbers).
  • The nusz@<N> tag is the Harbor build trigger: workflow “VUER - Autobuild and Publish” fires on the pushed tag + changed release.json, builds and pushes harbor.techteamer.com/nusz/{vuer_oss,vuer_css}:1.9.11.48.
  • nusz@N tag names do NOT match vuer_oss’s tag pattern (ruleset #4). So vuer-release has its own / looser tag rules — the @N convention is only valid on vuer-release.

Known inherited red on the .48 PRs (NOT a regression)

  • oss Unit Tests failed on the .48 PR: test/tests/unit/translations.test.js → “Directory not found: client/features” (hardcoded scan path vs the current devel structure). This is a known inherited failure — hence --admin.
  • css passed unit tests. The oss failure is the pre-existing one above, not something the devel-update introduced.

Worked example — NÚSZ 1.9.11.48 (executed 2026-08-25)

The .48 cut was run end-to-end today:

Stepvuer_ossvuer_css
devel-update PR squash-mergede01bf599f8511f79
changelog direct commitc8c5f7e708fc5380
source tag nusz-1.9.11.48 at(changelog commit)(changelog commit)
vuer-release release/17/release.jsoncommit 3bd20ec7
build trigger tagnusz@17 pushed

Build running at time of writing. Release ticket ASSNUSZ-126, prep ticket FKITDEV-9217. Test runbook: nusz-1.9.11.48-test-runbook.

vuer-release-cut-recipe · techteamer-commit-message-ruleset · nusz-1.9.11.48-test-runbook · nusz-1.9.11.47 · release-automation-design · release-pipeline-automation-spec