How the pipeline works
What runs on a pull request, on a merge, every night and on a release. What each run writes, the secrets it needs and what to do when it fails.
The Brazilian Utils libraries follow one contract in docs. Three workflows in that repository keep the contract, the libraries and this site in step:
| Workflow | File | What it does |
|---|---|---|
| CI | .github/workflows/ci.yml | checks the validator itself |
| site / check | .github/workflows/site-check.yml | checks this site on pull requests |
| Conformance | .github/workflows/conformance.yml | checks every library against the contract, keeps the issues and the suite PRs in the library repositories, and builds and publishes this site |
Each pull request that changes the site also gets a preview copy of it. It is described below.
What runs on a pull request
CI runs on every pull request. It runs actionlint on the workflows and on the library templates. Then it runs the typecheck, the lint and the unit tests. The language toolchains are installed, so the tests of each language adapter run too.
site / check runs when the pull request changes contract/, libs/ or site/. It runs these checks:
npm auditfinds no known vulnerability in the dependencies the site ships- every page and every string has both languages (
check:i18n --strict) - lint passes with no warnings
- the site builds
- the typecheck passes
- accessibility (axe) and design checks pass on every page type
This build does not run the validator. It takes the status of each library from the last published site.
Conformance runs when the pull request changes the contract, the library configs, baselines/, schema/, src/ or the package files. It clones every library at its default branch and runs check --tests. It fails on a regression against baselines/. Then it runs diff, which fails on a new divergence between libraries. The job summary shows the contract changelog and the issues that the merge would open. The run also builds the site with its own results. It writes nothing outside the run.
A newer push to the same pull request cancels the run in progress. These jobs run the code of the libraries, so their token can only read. They never get LIBS_TOKEN.
What runs on a merge to main
A merge to main starts the Conformance workflow when it changes the same paths as above, or site/. The workflow has three jobs.
-
conformance does everything that the pull request run does. It also exports the suite of each library: the JSON cases in
api-contract/and the library'sskip.json. It exports only into libraries that already haveapi-contract/. It clones each one, exports the suite and saves the difference as a patch. Then it builds the site with the results of this run. -
lib-repos runs only when
LIBS_TOKENis set. It starts from a clean checkout and runs no library code. It opens anImplement <function>issue in every library that lacks a function the merge added. It opens aFix <function>issue in every library that fails a case the merge added or changed. It refreshes every openapi-contractissue and closes the ones that are done. Last, it pushes each suite patch to anapi-contract/casesbranch in the library and opens a PR, if none is open. -
publish deploys the site to Cloudflare Pages. It runs only when the site is complete and
PUBLISH_SITEistrue.
A merge run is never cancelled, and a later run never replaces it. It is the only run that opens the issues for that merge.
A failed check does not stop the issues or the site. A regression or a new divergence fails the run, but the next jobs still run.
The site is complete when every library got a report and the site built. If a library crashed, or the build failed, the last site stays online. A library without a report gets no new issues in that run.
If someone cancels a run, the jobs that have not started do not start. A cancelled run does not publish.
The nightly run
The Conformance workflow runs every day at 09:00 UTC. It does what a merge run does, against the latest default branch of every library. It opens no issues, because no merge started it. It refreshes the open issues and closes the ones that are done. It refreshes the suite PRs and publishes the site again.
When a library releases
A library can tell the docs repository about a release. Its release workflow sends a repository_dispatch event of type lib-released. The usage files page has the step to copy. This event starts the same run as the nightly. The site then shows the usage files of the new release at once.
Nightly runs and release runs share one concurrency group. They run one at a time. A newer run that waits replaces an older run that waits.
Running it by hand
Go to Actions, then Conformance, then Run workflow, and choose main. The run has two inputs:
| Input | What it does |
|---|---|
since | a git ref. The run opens the issues for every contract change since that ref. |
backfill | core or all. The run also opens issues for everything that is already missing or failing. |
Use since when the run of a merge failed before its issues step. Set it to the commit just before the merge.
A manual run has its own concurrency group. A nightly run or a release run that starts later does not replace it, so it keeps its inputs.
The first merge that brings the contract into main opens no issues, on purpose. Before that merge there was no contract to compare with, so every function would count as new. Open those issues with a backfill run.
In each library
Each library copies templates/lib-ci/<language>.yml to .github/workflows/api-contract.yml. This workflow runs on pushes to main or master and on every pull request.
It runs the docs Action, which checks the library against the contract. The check fails only on a regression or on public API that is not in the contract. The job summary lists what is still missing.
Then the Action runs export-cases --check. When api-contract/ is behind the contract, the Action warns. With cases: check it fails. To fix it, merge the api-contract/cases PR that the bot opened.
The harness of the library runs the cases in api-contract/ in the library's own test command.
Preview deployments
The site / check workflow deploys a copy of the site for each push to a pull request that changes site/, contract/ or libs/. The copy goes to Cloudflare Pages, on the branch pr-<number>, and one comment on the pull request links to it. Each push updates the copy and the comment. A preview is served at the root of its own domain. The check does not run the validator, so the preview takes the status of each library from the published site. Pull requests from forks get no preview, because their runs have no secrets.
Search engines do not index any preview:
- Cloudflare adds the header
X-Robots-Tag: noindexto every preview response - every page has a
robotsmeta tag withnoindex robots.txtlists no sitemap- canonical links point at
SITE_URL
The official site is the one at SITE_URL. It is the only one that search engines index.
Publishing
The publish job deploys to the production branch, main, of the Cloudflare Pages project brazilian-utils-docs. It has its own concurrency group, cloudflare-pages. One deploy runs at a time. A run that finishes late does not put an older site over a newer one.
SITE_URL is the public address of the site, with its path. Its path becomes the base path of the site. The issues link to it, and so do the badges in the library READMEs. Without the variable, the workflow uses https://brazilian-utils.com.br.
site/public/_headers sets the response headers, and site/public/_redirects sends the pages of the old JavaScript library site to where they are now.
Secrets and variables
| Name | Kind | Where | What it does |
|---|---|---|---|
LIBS_TOKEN | secret | docs | A fine-grained token or a GitHub App, with write access to Issues, Contents and Pull requests on the library repositories. Never give it the Workflows permission. It turns on the issues and the suite PRs. |
PUBLISH_SITE | variable | docs | true turns on the deploys to Cloudflare Pages from main. |
CLOUDFLARE_API_TOKEN | secret | docs | A Cloudflare API token with the Cloudflare Pages: Edit permission. The publish job and the previews deploy with it. |
CLOUDFLARE_ACCOUNT_ID | secret | docs | The ID of the Cloudflare account that owns the Pages project. |
SITE_URL | variable | docs | The public address of the site, with its path. Set it when the site moves. |
DOCS_DISPATCH_TOKEN | secret | each library | A token that can send repository_dispatch to the docs repository (Contents: write). Without it, a release reaches the site at the next nightly run. |
A build outside the pipeline needs no variable. These are optional:
| Name | What it does |
|---|---|
SITE_URL | the address that canonical links point at |
SITE_DATA_URL | where the build reads the status from (default: SITE_URL) |
GITHUB_TOKEN | raises the GitHub API limit when the build reads the libraries |
SITE_DATA=skip | builds without the status |
SITE_PREVIEW=true | builds a preview: served at the root of its own domain, with the noindex meta tag |
What can go wrong
| Symptom | Cause | What to do |
|---|---|---|
Notice: LIBS_TOKEN is not set | the secret is missing | Add LIBS_TOKEN. Until then, no issues and no suite PRs. |
Notice: vars.PUBLISH_SITE is not 'true' | the variable is missing | Set PUBLISH_SITE to true. The site was built but not published. |
Warning: the site did not build | the site build failed | Read the log of the build step and fix it. The last site stays online. |
Warning: N of M libs have a report | a library crashed, for example its default branch does not build | Read the log of the check step. The last site stays online until every library gets a report. |
| A merge opened no issues | the run failed before its issues step | Run the workflow by hand with since set to the commit before the merge. |
Warning: <commit> is not in the repository | a force-push removed the commit before the merge | Run the workflow by hand with since set to a commit before the merge. |
| Two open issues for the same function | two runs opened it at the same time | Nothing. The next run closes the newer one and keeps the oldest. |
A Fix issue stays open after the fix | the tests of that library did not run | Nothing. The issue closes on a run where the tests run and pass. |
Error: the patch touches files outside api-contract/ | the export changed other files | Nothing is pushed. Read the export log for that library. |
The library CI warns that api-contract/ is behind | the suite PR is not merged | Merge the api-contract/cases PR. |
Last updated on
