From c1147b6512d8f27f35399cfe7864f3309bdad8f9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 19 Aug 2026 13:29:15 +0000 Subject: [PATCH] Publish the catalogue as a page on GitHub Pages samples and samples-controls each publish the question their corpus is actually asked - a learning path there, a search over 430 control ports here. This corpus is asked something else again, and neither page answers it: "my system is 7.50 and on-premise, what of this can I even run", and "is there a sample for WebSockets, and what do I set up first". Both are questions about the SYSTEM rather than about the sample, which is what this repository is made of. So web/ is a search over the catalogue with two facets - the system you have and the technology you came for - and every card carries what the sample needs from that system, its release floor, the class to start, its search terms and, where the class has one, its ABAP-Doc header, the fullest description this repository holds of a sample. No playground link, unlike the two sibling pages. The playground runs a class with no system behind it, and a system is precisely what every sample here requires: a Gateway service, a RAP business object, an APC channel, a launchpad. Each app would open there and then fail, so the cards link to the source, to the package README's "What you need" and to the one-package branch abapGit takes. No new source of truth: every fact is read out of what the repository already keeps - the scan behind SAMPLES.md (@summary, @keywords, the ABAP-Doc header, DESCRIPT), .github/packages.json and the README's package table. Adding a sample or a package therefore needs no step for the page. The title rule the two catalogues share moves into the scan as sampleTitle( ), so it cannot drift; SAMPLES.md is byte-identical. web/apps.json is generated and not committed, so a sample pull request carries no diff of derived data and the page can never be staler than the tree. deploy-web regenerates and publishes it; check-web runs the same generator with --check on every pull request, which is what catches a package with no README row, a row that no longer parses, or an app in a directory that is no package - all three break the page without touching web/, and none of them shows before a deploy. Settings -> Pages -> Source has to be set to "GitHub Actions" once for the first deploy to serve anything. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01CHNPdkwxjAfH3JxmteDiHt --- .github/workflows/check-web.yaml | 32 ++ .github/workflows/deploy-web.yaml | 95 ++++++ .gitignore | 4 + AGENTS.md | 27 ++ README.md | 23 ++ package.json | 6 +- scripts/generate-samples-md.mjs | 10 +- scripts/generate-web-index.mjs | 315 +++++++++++++++++++ scripts/lib/scan-samples.mjs | 26 +- web/README.md | 93 ++++++ web/index.html | 150 +++++++++ web/stack.css | 504 ++++++++++++++++++++++++++++++ web/stack.js | 356 +++++++++++++++++++++ 13 files changed, 1632 insertions(+), 9 deletions(-) create mode 100644 .github/workflows/check-web.yaml create mode 100644 .github/workflows/deploy-web.yaml create mode 100644 scripts/generate-web-index.mjs create mode 100644 web/README.md create mode 100644 web/index.html create mode 100644 web/stack.css create mode 100644 web/stack.js diff --git a/.github/workflows/check-web.yaml b/.github/workflows/check-web.yaml new file mode 100644 index 0000000..67d72f1 --- /dev/null +++ b/.github/workflows/check-web.yaml @@ -0,0 +1,32 @@ +name: check-web + +# The page in web/ is generated from four things at once: the classes, the +# package index, the package table of the README and the scan they share. A +# pull request can break that without touching web/ at all - a package with no +# README row, a row whose cells no longer parse, an app in a directory that is +# no package. None of it shows up until a deploy, and a deploy happens after +# the merge. This check runs the generator with --check on every pull request +# instead. Plain node, no dependencies, so it stays a few seconds. + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +concurrency: + group: check-web-${{ github.ref }} + cancel-in-progress: true + +jobs: + check-web: + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '22' + - run: node scripts/generate-web-index.mjs --check diff --git a/.github/workflows/deploy-web.yaml b/.github/workflows/deploy-web.yaml new file mode 100644 index 0000000..168d32e --- /dev/null +++ b/.github/workflows/deploy-web.yaml @@ -0,0 +1,95 @@ +name: deploy-web + +# Publishes the page in web/ to this repository's GitHub Pages. +# +# https://abap2ui5.github.io/samples-stack/ — every sample of this repository, +# searchable by the technology it plays with and by the release your system +# runs, with what it needs from that system on every card. It is static: three +# hand-written files plus web/apps.json, which this workflow generates from the +# tree on every deploy, so the page is never staler than the samples it +# describes and a sample pull request carries no diff of derived data. +# +# No dependencies are installed — the generator is plain node over the same +# scan SAMPLES.md is built from. +# +# This is the ONLY way the site is published: Settings -> Pages -> Source must +# be "GitHub Actions". A red "pages build and deployment" run on main is +# GitHub's built-in Jekyll builder rather than this workflow; re-saving the +# Pages source in Settings clears it. + +on: + workflow_dispatch: + push: + branches: [ main ] + paths: + # the page is derived from all of these: the classes (@summary, + # @keywords, the ABAP-Doc header, the DESCRIPT beside them), the package + # index, the package table of the README, and the page itself + - 'src/**' + - 'web/**' + - 'README.md' + - '.github/packages.json' + - 'scripts/generate-web-index.mjs' + - 'scripts/lib/scan-samples.mjs' + - '.github/workflows/deploy-web.yaml' + +permissions: + contents: read + pages: write + id-token: write + +# one Pages deployment at a time; let a newer run supersede an in-flight one +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: '22' + + - name: The catalogue behind the page + run: node scripts/generate-web-index.mjs + + # The gate this pipeline needs now that there is nothing here that can + # fail to build: a page whose data file is missing deploys exactly like a + # working one — it just says "the catalogue could not be loaded" to every + # visitor. Assert the four files and a non-trivial index before uploading. + - name: Check the artefact is complete + run: | + cd web + for f in index.html stack.css stack.js apps.json; do + test -s "$f" || { echo "deploy-web: $f is missing or empty"; exit 1; } + done + node -e ' + const x = require("./apps.json"); + if (!Array.isArray(x.apps) || x.apps.length < 20) { + console.error(`deploy-web: apps.json holds ${x.apps?.length} samples, expected 20+`); + process.exit(1); + } + if (!Array.isArray(x.packages) || x.packages.length < 5) { + console.error("deploy-web: apps.json has no package list"); + process.exit(1); + } + console.log(`deploy-web: ${x.apps.length} samples, ${x.packages.length} groups`); + ' + + - uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 + with: + path: web + + deploy: + needs: build + runs-on: ubuntu-latest + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - id: deployment + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 diff --git a/.gitignore b/.gitignore index 1406277..949adba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ node_modules output + +# derived: the catalogue behind the page in web/, written by +# scripts/generate-web-index.mjs on every deploy (AGENTS.md section 8) +web/apps.json diff --git a/AGENTS.md b/AGENTS.md index a329bd7..f53ce7f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -310,6 +310,33 @@ gone. 6. `npm run samples:md` and commit `SAMPLES.md` with it (§6). 7. `npm run check`. +## 8. The page in `web/` + +**** — the catalogue as a searchable +page, for somebody who has installed nothing yet and is asking whether their +system can run any of it. Four files: `index.html`, `stack.css`, `stack.js` and +the generated `web/apps.json`. [`web/README.md`](web/README.md) has the detail; +what matters here: + +- **It introduces no new source of truth.** Every fact on it is read out of + something the repository already keeps — the scan (`@summary`, `@keywords`, + the ABAP-Doc header, `DESCRIPT`), `.github/packages.json` (branch, release) + and the README's package table (what a package plays together with). Adding a + sample or a package therefore needs **no step for the page**: `npm run + samples:md`, and it is on both. +- **`web/apps.json` is generated and not committed** — `npm run web:index` + writes it, `deploy-web` writes it again on every deploy. A committed copy + would put a diff of derived data on every sample pull request. +- **`npm run check:web` is the gate** (its own workflow, and part of `npm run + check`): it runs the generator with `--check`, which fails on a package with + no README row, a row whose cells no longer parse, or an app in a directory + that is no package. All three break the page without touching `web/`, and + none of them shows up before a deploy — which happens after the merge. +- **No playground link, unlike the sibling repositories' pages.** The playground + runs a class with no system behind it, and a system is what every sample here + needs. Each app would open there and fail, so the cards link to the source, + to the package README's *What you need*, and to the one-package branch. +