Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .bumpy/ci-cd-integration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
mdcode-ts: patch
---

Added a CI/CD Integration section to the README. It puts the docs-sync check, the runnable-snippet check and release gating in one sequence, and shows how to publish only after they pass, either with `prepublishOnly` or with a GitHub Actions publish job that needs a checks job.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ To keep several documents in sync without repeating their paths, list them in `m

To check that snippets actually run, mark them `runnable=true` and copy [`examples/ci/validate-snippets.mjs`](examples/ci/validate-snippets.mjs). It extracts only those blocks into a temporary workspace, runs your test or lint command there, and fails CI naming the block that broke. See [Validating Runnable Snippets in CI](packages/mdcode/README.md#validating-runnable-snippets-in-ci).

To publish only after both checks pass, see [CI/CD Integration](packages/mdcode/README.md#cicd-integration). It shows the three stages in order and how to gate a release on them with `prepublishOnly` or a GitHub Actions publish job.

## Commands

| Command | What it does |
Expand Down
102 changes: 102 additions & 0 deletions packages/mdcode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,108 @@ jobs:

---

## CI/CD Integration

mdcode fits into CI in three stages. Each one stands alone, and each builds on the one before:

1. **Check the docs are in sync.** Fail when a block has drifted from the `file=` it points at. See
[Checking Docs in CI](#checking-docs-in-ci), or [Project Configuration](#locally-and-in-ci) to
list the documents once in `mdcode.config.json`.
2. **Run the runnable snippets.** Fail when a block written in the Markdown and marked
`runnable=true` no longer runs. See [Validating Runnable Snippets in CI](#validating-runnable-snippets-in-ci).
3. **Gate the release on both.** Publish only after your tests and both docs checks pass, as below.

Stages 1 and 2 give you two npm scripts, `docs:check` and `docs:snippets`. Run them on every pull
request so drift fails the change that caused it, then run them again before publishing so nothing
stale reaches npm.

### Gating a Release

When you publish from your own machine, the smallest gate is `prepublishOnly`. `npm publish` runs it
first and stops without publishing if it fails:

```json
{
"scripts": {
"test": "node --test",
"docs:check": "node scripts/check-docs-sync.mjs README.md docs/guide.md",
"docs:snippets": "node scripts/validate-snippets.mjs README.md docs/guide.md -- node {file}",
"prepublishOnly": "npm test && npm run docs:check && npm run docs:snippets"
},
"devDependencies": {
"mdcode-ts": "^0.1.0"
}
}
```

When GitHub Actions publishes, put the checks in their own job and make the publish job need it.
Each check is a named step, so a failed run names the gate that stopped it, and the publish job never
starts. This workflow publishes when you push a `v*` tag, using
[npm trusted publishing](https://docs.npmjs.com/trusted-publishers/), so no npm token is stored:

```yaml
name: Release

on:
push:
tags: ['v*']

permissions:
contents: read

jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- name: 'Gate: tests'
run: npm test
- name: 'Gate: docs in sync'
run: npm run docs:check
- name: 'Gate: runnable snippets'
run: npm run docs:snippets

publish:
needs: checks
runs-on: ubuntu-latest
environment: npm
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
# Trusted publishing needs npm 11.5.1 or later; Node 22 ships npm 10
- run: npm install -g npm@latest
- run: npm ci
- run: npm run build --if-present
# The checks job already passed; skip prepublishOnly so snippets never run here
- run: npm publish --ignore-scripts
```

Before the first run, add a trusted publisher for your package on npmjs.com, naming this repository,
the workflow file and the `npm` environment. To publish with a token instead, store it as a
repository secret, drop `id-token: write`, and pass it to `npm publish` as `NODE_AUTH_TOKEN`.

Only the `publish` job can mint an npm credential. The `checks` job runs the snippets, which is
running code from the Markdown, so it gets a read-only token and no `id-token`. That is why the
`publish` job builds explicitly and publishes with `--ignore-scripts`: a plain `npm publish` would run
a `prepublishOnly` like the one above, executing the snippets again in the job that can mint the
credential. `--ignore-scripts` also skips `prepare` and `prepack`, so run any step they did as its
own step before publishing.

mdcode-ts gates its own releases the same way; see its
[RELEASING.md](https://github.com/adrianbrowning/mdcode-ts/blob/main/RELEASING.md).

---

## CLI Flags Reference

All commands support these common flags:
Expand Down
Loading