From 3f1490fafe7edecaab7962bb6433ef601f3c0b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Luis=20Cano=20Rodr=C3=ADguez?= Date: Thu, 22 Oct 2026 11:44:54 +0200 Subject: [PATCH 1/2] Propose automatic template propagation to plugin repositories Assisted-by: OpenRouter:z-ai/glm-5.3-flash pi --- docs/proposals/template-propagation.md | 81 ++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 docs/proposals/template-propagation.md diff --git a/docs/proposals/template-propagation.md b/docs/proposals/template-propagation.md new file mode 100644 index 0000000..624e6b4 --- /dev/null +++ b/docs/proposals/template-propagation.md @@ -0,0 +1,81 @@ +# Proposal: automatic template propagation to plugin repositories + +Every change to the [template](https://github.com/obs-plugins-snaps/template) +(bug report templates, CI improvements, README wording, ...) currently +requires manual PRs to every plugin repository. This proposal automates +that: when the template gets a new tag, a workflow opens one update PR per +managed plugin repository. + +## Design + +### Source of truth for the plugin list + +`meta/plugins/` is the single source of truth. The propagation workflow +reads the directory listing via the GitHub API: + +- `plugin_name` = record filename minus the `-obs-studio.json` suffix + (same derivation rule as `scripts/generate.py`, documented in + `plugins/schema.json`) +- target repository = `plugin_name` + `-obs-studio-snap` + +Nothing is duplicated: adding a record to `meta/plugins/` is all it takes +to join the propagation set. If a record exists but the repository does +not yet (the creation-automation gap), the run skips it and reports it in +the job summary instead of failing. + +### Trigger + +`workflow_run` on completion of the template's auto-tag workflow (which +tags every merge to main with the next patch version), plus +`workflow_dispatch` with an optional tag override for manual runs. + +### Per-repository flow + +1. Read `.copier-answers.yml`; skip if `_commit` already equals the latest + tag. +2. Skip if the branch `template-update-` already exists (idempotent + re-runs). +3. Full clone, then `copier update --defaults --vcs-ref `. This is a + three-way merge from the recorded commit, so hand-tuned parts of a + plugin repository (build recipes, patches) are preserved; conflicts + are marked in the files for resolution in the PR. +4. Commit, push the branch, open a pull request "Update template to + " including the compare link between the old and new template + versions. + +A job summary table reports each plugin as skipped / updated / PR opened +/ failed, making every propagation run auditable from the template +repository's Actions tab. + +### Implementation location + +A single `propagate.yaml` workflow in the `template` repository. It runs +with the existing `obs-plugins-snaps-bot` GitHub App token, which now has +the required permissions (`contents: write`, `pull_requests: write`, +`workflows: write`) on all organization repositories. + +## Non-goals + +- No repository creation: repos without records are handled by the future + creation automation (separate proposal). +- No release automation changes: the existing auto-tag workflow is + untouched beyond being the trigger. + +## Alternatives considered + +- **Org API repo list instead of meta**: rejected — meta is the declared + single source of truth, and an API listing would also match future + non-plugin repositories and require name-prefix filtering anyway. +- **Per-repository dispatcher workflows**: more moving parts and one more + file per plugin; a single workflow in template keeps the logic in one + place. +- **Full re-render instead of `copier update`**: would discard + hand-tuned build recipes in plugin repositories; the three-way merge is + the whole point. + +## Rollout + +1. Merge this proposal and the `propagate.yaml` implementation PR. +2. Merge a template change; verify the first automatic propagation run + opens PRs on all plugin repositories (the pending v0.0.6 update is a + ready-made first test). From 53467c552866d38101f3881be22374eec35f0c1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Luis=20Cano=20Rodr=C3=ADguez?= Date: Thu, 22 Oct 2026 11:50:08 +0200 Subject: [PATCH 2/2] Record template propagation design as ADR-0001 The proposal from the discussion now lives as an architecture decision record (docs/adr/0001-template-propagation.md): meta plugins/ as the source of truth for the plugin list, a single propagate workflow in the template repository, copier update three-way merges, idempotency and per-run summaries, and the bot App permission requirements. The implementation itself is in obs-plugins-snaps/template#5. Also add a Records and decisions section to the README pointing at the plugin records and the ADR directory. Assisted-by: OpenRouter:z-ai/glm-5.3-flash pi --- README.md | 7 +++ docs/adr/0001-template-propagation.md | 69 ++++++++++++++++++++++ docs/adr/README.md | 6 ++ docs/proposals/template-propagation.md | 81 -------------------------- 4 files changed, 82 insertions(+), 81 deletions(-) create mode 100644 docs/adr/0001-template-propagation.md create mode 100644 docs/adr/README.md delete mode 100644 docs/proposals/template-propagation.md diff --git a/README.md b/README.md index f1a2ab1..74257ab 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,10 @@ This repo contains stateless GitOps repo reconciliation using OpenTofu (`import`-on-demand) and `just`. For now, it helps keeping existing repos in sync. + +## Records and decisions + +`plugins/` holds the per-plugin records (the single source of truth for +creation-time metadata), projected into `repos/*.tfvars` by +`scripts/generate.py` — see `plugins/schema.json`. Significant design +decisions are recorded as ADRs in [`docs/adr/`](docs/adr/). diff --git a/docs/adr/0001-template-propagation.md b/docs/adr/0001-template-propagation.md new file mode 100644 index 0000000..3354d82 --- /dev/null +++ b/docs/adr/0001-template-propagation.md @@ -0,0 +1,69 @@ +# ADR-0001: Automatic template propagation to plugin repositories + +Date: 2026-10-22 +Status: Accepted + +## Context + +Plugin repositories are generated from the +[template](https://github.com/obs-plugins-snaps/template) via Copier and +record the template version they were generated from in +`.copier-answers.yml`. The template auto-tags every merge to main with the +next patch version, so improvements to the shared scaffolding (bug report +templates, CI workflows, README wording) are available as a new tag +immediately. + +Without automation, propagating a template update means manually opening +one PR per plugin repository — repetitive, error-prone, and easily +forgotten, which lets the scaffolding drift apart across repositories. + +## Decision + +1. **meta `plugins/` is the source of truth for the plugin list.** The + propagation workflow reads the directory listing via the GitHub API at + runtime; every `plugins/-obs-studio.json` record maps to + the repository `-obs-studio-snap` — the same derivation + rule used by `scripts/generate.py` and documented in + `plugins/schema.json`. An org API repository listing was rejected: it + would include non-plugin repositories and duplicates knowledge that + already lives here. + +2. **The propagation workflow lives in the template repository** + (`propagate.yaml` + a stdlib-only Python driver). It is triggered by + `workflow_run` after the auto-tag workflow completes on main, and can + be run manually via `workflow_dispatch` with an explicit tag. A single + workflow keeps the logic in one place; per-repository dispatcher + workflows were rejected as unnecessary moving parts. + +3. **Updates use `copier update` (three-way merge), not re-rendering.** + Plugin repositories carry hand-tuned build recipes that must survive + template updates; conflicts are expected and surface in the PRs for + human resolution. + +4. **Idempotency and observability.** A run skips repositories already on + the target tag (read from `.copier-answers.yml`), skips ones with an + existing `template-update-` branch or open PR, and writes a + per-plugin summary table to the workflow run. Repositories that do not + exist yet (record present, repo not created — the creation-automation + gap) are skipped and reported, not fatal. + +5. **Permissions.** The `obs-plugins-snaps-bot` GitHub App carries + `contents: write`, `pull_requests: write` and `workflows: write` on all + organization repositories. The `workflows` scope is required because + template updates modify `.github/workflows/*` files, which GitHub gates + separately from ordinary content pushes. + +## Non-goals + +- Repository creation from records (separate future automation). +- Changes to the template's auto-tag workflow (it is only consumed as a + trigger). + +## Consequences + +- Merging any change to the template now results in update PRs on every + managed plugin repository within minutes; maintainers only review. +- Plugin repositories may hold open update PRs during active work; + merging them is a maintainer decision per repository. +- The first live run propagates v0.0.6 (bug report issue template) to all + four existing repositories. diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..7db1667 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,6 @@ +# Architecture decision records + +Significant design decisions for this repository's automation are recorded +here as short ADRs (context → decision → consequences), named +`NNNN-short-title.md`. Superseded ADRs stay in place with an updated +Status header. diff --git a/docs/proposals/template-propagation.md b/docs/proposals/template-propagation.md deleted file mode 100644 index 624e6b4..0000000 --- a/docs/proposals/template-propagation.md +++ /dev/null @@ -1,81 +0,0 @@ -# Proposal: automatic template propagation to plugin repositories - -Every change to the [template](https://github.com/obs-plugins-snaps/template) -(bug report templates, CI improvements, README wording, ...) currently -requires manual PRs to every plugin repository. This proposal automates -that: when the template gets a new tag, a workflow opens one update PR per -managed plugin repository. - -## Design - -### Source of truth for the plugin list - -`meta/plugins/` is the single source of truth. The propagation workflow -reads the directory listing via the GitHub API: - -- `plugin_name` = record filename minus the `-obs-studio.json` suffix - (same derivation rule as `scripts/generate.py`, documented in - `plugins/schema.json`) -- target repository = `plugin_name` + `-obs-studio-snap` - -Nothing is duplicated: adding a record to `meta/plugins/` is all it takes -to join the propagation set. If a record exists but the repository does -not yet (the creation-automation gap), the run skips it and reports it in -the job summary instead of failing. - -### Trigger - -`workflow_run` on completion of the template's auto-tag workflow (which -tags every merge to main with the next patch version), plus -`workflow_dispatch` with an optional tag override for manual runs. - -### Per-repository flow - -1. Read `.copier-answers.yml`; skip if `_commit` already equals the latest - tag. -2. Skip if the branch `template-update-` already exists (idempotent - re-runs). -3. Full clone, then `copier update --defaults --vcs-ref `. This is a - three-way merge from the recorded commit, so hand-tuned parts of a - plugin repository (build recipes, patches) are preserved; conflicts - are marked in the files for resolution in the PR. -4. Commit, push the branch, open a pull request "Update template to - " including the compare link between the old and new template - versions. - -A job summary table reports each plugin as skipped / updated / PR opened -/ failed, making every propagation run auditable from the template -repository's Actions tab. - -### Implementation location - -A single `propagate.yaml` workflow in the `template` repository. It runs -with the existing `obs-plugins-snaps-bot` GitHub App token, which now has -the required permissions (`contents: write`, `pull_requests: write`, -`workflows: write`) on all organization repositories. - -## Non-goals - -- No repository creation: repos without records are handled by the future - creation automation (separate proposal). -- No release automation changes: the existing auto-tag workflow is - untouched beyond being the trigger. - -## Alternatives considered - -- **Org API repo list instead of meta**: rejected — meta is the declared - single source of truth, and an API listing would also match future - non-plugin repositories and require name-prefix filtering anyway. -- **Per-repository dispatcher workflows**: more moving parts and one more - file per plugin; a single workflow in template keeps the logic in one - place. -- **Full re-render instead of `copier update`**: would discard - hand-tuned build recipes in plugin repositories; the three-way merge is - the whole point. - -## Rollout - -1. Merge this proposal and the `propagate.yaml` implementation PR. -2. Merge a template change; verify the first automatic propagation run - opens PRs on all plugin repositories (the pending v0.0.6 update is a - ready-made first test).