Skip to content

Commit 1c6c20f

Browse files
authored
Merge pull request #122 from acgetchell/ci/111-112-tooling-speedups
ci: modernize tooling checks and example execution
2 parents a4b9f64 + 758321a commit 1c6c20f

11 files changed

Lines changed: 97 additions & 34 deletions

File tree

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ jobs:
7373
- name: Set up Python
7474
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
7575
with:
76-
python-version: "3.12"
76+
python-version-file: ".python-version"
7777

7878
- name: Install uv
7979
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0

.github/workflows/codacy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
- name: Run Codacy Analysis CLI
8484
if: ${{ env.CODACY_PROJECT_TOKEN != '' }}
8585
id: codacy_analysis
86-
uses: codacy/codacy-analysis-cli-action@562ee3e92b8e92df8b67e0a5ff8aa8e261919c08 # pinned
86+
uses: codacy/codacy-analysis-cli-action@562ee3e92b8e92df8b67e0a5ff8aa8e261919c08 # v4.4.7
8787
with:
8888
# Check https://github.com/codacy/codacy-analysis-cli#project-token
8989
# to get your project token from your Codacy repository.

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ When user requests commit message generation:
125125
### Code Quality
126126

127127
- **ALLOWED**: Run formatters/linters: `cargo fmt`, `cargo clippy`, `cargo doc`, `taplo fmt`, `taplo lint`,
128-
`uv run ruff check --fix`, `uv run ruff format`, `shfmt -w`, `shellcheck -x`, `npx markdownlint --fix`,
128+
`uv run ruff check --fix`, `uv run ruff format`, `shfmt -w`, `shellcheck -x`, `rumdl`, `dprint`,
129129
`typos`, `actionlint`
130130
- **NEVER**: Use `sed`, `awk`, `perl` for code edits
131131
- **ALWAYS**: Use `edit_files` tool for edits (and `create_file` for new files)
@@ -205,8 +205,8 @@ macro-ification.
205205
## Common Commands
206206

207207
```bash
208-
just fix # Apply formatters/auto-fixes (mutating)
209208
just check # Lint/validators (non-mutating)
209+
just fix # Apply formatters/auto-fixes (mutating)
210210
just ci # Full CI simulation (checks + tests + examples + bench compile)
211211
just test # Lib + doc tests (fast)
212212
just test-all # All tests (Rust + Python)

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,14 @@ just fix # apply auto-fixes (mutating)
306306
just ci # lint + tests + examples + bench compile
307307
```
308308

309+
The repository uses Rust-native tooling for documentation and config checks:
310+
`rumdl` for Markdown, `dprint` with `pretty_yaml` for YAML, `taplo` for TOML,
311+
and `typos` for spelling. GitHub Actions references are SHA-pinned, restricted
312+
to an explicit allowlist, and kept with readable version comments for review.
313+
314+
CI runs `just ci` on Ubuntu, macOS, and Windows to keep platform coverage
315+
aligned with the local comprehensive validation path.
316+
309317
For coverage commands and report locations, see [`docs/COVERAGE.md`](docs/COVERAGE.md).
310318
For the full set of developer commands, see `just --list` and `AGENTS.md`.
311319

