Skip to content
Draft
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
27 changes: 11 additions & 16 deletions .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,8 @@ jobs:
}
- name: Show sccache statistics
if: always()
run: |
sccache --show-stats | tee sccache-stats.txt
sccache --show-stats --stats-format=json > sccache-stats.json
{
printf '### sccache\n\n```text\n'
cat sccache-stats.txt
printf '```\n'
} >> "$GITHUB_STEP_SUMMARY"
# Text and JSON files plus a step-summary section, from one script.
run: uv run --script scripts/ci/report_sccache_stats.py
- name: Save gate caches
# The action restricts each save to a push on `main` that missed the
# key, so a pull request never publishes a competing generation.
Expand Down Expand Up @@ -264,6 +258,13 @@ jobs:
toolchain: ${{ env.NETSUKE_RUST_TOOLCHAIN }}
mode: restore
profile: gate
- name: Setup uv
# The sccache report is a scripts/ci helper run through
# `uv run --script`; uv's own cache is not part of this lane's keys.
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990
with:
python-version: '3.14'
enable-cache: 'false'
- name: Install GNU Make
shell: pwsh
run: |
Expand Down Expand Up @@ -342,14 +343,8 @@ jobs:
}
- name: Show sccache statistics
if: always()
run: |
sccache --show-stats | tee sccache-stats.txt
sccache --show-stats --stats-format=json > sccache-stats.json
{
printf '### sccache\n\n```text\n'
cat sccache-stats.txt
printf '```\n'
} >> "$GITHUB_STEP_SUMMARY"
# Text and JSON files plus a step-summary section, from one script.
run: uv run --script scripts/ci/report_sccache_stats.py
- name: Save gate caches
# The action restricts each save to a push on `main` that missed the
# key, so a pull request never publishes a competing generation.
Expand Down
147 changes: 38 additions & 109 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,20 @@ jobs:
with:
mode: restore
sccache-local: ${{ vars.NETSUKE_SCCACHE_LOCAL_DIR }}
- name: Setup uv
# First, because the CI helper scripts under scripts/ci run through
# `uv run --script` from the next step on, and the uv-driven Ruff,
# Pylint, and df12 gates need it before Format.
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990
with:
python-version: ${{ env.PYTHON_BASELINE }}
# The gate cache already owns the uv download and tool stores, and
# the shim directory the yamllint step writes into.
enable-cache: 'false'
- name: Install test shell dependencies
run: |
sudo apt-get update
sudo apt-get install --yes --no-install-recommends gawk
# Ubuntu exposes awk through an alternatives symlink the sandbox
# probe cannot follow, so expose the packaged binary on PATH.
test_shell_bin="${RUNNER_TEMP}/netsuke-test-bin"
mkdir --parents "${test_shell_bin}"
install --mode=0755 "$(command -v gawk)" "${test_shell_bin}/awk"
echo "${test_shell_bin}" >> "${GITHUB_PATH}"
export PATH="${test_shell_bin}:${PATH}"

