GitHub Actions Integration
Overview
Metanorma provides a set of composable GitHub Actions at
actions-mn that handle compilation, site
deployment, per-document releases, and multi-repo aggregation.
GitHub is the only platform that supports the full feature set: compilation, site deployment, organization-scale publishing (per-document releases, channel-based routing, and multi-repo aggregation).
For the conceptual architecture and config file schemas, see Organization-Scale Publishing Setup. For other CI/CD platforms, see CI/CD integration.
The actions-mn ecosystem
| Action | Role | Used in |
|---|---|---|
Installs the |
Any workflow |
|
Caches files used by and generated by Metanorma during compilation (temporary fonts, Relaton data, site output) to speed up subsequent runs. |
Any build workflow |
|
Compiles a single Metanorma document to HTML/PDF/XML/etc. |
Single-document repos |
|
Compiles all documents from a |
Any repo with multiple documents |
|
Meta-action: calls |
Simple site deployments |
|
Deploys to GitHub Pages with PR preview support. Handles three scenarios: push to main (deploy), PR open/update (preview), PR close (cleanup). |
Any Pages deployment |
|
Discovers compiled documents, detects changes, and publishes them as per-document GitHub Releases with channel-based routing and stage gating. |
Organization-scale publishing |
|
Aggregates released Metanorma documents from multiple GitHub repositories with channel-based filtering. Discovers repos by topic, downloads artifacts, and generates a structured index. |
Portal repositories |
|
Installs extra or private Metanorma flavor gems (e.g., BSI, NIST, Plateau). |
Repos using non-standard flavors |
Pipeline patterns
Two pipeline patterns cover all use cases:
- Simple site (single repo)
-
Use
build-and-publish+deploy-pages. On every push, compile the site and deploy it. This is what most single-team or single-document projects use. - Organization-scale (multi-repo)
-
Use
site-gen+releasein each per-document repository, andaggregatein the portal repository. Each repo publishes its own documents as GitHub Releases. The portal discovers and collects them.
Simple site workflow
The following workflow compiles a Metanorma site and deploys it to GitHub Pages.
.github/workflows/generate.ymlname: generate
on:
push:
branches: [ main ]
pull_request:
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
container:
image: metanorma/metanorma:latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Cache Metanorma assets
uses: actions-mn/cache@v1
- name: Metanorma generate site
uses: actions-mn/build-and-publish@main
with:
token: ${{ secrets.GITHUB_TOKEN }}
agree-to-terms: true
deploy:
if: ${{ github.ref == 'refs/heads/main' }}
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
For more examples, see the
actions-mn/build-and-publish
action documentation.
Organization-scale publishing
The release + aggregate pipeline is for organizations that publish many documents across many repositories into a unified portal.
|
Tip
|
For a step-by-step tutorial, see the blog post. For the full config schemas and setup checklist, see Organization-Scale Publishing Setup. |
When to use
Use this pipeline when you have:
-
Multiple document repositories that each produce one or more documents
-
A portal site that aggregates documents from all repositories
-
Different document types (standards, reports, directives) that should appear on different portals or in different sections
-
A need to ensure that internal or draft documents never appear on public portals
For single-document sites, actions-mn/build-and-publish is simpler and
sufficient.
Architecture
The publication pipeline has three stages:
Author Per-document repo GitHub Portal repo
sources/ .github/workflows Releases .github/workflows
*.adoc → site-gen + release → per-document → aggregate → site
releases + index.json
| Component | Role | Where |
|---|---|---|
|
Compiles AsciiDoc sources to HTML/PDF/XML/RXL |
Per-document repo (CI) |
|
Discovers compiled documents, detects changes, publishes per-document GitHub Releases |
Per-document repo (CI) |
GitHub Releases |
Stores release artifacts (zip) + metadata (channels, stage, edition) |
GitHub |
|
Discovers repos by topic, filters by channel, downloads and indexes released documents |
Portal repo (CI) |
Channels
A channel is an audience/category pair that determines where a document appears:
-
audience:
public,members, orinternal -
category: free-form identifier
public/standards ← published standards, visible to everyone
public/reports ← conference and technical reports
members/internal-review ← only visible to organization members
internal/working-draft ← never aggregated by any external portal
The publisher sets the channel. The aggregator filters by it. A portal cannot override or discover channels the publisher didn’t assign.
For the channel routing config, see Release manifest.
Per-document repository structure
A repository participating in the organization-scale pipeline follows this structure:
my-documents/
.github/workflows/
release.yml ← compiles and releases on push to main
generate.yml ← builds preview site on push and PRs
sources/
cc-s-51015.adoc ← AsciiDoc authoring sources
metanorma.yml ← compilation manifest (lists source files)
metanorma.release.yml ← release manifest (channel routing + stage gating)
Gemfile ← typically just "metanorma-cli"
For the contents of metanorma.release.yml, see
Release manifest.
Reusable workflows
Per-document repositories can use reusable workflows from actions-mn/.github
to avoid defining their own build logic:
actions-mn/.github/.github/workflows/metanorma-release.yml-
Checks out the repo, runs
actions-mn/site-gen@v1to compile documents, then runsactions-mn/release@v1to publish changed documents as GitHub Releases. actions-mn/.github/.github/workflows/metanorma-generate.yml-
Checks out the repo inside the
metanorma/metanormaDocker container, runsactions-mn/cache@v1andactions-mn/build-and-publish@v1, then deploys the preview to GitHub Pages.
A per-document repository’s entire release workflow is:
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
paths: ['sources/**', 'metanorma.yml', 'metanorma.release.yml']
workflow_dispatch:
permissions:
contents: write
jobs:
release:
uses: actions-mn/.github/.github/workflows/metanorma-release.yml@main
with:
default-visibility: private
secrets: inherit
A preview workflow builds a site on every push and PR:
# .github/workflows/generate.yml
name: Generate
on:
push:
pull_request:
jobs:
build:
uses: actions-mn/.github/.github/workflows/metanorma-generate.yml@main
secrets: inherit
The metanorma-release topic
The portal discovers document repositories via the metanorma-release GitHub
topic. Add it to each participating repository:
gh api repos/{owner}/{repo}/topics -X PUT --field names='["metanorma-release"]'
If topic-based discovery is not suitable (e.g., aggregating from multiple
organizations), use the repos input on the aggregate action:
- uses: actions-mn/aggregate@v1
with:
repos: 'my-org/repo-a,other-org/repo-b'
channels: 'public/standards'
Document stages in CI
Stage filtering can be applied at the CI level to narrow the manifest policy for a specific run:
- uses: actions-mn/release@v1
with:
stages: 'published,final-draft'
For the full stage codes table, see Document stages.
Published releases are immutable — the tag is created once and never overwritten. Draft releases are rolling — the same tag is updated in-place as the draft evolves.
Action reference
Release action inputs (actions-mn/release)
| Input | Default | Description |
|---|---|---|
|
|
Source path containing the metanorma configuration |
|
|
Output directory containing compiled documents |
|
|
Release manifest file |
|
|
Default visibility for unlisted documents ( |
|
|
Force release even if content hash matches |
|
|
Comma-separated doc IDs or glob patterns to force-replace (deletes and recreates specific releases) |
|
|
Glob pattern to filter documents for release |
|
|
Comma-separated stages to release. Empty = all. |
|
|
Override channels for all documents. Empty = use manifest. |
|
|
Max parallel document processing |
|
|
GitHub token for creating releases |
Aggregate action inputs (actions-mn/aggregate)
| Input | Default | Description |
|---|---|---|
|
|
Comma-separated GitHub organizations to scan for repos |
|
|
Repository topic for auto-discovery |
|
|
Explicit repo list ( |
|
|
Comma-separated channels to include. Empty = all. |
|
|
Comma-separated stages to include. Empty = all. |
|
|
Directory for extracted document files |
|
|
Strip edition suffixes from filenames |
|
|
Max parallel repo processing |
|
|
Directory for persistent cache (ETags, delta state) |
|
|
GitHub token for API access |
Release metadata protocol
Each GitHub Release published by actions-mn/release carries structured metadata:
content-hash:abc123...
<!-- mn-release-metadata
{"version":1,"id":"cc-s-51015","channels":["public/standards"],
"stage":"published","edition":"1","title":"My Standard"}
-->
## CC/S 51015
| Field | Value |
|---|---|
| Document | cc-s-51015 |
| Edition | 1 |
| Status | published |
| Channels | public/standards |
The content-hash on the first line enables incremental aggregation — unchanged
releases are skipped. The mn-release-metadata JSON block (inside an HTML comment)
is parsed by actions-mn/aggregate for channel filtering and indexing.
Force-replacing releases
Published releases are immutable by default. To selectively re-release a
specific document (e.g. to fix bad metadata), use the force-replace input:
- uses: actions-mn/release@v1
with:
force-replace: 'cc-s-51015' # exact doc ID
# or: force-replace: 'cc-s-*' # glob pattern
token: ${{ secrets.GITHUB_TOKEN }}
Only matched documents are deleted and recreated. Other documents in the same repo are completely unaffected.