Skip to content

feat: add --json output - #4

Merged
SafeEval merged 1 commit into
mainfrom
agent/json-output
Jul 30, 2026
Merged

feat: add --json output#4
SafeEval merged 1 commit into
mainfrom
agent/json-output

Conversation

@SafeEval

Copy link
Copy Markdown
Member

lint.Problem already carried json:"rule" and json:"message" tags, but nothing ever emitted them. A linter that runs in CI should be able to hand its results to something other than a human, so this finishes the API the types already declared.

$ commitlint lint --json "Add gateway"
{
  "conforms": false,
  "checked": 1,
  "failed": 1,
  "blocking": true,
  "results": [
    {
      "label": "message",
      "subject": "Add gateway",
      "problems": [
        {
          "rule": "format",
          "message": "subject must be `type(scope)?: description`, got \"Add gateway\""
        }
      ]
    }
  ]
}

Design

Results are collected into a Report and rendered as either text or JSON, so both formats derive from one structure and can't disagree about what was found or what the exit code should be.

Two details worth calling out:

  • blocking is separate from failed. In --mode warn a run has problems but doesn't fail. A consumer needs to distinguish "found problems" from "failed the run", and failed > 0 alone can't express that.
  • problems is always [], never null. Callers can iterate without a nil check.

Verification

  • Text output is byte-for-byte unchanged, diffed against a binary built from merged main (1c3a0df) across conforming, violating, warn-mode, and multi-problem-file cases. This was the main regression risk in the refactor.
  • JSON validated by parsing with a real JSON reader (not eyeballing), for conforming, violating, warn-mode, and multi-message --range runs.
  • The README example is copied from actual output and matches byte for byte.
  • First tests for package main, which previously had none — covering the JSON shape as a CLI contract, the []-not-null guarantee, and all three text renderings.
  • gofmt, go vet, go test -race ./... clean. Zero third-party dependencies preserved (encoding/json is stdlib).

Release impact

This is a feat:, so merging cuts v1.1.0 — not the v1.0.1 discussed earlier. That's the automation working as designed: the version follows the change type. The comment-stripping fix from #1 ships in v1.1.0 along with this.

This will also be the first live exercise of release.yml via the merge-to-main path.

🤖 Generated with Claude Code

https://claude.ai/code/session_01VSrrciEDBTuFNMtKocScML

lint.Problem already carried `json:"rule"` and `json:"message"` tags, but
nothing ever emitted them. A linter that runs in CI should be able to hand
its results to something other than a human, so finish the API the types
already declared.

Collect results into a Report and render it as either text or JSON, so
both formats derive from one structure and cannot disagree about what was
found or what the exit code should be. Text output is unchanged, verified
byte-for-byte against the previous binary.

The payload reports `blocking` separately from `failed`: in warn mode a run
has problems but does not fail, and a consumer needs to tell those apart.
Empty problem lists marshal as [] rather than null so callers can iterate
without a nil check.

Adds the first tests for package main, covering the JSON shape as a CLI
contract, the [] guarantee, and the three text renderings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VSrrciEDBTuFNMtKocScML
@SafeEval
SafeEval marked this pull request as ready for review July 30, 2026 17:11
@SafeEval
SafeEval merged commit f937092 into main Jul 30, 2026
1 check passed
@SafeEval
SafeEval deleted the agent/json-output branch July 30, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant