Skip to content
Open
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
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,20 @@ jobs:
go-version: '1.26.1'
cache: true

# Node is required by the TS mutation evals (npm test -> vitest /
# node). Minimum 22.6 so `--experimental-strip-types` is default.
- uses: actions/setup-node@v4
with:
node-version: '22'

- name: Cache npm
uses: actions/cache@v4
with:
path: ~/.npm
key: npm-${{ runner.os }}-${{ hashFiles('**/package.json', '**/package-lock.json') }}
restore-keys: |
npm-${{ runner.os }}-

- name: Build
run: go build ./...

Expand All @@ -30,6 +44,11 @@ jobs:
- name: Vet
run: go vet ./...

- name: Eval — TypeScript (EVAL-3)
env:
CI: "true"
run: make eval-ts

diffguard:
# Dogfooding: run diffguard's own quality gate against this repo.
# Mutation testing runs at 20% sample rate here as a fast smoke
Expand Down
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ BINARY := diffguard
PKG := ./cmd/diffguard
PATHS := internal/,cmd/

.PHONY: all build install test coverage check check-mutation check-fast clean help
# Shared env for evaluation suites. CI=true nudges sub-commands (cargo,
# npm) into non-interactive modes; CARGO_INCREMENTAL=0 keeps the
# mutation runs deterministic and avoids a multi-GB incremental cache.
EVAL_ENV := CI=true CARGO_INCREMENTAL=0

.PHONY: all build install test coverage check check-mutation check-fast eval-ts clean help

all: build

Expand All @@ -28,6 +33,9 @@ check: build ## Run the full quality gate including 100% mutation testing (slow)
check-mutation: build ## Only the mutation section, full codebase
./$(BINARY) --paths $(PATHS) --fail-on warn .

eval-ts: ## Run the TypeScript correctness eval (EVAL-3). Requires node+npm for mutation tests.
Comment thread
donnfelker marked this conversation as resolved.
$(EVAL_ENV) go test ./internal/lang/tsanalyzer/... -run TestEval -count=1 -v

clean: ## Remove build artifacts
rm -f $(BINARY) coverage.out

Expand Down
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# diffguard

A targeted code quality gate for Go repositories. Analyzes either the changed regions of a git diff (CI mode) or specified files/directories (refactoring mode), and reports on complexity, size, dependency structure, churn risk, and mutation test coverage.
A targeted code quality gate for Go and TypeScript repositories. Analyzes either the changed regions of a git diff (CI mode) or specified files/directories (refactoring mode), and reports on complexity, size, dependency structure, churn risk, and mutation test coverage.

## Why

Expand Down Expand Up @@ -42,6 +42,10 @@ diffguard --base main /path/to/repo
diffguard --paths internal/foo/bar.go /path/to/repo
diffguard --paths internal/foo/,internal/bar/ /path/to/repo

# TypeScript project (vitest/jest auto-detected from package.json)
diffguard --base main /path/to/ts-repo
diffguard --paths src/auth/,src/billing/ /path/to/ts-repo

# Skip mutation testing (fastest)
diffguard --skip-mutation /path/to/repo

Expand Down Expand Up @@ -70,6 +74,40 @@ diffguard \

**Generated-file skipping (`--skip-generated`):** Enabled by default. Files marked with a standard generated-code banner such as `Code generated ... DO NOT EDIT` are excluded before they reach any analyzer. Pass `--skip-generated=false` to include them.

## Languages

Diffguard auto-detects supported languages from the files it sees. No flag selects the language — analyzers activate on their own file types.

| Language | Files | Test runner |
|------------|----------------|--------------------------------------------------------------------------------|
| Go | `*.go` | `go test` |
| TypeScript | `*.ts`, `*.tsx`| Auto-detected from `package.json`: `npx vitest run` → `npx jest` → `npm test` |

**TypeScript prerequisites.** `node` and `npm` (or `npx`) must be on `PATH` for mutation testing. The TypeScript analyzer only activates when the repo has a `package.json` AND at least one `.ts` / `.tsx` file, so pure-JS projects are left alone. Test files (`*.test.ts`, `*.spec.ts`, `*.test.tsx`, `*.spec.tsx`, or anything under a `__tests__` / `__mocks__` segment) are excluded from mutation. Mutation testing spawns the detected runner once per mutant, so expect TS runs to take longer than Go runs (node startup + TS compile per mutant) — use `--mutation-sample-rate` for fast PR feedback.

### TypeScript example

```bash
# Go install once
go install github.com/0xPolygon/diffguard/cmd/diffguard@latest

# From your TypeScript repo, PR-style diff mode with a 20% mutation sample
cd /path/to/ts-repo
diffguard --mutation-sample-rate 20 --base origin/main .

# Or scope to specific subdirectories in refactoring mode
diffguard --paths src/billing/,src/auth/ .
```

In GitHub Actions, add `actions/setup-node` and an `npm ci` step to the [Per-PR gate workflow](#github-actions) below so `npx vitest` / `npx jest` are available when diffguard spawns mutant runs. The extra steps, inserted after `actions/setup-go`:

```yaml
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci # installs vitest / jest so diffguard can invoke them per mutant
```

## What It Measures

### Cognitive Complexity
Expand Down
1 change: 1 addition & 0 deletions cmd/diffguard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/0xPolygon/diffguard/internal/diff"
"github.com/0xPolygon/diffguard/internal/lang"
_ "github.com/0xPolygon/diffguard/internal/lang/goanalyzer"
_ "github.com/0xPolygon/diffguard/internal/lang/tsanalyzer"
"github.com/0xPolygon/diffguard/internal/mutation"
"github.com/0xPolygon/diffguard/internal/report"
"github.com/0xPolygon/diffguard/internal/sizes"
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/0xPolygon/diffguard

go 1.26.1

require github.com/smacker/go-tree-sitter v0.0.0-20240827094217-dd81d9e9be82
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/smacker/go-tree-sitter v0.0.0-20240827094217-dd81d9e9be82 h1:6C8qej6f1bStuePVkLSFxoU22XBS165D3klxlzRg8F4=
github.com/smacker/go-tree-sitter v0.0.0-20240827094217-dd81d9e9be82/go.mod h1:xe4pgH49k4SsmkQq5OT8abwhWmnzkhpgnXeekbx2efw=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading
Loading