Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
28 changes: 26 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,18 +64,42 @@ jobs:
- name: Lint
run: make lint

test:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

# Node 20 rather than the runner's default: the hook scripts run under
# whatever Node the user's harness carries, so the floor is the version
# worth testing on. No matrix -- CONTRIBUTING.md has why.
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: "20"

# No pip cache, for the same reason the Verify job gives: the test suite is
# stdlib-only, so there is nothing to install and nothing to key a cache on.
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"

- name: Test
run: make test

# The required status check. Do NOT add a `name:` -- the ruleset matches the
# context by job id, so naming it silently stops the check from matching.
check:
if: always()
# When you add jobs above, add them to BOTH the needs list and the results
# array below.
needs: [verify, lint]
needs: [verify, lint, test]
runs-on: ubuntu-24.04
timeout-minutes: 2
steps:
- run: |
results=("${{ needs.verify.result }}" "${{ needs.lint.result }}")
results=("${{ needs.verify.result }}" "${{ needs.lint.result }}" "${{ needs.test.result }}")
for r in "${results[@]}"; do
if [[ "$r" != "success" && "$r" != "skipped" ]]; then
echo "Check failed: $r"
Expand Down
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,11 @@ done, confirm:
```bash
make verify
make lint
make test
```

`make test` joins these two once the suite lands -- it is specified in
`CONTRIBUTING.md` and arrives with its first tests, not ahead of them.
`CONTRIBUTING.md` has what `make test` covers, what it deliberately does not,
and where a new test goes.

CI runs the same checks. `AGENTS.md` is a symlink to this file, not a second
source of truth -- edit `CLAUDE.md`.
Expand Down
6 changes: 4 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ error.
```bash
make lint
make verify
make test
```

Both must pass -- CI runs the same checks. `make help` lists what each target
covers. `make test` joins them once the suite lands; see [Tests](#tests).
All three must pass -- CI runs the same checks. `make help` lists what each
target covers, and [Tests](#tests) has what the suite covers, what it
deliberately does not, and where a new test goes.

## Tests

Expand Down
20 changes: 19 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# CI calls these targets directly, so this file is the single definition of the
# checks. Recipes run under dash both here and on the runners -- no bashisms.

.PHONY: help install lint verify
.PHONY: help install lint verify test

help: ## Show available targets
@grep -E '^[a-zA-Z_-]+:.*?## ' $(MAKEFILE_LIST) | awk 'BEGIN{FS=":.*?## "}{printf " %-12s %s\n", $$1, $$2}'
Expand Down Expand Up @@ -29,3 +29,21 @@ verify: ## Run the correctness gate (ASCII, JSON parses, Codex drift)
@python3 -c "import json,subprocess; files=subprocess.run(['git','ls-files','*.json'],capture_output=True,text=True,check=True).stdout.split(); assert files, 'git ls-files matched no JSON -- gate would pass having checked nothing'; [json.load(open(f)) for f in files]"
@echo "Checking generated Codex files against their sources..."
@python3 scripts/generate-codex.py --check

# Each half hands its runner an explicit file list from `git ls-files`, and
# asserts the list is non-empty for the same reason the JSON check above does:
# `git ls-files` exits 0 on no match and `node --test` with no arguments walks
# the whole tree instead of failing, so an unguarded list is a silent pass.
# Why a list rather than a directory or a glob: see CONTRIBUTING.md.
#
# Node runs first, and Make stops at the first failing line, so a Node failure
# hides the Python result -- the same trade `verify` makes above.
test: ## Run the unit tests and hook process contracts (Node, then Python)
@echo "Running the Node tests..."
@files=$$(git ls-files 'tests/*.test.js'); \
if [ -z "$$files" ]; then echo "ERROR: git ls-files matched no Node tests -- gate would pass having checked nothing"; exit 1; fi; \
node --test $$files
@echo "Running the Python tests..."
@files=$$(git ls-files 'tests/test_*.py' 'tests/*/test_*.py'); \
if [ -z "$$files" ]; then echo "ERROR: git ls-files matched no Python tests -- gate would pass having checked nothing"; exit 1; fi; \
python3 -m unittest $$files
2 changes: 1 addition & 1 deletion plugins/praxis/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "praxis",
"version": "1.4.0",
"version": "1.4.1",
"description": "Development workflow -- issue planning, implementation, PR creation, code review with specialized reviewers, and project conventions",
"author": {
"name": "Jartan LLC",
Expand Down
2 changes: 1 addition & 1 deletion plugins/praxis/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "praxis",
"version": "1.4.0",
"version": "1.4.1",
"description": "Development workflow -- issue planning, implementation, PR creation, code review with specialized reviewers, and project conventions",
"interface": {
"displayName": "Praxis",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,6 @@ function main() {
report(dedupePairs(findings));
}

module.exports = { buildSkipMatcher, prose, buildCommentIndex, findRetoldInDiff, dedupePairs };
module.exports = { parseArgs, buildSkipMatcher, prose, trackedPaths, buildCommentIndex, findRetoldInDiff, dedupePairs };

if (require.main === module) main();
Loading