Files
Dario LipicarandClaude Opus 5 a91569992d ci: use logos-co/setup-nix-cache-action for Nix setup and caching (#18)
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>
2026-08-18 23:48:40 -03:00

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 });
}