command -v awk
awk --version
# Installs gawk and stages a regular-file `awk` the sandbox probe can
# follow; see the script's docstring and scripts/tests/test_ci_stage_test_shell.py.
run: uv run --script scripts/ci/stage_test_shell.py
- name: Install sccache
uses: taiki-e/install-action@18b1216eba7f8039b0f8d131d5473787f0edce68 # v2.85.3
with:
Expand Down Expand Up @@ -144,65 +144,28 @@ jobs:
# The gate cache owns `~/.local/bin`, so a warm run finds it present.
with:
version: ${{ env.MDTABLEFIX_VERSION }}
- name: Setup uv
# Before Format: the uv-driven Ruff, Pylint, and df12 gates need it.
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990
with:
python-version: ${{ env.PYTHON_BASELINE }}
# The gate cache already owns the uv download and tool stores, and
# the shim directory the next step writes into.
enable-cache: 'false'
- name: Install yamllint
run: |
uv tool install "yamllint==${YAMLLINT_VERSION}"
echo "${UV_TOOL_BIN_DIR}" >> "$GITHUB_PATH"
- name: Download actionlint
id: get_actionlint
# The gate cache owns `actionlint`; reuse it only at the pinned
# version, so a bump cannot reuse a stale executable.
run: |
set -euo pipefail
readonly ACTIONLINT_VERSION='1.7.12'
if [[ -x ./actionlint ]] \
&& [[ "$(./actionlint --version | head --lines=1)" == "${ACTIONLINT_VERSION}" ]]; then
echo "actionlint ${ACTIONLINT_VERSION} restored from the cache volume"
exit 0
fi
readonly ACTIONLINT_SHA256='8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8'
readonly ACTIONLINT_INSTALLER_COMMIT='914e7df21a07ef503a81201c76d2b11c789d3fca'
readonly ACTIONLINT_ARCHIVE="actionlint_${ACTIONLINT_VERSION}_linux_amd64.tar.gz"
readonly ACTIONLINT_RAW_BASE='https://raw.githubusercontent.com/rhysd/actionlint'
readonly ACTIONLINT_SCRIPT='scripts/download-actionlint.bash'
readonly ACTIONLINT_INSTALLER_URL="${ACTIONLINT_RAW_BASE}/${ACTIONLINT_INSTALLER_COMMIT}/${ACTIONLINT_SCRIPT}"
readonly ACTIONLINT_RELEASE_ROOT='https://github.com/rhysd/actionlint/releases/download'
readonly ACTIONLINT_RELEASE_BASE="${ACTIONLINT_RELEASE_ROOT}/v${ACTIONLINT_VERSION}"
readonly ACTIONLINT_RELEASE_URL="${ACTIONLINT_RELEASE_BASE}/${ACTIONLINT_ARCHIVE}"
ACTIONLINT_INSTALLER_PATH="$(mktemp)"
ACTIONLINT_ARCHIVE_PATH="$(mktemp)"
trap 'rm -f "${ACTIONLINT_INSTALLER_PATH}" "${ACTIONLINT_ARCHIVE_PATH}"' EXIT
# Feed the verified archive to reviewed installer without second download.
curl() {
if [[ "${*: -1}" == "${ACTIONLINT_RELEASE_URL}" ]]; then
cat "${ACTIONLINT_ARCHIVE_PATH}"
else
command curl "$@"
fi
}
export -f curl
command curl --fail --location --show-error --output "${ACTIONLINT_INSTALLER_PATH}" \
"${ACTIONLINT_INSTALLER_URL}"
command curl --fail --location --show-error --output "${ACTIONLINT_ARCHIVE_PATH}" \
"${ACTIONLINT_RELEASE_URL}"
printf '%s %s\n' "${ACTIONLINT_SHA256}" "${ACTIONLINT_ARCHIVE_PATH}" | sha256sum --check --
bash "${ACTIONLINT_INSTALLER_PATH}" "${ACTIONLINT_VERSION}"
shell: bash
# The gate cache owns `actionlint`; the script reuses it only at the
# pinned version, so a bump cannot reuse a stale executable, and
# otherwise installs the checksum-verified release archive.
env:
INPUT_ACTIONLINT_VERSION: '1.7.12'
INPUT_ACTIONLINT_SHA256: 8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc387b349a3d8
run: uv run --script scripts/ci/install_actionlint.py
- name: Install Nixie
uses: >-
leynos/shared-actions/.github/actions/install-nixie@e041cb75c35c3524201a32d5e57c87408fbd5874
with:
python-version: '3.14'
- name: Markdown formatter checker tests
run: make test-markdown-format
- name: CI helper script tests
run: make test-ci-scripts
- name: Format
run: make check-fmt
- name: Install Whitaker
Expand Down Expand Up @@ -262,22 +225,13 @@ jobs:
if-no-files-found: error
- name: Show sccache statistics
if: always()
run: |
sccache --show-stats | tee sccache-stats.txt
sccache --show-stats --stats-format=json > sccache-stats.json
{
printf '### sccache\n\n```text\n'
cat sccache-stats.txt
printf '```\n'
} >> "$GITHUB_STEP_SUMMARY"
# Text and JSON files plus a step-summary section, from one script.
run: uv run --script scripts/ci/report_sccache_stats.py
- name: Discard the instrumented build tree
# No consumer once the report exists, and the second tree on a volume
# a sibling repository exhausted. Removed before any cache save.
if: always()
run: |
df -h .
rm --recursive --force target/llvm-cov-target target/llvm-cov
df -h .
run: uv run --script scripts/ci/discard_instrumented_tree.py
- name: Report peak resource use
if: always()
uses: ./.github/actions/memory-sampler
Expand Down Expand Up @@ -336,6 +290,13 @@ jobs:
with:
mode: restore
runner-image: ${{ env.NETSUKE_RUNNER_IMAGE }}
- name: Setup uv
# The installer below is a scripts/ci helper run through
# `uv run --script`; uv's own cache is not part of the Kani key.
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990
with:
python-version: ${{ env.PYTHON_BASELINE }}
enable-cache: 'false'
- name: Setup Rust
uses: leynos/shared-actions/.github/actions/setup-rust@e041cb75c35c3524201a32d5e57c87408fbd5874
with:
Expand All @@ -348,44 +309,12 @@ jobs:
- name: Install prebuilt Kani
# Two payloads from pinned checksummed archives under
# version-qualified directories, so a bump cannot reuse a stale one.
run: |
set -euo pipefail
kani_version="$(tr -d '\r\n' < tools/kani/VERSION)"
test "${kani_version}" = '0.67.0'
frontend_bin="${CARGO_HOME}/frontend/kani-${kani_version}"
kani_dir="${KANI_HOME}/kani-${kani_version}"
mkdir --parents "${frontend_bin}" "${KANI_HOME}" "${RUSTUP_HOME}"
export PATH="${frontend_bin}:${PATH}"
echo "${frontend_bin}" >> "$GITHUB_PATH"

