From 84706810ab4bae8e9a99816b0b76aaf04d181649 Mon Sep 17 00:00:00 2001 From: Thomas Jung Date: Sun, 25 Oct 2026 12:50:43 +0100 Subject: [PATCH 1/3] fix(ci): regenerate fingerprinted CSS before QA Hugo build (#2912) The QA rebuild workflow builds Hugo directly via /tmp/hugo rather than `npm run build:all`, but was never given the build:icon-subset + build:css steps that commit ac6b7e39f (#2896 follow-up) added to the prod rebuild-content.yml when it .gitignored those generated CSS outputs. On a clean CI checkout fundamental-styles-icon.css is therefore absent, so head.html:27 (resources.Get "css/fundamental-styles-icon.css" | minify) fails with "wrong type for value; expected resources.ResourceTransformer; got resource.Resource" and every QA full rebuild dies at the Hugo step. Add a "Build fingerprinted CSS" step before the QA Hugo build, mirroring rebuild-content.yml, so QA and prod regenerate byte-identical CSS and agree on the fingerprint. --- .github/workflows/rebuild-content-qa.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/rebuild-content-qa.yml b/.github/workflows/rebuild-content-qa.yml index ead034b04..6a736df0a 100644 --- a/.github/workflows/rebuild-content-qa.yml +++ b/.github/workflows/rebuild-content-qa.yml @@ -381,6 +381,22 @@ jobs: - name: Build island fingerprint manifest run: npm run build:island-manifest + # Generated CSS (#2896 follow-up, mirrors rebuild-content.yml). Commit + # ac6b7e39f stopped committing sap-fundamental.css (build:css, postcss) + # and fundamental-styles-icon.css (build:icon-subset) — both are now + # .gitignored build outputs. head.html does `resources.Get | minify` on + # the icon subset, so on a clean CI checkout where the file is absent the + # QA Hugo build fails at head.html:27 ("wrong type ...; got + # resource.Resource"). This workflow drives /tmp/hugo directly rather than + # `npm run build:all`, so — like the feed fetchers above — it must + # regenerate them BEFORE the Hugo build. build:css + build:icon-subset + # produce byte-identical output to the deploy's build:all, so QA and prod + # agree on the fingerprint. (QA regression #2912.) + - name: Build fingerprinted CSS (sap-fundamental + icon subset) + run: | + npm run build:icon-subset + npm run build:css + - name: Build QA Hugo site # Hugo was downloaded to /tmp/hugo (line 44). The build:qa npm script # invokes 'hugo' (bare binary name) — works locally where hugo is From 844736f16b99e096d48ea47501840f486d14062b Mon Sep 17 00:00:00 2001 From: Thomas Jung Date: Sun, 25 Oct 2026 12:52:26 +0100 Subject: [PATCH 2/3] fix(ci): QA rebuild workflow must build CSS + icon subset before Hugo rebuild-content-qa.yml jumped from the island-manifest step straight to build:qa, with no step to generate the two gitignored CSS build outputs (fundamental-styles-icon.css via build:icon-subset, sap-fundamental.css via build:css). rebuild-content.yml (PROD) has had that step all along, so a clean QA checkout died at head.html:27 (resources.Get on the missing icon CSS) while PROD was unaffected. - Add the 'Build fingerprinted CSS (sap-fundamental + icon subset)' step to the QA workflow, in the same position PROD runs it (before the Hugo build). - Document the two-workflow parity rule + the list of gitignored Hugo build inputs in mta-deployment.md so the drift that caused this doesn't recur. --- .github/workflows/rebuild-content-qa.yml | 15 +++++++++++++++ docs/developers/operations/mta-deployment.md | 17 +++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/.github/workflows/rebuild-content-qa.yml b/.github/workflows/rebuild-content-qa.yml index ead034b04..83028cf45 100644 --- a/.github/workflows/rebuild-content-qa.yml +++ b/.github/workflows/rebuild-content-qa.yml @@ -381,6 +381,21 @@ jobs: - name: Build island fingerprint manifest run: npm run build:island-manifest + # [#2896 follow-up] Generated CSS parity with rebuild-content.yml (its + # "Build fingerprinted CSS (sap-fundamental + icon subset)" step). Both + # sap-fundamental.css (build:css, postcss) and fundamental-styles-icon.css + # (build:icon-subset) are build outputs — no longer committed, they are + # .gitignored. This workflow drives /tmp/hugo directly rather than + # `npm run build:all`, so — exactly like the island manifest above — these + # must be generated explicitly before the QA Hugo build. Without them a + # clean QA checkout has no hugo/assets/css/fundamental-styles-icon.css and + # Hugo's `resources.Get` fails at head.html:27 (the 2026-10-25 QA-head + # build break). Layouts are shared prod/QA, so QA needs the same two outputs. + - name: Build fingerprinted CSS (sap-fundamental + icon subset) + run: | + npm run build:icon-subset + npm run build:css + - name: Build QA Hugo site # Hugo was downloaded to /tmp/hugo (line 44). The build:qa npm script # invokes 'hugo' (bare binary name) — works locally where hugo is diff --git a/docs/developers/operations/mta-deployment.md b/docs/developers/operations/mta-deployment.md index 7dbaa040d..f7d9b9120 100644 --- a/docs/developers/operations/mta-deployment.md +++ b/docs/developers/operations/mta-deployment.md @@ -627,3 +627,20 @@ the static first rather than swapping. Override the derived idle URL with `IDLE_APPROUTER_URL` if the `-idle` naming ever changes. CI mirrors this as a non-gating post-deploy step in the `smoke-test` job (CI prod uses `--skip-testing-phase`, so it probes the live approuter after the auto-swap). + +### The two rebuild-content workflows must stay in parity on build-output steps (2026-10-25 QA-head break) + +Hugo's `resources.Get` in [`hugo/layouts/partials/head.html`](../../../hugo/layouts/partials/head.html) reads CSS that is **generated, not committed** — several build outputs under `hugo/assets/css/` are `.gitignored`, so a clean checkout does not have them until a build step produces them. The two content-rebuild workflows each drive `/tmp/hugo` **directly** (not `npm run build:all`, which would chain every generator), so each workflow must list the generator steps explicitly — and the two lists must match. + +They drifted: `rebuild-content.yml` (PROD) had a **"Build fingerprinted CSS (sap-fundamental + icon subset)"** step (`npm run build:icon-subset` → `fundamental-styles-icon.css`; `npm run build:css` → `sap-fundamental.css`) ahead of its Hugo build, but `rebuild-content-qa.yml` (QA) was never given it. A clean QA checkout therefore had no `fundamental-styles-icon.css`, and the QA Hugo build died at `head.html:27` (`resources.Get "css/fundamental-styles-icon.css"` → nil). PROD was unaffected because its workflow generated the file first. + +**Why:** `npm run build:all` chains `build:island-manifest`, `build:icon-subset`, `build:css`, `build:highlight`, etc. The rebuild workflows bypass that chain for speed/control, so every gitignored build output the Hugo layouts reference has to be regenerated by an explicit named step in **both** workflows. Omit one in one workflow and only that channel breaks — invisibly, because the other channel still works. + +**How to apply:** + +- **Mirror build-output steps across both workflows.** Any step that generates a gitignored Hugo build input added to `rebuild-content.yml` MUST be added to `rebuild-content-qa.yml` (and vice-versa), in the same position relative to the Hugo build. The QA Hugo build runs against `dataDir=data-qa` (hugo.qa.toml) which **replaces** the data root, so island-manifest/CSS outputs must be present before `build:qa` just as they are before PROD's Hugo build. +- **Gitignored Hugo build inputs that need an explicit generator step** (grep `.gitignore` for the authoritative list; as of 2026-10-25): + - `hugo/assets/css/fundamental-styles-icon.css` → `npm run build:icon-subset` + - `hugo/assets/css/sap-fundamental.css` → `npm run build:css` + - `hugo/data/island_manifest.json` → `npm run build:island-manifest` (+ `npm --prefix hugo-apps run build` for the Vite bundles) +- **Local/operator deploys are covered already:** `npm run deploy` runs `npm run build:deploy` → `build:all`, which chains all generators, and `deploy-mta.cjs` Steps 2.5/2.7/3.6 guard the island-manifest + QA navigator outputs. The drift only bites the **CI rebuild workflows**, which don't call `build:all`. There is no guard that cross-checks the two workflows' step lists, so parity is a review-time discipline — diff the two files' Hugo-build preamble when touching either. From de44e3a4b87de0aa2bc3e49b50a4373e3fb035ef Mon Sep 17 00:00:00 2001 From: Thomas Jung Date: Sun, 25 Oct 2026 13:02:32 +0100 Subject: [PATCH 3/3] chore(release): 1.41.2 --- .deploy/mta.yaml | 2 +- hugo/data/whats_new.json | 93 +++++++++++++++++++++++++++++++++++++++- mta-mcp.yaml | 2 +- 3 files changed, 94 insertions(+), 3 deletions(-) diff --git a/.deploy/mta.yaml b/.deploy/mta.yaml index f71d5e5ab..58bea8370 100644 --- a/.deploy/mta.yaml +++ b/.deploy/mta.yaml @@ -10,7 +10,7 @@ ID: tutorials-ims # Bump this on each release you deploy — it's the version shown by `cf mtas` # and in the mtar filename (tutorials-ims_.mtar). Deploy is manual: # `cd .deploy && mbt build && cf deploy mta_archives/tutorials-ims_.mtar -e ../deploy/.mtaext -f`. -version: 1.41.0 +version: 1.41.2 # Top-level parameters (overridable per-env via deploy/.mtaext). parameters: diff --git a/hugo/data/whats_new.json b/hugo/data/whats_new.json index 736efa9c9..54bd989fc 100644 --- a/hugo/data/whats_new.json +++ b/hugo/data/whats_new.json @@ -1,5 +1,5 @@ { - "generatedAt": "2026-10-24T10:33:13.644Z", + "generatedAt": "2026-10-25T12:02:19.765Z", "repos": [ { "key": "tutorials-ims", @@ -8,6 +8,97 @@ } ], "entries": [ + { + "id": "tutorials-ims#2918", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2918, + "title": "docs: record QA/PROD rebuild-workflow parity rule (follow-up to #2917)", + "summary": "Documented the parity rule that keeps the QA and production content-rebuild pipelines generating identical CSS, preventing a class of build break.", + "category": "Maintenance", + "mergedAt": "2026-10-25T11:59:44Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2918" + }, + { + "id": "tutorials-ims#2917", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2917, + "title": "QA tutorial previews build and style correctly again", + "summary": "The QA author-preview channel now regenerates its icon and base CSS before building, so author previews render with full styling instead of failing the build.", + "category": "Fix", + "mergedAt": "2026-10-25T11:53:50Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2917" + }, + { + "id": "tutorials-ims#2916", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2916, + "title": "release v1.41.1 DEV to main promotion", + "summary": "Release 1.41.1 promoted the prior window of fixes from DEV to the production branch.", + "category": "Maintenance", + "mergedAt": "2026-10-25T11:44:57Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2916" + }, + { + "id": "tutorials-ims#2915", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2915, + "title": "Prize-drawing winner cards show the winner's email again", + "summary": "Prize-drawing winner cards now show the winner's email by falling back to their verified sign-in identity when no address is on their main profile, so operators can reach winners instead of seeing \"No Email on File\".", + "category": "Fix", + "mergedAt": "2026-10-25T08:20:00Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2915" + }, + { + "id": "tutorials-ims#2914", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2914, + "title": "Badge scanner shows the contestant name in dark mode", + "summary": "The badge scanner's contestant name is now legible in dark mode instead of rendering dark-on-dark, and the underlying theme fix also corrects icon and card-border colors across every page island.", + "category": "Fix", + "mergedAt": "2026-10-25T08:08:40Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2914" + }, + { + "id": "tutorials-ims#2913", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2913, + "title": "App Space parallel-path timelines use the full width", + "summary": "App Space tracks with multiple parallel lanes now widen to fill the available space so card titles stop wrapping one word per line, while single-path tracks keep their comfortable reading width.", + "category": "Fix", + "mergedAt": "2026-10-24T14:02:14Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2913" + }, + { + "id": "tutorials-ims#2911", + "repo": "tutorials-ims", + "label": "Developer Portal", + "number": 2911, + "title": "release v1.41.0 DEV to main promotion", + "summary": "Release 1.41.0 promoted the prior window of fixes and features from DEV to the production branch.", + "category": "Maintenance", + "mergedAt": "2026-10-24T10:35:54Z", + "week": "2026-W43", + "weekStart": "2026-10-19", + "url": "https://github.com/sap-tutorials/tutorials-ims/pull/2911" + }, { "id": "tutorials-ims#2910", "repo": "tutorials-ims", diff --git a/mta-mcp.yaml b/mta-mcp.yaml index fee769d2b..d8855ef84 100644 --- a/mta-mcp.yaml +++ b/mta-mcp.yaml @@ -4,7 +4,7 @@ _schema-version: 3.3.0 # This file lives at repo root → path: gen/srv-mcp (root-relative, no ../). # before-all runs from ROOT (no cd ..) — mbt uses the descriptor's directory as cwd. ID: tutorials-mcp -version: 1.1.0 +version: 1.1.2 # Destinations are subaccount-level, so DEV and PROD (sharing one subaccount) # need DISTINCT destination names. `dest-main-srv` defaults to the PROD name;