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. +