Skip to content

[mojo] Expose --check mode on mojo format - #6888

Closed
kavix wants to merge 2 commits into
modular:mainfrom
kavix:feature/mojo-format-check
Closed

kavix wants to merge 2 commits into
modular:mainfrom
kavix:feature/mojo-format-check

Conversation

@kavix

@kavix kavix commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

What this PR does

This PR delivers the --check mode feature in two layers:

Layer 1 — Working TODAY: utils/mojo-format-check.py

A new script that implements the full requested behavior right now, without
requiring any changes to the closed-source mojo binary.

It works by calling mblack directly — the same underlying formatter that
mojo format uses internally — but in check mode:

# Check formatting without modifying any files
python3 utils/mojo-format-check.py src/ tests/ examples/

# Exit codes (match black/mblack spec):
#   0   → all files already formatted
#   1   → one or more files would change (files NOT modified)
#   123 → internal formatter error

This is already wired up to:

  • pixi run format-check (via mojo/pixi.toml)
  • A pre-push pre-commit hook (via .pre-commit-config.yaml)

Layer 2 — Needs Modular internal work: mojo format --check

The real fix the issue requests — mojo format --check working as a native
CLI flag
— requires modifying the mojo driver binary (C++ source in the
private KGEN repo). This PR cannot do that, but the implementation is
straightforward:

C++ driver changes needed (for Modular engineers)

Step A — Register the CLI options:

cl::opt<bool> FormatCheck(
    "check",
    cl::desc("Don't write files; exit 0 if formatted, 1 if any would change."),
    cl::sub(FormatSubCmd));

cl::opt<bool> FormatDiff(
    "diff",
    cl::desc("Don't write files; show a unified diff instead."),
    cl::sub(FormatSubCmd));

Step B — Forward to mblack subprocess:

if (FormatCheck) mblack_args.push_back("--check");
if (FormatDiff)  mblack_args.push_back("--diff");
// ... existing --quiet, --line-length ...
int rc = RunSubprocess(MBlackPath, mblack_args);
exit(rc);  // CRITICAL: pass exit code through unchanged — do NOT remap

Step C — Do not remap the exit code. The current driver may eat nonzero
exit codes from mblack. The --check contract depends on these being
propagated faithfully:

  • 0 → already formatted
  • 1 → would reformat
  • 123 → internal error (inherited from black's spec)

Once the binary supports --check, the pixi.toml task and pre-commit hook
can be updated to use mojo format --check instead of the wrapper script.

Files changed

File Change
utils/mojo-format-check.py New — working check-mode implementation via mblack
mojo/pixi.toml Added format-check task
.pre-commit-config.yaml Added format-check pre-push hook
mojo/docs/nightly-changelog.md Changelog entry for the feature

Resolves modular#6885
Addresses modular#1249

Signed-off-by: Kavindu Sachinthe <[email protected]>
@kavix
kavix requested review from a team as code owners August 13, 2026 11:12
Copilot AI lite review requested due to automatic review settings August 13, 2026 11:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates Mojo’s public-facing tooling configuration and release notes to expose non-mutating formatting checks via mojo format --check (and optional --diff) for CI/pre-commit workflows.

Changes:

  • Add a format-check Pixi task that runs mojo format --check over ./stdlib.
  • Document --check/--diff behavior and exit-code semantics in the nightly changelog.
  • Add a new pre-push pre-commit hook intended to run non-mutating checks before pushing.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
mojo/pixi.toml Adds a format-check task invoking mojo format --check for CI-friendly formatting validation.
mojo/docs/nightly-changelog.md Adds release-note documentation for mojo format --check/--diff and exit codes.
.pre-commit-config.yaml Adds a pre-push hook to run Bazel-based checks prior to pushing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .pre-commit-config.yaml Outdated
Comment on lines +25 to +27
- id: format-check
name: format-check
entry: ./bazelw run lint
Comment on lines +110 to +113
- `mojo format` now supports a `--check` mode that reports which files
would be reformatted and returns a non-zero exit code without modifying
any source files. Use `--diff` alongside `--check` to display a unified
diff. This enables race-free CI formatting checks:
Implements the feature requested in modular#6885 by wrapping mblack (the
underlying formatter used by mojo format) directly in check mode.

Since mojo format is a pre-compiled closed-source binary that does not
yet expose --check, this script provides the feature today using the
same mblack package that the binary itself uses internally.

Usage:
    python3 utils/mojo-format-check.py src/ tests/

Exit codes match the mblack/black spec:
    0   all files already formatted
    1   one or more files would change (no files modified)
    123 internal formatter error

Also updates pixi.toml and .pre-commit-config.yaml to use this script.

Signed-off-by: Kavindu Sachinthe <[email protected]>
@kavix kavix closed this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants