--- name: monorepo-cicd description: Syncs CI/CD and infrastructure configuration at the monorepo root (compose files, install scripts, env templates, CI service tables) after one or more components changed. Reads `_docs/_repo-config.yaml` (produced by monorepo-discover) to know which CI artifacts are in play and how they're structured. Touches ONLY CI/infra files — never documentation, component directories, or per-component CI configs. Use when a component added/changed a Dockerfile path, port, env var, image tag format, or runtime dependency. --- # Monorepo CI/CD Propagates component changes into the repo-level CI/CD and infrastructure artifacts. Strictly scoped — never edits docs, component internals, or per-component CI configs. ## Scope — explicit | In scope | Out of scope | | -------- | ------------ | | `docker-compose.*.yml` at repo root | Unified docs in `_docs/*.md` → use `monorepo-document` | | `.env.example` / `.env.template` | Root `README.md` documentation → `monorepo-document` | | Install scripts (`ci-*.sh`, `setup.sh`, etc.) | Per-component CI configs (`/.woodpecker/*`, `/.github/*`) | | CI service-registry docs (`ci_steps.md` or similar — the human-readable index of pipelines; in scope only if the config says so under `ci.service_registry_doc`) | Component source code, Dockerfiles, or internal docs | | Kustomization / Helm manifests at repo root | `_docs/_repo-config.yaml` itself (only `monorepo-discover` and `monorepo-onboard` write it) | If a component change needs doc updates too, tell the user to also run `monorepo-document`. **Special case**: `ci.service_registry_doc` (e.g., `ci_steps.md`) is a **CI artifact that happens to be markdown**. It's in this skill's scope, not `monorepo-document`'s, because it describes the pipeline/service topology — not user-facing feature docs. ## Preconditions (hard gates) 1. `_docs/_repo-config.yaml` exists. 2. Top-level `confirmed_by_user: true`. 3. `ci.*` section is populated in config (not empty). 4. Components-in-scope have confirmed CI mappings, OR user explicitly approves inferred ones. If any gate fails, redirect to `monorepo-discover` or ask for confirmation. ## Mitigations (M1–M7) - **M1** Separation: this skill only touches CI/infra files; no docs, no component internals. - **M3** Factual vs. interpretive: image tag format, port numbers, env var names — FACTUAL, read from code. Doc cross-references — out of scope entirely (belongs to `monorepo-document`). - **M4** Batch questions at checkpoints. - **M5** Skip over guess: component with no CI mapping → skip and report. - **M6** Assumptions footer + append to `_repo-config.yaml` `assumptions_log`. - **M7** Drift detection: verify every file in `ci.orchestration_files`, `ci.install_scripts`, `ci.env_template` exists; stop if not. ## Workflow ### Phase 1: Drift check (M7) Verify every CI file listed in config exists on disk. Missing file → stop, ask user: - Run `monorepo-discover` to refresh, OR - Skip the missing file (recorded in report) Do NOT recreate missing infra files automatically. ### Phase 2: Determine scope Ask the user (unless specified): > Which components changed? (a) list them, (b) auto-detect, (c) skip detection (I'll apply specific changes). For **auto-detect**, for each component: ```bash git -C log --oneline -20 # submodule # or git log --oneline -20 -- # monorepo subfolder ``` Flag commits that touch CI-relevant concerns: - Dockerfile additions, renames, or path changes - CI pipeline files (`/.woodpecker/*`, `/.github/workflows/*`, etc.) - New exposed ports - New environment variables consumed by the component - Changes to image name / tag format - New dependency on another service (e.g., new DB, new broker) Present the flagged list; confirm. ### Phase 3: Classify changes per component | Change type | Target CI files | | ----------- | --------------- | | Dockerfile path moved/renamed | `ci.service_registry_doc` service table; per-component CI is OUT OF SCOPE (tell user to update it) | | New port exposed | `ci.service_registry_doc` ports section (if infra port); component's service block in orchestration file | | Registry URL changed | `ci.install_scripts` (all of them); `ci.env_template`; `ci.service_registry_doc` | | Branch naming convention changed | All `ci.install_scripts`; all `ci.orchestration_files` referencing the branch; `ci.service_registry_doc` | | New runtime env var | `ci.env_template`; component's service block in orchestration file | | New infrastructure component (DB, cache, broker) | Relevant `ci.orchestration_files`; `ci.service_registry_doc` architecture section | | New image tag format | All `ci.orchestration_files`; `ci.install_scripts`; `ci.service_registry_doc` | | Watchtower/polling config change | Specific `ci.orchestration_files`; `ci.service_registry_doc` | If a change type isn't covered here or in the config, add to an unresolved list and skip (M5). ### Phase 4: Apply edits For each (change → target file) pair: 1. Read the target file. 2. Locate the service block / table row / section. 3. Edit carefully: - **Orchestration files (compose/kustomize/helm)**: YAML; preserve indentation, anchors, and references exactly. Match existing service-block structure. Never reformat unchanged lines. - **Install scripts (`*.sh`)**: shell; any edit must remain **idempotent**. Re-running the script on an already-configured host must not break it. If an edit cannot be made idempotent, flag for the user and skip. - **`.env.example`**: append new vars at the appropriate section; never remove user's local customizations (file is in git, so comments may be significant). - **`ci.service_registry_doc`** (markdown): preserve column widths, ordering (alphabetical or compose-order — whichever existed), ASCII diagrams. ### Phase 5: Skip-and-report (M5) Skip a component if: - No `ci_config` in its config entry AND no entry in config's CI mappings - `confirmed: false` on its mapping and user didn't approve - Component's Dockerfile path declared in config doesn't exist on disk — surface contradiction - Change type unrecognized — skip, report for manual handling ### Phase 6: Idempotency / lint check - Shell: if `shellcheck` available, run on any edited `*.sh`. - YAML: if `yamllint` or `prettier` available, run on edited `*.yml` / `*.yaml`. - For edited install scripts, **mentally re-run** the logic: would a second invocation crash, duplicate, or corrupt? Flag anything that might. Skip linters silently if none configured — don't install tools. ### Phase 7: Report + assumptions footer (M6) ``` monorepo-cicd run complete. CI files updated (N): - docker-compose.run.yml — added `loader` service block - .env.example — added LOADER_BUCKET_NAME placeholder - ci_steps.md — added `loader` row in service table Skipped (K): - satellite-provider: no ci_config in repo-config.yaml - detections: Dockerfile path in config (admin/src/Dockerfile) does not exist on disk Manual actions needed (M): - Update `/.woodpecker/*.yml` inside the submodule's own workspace (per-component CI is not maintained by this skill) Assumptions used this run: - image tag format: ${REGISTRY}/${NAME}:${BRANCH}-${ARCH_TAG} (confirmed in config) - target branch for triggers: [stage, main] (confirmed in config) Next step: review the diff, then commit with ` Sync CI after ` (or your own message). ``` Append run entry to `_docs/_repo-config.yaml` `assumptions_log:`. ## What this skill will NEVER do - Modify files inside component directories - Edit unified docs under `docs.root` - Edit per-component CI configs (`.woodpecker/*`, `.github/*`, etc.) - Auto-generate CI pipeline YAML for components (only provide template guidance) - Set `confirmed_by_user` or `confirmed:` flags - Auto-commit - Install tools (shellcheck, yamllint, etc.) — use if present, skip if absent ## Edge cases - **Compose file has service blocks for components NOT in config**: note in report; ask user whether to rediscover (`monorepo-discover`) or leave them alone. - **`.env.example` has entries for removed components**: don't auto-remove; flag to user. - **Install script edit cannot be made idempotent**: don't save; ask user to handle manually. - **Branch trigger vs. runtime branch mismatch**: if config says triggers are `[stage, main]` but a compose file references a branch tag `develop`, stop and ask.