Skip to content

feat(auto-derive): atomic flip — retire bump-tag.yml + tools/release/ PHP toolchain#141

Merged
bradymiller merged 1 commit into
openemr:masterfrom
bradymiller:demo-farm-pr3-retire-bumper
Jun 28, 2026
Merged

feat(auto-derive): atomic flip — retire bump-tag.yml + tools/release/ PHP toolchain#141
bradymiller merged 1 commit into
openemr:masterfrom
bradymiller:demo-farm-pr3-retire-bumper

Conversation

@bradymiller

@bradymiller bradymiller commented Jun 28, 2026

Copy link
Copy Markdown
Member

What changes

  • Delete .github/workflows/bump-tag.yml (the repository_dispatch types=openemr-tag consumer).
  • Delete tools/release/ (composer/PHPUnit/IpMapBumper.php PHP toolchain).
  • Add repository_dispatch types=release-targets-changed listener to derive-ip-map.yml.
  • Update the reconcile job's if: guard to allow the new event (alongside existing schedule + workflow_dispatch mode=reconcile).
  • README + workflow header comments updated to reflect retired state (no more PR-scoping scaffolding).

Why now

PRs #135 + #138 made the auto-derive bot the canonical writer of ip_map_branch.txt + docker/scripts/demoLibrary.source. The PHP bumper's job (manual tag-bump of production-demo rows on each release) is now performed daily and idempotently by the bot from upstream release-targets.yml. Keeping both wired risks dueling writers; pulling the PHP toolchain is the atomic flip.

Behavior during transition (before openemr-side companion lands)

  • Bot fires daily at 07:00 UTC and on manual workflow_dispatch.
  • Reflection latency from a tag ship to demos: up to 24h worst case.

Behavior after openemr-side companion lands

  • File-change on openemr/openemr master .github/release-targets.yml -> openemr-side workflow dispatches release-targets-changed to this repo -> bot reconciles immediately.

Existing openemr-tag dispatch

Still fires from openemr/openemr/.github/workflows/release-prep.yml:328-337 but now lands here with no listener (harmless no-op). The companion PR will both add the new dispatch and remove the dead one.

Trigger x job matrix (post-flip)

Trigger test job reconcile job dry-run job
schedule (07:00 UTC) runs runs (after test green) skipped
repository_dispatch release-targets-changed runs runs (after test green) skipped
workflow_dispatch mode=reconcile runs runs (after test green) skipped
workflow_dispatch mode=dry-run runs skipped runs
pull_request (touching scoped paths) runs skipped skipped

pull_request is excluded from reconcile by the explicit-allowlist event_name clause. Repo-owner + repository == openemr/demo_farm_openemr guards preserved.

Test plan

  • CI passes (test + dry-run jobs gated as before)
  • Manual workflow_dispatch mode=reconcile from master after merge produces sensible output
  • Companion PR in openemr/openemr filed as follow-up (add release-targets-changed dispatch on master push of .github/release-targets.yml; remove now-dead openemr-tag dispatch from release-prep.yml)

Verification done locally

  • python3 -c "import yaml; yaml.safe_load(open('.github/workflows/derive-ip-map.yml'))" -> clean
  • grep -rn "bump-tag|tools/release|IpMapBumper|bump-ip-map|openemr-tag" -> only this PR's historical README lines explaining what was retired
  • find confirms no remaining tools/release/ and no .github/workflows/bump-tag*

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Removed the tag-bump automation and related release-tooling files.
    • Simplified the release process by dropping several local build, test, and analysis configurations.
  • Bug Fixes
    • Updated the IP map reconciliation workflow to react automatically when release target changes are announced.
  • Documentation
    • Clarified the auto-derive release notes to reflect the latest trigger behavior.

… PHP toolchain