cliff.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ commit_parsers = [
9595
# Dependency bumps: keep all bump commits so archived release history
9696
# preserves CI/action/tooling dependency updates as well as Rust crates.
9797
{ message = "^chore\\(deps\\): bump ", group = "Dependencies" },
98-
{ message = "(?i)^bump ", group = "Dependencies" },
98+
{ message = "(?i)^bump\\s+(deps?\\b|dependencies\\b|[A-Za-z0-9_.-]+/[A-Za-z0-9_./-]+|[A-Za-z0-9_.-]+\\s+from\\s+)", group = "Dependencies" },
9999

100100
# Conventional commit types
101101
{ message = "^feat", group = "Added" },

justfile

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ _ensure-cargo-llvm-cov:
2727
set -euo pipefail
2828
installed_version=""
2929
if command -v cargo-llvm-cov >/dev/null; then
30-
installed_version="$(cargo llvm-cov --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
30+
installed_version="$(cargo llvm-cov --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
3131
fi
3232
if [[ "$installed_version" != "{{cargo_llvm_cov_version}}" ]]; then
3333
echo "❌ 'cargo-llvm-cov' {{cargo_llvm_cov_version}} not found. Install with:"
@@ -40,7 +40,7 @@ _ensure-cargo-nextest:
4040
set -euo pipefail
4141
installed_version=""
4242
if cargo nextest --version >/dev/null 2>&1; then
43-
installed_version="$(cargo nextest --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
43+
installed_version="$(cargo nextest --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
4444
fi
4545
if [[ "$installed_version" != "{{cargo_nextest_version}}" ]]; then
4646
echo "❌ 'cargo-nextest' {{cargo_nextest_version}} not found. Install with:"
@@ -53,7 +53,7 @@ _ensure-dprint:
5353
set -euo pipefail
5454
installed_version=""
5555
if command -v dprint >/dev/null; then
56-
installed_version="$(dprint --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
56+
installed_version="$(dprint --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
5757
fi
5858
if [[ "$installed_version" != "{{dprint_version}}" ]]; then
5959
echo "❌ 'dprint' {{dprint_version}} not found. Install with:"
@@ -66,7 +66,7 @@ _ensure-git-cliff:
6666
set -euo pipefail
6767
installed_version=""
6868
if command -v git-cliff >/dev/null; then
69-
installed_version="$(git-cliff --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
69+
installed_version="$(git-cliff --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
7070
fi
7171
if [[ "$installed_version" != "{{git_cliff_version}}" ]]; then
7272
echo "❌ 'git-cliff' {{git_cliff_version}} not found. Install with:"
@@ -84,7 +84,7 @@ _ensure-rumdl:
8484
set -euo pipefail
8585
installed_version=""
8686
if command -v rumdl >/dev/null; then
87-
installed_version="$(rumdl --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
87+
installed_version="$(rumdl --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
8888
fi
8989
if [[ "$installed_version" != "{{rumdl_version}}" ]]; then
9090
echo "❌ 'rumdl' {{rumdl_version}} not found. Install with:"
@@ -107,7 +107,7 @@ _ensure-taplo:
107107
set -euo pipefail
108108
installed_version=""
109109
if command -v taplo >/dev/null; then
110-
installed_version="$(taplo --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
110+
installed_version="$(taplo --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
111111
fi
112112
if [[ "$installed_version" != "{{taplo_version}}" ]]; then
113113
echo "❌ 'taplo' {{taplo_version}} not found. Install with:"
@@ -121,7 +121,7 @@ _ensure-typos:
121121
set -euo pipefail
122122
installed_version=""
123123
if command -v typos >/dev/null; then
124-
installed_version="$(typos --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
124+
installed_version="$(typos --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
125125
fi
126126
if [[ "$installed_version" != "{{typos_version}}" ]]; then
127127
echo "❌ 'typos' {{typos_version}} not found. Install with:"
@@ -139,7 +139,7 @@ _ensure-zizmor:
139139
set -euo pipefail
140140
installed_version=""
141141
if command -v zizmor >/dev/null; then
142-
installed_version="$(zizmor --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)"
142+
installed_version="$(zizmor --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
143143
fi
144144
if [[ "$installed_version" != "{{zizmor_version}}" ]]; then
145145
echo "❌ 'zizmor' {{zizmor_version}} not found. Install with:"
@@ -318,13 +318,20 @@ doc-check:
318318

319319
# Examples
320320
examples:
321-
cargo run --quiet --example det_5x5
322-
cargo run --quiet --example solve_5x5
323-
cargo run --quiet --example ldlt_solve_3x3
324-
cargo run --quiet --example const_det_4x4
325-
cargo run --quiet --features exact --example exact_det_3x3
326-
cargo run --quiet --features exact --example exact_sign_3x3
327-
cargo run --quiet --features exact --example exact_solve_3x3
321+
#!/usr/bin/env bash
322+
set -euo pipefail
323+
cargo build --examples
324+
cargo build --features exact --examples
325+
326+
exe_suffix=""
327+
if [[ "${OS:-}" == "Windows_NT" ]]; then
328+
exe_suffix=".exe"
329+
fi
330+
331+
for example in det_5x5 solve_5x5 ldlt_solve_3x3 const_det_4x4 exact_det_3x3 exact_sign_3x3 exact_solve_3x3; do
332+
"target/debug/examples/${example}${exe_suffix}"
333+
done
334+
328335
329336
# Fix (mutating): apply formatters/auto-fixes
330337
fix: toml-fmt fmt python-fix shell-fmt markdown-fix yaml-fix
@@ -492,35 +499,35 @@ setup-tools:
492499
493500
echo "Ensuring cargo tools..."
494501
cargo_llvm_cov_version="{{cargo_llvm_cov_version}}"
495-
if ! have cargo-llvm-cov || [[ "$(cargo llvm-cov --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$cargo_llvm_cov_version" ]]; then
502+
if ! have cargo-llvm-cov || [[ "$(cargo llvm-cov --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$cargo_llvm_cov_version" ]]; then
496503
cargo install --locked cargo-llvm-cov --version "$cargo_llvm_cov_version"
497504
fi
498505
cargo_nextest_version="{{cargo_nextest_version}}"
499-
if ! cargo nextest --version >/dev/null 2>&1 || [[ "$(cargo nextest --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$cargo_nextest_version" ]]; then
506+
if ! cargo nextest --version >/dev/null 2>&1 || [[ "$(cargo nextest --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$cargo_nextest_version" ]]; then
500507
cargo install --locked cargo-nextest --version "$cargo_nextest_version"
501508
fi
502509
dprint_version="{{dprint_version}}"
503-
if ! have dprint || [[ "$(dprint --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$dprint_version" ]]; then
510+
if ! have dprint || [[ "$(dprint --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$dprint_version" ]]; then
504511
cargo install --locked dprint --version "$dprint_version"
505512
fi
506513
git_cliff_version="{{git_cliff_version}}"
507-
if ! have git-cliff || [[ "$(git-cliff --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$git_cliff_version" ]]; then
514+
if ! have git-cliff || [[ "$(git-cliff --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$git_cliff_version" ]]; then
508515
cargo install --locked git-cliff --version "$git_cliff_version"
509516
fi
510517
rumdl_version="{{rumdl_version}}"
511-
if ! have rumdl || [[ "$(rumdl --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$rumdl_version" ]]; then
518+
if ! have rumdl || [[ "$(rumdl --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$rumdl_version" ]]; then
512519
cargo install --locked rumdl --version "$rumdl_version"
513520
fi
514521
taplo_version="{{taplo_version}}"
515-
if ! have taplo || [[ "$(taplo --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$taplo_version" ]]; then
522+
if ! have taplo || [[ "$(taplo --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$taplo_version" ]]; then
516523
cargo install --locked taplo-cli --version "$taplo_version"
517524
fi
518525
typos_version="{{typos_version}}"
519-
if ! have typos || [[ "$(typos --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$typos_version" ]]; then
526+
if ! have typos || [[ "$(typos --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$typos_version" ]]; then
520527
cargo install --locked typos-cli --version "$typos_version"
521528
fi
522529
zizmor_version="{{zizmor_version}}"
523-
if ! have zizmor || [[ "$(zizmor --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)" != "$zizmor_version" ]]; then
530+
if ! have zizmor || [[ "$(zizmor --version 2>/dev/null | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)" != "$zizmor_version" ]]; then
524531
cargo install --locked zizmor --version "$zizmor_version"
525532
fi
526533
echo ""
@@ -535,6 +542,11 @@ setup-tools:
535542
exit 1
536543
fi
537544
545+
if ! have jq; then
546+
echo "❌ 'jq' not found. See 'just setup' or install: brew install jq"
547+
echo ""
548+
fi
549+
538550
echo ""
539551
echo "Verifying required commands are available..."
540552
missing=0
@@ -599,6 +611,8 @@ shell-fmt: _ensure-shfmt
599611
600612
shell-lint: shell-check
601613

614+
shell-fix: shell-fmt
615+
602616
# Spell check (typos)
603617
spell-check: _ensure-typos
604618
#!/usr/bin/env bash
@@ -707,6 +721,10 @@ toml-lint: _ensure-taplo
707721
echo "No TOML files found to lint."
708722
fi
709723
724+
toml-check: toml-fmt-check toml-lint
725+
726+
toml-fix: toml-fmt
727+
710728
# File validation
711729
validate-json: _ensure-jq
712730
#!/usr/bin/env bash

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ package = true
141141
dev = [
142142
"actionlint-py==1.7.12.24",
143143
"mypy>=1.19.0",
144-
"pytest>=9.0.3",
144+
"pytest==9.0.3",
145145
"ruff>=0.15.14",
146146
"semgrep==1.164.0",
147147
"ty>=0.0.40",

scripts/tag_release.py

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#!/usr/bin/env python3
1+
#!/usr/bin/env -S uv run
22
"""Create annotated git tags from CHANGELOG.md sections.
33
44
Handles GitHub's 125KB tag-annotation size limit by falling back to a short

scripts/tests/test_subprocess_utils.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,29 @@ def test_run_safe_command_uses_safe_executable(self, mock_run: MagicMock, _mock_
131131
args, _kwargs = mock_run.call_args
132132
assert args[0] == ["/usr/bin/gnuplot", "--version"]
133133

134-
def test_git_convenience_helpers(self) -> None:
135-
assert get_git_commit_hash()
136-
assert get_git_remote_url()
134+
@patch("subprocess_utils.run_git_command")
135+
def test_git_convenience_helpers(self, mock_run_git: MagicMock) -> None:
136+
def fake_run_git(args: list[str], **_kwargs: object) -> subprocess_utils.subprocess.CompletedProcess[str]:
137+
stdout_by_args = {
138+
("rev-parse", "HEAD"): "abc123def456\n",
139+
("remote", "get-url", "origin"): "https://github.com/example/repo.git\n",
140+
("rev-parse", "--git-dir"): ".git\n",
141+
("log", "--oneline", "-n", "1"): "abc123d message\n",
142+
}
143+
return subprocess_utils.subprocess.CompletedProcess(args=["git", *args], returncode=0, stdout=stdout_by_args[tuple(args)])
144+
145+
mock_run_git.side_effect = fake_run_git
146+
147+
assert get_git_commit_hash() == "abc123def456"
148+
assert get_git_remote_url() == "https://github.com/example/repo.git"
137149
assert check_git_repo() is True
138150
assert check_git_history() is True
151+
assert [call_args.args[0] for call_args in mock_run_git.call_args_list] == [
152+
["rev-parse", "HEAD"],
153+
["remote", "get-url", "origin"],
154+
["rev-parse", "--git-dir"],
155+
["log", "--oneline", "-n", "1"],
156+
]
139157

140158
def test_find_project_root(self) -> None:
141159
assert (find_project_root() / "Cargo.toml").is_file()

semgrep.yaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,22 @@ rules:
115115
- "/.github/workflows/**/*.yaml"
116116
patterns:
117117
- pattern-regex: '(?m)^\s*uses:\s*(?!\./)(?!docker://)[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+(?:/[A-Za-z0-9_.-]+)?@[a-fA-F0-9]{40}\s*$'
118+
119+
- id: la-stack.docs.check-before-fix-command-order
120+
languages:
121+
- regex
122+
severity: WARNING
123+
message: "Document non-mutating just check commands before mutating just fix commands."
124+
metadata:
125+
category: maintainability
126+
rationale: "User-facing workflow docs should encourage validation before mutation."
127+
paths:
128+
include:
129+
- "/AGENTS.md"
130+
- "/README.md"
131+
- "/docs/**/*.md"
132+
- "/justfile"
133+
exclude:
134+
- "/docs/archive/**"
135+
patterns:
136+
- pattern-regex: '(?ms)\bjust\s+fix\b.{0,400}\bjust\s+check\b|\bjust\s+python-fix\b.{0,400}\bjust\s+python-check\b'

0 commit comments

Comments
 (0)