target='x86_64-unknown-linux-gnu'
quickinstall='https://github.com/cargo-bins/cargo-quickinstall'
upstream='https://github.com/model-checking/kani'

if [[ ! -x "${frontend_bin}/cargo-kani" || ! -x "${frontend_bin}/kani" ]]; then
frontend_name="kani-verifier-${kani_version}-${target}.tar.gz"
frontend_archive="${RUNNER_TEMP}/${frontend_name}"
curl --fail --location --proto '=https' --tlsv1.2 \
"${quickinstall}/releases/download/kani-verifier-${kani_version}/${frontend_name}" \
--output "${frontend_archive}"
printf '%s %s\n' \
'ed2bafc239b834e14c6b66fc4838e342e3bc0b814e548e72ea30e84f83dc0974' \
"${frontend_archive}" | sha256sum --check --
tar --extract --gzip --file "${frontend_archive}" \
--directory "${frontend_bin}" cargo-kani kani
fi

if [[ ! -x "${kani_dir}/bin/kani-driver" ]]; then
bundle_name="kani-${kani_version}-${target}.tar.gz"
bundle="${RUNNER_TEMP}/${bundle_name}"
curl --fail --location --proto '=https' --tlsv1.2 \
"${upstream}/releases/download/kani-${kani_version}/${bundle_name}" \
--output "${bundle}"
printf '%s %s\n' \
'3b5f7afd3b51603ee720db7bc1bc4fe46b5a4f5d36daad9939c4b4c658b51ac0' \
"${bundle}" | sha256sum --check --
cargo kani setup --use-local-bundle "${bundle}"
fi
# The version must equal tools/kani/VERSION, which the cache key reads.
env:
INPUT_KANI_VERSION: '0.67.0'
INPUT_FRONTEND_SHA256: ed2bafc239b834e14c6b66fc4838e342e3bc0b814e548e72ea30e84f83dc0974
INPUT_BUNDLE_SHA256: 3b5f7afd3b51603ee720db7bc1bc4fe46b5a4f5d36daad9939c4b4c658b51ac0
run: uv run --script scripts/ci/install_kani.py
- name: Kani version check
run: cargo kani --version | grep --fixed-strings "0.67.0"
- name: Run Kani harnesses
Expand Down
22 changes: 10 additions & 12 deletions .github/workflows/coverage-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,13 @@ jobs:
# Before the installer, so before anything can start the server: a
# server started without these stays on local disk all job.
uses: ./.github/actions/sccache-gha-credentials
- name: Setup uv
# The sccache report is a scripts/ci helper run through
# `uv run --script`; uv's own cache is not part of this lane's keys.
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990
with:
python-version: '3.14'
enable-cache: 'false'
- name: Start resource sampler
uses: ./.github/actions/memory-sampler
with:
Expand Down Expand Up @@ -218,25 +225,16 @@ jobs:
# reached the compiler cache, which is a failed integration rather
# than a quiet no-op.
if: always()
run: |
sccache --show-stats | tee sccache-stats.txt
sccache --show-stats --stats-format=json > sccache-stats.json
{
printf '### sccache\n\n```text\n'
cat sccache-stats.txt
printf '```\n'
} | tee -a "$GITHUB_STEP_SUMMARY"
# Text and JSON files plus a step-summary section, from one script.
run: uv run --script scripts/ci/report_sccache_stats.py
- name: Discard the instrumented build tree
# `llvm-cov`'s target tree has no consumer once the report is written,
# and it is the second tree on a volume that a sibling repository
# exhausted on the smaller shape. Removed before any cache save, so
# the archive never carries it and the sampler's least-free figure
# reflects the job's real high-water mark.
if: always()
run: |
df -h .
rm --recursive --force target/llvm-cov-target target/llvm-cov
df -h .
run: uv run --script scripts/ci/discard_instrumented_tree.py
- name: Report peak resource use
if: always()
uses: ./.github/actions/memory-sampler
Expand Down
17 changes: 9 additions & 8 deletions .github/workflows/netsukefile-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ jobs:
# Before the installer, so before anything can start the server: a
# server started without these stays on local disk all job.
uses: ./.github/actions/sccache-gha-credentials
- name: Setup uv
# The sccache report is a scripts/ci helper run through
# `uv run --script`; uv's own cache is not part of this lane's keys.
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990
with:
python-version: '3.14'
enable-cache: 'false'
- name: Render cache keys
# This lane owns its own key family: nothing else in the repository
# runs on Ubuntu 22.04, so a 24.04 archive must never reach it. The
Expand Down Expand Up @@ -187,14 +194,8 @@ jobs:
run: scripts/assert-file-absent.sh unused.txt
- name: Show sccache statistics
if: always()
run: |
sccache --show-stats | tee sccache-stats.txt
sccache --show-stats --stats-format=json > sccache-stats.json
{
printf '### sccache\n\n```text\n'
cat sccache-stats.txt
printf '```\n'
} | tee -a "$GITHUB_STEP_SUMMARY"
# Text and JSON files plus a step-summary section, from one script.
run: uv run --script scripts/ci/report_sccache_stats.py
# This job is the only writer of the Ubuntu 22.04 key family, and only
# on the trunk, so a pull request never publishes a competing archive.
- name: Save Cargo download store
Expand Down
20 changes: 18 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: help all clean test test-nextest doctest test-workflow-contracts test-release-admission test-coverage-artifact test-markdown-format test-typos-config build release lint lint-clippy lint-whitaker lint-python github-actions-lint doc-coverage doc-coverage-test validate-coverage-artifact fmt check-fmt typecheck typecheck-python markdownlint spelling spelling-config spelling-helper-test nixie install-kani kani-check kani-full kani-ir install-verus verus formal-pr install-dev-fast dev-fast-check dev-build dev-test bench-build bench-config-load bench-glob-expansion
.PHONY: help all clean test test-nextest doctest test-workflow-contracts test-release-admission test-coverage-artifact test-markdown-format test-ci-scripts test-typos-config build release lint lint-clippy lint-whitaker lint-python github-actions-lint doc-coverage doc-coverage-test validate-coverage-artifact fmt check-fmt typecheck typecheck-python markdownlint spelling spelling-config spelling-helper-test nixie install-kani kani-check kani-full kani-ir install-verus verus formal-pr install-dev-fast dev-fast-check dev-build dev-test bench-build bench-config-load bench-glob-expansion

