diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 8ee9f9e..52cc646 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -17,9 +17,8 @@ - [ ] `uv run pyright` passes - [ ] New tests added for new functionality - [ ] Documentation updated (if applicable) +- [ ] All commits are signed off (DCO) — committed with `git commit -s`. If the `DCO` check fails, follow the remediation command it comments (no rebase needed). ## Related Issues - - diff --git a/.github/dco.yml b/.github/dco.yml new file mode 100644 index 0000000..20abde6 --- /dev/null +++ b/.github/dco.yml @@ -0,0 +1,19 @@ +# Config for the dcoapp GitHub App (https://github.com/apps/dco), which replaces +# the old in-repo tim-actions/dco job. The app posts a single "DCO" status check +# and, on failure, comments the exact remediation command on the PR. +# +# Why these settings make sign-off easier for contributors: +# require.members: false -> commits by KrakenNet org members don't need +# a sign-off line (maintainers stop tripping it). +# allowRemediationCommits.* -> a missing sign-off is fixed by pushing ONE +# extra commit (the app gives you the command), +# instead of rewriting history with a rebase. +# individual: true -> the original author can self-remediate. +# thirdParty: true -> a maintainer can sign off on someone else's +# behalf — including an unsigned bot commit +# (e.g. autofix.ci) that used to deadlock DCO. +require: + members: false +allowRemediationCommits: + individual: true + thirdParty: true diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4192e4c..277d939 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,12 +14,15 @@ jobs: # (Postgres/pgbouncer, Neo4j testcontainer, all-extras serve surface) run only # when their domain — or a shared/core path — actually changed. On push to main # every gate runs regardless (see each job's ``if:``), so main stays fully - # covered; PRs get a smaller, faster, less infra-flaky check set. The always-on - # ``lint`` + ``test`` jobs (the only required checks) are never filtered. + # covered; PRs get a smaller, faster, less infra-flaky check set. The required + # ``lint`` + ``test`` jobs run on every PR that touches code; a docs-only PR + # (``code`` filter false) skips them — a skipped required check counts as a + # pass, so docs PRs stay mergeable without burning the full toolchain. changes: runs-on: ubuntu-latest timeout-minutes: 5 outputs: + code: ${{ steps.filter.outputs.code }} engine: ${{ steps.filter.outputs.engine }} knowledge: ${{ steps.filter.outputs.knowledge }} cypher: ${{ steps.filter.outputs.cypher }} @@ -30,6 +33,17 @@ jobs: id: filter with: filters: | + # True when the PR changes anything that isn't pure documentation. + # Negation-only failure mode is safe: if dorny ever ignored the + # ``!`` patterns, ``**`` matches everything → ``code`` stays true → + # lint/test run anyway (today's behavior). They only skip when every + # changed file is docs/markdown. + code: + - '**' + - '!**/*.md' + - '!docs/**' + - '!mkdocs.yml' + - '!LICENSE' core: &core - 'pyproject.toml' - 'uv.lock' @@ -65,6 +79,8 @@ jobs: - 'docs/reference/openapi.json' lint: + needs: changes + if: github.event_name == 'push' || needs.changes.outputs.code == 'true' runs-on: ubuntu-latest timeout-minutes: 20 env: @@ -104,6 +120,8 @@ jobs: # on PR branches alike), so it has never produced a signal that # ubuntu didn't. Linux is the canonical platform; restore the slot if # macos-specific coverage is ever needed. + needs: changes + if: github.event_name == 'push' || needs.changes.outputs.code == 'true' runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -326,22 +344,10 @@ jobs: - run: git diff --exit-code docs/reference/openapi.json - run: uv run python scripts/lineage_audit.py --help - dco: - # Only run on PRs; reject if any commit lacks Signed-off-by. - # Skip release-please PRs — its bot commits are not signed off. - if: github.event_name == 'pull_request' && !startsWith(github.head_ref, 'release-please--') - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v7 - with: - fetch-depth: 0 - - uses: tim-actions/get-pr-commits@v1.3.1 - id: pr-commits - with: - token: ${{ secrets.GITHUB_TOKEN }} - - uses: tim-actions/dco@v1.1.0 - with: - commits: ${{ steps.pr-commits.outputs.commits }} + # DCO sign-off is enforced by the dcoapp GitHub App (config in .github/dco.yml), + # not an in-repo job. The app exempts org members and lets contributors fix a + # missing sign-off with a remediation commit instead of a history rewrite — + # see CONTRIBUTING.md. changelog-check: # Enforce CHANGELOG.md entry when IR/schema files change (NFR-2). diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d85d9f1..22f3b39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -13,7 +13,8 @@ repos: rev: v2.4.1 hooks: - id: codespell - args: [--skip, "uv.lock,docs/reference/*"] + # `thirdParty` is a required dcoapp config key (.github/dco.yml), not a typo. + args: [--skip, "uv.lock,docs/reference/*", -L, thirdparty] - repo: local hooks: # ruff lint + format run via `uv run` so the version always tracks diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 25a8fc9..586385c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,9 +15,9 @@ Every commit must be signed off: git commit -s -m "Add feature X" -This appends `Signed-off-by: Your Name ` to the commit message, certifying you can legally contribute the code (full text: https://developercertificate.org/). The CI rejects PRs with unsigned commits. To fix existing commits: +This appends `Signed-off-by: Your Name ` to the commit message, certifying you can legally contribute the code (full text: https://developercertificate.org/). The `DCO` check rejects PRs with unsigned commits. - git rebase --signoff origin/main +**Forgot to sign off?** You don't need to rewrite history. When the `DCO` check fails it comments the exact one-line command to push a *remediation commit* that signs off your earlier commits — just run it and push. (If you'd rather rewrite history, `git rebase --signoff origin/main` also works.) ## Development Setup