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:

WorkflowFileWhat it does
CI.github/workflows/ci.ymlchecks the validator itself
site / check.github/workflows/site-check.ymlchecks this site on pull requests
Conformance.github/workflows/conformance.ymlchecks 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 audit finds 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.

  1. 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's skip.json. It exports only into libraries that already have api-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.

  2. lib-repos runs only when LIBS_TOKEN is set. It starts from a clean checkout and runs no library code. It opens an Implement <function> issue in every library that lacks a function the merge added. It opens a Fix <function> issue in every library that fails a case the merge added or changed. It refreshes every open api-contract issue and closes the ones that are done. Last, it pushes each suite patch to an api-contract/cases branch in the library and opens a PR, if none is open.

  3. publish deploys the site to Cloudflare Pages. It runs only when the site is complete and PUBLISH_SITE is true.

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:

InputWhat it does
sincea git ref. The run opens the issues for every contract change since that ref.
backfillcore 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: noindex to every preview response
  • every page has a robots meta tag with noindex
  • robots.txt lists 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

NameKindWhereWhat it does
LIBS_TOKENsecretdocsA 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_SITEvariabledocstrue turns on the deploys to Cloudflare Pages from main.
CLOUDFLARE_API_TOKENsecretdocsA Cloudflare API token with the Cloudflare Pages: Edit permission. The publish job and the previews deploy with it.
CLOUDFLARE_ACCOUNT_IDsecretdocsThe ID of the Cloudflare account that owns the Pages project.
SITE_URLvariabledocsThe public address of the site, with its path. Set it when the site moves.
DOCS_DISPATCH_TOKENsecreteach libraryA 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:

NameWhat it does
SITE_URLthe address that canonical links point at
SITE_DATA_URLwhere the build reads the status from (default: SITE_URL)
GITHUB_TOKENraises the GitHub API limit when the build reads the libraries
SITE_DATA=skipbuilds without the status
SITE_PREVIEW=truebuilds a preview: served at the root of its own domain, with the noindex meta tag

What can go wrong

SymptomCauseWhat to do
Notice: LIBS_TOKEN is not setthe secret is missingAdd LIBS_TOKEN. Until then, no issues and no suite PRs.
Notice: vars.PUBLISH_SITE is not 'true'the variable is missingSet PUBLISH_SITE to true. The site was built but not published.
Warning: the site did not buildthe site build failedRead the log of the build step and fix it. The last site stays online.
Warning: N of M libs have a reporta library crashed, for example its default branch does not buildRead the log of the check step. The last site stays online until every library gets a report.
A merge opened no issuesthe run failed before its issues stepRun the workflow by hand with since set to the commit before the merge.
Warning: <commit> is not in the repositorya force-push removed the commit before the mergeRun the workflow by hand with since set to a commit before the merge.
Two open issues for the same functiontwo runs opened it at the same timeNothing. The next run closes the newer one and keeps the oldest.
A Fix issue stays open after the fixthe tests of that library did not runNothing. The issue closes on a run where the tests run and pass.
Error: the patch touches files outside api-contract/the export changed other filesNothing is pushed. Read the export log for that library.
The library CI warns that api-contract/ is behindthe suite PR is not mergedMerge the api-contract/cases PR.
Edit on GitHub

Last updated on

On this page