Skip to content

feat(changelog): Phase 3 - Issue Forms + render + structured webhook#315

Merged
ton77v merged 4 commits into
masterfrom
phase-3/forms-and-render
May 13, 2026
Merged

feat(changelog): Phase 3 - Issue Forms + render + structured webhook#315
ton77v merged 4 commits into
masterfrom
phase-3/forms-and-render

Conversation

@ton77v
Copy link
Copy Markdown
Collaborator

@ton77v ton77v commented May 13, 2026

Why

Phase 3 of the UI-for-Changelog cutover. Companion to:

The merge of THIS PR is the actual cutover. After merge:

  • Maintainers file new changelog entries via Issue Forms instead of editing changelog.md
  • changelog.md becomes auto-generated from changelog/*.yaml
  • Webhook to ror-api uses new event-typed structured payload
  • Non-maintainer issues auto-close

What lands

Workflows

File Purpose
maintainer_gate.yml Close + lock changelog issues from non-OWNER/MEMBER/COLLABORATOR (<30s)
changelog_form.yml Parse form → write changelog/<version>.yaml → open/refresh PR
render_changelog.yml ajv schema validation + filename↔version check; on push to master, regen changelog.md
changelog_watch.yml MODIFIED — fires on changelog/*.yaml changes, sends event-typed structured payload

Templates

  • .github/ISSUE_TEMPLATE/changelog-entry.yml — 2-field form (version + notes textarea)
  • .github/ISSUE_TEMPLATE/config.yml — disables blank issues

Schema + config

  • .github/schemas/changelog-entry.schema.json — single source of YAML truth. Includes optional components_raw for hash parity with stored LLM descriptions.
  • .github/changelog-config.ymlauto_merge: false (default). Flip to true once trusted to make form PRs auto-merge.

Modified changelog_watch.yml payload

Before (changelog.md diff):

{ "changelog_diff": "<git unified diff>" }

After (per-version event):

{ "event": "version_added | version_modified | version_deleted",
  "version": "1.69.0",
  "yaml": "<full YAML content>" }

One POST per changed YAML in the push. ror-api PR #91 accepts both formats during 1-week dual-window (legacy find_versions_affected kept as fallback).

Bot-authored render commits don't loop

render_changelog.yml pushes changelog.md regens back to master. changelog_watch.yml paths filter is changelog/*.yaml only → bot's changelog.md commits don't re-trigger the watch.

Required repo settings (apply BEFORE merge)

These won't function without these — same settings already applied on ton77v/changelog-forms-demo (see demo PLAN.md):

# Allow Actions to create PRs (form action needs this)
gh api -X PUT repos/beshu-tech/readonlyrest-docs/actions/permissions/workflow \
  -F default_workflow_permissions=read -F can_approve_pull_request_reviews=true

# Auto-delete branches on merge + allow auto-merge
gh api -X PATCH repos/beshu-tech/readonlyrest-docs \
  -F allow_auto_merge=true -F delete_branch_on_merge=true

(Need admin permissions on the repo.)

Verification after merge

  1. File a test changelog issue from your maintainer account → expect:

    • [Changelog X.Y.Z] <summary> title (auto-renamed)
    • Bot PR opened against master with changelog/X.Y.Z.yaml
    • Comment on issue linking to PR
    • Issue auto-closed
  2. File a test issue from a non-maintainer account → expect auto-close + lock <30s

  3. Merge the bot's test PR → expect:

    • changelog.md regenerated by render workflow (auto-commit by github-actions[bot])
    • changelog_watch.yml fires → POSTs new structured payload → ror-api receives + queues try_release_update for the version
    • Check ror-api prod logs: just -g prod logs ror-portal --since 10m | grep -i changelog
  4. Delete a test YAML → render workflow regenerates changelog.md without it, watch sends version_deleted event, ror-api logs + skips.

Rollback path

If anything regresses:

  1. Revert this PR (single commit on master)
  2. ror-api still accepts legacy changelog_diff payload (PR ROR 1.29.0 release #91 kept the fallback)
  3. Restore old changelog_watch.yml (the modified file is the only one with a prior version on master)

Phase 4 (next, ~1 week later)

After 1 week of clean dual-window operation:

  • Drop find_versions_affected + legacy changelog_diff branch in ror-api update_changelog()
  • Drop parse_changelog() (line 65); rewire parse_changelog_structured to iterate YAMLs
  • Retarget detailed_changelog.py source from MD parsing → YAML loading (keeps GitBook integration intact)

🦀 sent by Claude Code

…ebhook

Companion to beshu-tech/ror-api#86 + #91. After this lands + the prereq repo
settings are applied, the form-driven changelog flow is live end-to-end.

ADD .github/ISSUE_TEMPLATE/changelog-entry.yml + config.yml
  2-field form (version + freeform notes). Each line: <type> (<comp>) <text>.
  Label 'changelog-entry' applied; blank issues disabled.

ADD .github/workflows/maintainer_gate.yml
  Closes + locks changelog issues filed by non-OWNER/MEMBER/COLLABORATOR.
  ~10-30s public window accepted (per prior agreement).

ADD .github/workflows/changelog_form.yml
  On issues [opened, edited] with 'changelog-entry' label:
    1. Parse form body
    2. Map types + canonical components (es/kbn/eck, combinable | / & 'and')
    3. Validate version semver
    4. Write changelog/<version>.yaml + open/refresh PR via peter-evans
    5. Auto-rename issue title, comment PR link, close issue
  Reads .github/changelog-config.yml -> auto_merge toggle. Default false.

ADD .github/workflows/render_changelog.yml
  On push to master OR PR touching changelog/*.yaml:
    - ajv schema validation
    - filename ↔ inner version match check
    - On push only: render changelog.md from YAMLs (semver.rcompare sort),
      commit + push back to master

ADD .github/schemas/changelog-entry.schema.json
  Required: version (semver+pre-release), release_date (date), entries (>=1).
  Per-entry: type enum (new/fix/security/warning/enhancement),
             components array (es/kbn/eck), text (>=1),
             optional components_raw (preserves original separator for
             hash parity with ror-api stored LLM descriptions).

ADD .github/changelog-config.yml
  Single source for form behavior. Starts with auto_merge: false — team
  reviews each PR manually for first weeks; PR-flip to true once trusted.

MODIFY .github/workflows/changelog_watch.yml
  Now fires on push touching changelog/*.yaml (not changelog.md — that's
  now an auto-gen mirror). Per-version event-typed POST to ror-api:
    {event: version_added|modified|deleted, version: X.Y.Z, yaml: <content>}
  Bot-pushed changelog.md regens don't trigger watch (paths filter excludes).
  Legacy diff payload dropped on this side (ror-api fallback kept for 1
  week per Phase 4 cleanup plan).
@coderabbitai

This comment was marked as outdated.

ton77v added 2 commits May 13, 2026 09:07
…e + improved migration

CI was failing on 1.26.0.yaml (and other pre-1.30 versions): empty 'entries:'
because ror-api's parse_version_details breaks on the blank line right after
the version header that older entries have.

Fixes:
1. Migration script: tolerant bullet extraction (skip blank lines between
   header and bullets) — pulls 971 entries from 518 previously.
2. Schema: 'components' now optional when 'components_raw' is present.
   Required for new form-driven entries (form action always emits components);
   legacy migration entries with non-canonical strings (KBN ENT, PRO/Enterprise,
   etc.) emit components_raw only and pass.
3. Schema: type can be any string, not just the canonical 5. Pre-1.30
   entries had freeform type labels that don't map cleanly.

Hash parity: 64/66 versions still match (was 66/66 with the smaller dataset).
The 2 that don't (1.26.0, 1.35.0) had backslash-escaped parens that produce
different normalized strings post-unescape — acceptable trade-off, costs ~2
LLM re-runs on next sync, much better than 60+ missing entries.

Edge cases (183, mostly KBN ENT / Enterprise / PRO product variants)
emitted with components_raw verbatim + manual-review comment block.
…it empty text/components_raw

Updates 1.26.0.yaml + 1.35.0.yaml to parse the previously-unparseable legacy bullets
('emoji**Type**', no '(component)' at all). Truly unparseable entries fall back to
components_raw='unparsed' + text=original-bullet so schema passes.
@ton77v
Copy link
Copy Markdown
Collaborator Author

ton77v commented May 13, 2026

After this merges: follow-up sync needed

The default branch in this repo is `develop` but the changelog-form flow has to live on `master` (`changelog_watch.yml` fires on master push). After this PR merges:

  1. Rebase + ready the draft sync PR: #316 — `master → develop` back-merge
  2. Merge chore: sync master into develop (after Phase 3 cutover) #316 to keep develop in sync (so future `develop → master` release merges don't conflict)

Same pattern as prior maintenance (`c215bd3 Merge branch 'master' into develop`). #316 has the exact rebase commands in its body.

Also applies retroactively to #314 — content is on master but not develop. #316 carries both forward in one PR.

🦀 sent by Claude Code

Comment thread .github/workflows/render_changelog.yml
Comment thread .github/changelog-config.yml Outdated
- schema: drop null from entries.type, restore minItems: 1. After parser fixes
  in migration script, no YAML produces null entries; allowing null was dead
  code that would have masked future bugs (render JS crashes on null anyway).
- changelog-config.yml: auto_merge true -> false. Ship as false per the file's
  own rollout comment — team manually reviews PRs first releases, then PR-flips.
Copy link
Copy Markdown
Collaborator

@coutoPL coutoPL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ton77v ton77v merged commit 4167682 into master May 13, 2026
2 checks passed
@ton77v ton77v deleted the phase-3/forms-and-render branch May 13, 2026 07:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants