mirror of
https://github.com/logos-co/logos-dev-boost.git
synced 2026-08-27 16:11:11 +00:00
Replaces the per-repo installer + cachix pair with the shared action, which
installs Nix with the Logos Attic cache (cache.nix.logos.co) preconfigured and
publishes what the job builds — master to the public cache, every other ref to
ci.
Each converted job also gains
environment: ${{ github.ref == 'refs/heads/master' && 'public-cache' || '' }}
because ATTIC_TOKEN_PUBLIC only exists inside that environment. Without it the
secret resolves empty on master and publishing is silently skipped — the job
still passes, so the omission would not show up as a failure.
The action installs Nix itself on every runner, macOS included. That is a
deliberate reversal of the workaround these files carried: the comments here
said cachix/install-nix-action collides with the runner's pre-existing _nixbld
users (eDSRecordAlreadyExists), so DeterminateSystems' installer was used
instead. It no longer reproduces — logos-delivery-module has already been
converted the plain way and its `build-and-test (macos-latest)` leg passes.
Keeping the workaround would have meant a second installer plus a duplicated
substituter/key block in ten files, guarding against something two green runs
say does not happen. If it ever recurs it fails loudly at install, which is
recoverable; the silent-skip above is the failure mode worth engineering
against.
One property is deliberately NOT carried over: the old cachix step ran with
`continue-on-error: true` so a failed cache push could not fail a job whose
tests passed. The action exposes no equivalent, and adding one here would also
swallow genuine setup failures now that the same step installs Nix rather than
only publishing at the end.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
288 lines
12 KiB
YAML
288 lines
12 KiB
YAML
name: CI
|
|
|
|
on:
|
|
push:
|
|
branches: [master, main]
|
|
pull_request:
|
|
branches: [master, main]
|
|
|
|
# One-time setup for the clickable doc-test report links (publish-report job):
|
|
# Repo Settings → Pages → "Build and deployment" → Source: "Deploy from a
|
|
# branch", Branch: `gh-pages` / `(root)`. The publish-report job creates the
|
|
# gh-pages branch on its first run; GITHUB_TOKEN already has the permissions
|
|
# granted below. The doc-tests run on both ubuntu-latest and macos-latest, and
|
|
# each run publishes one HTML report per OS to
|
|
# https://<owner>.github.io/<repo>/pr-<N>/<os>/ (PRs) or .../main/<os>/
|
|
# (pushes), with a landing page at .../pr-<N>/ linking to both. It also
|
|
# posts/updates a PR comment with the per-OS links. Fork PRs get a read-only
|
|
# token, so for them the Pages push and comment are skipped (the per-OS
|
|
# artifacts are still made).
|
|
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
build:
|
|
# ATTIC_TOKEN_PUBLIC only exists in the public-cache environment; master
|
|
# jobs must opt into it to publish to the public cache.
|
|
environment: ${{ github.ref == 'refs/heads/master' && 'public-cache' || '' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: logos-co/setup-nix-cache-action@v1
|
|
with:
|
|
attic-token-ci: ${{ secrets.ATTIC_TOKEN_CI }}
|
|
attic-token-public: ${{ secrets.ATTIC_TOKEN_PUBLIC }}
|
|
extra-nix-config: |
|
|
experimental-features = nix-command flakes
|
|
|
|
- name: Build logos-dev-boost CLI
|
|
run: nix build -L
|
|
|
|
scaffold-tests:
|
|
# ATTIC_TOKEN_PUBLIC only exists in the public-cache environment; master
|
|
# jobs must opt into it to publish to the public cache.
|
|
environment: ${{ github.ref == 'refs/heads/master' && 'public-cache' || '' }}
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
type:
|
|
- module
|
|
- ui-qml
|
|
- ui-qml-backend
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: logos-co/setup-nix-cache-action@v1
|
|
with:
|
|
attic-token-ci: ${{ secrets.ATTIC_TOKEN_CI }}
|
|
attic-token-public: ${{ secrets.ATTIC_TOKEN_PUBLIC }}
|
|
extra-nix-config: |
|
|
experimental-features = nix-command flakes
|
|
|
|
# git is needed inside the scaffolded project so `nix build` can see
|
|
# the files (flakes only consider git-tracked files).
|
|
- name: Configure git identity for scaffold init
|
|
run: |
|
|
git config --global user.email "ci@logos.test"
|
|
git config --global user.name "Logos CI"
|
|
|
|
- name: Scaffold + build --type ${{ matrix.type }}
|
|
run: ./tests/run-scaffold-tests.sh ${{ matrix.type }}
|
|
|
|
# Runs the executable module-scaffold doc-test
|
|
# (doctests/dev-boost-scaffold-module.test.yaml) end-to-end via the shared
|
|
# doctest CLI: scaffolds a crypto_utils module with THIS commit of dev-boost,
|
|
# builds it, introspects it with lm, runs its unit tests, calls it through
|
|
# logoscore, and asserts on the output.
|
|
doctests:
|
|
# ATTIC_TOKEN_PUBLIC only exists in the public-cache environment; master
|
|
# jobs must opt into it to publish to the public cache.
|
|
environment: ${{ github.ref == 'refs/heads/master' && 'public-cache' || '' }}
|
|
name: dev-boost doc-tests (${{ matrix.os }})
|
|
needs: build
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
os: [ubuntu-latest, macos-latest]
|
|
runs-on: ${{ matrix.os }}
|
|
timeout-minutes: 90
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: logos-co/setup-nix-cache-action@v1
|
|
with:
|
|
attic-token-ci: ${{ secrets.ATTIC_TOKEN_CI }}
|
|
attic-token-public: ${{ secrets.ATTIC_TOKEN_PUBLIC }}
|
|
|
|
# git is needed inside the scaffolded project so `nix build` can see
|
|
# the files (flakes only consider git-tracked files).
|
|
- name: Configure git identity for scaffold init
|
|
run: |
|
|
git config --global user.email "ci@logos.test"
|
|
git config --global user.name "Logos CI"
|
|
|
|
# Resolve the commit under test. For pull requests this is the PR's head
|
|
# commit (not the synthetic merge commit); for pushes it's the pushed
|
|
# commit. Passed to --release-for so the doc-test scaffolds with THIS commit
|
|
# of logos-dev-boost instead of the latest published flake.
|
|
#
|
|
# Fork PRs are the exception: their head commit lives in the fork, not in
|
|
# logos-co/logos-dev-boost, so nix could not fetch
|
|
# `github:logos-co/logos-dev-boost/<sha>`. We blank the SHA for forks
|
|
# (--release-for repo= → pins that repo to latest), so the doc-test still
|
|
# runs for fork PRs, just against master.
|
|
- name: Resolve commit under test
|
|
id: commit
|
|
shell: bash
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "pull_request" ] && \
|
|
[ "${{ github.event.pull_request.head.repo.fork }}" = "true" ]; then
|
|
echo "sha=" >> "$GITHUB_OUTPUT"
|
|
echo "Fork PR detected — doc-test will run against latest master."
|
|
else
|
|
echo "sha=${{ github.event.pull_request.head.sha || github.sha }}" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
|
|
# --release-for pins the {release} placeholder for logos-dev-boost to the
|
|
# commit under test, so `github:logos-co/logos-dev-boost{release}` in the
|
|
# spec becomes `.../<sha>`. Every other repo URL still resolves to latest.
|
|
# --report writes the two-column HTML report (rendered tutorial + the
|
|
# commands actually run and their output) that publish-report deploys.
|
|
# --continue-on-fail so the run walks every step and the report is complete;
|
|
# the job still fails (non-zero exit) if any step failed.
|
|
# All scaffold specs run back-to-back into one combined report (one
|
|
# dropdown entry each): the pure C++ module, the module wrapping an
|
|
# external C library, the pure QML UI app (driven headlessly), and the
|
|
# QML UI app with a process-isolated C++ backend.
|
|
- name: Run module-scaffold doc-tests
|
|
run: |
|
|
nix run github:logos-co/logos-doctest -- run \
|
|
doctests/dev-boost-scaffold-module.test.yaml \
|
|
doctests/dev-boost-scaffold-external-lib.test.yaml \
|
|
doctests/dev-boost-scaffold-ui-qml.test.yaml \
|
|
doctests/dev-boost-scaffold-ui-qml-backend.test.yaml \
|
|
--verbose \
|
|
--continue-on-fail \
|
|
--release-for logos-dev-boost=${{ steps.commit.outputs.sha }} \
|
|
--report "${{ runner.temp }}/dev-boost-doctest-report.html"
|
|
|
|
- name: Stage report for upload
|
|
if: always()
|
|
shell: bash
|
|
run: |
|
|
mkdir -p report-out
|
|
# Name it index.html so the published directory URL renders directly.
|
|
if [ -f "${{ runner.temp }}/dev-boost-doctest-report.html" ]; then
|
|
cp "${{ runner.temp }}/dev-boost-doctest-report.html" report-out/index.html
|
|
else
|
|
echo "<h1>No report produced</h1>" > report-out/index.html
|
|
fi
|
|
|
|
- name: Upload doc-test execution report
|
|
if: always()
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: dev-boost-doctest-report-${{ matrix.os }}
|
|
path: report-out/index.html
|
|
if-no-files-found: warn
|
|
|
|
- name: Verify markdown generation
|
|
run: |
|
|
for spec in dev-boost-scaffold-module dev-boost-scaffold-external-lib dev-boost-scaffold-ui-qml dev-boost-scaffold-ui-qml-backend; do
|
|
nix run github:logos-co/logos-doctest -- generate \
|
|
"doctests/$spec.test.yaml" \
|
|
--release-for logos-dev-boost=${{ steps.commit.outputs.sha }} \
|
|
-o "/tmp/$spec.md"
|
|
test -s "/tmp/$spec.md"
|
|
done
|
|
echo "Generated markdown successfully"
|
|
|
|
publish-report:
|
|
name: Publish doc-test report to GitHub Pages
|
|
needs: doctests
|
|
# Run even when the doc-test fails — a failing run is exactly when you want to
|
|
# open the report. Skip on forks, where GITHUB_TOKEN can't push or comment.
|
|
if: ${{ always() && github.event.pull_request.head.repo.fork != true }}
|
|
runs-on: ubuntu-latest
|
|
|
|
permissions:
|
|
contents: write # push to the gh-pages branch
|
|
pull-requests: write # post/update the PR comment
|
|
|
|
# Serialize Pages pushes so two refs can't race on the gh-pages branch.
|
|
concurrency:
|
|
group: gh-pages-publish
|
|
cancel-in-progress: false
|
|
|
|
steps:
|
|
- name: Download all reports
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: artifacts
|
|
# No `name:` → downloads every artifact into artifacts/<name>/...
|
|
|
|
- name: Arrange site directory
|
|
id: arrange
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
BASE="pr-${{ github.event.pull_request.number }}"
|
|
else
|
|
BASE="main"
|
|
fi
|
|
echo "base=$BASE" >> "$GITHUB_OUTPUT"
|
|
|
|
mkdir -p "site/$BASE"
|
|
found=""
|
|
for os in ubuntu-latest macos-latest; do
|
|
src="artifacts/dev-boost-doctest-report-$os/index.html"
|
|
if [ -f "$src" ]; then
|
|
mkdir -p "site/$BASE/$os"
|
|
cp "$src" "site/$BASE/$os/index.html"
|
|
found="$found $os"
|
|
fi
|
|
done
|
|
echo "found=$found" >> "$GITHUB_OUTPUT"
|
|
|
|
# Landing page for this ref linking to each OS report.
|
|
{
|
|
echo "<!doctype html><meta charset=utf-8>"
|
|
echo "<title>dev-boost doc-test reports — $BASE</title>"
|
|
echo "<style>body{font:16px system-ui;margin:40px;max-width:640px}a{color:#2563eb}</style>"
|
|
echo "<h1>dev-boost doc-test reports</h1>"
|
|
echo "<p><strong>$BASE</strong> · commit <code>${GITHUB_SHA::7}</code></p><ul>"
|
|
for os in ubuntu-latest macos-latest; do
|
|
if [ -d "site/$BASE/$os" ]; then
|
|
echo "<li><a href=\"./$os/\">$os</a></li>"
|
|
fi
|
|
done
|
|
echo "</ul>"
|
|
} > "site/$BASE/index.html"
|
|
|
|
- name: Deploy to gh-pages
|
|
if: steps.arrange.outputs.found != ''
|
|
uses: peaceiris/actions-gh-pages@v4
|
|
with:
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
publish_dir: ./site
|
|
keep_files: true # don't wipe other PRs' directories
|
|
commit_message: "Publish dev-boost doc-test report for ${{ steps.arrange.outputs.base }} (${{ github.sha }})"
|
|
|
|
- name: Comment on PR with report links
|
|
if: ${{ github.event_name == 'pull_request' && steps.arrange.outputs.found != '' }}
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const base = "${{ steps.arrange.outputs.base }}";
|
|
const owner = context.repo.owner;
|
|
const repo = context.repo.repo;
|
|
const root = `https://${owner}.github.io/${repo}/${base}`;
|
|
const oses = "${{ steps.arrange.outputs.found }}".trim().split(/\s+/).filter(Boolean);
|
|
|
|
const links = oses.map(os => `- [\`${os}\` report](${root}/${os}/)`).join("\n");
|
|
const marker = "<!-- dev-boost-doctest-report-links -->";
|
|
const body =
|
|
`${marker}\n` +
|
|
`### 📊 dev-boost doc-test report\n\n` +
|
|
`The \`crypto_utils\` module scaffolded from this commit, built and run ` +
|
|
`end-to-end — rendered alongside the commands actually run and their ` +
|
|
`output (updated each run, commit \`${context.sha.slice(0,7)}\`):\n\n` +
|
|
`${links}\n\n` +
|
|
`_Pages can take a minute to update after the run finishes._`;
|
|
|
|
const { data: comments } = await github.rest.issues.listComments({
|
|
owner, repo, issue_number: context.issue.number, per_page: 100,
|
|
});
|
|
const existing = comments.find(c => c.body && c.body.includes(marker));
|
|
if (existing) {
|
|
await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body });
|
|
} else {
|
|
await github.rest.issues.createComment({ owner, repo, issue_number: context.issue.number, body });
|
|
}
|