Audience: the
tutorials-imsmaintainer. This doc covers how the two "notify" workflows get installed into the org's other repos, how to add them to newly-created repos, and how the installer stays safe to re-run.
Two workflows in other sap-tutorials repos fire repository_dispatch at
tutorials-ims to trigger content rebuilds:
| Workflow (in the other repo) | Installed into | Fires event | Consumed by |
|---|---|---|---|
.github/workflows/notify-tutorials-ims.yml |
every tutorial source repo | tutorial-updated |
rebuild-content.yml (PROD content) |
.github/workflows/notify-qa.yml |
every *-Contribution repo |
tutorial-qa-updated |
rebuild-content-qa.yml (QA preview) |
Templates (source of truth, edit these):
Both authenticate via the sap-tutorials-builder GitHub App (installation
token) with a classic-PAT fallback — see github-app-setup.md.
scripts/install-notify-workflows.ts (npm run install-notify-workflows)
discovers the org's repos live, classifies them (source vs *-Contribution),
and installs the right template into each.
For each repo it GETs the existing workflow file and content-compares (trailing-whitespace-insensitive) against the rendered template:
| Existing state | Action |
|---|---|
| file absent | install (create on default branch) |
| identical to template | skip — no write |
| differs from template | update (overwrite with prior sha) |
Re-running when everything is current commits nothing. So it's the single command to run both for the first rollout and whenever repos are added or a template changes.
npm run install-notify-workflows # DRY-RUN: reports per-repo decision, writes nothing
npm run install-notify-workflows -- --execute # commits directly to each repo's default branch
npm run install-notify-workflows -- --only qa # only the QA / *-Contribution set
npm run install-notify-workflows -- --only prod # only the PROD / source-repo setAuth: set GITHUB_TOKEN (or TUTORIALS_GITHUB_TOKEN) to a token with
Contents: write on the target repos. The App private key isn't used here —
this is an operator-run script; a PAT or gh auth token is simplest. Apply
mechanism is a direct commit to the default branch (no PR), per the #1154
rollout decision — merge-to-main on the source content is the review gate;
these notify workflows are infrastructure.
Some source repos have branch protection / rulesets that reject a direct commit
to the default branch (409 Repository rule violations found — Changes must be made through a pull request). For those, --execute falls back to PR mode
automatically instead of erroring:
- resolve the default-branch head sha,
- create/reuse the feature branch
chore/1154-notify-workflow-refresh(422 already exists→ reuse), - compare the file already on that branch — skip the commit if it's current,
- PUT the rendered template to the branch,
- open a PR against the default branch (
422 already open→ reuse and surface the existing PR URL).
These land as a distinct outcome in the per-repo log and the summary tally —
pr-opened (new PR) / pr-updated (PR already open) — so a protected repo
delivered via PR is not counted as an error. Re-running when the PR branch
is already current opens/commits nothing (idempotent). Unprotected repos still
get the direct commit — unchanged. The maintainer merges the resulting PRs
(e.g. abap-core-development#2722, btp-dev-guidance#953, btp-foundation#2417 in
the manual 2026-07-27 catch-up that motivated this).
Dry-run doesn't reveal the PR path. The 409 only surfaces on a real PUT, which dry-run never issues — so a branch-protected repo shows as
would-install/would-updatein dry-run and only flips toPR-OPENED/PR-UPDATEDunder--execute. This is expected.
Nothing special — discovery is live. When a new tutorial source repo or
*-Contribution repo is created:
npm run install-notify-workflows # dry-run: confirm the new repo shows "would-install"
npm run install-notify-workflows -- --execute # install it (existing repos skip as no-ops)The new repo is picked up automatically because the installer lists the org
every run. Repos named in EXCLUDED_REPOS (tutorials-ims, sandbox,
sandbox-Contribution) are always skipped; archived / disabled / fork repos
are ignored.
Enabling App auth per repo: after the workflow file lands, set the repo variable
USE_GITHUB_APP=trueand add theTUTORIALS_APP_ID+TUTORIALS_APP_PRIVATE_KEYActions secrets so the notify workflow mints an App token instead of the PAT fallback. Until then it uses the legacy PAT (TUTORIALS_DISPATCH_TOKENfor source repos,TUTORIALS_POC_DISPATCH_TOKENfor Contribution repos).
The PROD template sends client_payload.environment (default prod, override
per-repo via a REBUILD_ENVIRONMENT repo variable). rebuild-content.yml
validates it against dev|qa|prod and defaults to dev when absent. A push to
a source repo's main therefore rebuilds the configured environment — branch
protection on that repo is the publish gate; no additional approval is layered
on (deliberate — see the "Trust model" comment in rebuild-content.yml).
Currently the installer is run manually. If drift becomes a maintenance burden,
wrap it in a scheduled GitHub Actions workflow (weekly --execute) so new
repos are covered without anyone remembering. Not done yet — YAGNI until the
repo set churns enough to justify it.