Merge pull request #282 from sap-tutorials/fix/md-source-1963-batch-2 #4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Tutorial Repo Dispatch Workflow | |
| # | |
| # Copy this file to .github/workflows/notify-tutorials-ims.yml in each | |
| # sap-tutorials tutorial *source* repo that should trigger a content rebuild. | |
| # | |
| # Auth (#1154): prefers a GitHub App installation token, falls back to a PAT. | |
| # - App path (recommended): set repo variable USE_GITHUB_APP=true and add | |
| # Actions secrets TUTORIALS_APP_ID + TUTORIALS_APP_PRIVATE_KEY. The App | |
| # (sap-tutorials-builder) must be installed on this repo and hold | |
| # Contents: write on sap-tutorials/tutorials-ims (repository_dispatch). | |
| # See docs/developers/operations/github-app-setup.md. | |
| # - PAT fallback (legacy): TUTORIALS_DISPATCH_TOKEN — GitHub PAT with `repo` | |
| # scope on tutorials-ims. Used while USE_GITHUB_APP is unset/false. | |
| # | |
| # NOTE: the || fallback only engages if App-token GENERATION fails — NOT if | |
| # the dispatch itself is unauthorized. Grant the App Contents:write on | |
| # tutorials-ims BEFORE setting USE_GITHUB_APP=true here. | |
| # | |
| # Target env (#1154): this template sends client_payload.environment (default | |
| # 'prod', override per-repo via the REBUILD_ENVIRONMENT repo variable). | |
| # rebuild-content.yml honors that field (allowlist dev|qa|prod) as of PR #1273. | |
| # BOTH must be merged before rolling this out to production source repos — on | |
| # a rebuild-content.yml that predates #1273, repository_dispatch still routes | |
| # to DEV regardless of payload, so every tutorial push would rebuild DEV. | |
| name: Notify Tutorials Platform | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - '**.md' | |
| - '**.png' | |
| - '**.jpg' | |
| - '**.gif' | |
| jobs: | |
| notify: | |
| runs-on: ubuntu-latest | |
| steps: | |
| # Determine the single changed tutorial slug (if exactly one), so the | |
| # rebuild can run in fast slug-targeted mode (~2 min) instead of a full | |
| # rebuild (~10 min). Mirrors notify-qa.yml.template. Needs full history | |
| # (fetch-depth: 0) for the before..after diff. Empty slug (0 or >1 | |
| # tutorials touched) → rebuild-content.yml falls back to a full rebuild. | |
| - uses: actions/checkout@v4 | |
| with: { fetch-depth: 0 } | |
| - name: Determine changed slug | |
| id: slug | |
| run: | | |
| changed=$(git diff --name-only ${{ github.event.before }} ${{ github.sha }} \ | |
| | awk -F/ '/^tutorials\//{print $2}' | sort -u) | |
| count=$(echo "$changed" | wc -l) | |
| # Only emit a slug when EXACTLY one tutorial changed AND it matches the | |
| # strict slug charset (whole-value POSIX case match). Anything else → | |
| # empty slug → rebuild-content.yml runs a full rebuild. Validating here | |
| # (sender) too — not just the receiver — keeps a malformed dir name out | |
| # of the dispatch payload entirely. | |
| if [ "$count" = "1" ] && [ -n "$changed" ]; then | |
| case "$changed" in | |
| *[!a-z0-9-]* | -* ) echo "slug=" >> "$GITHUB_OUTPUT" ;; | |
| *) echo "slug=$changed" >> "$GITHUB_OUTPUT" ;; | |
| esac | |
| else | |
| echo "slug=" >> "$GITHUB_OUTPUT" | |
| fi | |
| # GitHub App token (preferred). Activates when this repo has | |
| # USE_GITHUB_APP=true and the TUTORIALS_APP_* secrets populated. Falls | |
| # back to the classic TUTORIALS_DISPATCH_TOKEN PAT while unset. | |
| - name: Generate GitHub App token | |
| id: app-token | |
| if: ${{ vars.USE_GITHUB_APP == 'true' }} | |
| uses: actions/create-github-app-token@v1 | |
| with: | |
| app-id: ${{ secrets.TUTORIALS_APP_ID }} | |
| private-key: ${{ secrets.TUTORIALS_APP_PRIVATE_KEY }} | |
| owner: sap-tutorials | |
| repositories: tutorials-ims | |
| - name: Trigger content rebuild | |
| env: | |
| DISPATCH_TOKEN: ${{ steps.app-token.outputs.token || secrets.TUTORIALS_DISPATCH_TOKEN }} | |
| # rebuild-content.yml routes on client_payload.environment (allowlist | |
| # dev|qa|prod, defaults dev when absent). This is the PRODUCTION | |
| # source-repo template, so it targets prod; override per-repo with a | |
| # REBUILD_ENVIRONMENT repo variable (e.g. a staging source repo → qa). | |
| TARGET_ENV: ${{ vars.REBUILD_ENVIRONMENT || 'prod' }} | |
| # Single changed slug (empty if 0 or >1 or non-slug-charset) → | |
| # rebuild-content.yml uses it to run slug-targeted (fast) vs full. | |
| SLUG: ${{ steps.slug.outputs.slug }} | |
| # Pin the github context values into env too, so the JSON body is | |
| # assembled entirely from shell vars via jq (no template interpolation | |
| # into the payload string). | |
| REPO: ${{ github.repository }} | |
| REF: ${{ github.ref }} | |
| SHA: ${{ github.sha }} | |
| run: | | |
| # Build the payload with jq so every value is correctly JSON-escaped | |
| # (a slug / ref / repo containing quotes or backslashes can't break out | |
| # of the JSON — the string-interpolation form was a json-injection risk). | |
| BODY=$(jq -nc \ | |
| --arg repo "$REPO" --arg ref "$REF" --arg sha "$SHA" \ | |
| --arg env "$TARGET_ENV" --arg slug "$SLUG" \ | |
| '{event_type:"tutorial-updated", client_payload:{repository:$repo, ref:$ref, sha:$sha, environment:$env, slug:$slug}}') | |
| curl -X POST \ | |
| -H "Authorization: Bearer ${DISPATCH_TOKEN}" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| --data "$BODY" \ | |
| "https://api.github.com/repos/sap-tutorials/tutorials-ims/dispatches" |