The auto-derive bot (PRs openemr#135, openemr#138) is now the canonical writer of
ip_map_branch.txt + docker/scripts/demoLibrary.source. The legacy
PHP-based per-tag bumper is fully redundant; remove it.

Changes:
- Delete .github/workflows/bump-tag.yml (repository_dispatch openemr-tag
  consumer).
- Delete tools/release/ (composer/PHPUnit/IpMapBumper.php toolchain).
- Add `repository_dispatch types=release-targets-changed` listener to
  derive-ip-map.yml so the bot reconciles immediately when upstream
  pushes release-targets.yml instead of waiting for the next 07:00 UTC
  tick.
- Update reconcile job's if-guard to allow repository_dispatch while
  preserving the existing schedule + workflow_dispatch-reconcile paths
  and the repo-owner/test-success gates. pull_request is still excluded
  from reconcile by the explicit allowlist.
- README + workflow header comments updated to reflect retired-state.

Cross-repo follow-up (tracked separately): openemr/openemr companion PR
to (a) dispatch `release-targets-changed` from a workflow that watches
.github/release-targets.yml on master and (b) stop dispatching the now
unlistened-for `openemr-tag` event from release-prep.yml:328-337.
During the transition the openemr-tag dispatches land here with no
listener — harmless no-op.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 75ca19dc-a921-4241-b091-6373d37c56c6

📥 Commits

Reviewing files that changed from the base of the PR and between 97fc00c and 53239fd.

⛔ Files ignored due to path filters (1)
  • tools/release/composer.lock is excluded by !**/*.lock
📒 Files selected for processing (13)
  • .github/workflows/bump-tag.yml
  • .github/workflows/derive-ip-map.yml
  • tools/auto-derive/README.md
  • tools/release/.gitignore
  • tools/release/Taskfile.yml
  • tools/release/bin/bump-ip-map.php
  • tools/release/composer.json
  • tools/release/phpcs.xml
  • tools/release/phpstan.neon
  • tools/release/phpunit.xml.dist
  • tools/release/rector.php
  • tools/release/src/IpMapBumper.php
  • tools/release/tests/IpMapBumperTest.php
💤 Files with no reviewable changes (11)
  • tools/release/phpunit.xml.dist
  • .github/workflows/bump-tag.yml
  • tools/release/phpstan.neon
  • tools/release/composer.json
  • tools/release/bin/bump-ip-map.php
  • tools/release/Taskfile.yml
  • tools/release/tests/IpMapBumperTest.php
  • tools/release/.gitignore
  • tools/release/rector.php
  • tools/release/src/IpMapBumper.php
  • tools/release/phpcs.xml

📝 Walkthrough

Walkthrough

Removes the bump-tag.yml GitHub Actions workflow and the entire tools/release PHP toolchain (Composer project, PHPUnit/PHPStan/Rector/PHPCS configs, IpMapBumper class, CLI script, and tests). Adds a repository_dispatch trigger (release-targets-changed) to derive-ip-map.yml for immediate reconciliation, and updates the auto-derive README to reflect the completed workstream.

Release toolchain removal and event-driven reconcile

Layer / File(s) Summary
Remove tools/release PHP toolchain
tools/release/composer.json, tools/release/Taskfile.yml, tools/release/phpunit.xml.dist, tools/release/phpstan.neon, tools/release/phpcs.xml, tools/release/rector.php, tools/release/src/IpMapBumper.php, tools/release/bin/bump-ip-map.php, tools/release/tests/IpMapBumperTest.php, tools/release/.gitignore
Deletes the entire PHP release toolchain including the IpMapBumper class, CLI entry point, test suite, and all static analysis and task runner configuration files. Also removes the bump-tag.yml workflow that invoked this toolchain.
Add repository_dispatch trigger to derive-ip-map.yml
.github/workflows/derive-ip-map.yml
Adds repository_dispatch: types: [release-targets-changed] as a new workflow trigger and expands the reconcile job's if: condition to include github.event_name == 'repository_dispatch', with updated header comments documenting the cross-repo event source.
Update auto-derive README
tools/auto-derive/README.md
Updates PR scope section to mark the workstream as fully shipped, adjusts PR #2 wording, and specifies types=release-targets-changed for the PR #3 repository_dispatch wiring.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

  • openemr/demo_farm_openemr#135: Introduced the derive-ip-map workflow and auto-derive tooling that this PR extends with the new repository_dispatch trigger.
  • openemr/demo_farm_openemr#138: Also modifies derive-ip-map.yml's reconcile job behavior, making it directly related to the trigger expansion in this PR.

Poem

🐇 The PHP toolchain? Gone without a trace,
No bumper, no rector, no test to embrace.
Now a dispatch event rings the bell instead,
release-targets-changed — reconcile ahead!
Less PHP, more webhooks, the rabbit's delight,
Event-driven hops through the workflow tonight. 🌙

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: retiring the legacy bump-tag workflow and the tools/release PHP toolchain.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@bradymiller
bradymiller merged commit 83fd965 into openemr:master Jun 28, 2026
4 checks passed
bradymiller added a commit to bradymiller/openemr that referenced this pull request Jun 28, 2026
Adds a fifth cross-repo dispatch event, `release-targets-changed`, plus
a workflow that emits it whenever `.github/release-targets.yml` is
pushed to master. Companion to openemr/demo_farm_openemr#141, which
adds a `repository_dispatch` listener to that repo's
`derive-ip-map.yml` so its auto-derive bot reconciles immediately
instead of waiting for the next daily 07:00 UTC tick — removes up to
24h of latency without changing the bot's existing daily-schedule
safety net.

Schema (`tools/release/contracts/dispatch.schema.json`):
- Add `release-targets-changed` to the `event` enum and a matching
  `oneOf` arm bound to a new `releaseTargetsChangedData` definition.
- The data block is intentionally empty (`additionalProperties:false`,
  no properties). The envelope's `sha`/`actor`/`dispatched_at` fully
  identify the change; consumers re-read release-targets.yml directly
  from openemr/openemr@master rather than carrying it in the payload.
- Update the `event` field description to reflect the conductor now
  also emits this event alongside the rel-cut/rel-update/tag trio.

PHP:
- `DispatchRequest::EVENT_RELEASE_TARGETS_CHANGED` constant.
- `DispatchDataBuilder` match arm returning `[]` (no CLI options to
  collect; the empty `data` block is built from no inputs).
- `Dispatcher::DEFAULT_TARGET_REPOS` is left untouched — the new
  workflow scopes the dispatch via explicit
  `--target-repos=openemr/demo_farm_openemr` so devops + website don't
  receive an event they don't consume.

Workflow (`.github/workflows/notify-release-targets-changed.yml`):
- Trigger: push to master touching `.github/release-targets.yml`, plus
  manual `workflow_dispatch` as a recovery / rerun escape hatch.
- Mints a release-App installation token scoped to demo_farm_openemr
  only (`repositories: demo_farm_openemr`) — minimum surface needed.
- Reuses the existing `./.github/actions/setup-php-composer` composite
  action on PHP 8.5, matching the release-permissions-check pattern
  (conductor tooling tracks latest stable PHP, not the app floor).
- Runs `tools/release/bin/dispatch.php` with
  `--event=release-targets-changed` and the explicit target-repos.
- `permissions: {}` at the workflow level; the dispatch authenticates
  via the App token, not the workflow's `GITHUB_TOKEN`.

Tests:
- `DispatchDataBuilderTest::testReleaseTargetsChangedBuildsEmptyData`
  asserts the match arm returns `[]`.
- `DispatchSchemaTest` data providers add good + bad fixtures for the
  new event. Good fixture: minimal envelope with `"data": {}`. Bad
  fixture: a stray field inside `data` to exercise
  `additionalProperties:false`.

Existing `openemr-tag` dispatch (release-prep.yml lines ~328-342) is
left intact — openemr-devops's release-announcements.yml still
consumes it.

Vendor-sync follow-up: openemr-devops carries a vendored copy of
`dispatch.schema.json` validated by `tools/release/bin/check-vendored.php`
in its CI. That check will fail on the next devops PR after this lands;
a small sync PR there resolves it. Not blocking for this PR —
demo_farm_openemr consumes the dispatch directly via the workflow
listener and does no schema validation of its own.

Assisted-by: Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bradymiller added a commit to bradymiller/openemr that referenced this pull request Jun 28, 2026
Adds a fifth cross-repo dispatch event, `release-targets-changed`, plus
a workflow that emits it whenever `.github/release-targets.yml` is
pushed to master. Companion to openemr/demo_farm_openemr#141, which
adds a `repository_dispatch` listener to that repo's
`derive-ip-map.yml` so its auto-derive bot reconciles immediately
instead of waiting for the next daily 07:00 UTC tick — removes up to
24h of latency without changing the bot's existing daily-schedule
safety net.

Schema (`tools/release/contracts/dispatch.schema.json`):
- Add `release-targets-changed` to the `event` enum and a matching
  `oneOf` arm bound to a new `releaseTargetsChangedData` definition.
- The data block is intentionally empty (`additionalProperties:false`,
  no properties). The envelope's `sha`/`actor`/`dispatched_at` fully
  identify the change; consumers re-read release-targets.yml directly
  from openemr/openemr@master rather than carrying it in the payload.
- Update the `event` field description to reflect the conductor now
  also emits this event alongside the rel-cut/rel-update/tag trio.

PHP:
- `DispatchRequest::EVENT_RELEASE_TARGETS_CHANGED` constant.
- `DispatchDataBuilder` match arm returning `[]` (no CLI options to
  collect; the empty `data` block is built from no inputs).
- `Dispatcher::DEFAULT_TARGET_REPOS` is left untouched — the new
  workflow scopes the dispatch via explicit
  `--target-repos=openemr/demo_farm_openemr` so devops + website don't
  receive an event they don't consume.

Workflow (`.github/workflows/notify-release-targets-changed.yml`):
- Trigger: push to master touching `.github/release-targets.yml`, plus
  manual `workflow_dispatch` as a recovery / rerun escape hatch.
- Mints a release-App installation token scoped to demo_farm_openemr
  only (`repositories: demo_farm_openemr`) — minimum surface needed.
- Reuses the existing `./.github/actions/setup-php-composer` composite
  action on PHP 8.5, matching the release-permissions-check pattern
  (conductor tooling tracks latest stable PHP, not the app floor).
- Runs `tools/release/bin/dispatch.php` with
  `--event=release-targets-changed` and the explicit target-repos.
- `permissions: {}` at the workflow level; the dispatch authenticates
  via the App token, not the workflow's `GITHUB_TOKEN`.

Tests:
- `DispatchDataBuilderTest::testReleaseTargetsChangedBuildsEmptyData`
  asserts the match arm returns `[]`.
- `DispatchSchemaTest` data providers add good + bad fixtures for the
  new event. Good fixture: minimal envelope with `"data": {}`. Bad
  fixture: a stray field inside `data` to exercise
  `additionalProperties:false`.

Existing `openemr-tag` dispatch (release-prep.yml lines ~328-342) is
left intact — openemr-devops's release-announcements.yml still
consumes it.

Vendor-sync follow-up: openemr-devops carries a vendored copy of
`dispatch.schema.json` validated by `tools/release/bin/check-vendored.php`
in its CI. That check will fail on the next devops PR after this lands;
a small sync PR there resolves it. Not blocking for this PR —
demo_farm_openemr consumes the dispatch directly via the workflow
listener and does no schema validation of its own.

Assisted-by: Claude Code

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bradymiller added a commit to openemr/openemr that referenced this pull request Jun 28, 2026
…12657)

## What

Adds a fifth cross-repo dispatch event, `release-targets-changed`, plus
a new workflow that emits it:

- **Schema** (`tools/release/contracts/dispatch.schema.json`):
  - `release-targets-changed` added to the `event` enum
- New `releaseTargetsChangedData` definition with `additionalProperties:
false` and no properties (the envelope's `sha`/`actor`/`dispatched_at`
fully identify the change; consumers re-read release-targets.yml
directly from `openemr/openemr@master`)
  - Matching `oneOf` arm
  - `event` field description updated
- **PHP**:
  - `DispatchRequest::EVENT_RELEASE_TARGETS_CHANGED`
  - `DispatchDataBuilder` match arm returning `[]`
- **Workflow** (`.github/workflows/notify-release-targets-changed.yml`):
- Triggered by push to `master` touching `.github/release-targets.yml`,
plus manual `workflow_dispatch`
  - Mints the release App token scoped to `demo_farm_openemr` only
- Reuses `./.github/actions/setup-php-composer` on PHP 8.5
(conductor-tooling convention)
- Calls `tools/release/bin/dispatch.php --event=release-targets-changed
--target-repos=openemr/demo_farm_openemr`
- **Tests**:
  - `DispatchDataBuilderTest::testReleaseTargetsChangedBuildsEmptyData`
- `DispatchSchemaTest` good + bad fixtures (bad fixture exercises
`additionalProperties: false` via a stray data key)

## Why

To drive openemr/demo_farm_openemr's auto-derive bot immediately when
`.github/release-targets.yml` changes, instead of waiting for its daily
07:00 UTC tick. Removes up to ~24h of latency between editing
release-targets.yml and demo_farm reconciling. The bot's existing
daily-schedule safety net is unaffected — this is purely additive.

## Companion PR

openemr/demo_farm_openemr#141 adds the `repository_dispatch: types:
[release-targets-changed]` listener on the bot side. That PR works on
its own (daily schedule still ticks). This PR is what makes the dispatch
arrive.

## Scope decisions

- **`Dispatcher::DEFAULT_TARGET_REPOS` left untouched** — the new
workflow scopes via explicit `--target-repos` so openemr-devops and
website-openemr don't receive an event they don't consume.
- **Existing `openemr-tag` dispatch in `release-prep.yml` left intact**
— openemr-devops's `release-announcements.yml` still consumes it.

## Vendor sync follow-up

openemr-devops carries a vendored copy of `dispatch.schema.json`
validated by `tools/release/bin/check-vendored.php` in its CI. That
check will fail on the next devops PR after this lands; a small sync PR
there will resolve it. **Not blocking for this PR** — demo_farm_openemr
consumes the dispatch directly via the workflow listener and does no
schema validation itself, so the bot works end-to-end the moment both
PRs are merged regardless of when the devops vendor copy catches up.

## Test plan

- [ ] CI passes (isolated release tests run all schema fixtures + new
DispatchDataBuilder case; actionlint passes on the new workflow)
- [ ] After merge: editing `.github/release-targets.yml` on master fires
`notify-release-targets-changed`, which dispatches
`release-targets-changed` to demo_farm_openemr; the demo_farm bot's
derive-ip-map run starts within seconds rather than at the next 07:00
UTC tick
- [ ] `openemr-tag` dispatch from `release-prep.yml` continues to fire
normally on the next release-prep merge
- [ ] Open the follow-up vendor-sync PR against openemr-devops once that
repo's CI surfaces the drift

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bradymiller added a commit to openemr/openemr that referenced this pull request Jun 28, 2026
…rgets-changed event (#12660)

## Summary

Updates `docs/RELEASE_PROCESS.md` to describe the new demo_farm flow
that shipped 2026-06-28.

**What changed in the demo_farm flow.** The old `bump-tag.yml` workflow
in `demo_farm_openemr` (which consumed `openemr-tag` and pushed directly
to master after rewriting matching production-demo rows in
`ip_map_branch.txt`) was retired. The new `derive-ip-map` auto-derive
bot is now the canonical writer for `ip_map_branch.txt` +
`docker/scripts/demoLibrary.source`: it regenerates both files from
upstream `openemr/openemr` state (`.github/release-targets.yml` +
per-rel-branch Dockerfile ARGs + `ci/apache_*` listing + flex
Dockerfile) and reconciles them onto the `auto-derive/reconciliation`
stable branch via a reviewable PR. Triggers: `repository_dispatch types:
[release-targets-changed]` (immediate), daily 07:00 UTC cron
(self-healing fallback), `workflow_dispatch` (manual).

**Why.** This is the cross-repo trio's final piece — companion to:
- #12657 — added the notifier side in this repo
(`.github/workflows/notify-release-targets-changed.yml`, fires
`release-targets-changed` to demo_farm on master pushes that touch
`.github/release-targets.yml`)
- openemr/demo_farm_openemr#141 series (PRs #135/#138/#141/#142/#143) —
added the consumer side: the auto-derive bot, the reconciliation PR
pattern, and retirement of `bump-tag.yml`

Without this doc update, `RELEASE_PROCESS.md` describes a flow that no
longer exists.

## Sections rewritten

- **Intro paragraph (line ~5):** now correctly says *three* repos open
reviewable PRs (conductor, docs, demo_farm reconciliation), not two.
- **Per-repo role table (line ~16):** `demo_farm_openemr` row rewritten
for the auto-derive bot's trigger set, output files, and reviewable-PR
pattern.
- **Cross-repo flow mermaid diagram:** `bump-tag.yml` workflow node
(purple hex) replaced with the auto-derive reconciliation PR as a blue
(reviewable) node — same shape as the conductor + docs PRs. The
`openemr-tag -> bump` arrow is gone; the new `release-targets-changed`
arrow sources from the `oe` subgraph (since the dispatch fires on master
pushes, not from the conductor PR).
- **Diagram legend:** rewritten to describe the auto-derive bot's three
triggers (dispatch + daily cron + manual `workflow_dispatch`) instead of
`bump-tag.yml`.
- **Cross-repo events intro + table:** intro now mentions
`master`-push-driven dispatch; `openemr-tag` row drops
`demo_farm_openemr` as a consumer; new `release-targets-changed` row
added with payload `{}` (envelope's `sha`/`actor`/`dispatched_at` fully
identify the change).
- **Phase 2 step 2:** production-demo-row seeding prerequisite for new
minor lines is gone — `release-targets.yml` is the contract; new minor
lines flow through naturally once represented there.
- **Phase 4 prelude (ship phase):** "demo-farm bump" dropped from the
`openemr-tag` cascade list; demo-farm runs on its own track (step 15).
- **Phase 6 step 15:** full rewrite for the `derive-ip-map` bot —
workflow link, derivation inputs, reconciliation-branch PR pattern,
triggers, maintainer-review note.
- **Automation gaps table:** `demo_farm_openemr#110` row
(seed-new-minor-rows) removed; added to the "Recently closed" paragraph
with the auto-derive-rewrite as rationale. Umbrella issue's sub-issue
count updated from five to four.
- **Out-of-band tag recovery row (line ~230):** stray `bump-tag.yml`
reference dropped from the "dispatch fired" sub-case.

## Test plan

- [ ] Render the mermaid diagram (GitHub PR preview is sufficient) and
confirm the new `auto-derive/reconciliation PR` node renders blue and
the `release-targets-changed` arrow lands on it
- [ ] Scan the rendered doc end-to-end for any remaining `bump-tag.yml`,
`production-demo` seeding, or `direct push to master` references — none
should remain
- [ ] Confirm cross-repo events table reads cleanly with the new fourth
row and the trimmed `openemr-tag` target list
- [ ] Confirm Phase 2 step 2 no longer carries a demo_farm seeding
prerequisite

## Out of scope

- The conductor's `release-prep.yml` still emits `openemr-tag` to
`demo_farm_openemr` (`.github/workflows/release-prep.yml:328-337`). With
no listener there it's a harmless no-op; cleanup is its own follow-up
PR.
- Other sections of `RELEASE_PROCESS.md` unrelated to the demo_farm
flow.
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.

1 participant