RUST_TOOLCHAIN_FILE ?= rust-toolchain.toml
# Export this path before shell probes expand it, so Make does not interpolate
Expand Down Expand Up @@ -86,6 +86,15 @@ RUFF = $(UV_ENV) $(UV) tool run --from ruff==$(RUFF_VERSION) ruff
# typecheck gate without any code change. Bump deliberately and fix new
# diagnostics in the same commit.
TY_VERSION ?= 0.0.74
# The CI helper scripts under scripts/ci declare these in their PEP 723
# blocks; scripts/tests/test_ci_scripts_metadata.py holds the two in step, so
# `uv run --script` in CI and the test and typecheck gates resolve one release.
# cuprum is pinned to a leynos/cuprum commit until 0.2.0 ships the
# `RunOutputOptions` runtime the scripts use.
CYCLOPTS_VERSION ?= 4.25.2
CUPRUM_REF ?= a2134c7a3966b224eaed917efb94f8090ce5104a
CUPRUM_SOURCE = cuprum @ git+https://github.com/leynos/cuprum@$(CUPRUM_REF)
CI_SCRIPT_DEPS = --with cyclopts==$(CYCLOPTS_VERSION) --with '$(CUPRUM_SOURCE)'
# Every Python source the repository owns. Ruff and Pylint resolve their own
# configuration and exclusions from pyproject.toml, so these paths only bound
# the walk.
Expand Down Expand Up @@ -183,6 +192,12 @@ test-markdown-format: ## Validate the Markdown formatter checker
python -m pytest scripts/tests/test_check_markdown_format.py -c /dev/null \
--rootdir=. -p no:cacheprovider

test-ci-scripts: ## Test the CI helper scripts under scripts/ci with pytest and cmd-mox
@PYTHONPATH=scripts/ci:scripts $(UV_ENV) $(UV) run --no-project --python $(PYTHON_BASELINE) \
--with pytest==9.0.2 --with cmd-mox==0.2.0 $(CI_SCRIPT_DEPS) \
python -m pytest -p cmd_mox.pytest_plugin scripts/tests/test_ci_*.py \
-c /dev/null --rootdir=. -p no:cacheprovider

test-typos-config: spelling-helper-test ## Verify the shared spelling-policy integration

target/%/$(APP): ## Build binary in debug or release mode
Expand Down Expand Up @@ -257,8 +272,9 @@ typecheck-python: ## Typecheck the Python sources with ty
$(UV_ENV) $(UV) tool run --python $(PYTHON_BASELINE) \
--from ty==$(TY_VERSION) --with pytest==9.0.2 --with pytest-cov==7.0.0 \
--with 'pyyaml>=6' --with 'hypothesis>=6' --with 'cmd-mox==0.2.0' \
$(CI_SCRIPT_DEPS) \
ty check --python-version $(PYTHON_BASELINE) \
--extra-search-path scripts $(PYTHON_SOURCES)
--extra-search-path scripts/ci --extra-search-path scripts $(PYTHON_SOURCES)

markdownlint: spelling ## Lint Markdown and enforce en-GB-oxendict spelling
@unset FORCE_COLOR; $(MDLINT) "**/*.md"
Expand Down
Loading
Loading