[PATCH v2] checkpatch: add --json output mode

Sasha Levin posted 1 patch 2 months, 1 week ago
There is a newer version of this series
Documentation/dev-tools/checkpatch.rst |  7 +++
scripts/checkpatch.pl                  | 64 +++++++++++++++++++++++---
2 files changed, 65 insertions(+), 6 deletions(-)
[PATCH v2] checkpatch: add --json output mode
Posted by Sasha Levin 2 months, 1 week ago
Add a --json flag to checkpatch.pl that emits structured JSON output,
making results machine-parseable for CI systems, IDE integrations, and
AI-assisted code review tools.

The JSON output includes per-file totals (errors, warnings, checks,
lines) and an array of individual issues with structured fields for
level, type, message, file path, and line number.

The --json flag is mutually exclusive with --terse and --emacs.
Normal text output behavior is completely unchanged when --json is
not specified.

Assisted-by: Claude:claude-opus-4-6
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
Changes since v1:
- Replace hand-rolled json_escape()/json_encode_issue() with JSON::PP
  module (core since perl 5.14), as suggested by Konstantin and Joe
- Factor duplicated empty-result JSON blocks into json_print_result()
  helper
- Include used_types and ignored_types arrays in JSON output instead of
  suppressing hash_show_words, per Joe's suggestion
---
 Documentation/dev-tools/checkpatch.rst |  7 +++
 scripts/checkpatch.pl                  | 64 +++++++++++++++++++++++---
 2 files changed, 65 insertions(+), 6 deletions(-)

diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst
index dccede68698ca..17e5744d3dee6 100644
--- a/Documentation/dev-tools/checkpatch.rst
+++ b/Documentation/dev-tools/checkpatch.rst
@@ -64,6 +64,13 @@ Available options:
 
    Output only one line per report.
 
+ - --json
+
+   Output results as a JSON object.  The object includes total error, warning,
+   and check counts, plus an array of individual issues with structured fields
+   for level, type, message, file, and line number.  Cannot be used with
+   --terse or --emacs.
+
  - --showfile
 
    Show the diffed file position instead of the input file position.
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index e56374662ff79..38d1a4a13ee8e 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -14,6 +14,7 @@ use File::Basename;
 use Cwd 'abs_path';
 use Term::ANSIColor qw(:constants);
 use Encode qw(decode encode);
+use JSON::PP;
 
 my $P = $0;
 my $D = dirname(abs_path($P));
@@ -33,6 +34,7 @@ my $chk_patch = 1;
 my $tst_only;
 my $emacs = 0;
 my $terse = 0;
+my $json = 0;
 my $showfile = 0;
 my $file = 0;
 my $git = 0;
@@ -93,6 +95,7 @@ Options:
   --patch                    treat FILE as patchfile (default)
   --emacs                    emacs compile window format
   --terse                    one line per report
+  --json                     output results as JSON
   --showfile                 emit diffed file position, not input file position
   -g, --git                  treat FILE as a single commit or git revision range
                              single git commit with:
@@ -320,6 +323,7 @@ GetOptions(
 	'patch!'	=> \$chk_patch,
 	'emacs!'	=> \$emacs,
 	'terse!'	=> \$terse,
+	'json!'		=> \$json,
 	'showfile!'	=> \$showfile,
 	'f|file!'	=> \$file,
 	'g|git!'	=> \$git,
@@ -379,6 +383,7 @@ help($help - 1) if ($help);
 
 die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
 die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
+die "$P: --json cannot be used with --terse or --emacs\n" if ($json && ($terse || $emacs));
 
 if ($color =~ /^[01]$/) {
 	$color = !$color;
@@ -1351,7 +1356,7 @@ for my $filename (@ARGV) {
 	}
 	close($FILE);
 
-	if ($#ARGV > 0 && $quiet == 0) {
+	if (!$json && $#ARGV > 0 && $quiet == 0) {
 		print '-' x length($vname) . "\n";
 		print "$vname\n";
 		print '-' x length($vname) . "\n";
@@ -1372,7 +1377,7 @@ for my $filename (@ARGV) {
 	$file = $oldfile if ($is_git_file);
 }
 
-if (!$quiet) {
+if (!$quiet && !$json) {
 	hash_show_words(\%use_type, "Used");
 	hash_show_words(\%ignore_type, "Ignored");
 
@@ -2395,6 +2400,18 @@ sub report {
 
 	push(our @report, $output);
 
+	if ($json) {
+		our ($realfile, $realline);
+		my %issue = (
+			level => $level,
+			type => $type,
+			message => $msg,
+		);
+		$issue{file} = $realfile if (defined $realfile && $realfile ne '');
+		$issue{line} = $realline + 0 if (defined $realline && $realline);
+		push(our @json_issues, \%issue);
+	}
+
 	return 1;
 }
 
@@ -2402,6 +2419,23 @@ sub report_dump {
 	our @report;
 }
 
+sub json_print_result {
+	my ($filename, $total_errors, $total_warnings, $total_checks,
+	    $total_lines, $issues, $used_types, $ignored_types) = @_;
+	my %result = (
+		filename       => $filename,
+		total_errors   => $total_errors + 0,
+		total_warnings => $total_warnings + 0,
+		total_checks   => $total_checks + 0,
+		total_lines    => $total_lines + 0,
+		issues         => $issues,
+	);
+	$result{used_types} = $used_types if (defined $used_types);
+	$result{ignored_types} = $ignored_types if (defined $ignored_types);
+	my $json_encoder = JSON::PP->new->canonical->utf8;
+	print $json_encoder->encode(\%result) . "\n";
+}
+
 sub fixup_current_range {
 	my ($lineRef, $offset, $length) = @_;
 
@@ -2690,14 +2724,15 @@ sub process {
 	my $last_coalesced_string_linenr = -1;
 
 	our @report = ();
+	our @json_issues = ();
 	our $cnt_lines = 0;
 	our $cnt_error = 0;
 	our $cnt_warn = 0;
 	our $cnt_chk = 0;
 
 	# Trace the real file/line as we go.
-	my $realfile = '';
-	my $realline = 0;
+	our $realfile = '';
+	our $realline = 0;
 	my $realcnt = 0;
 	my $here = '';
 	my $context_function;		#undef'd unless there's a known function
@@ -7791,18 +7826,27 @@ sub process {
 	# If we have no input at all, then there is nothing to report on
 	# so just keep quiet.
 	if ($#rawlines == -1) {
+		if ($json) {
+			json_print_result($filename, 0, 0, 0, 0, []);
+		}
 		exit(0);
 	}
 
 	# In mailback mode only produce a report in the negative, for
 	# things that appear to be patches.
 	if ($mailback && ($clean == 1 || !$is_patch)) {
+		if ($json) {
+			json_print_result($filename, 0, 0, 0, 0, []);
+		}
 		exit(0);
 	}
 
 	# This is not a patch, and we are in 'no-patch' mode so
 	# just keep quiet.
 	if (!$chk_patch && !$is_patch) {
+		if ($json) {
+			json_print_result($filename, 0, 0, 0, 0, []);
+		}
 		exit(0);
 	}
 
@@ -7850,6 +7894,13 @@ sub process {
 		}
 	}
 
+	if ($json) {
+		my @used = sort keys %use_type;
+		my @ignored = sort keys %ignore_type;
+		json_print_result($filename, $cnt_error, $cnt_warn,
+				  $cnt_chk, $cnt_lines, \@json_issues,
+				  \@used, \@ignored);
+	} else {
 	print report_dump();
 	if ($summary && !($clean == 1 && $quiet == 1)) {
 		print "$filename " if ($summary_file);
@@ -7878,8 +7929,9 @@ NOTE: Whitespace errors detected.
 EOM
 		}
 	}
+	} # end !$json
 
-	if ($clean == 0 && $fix &&
+	if (!$json && $clean == 0 && $fix &&
 	    ("@rawlines" ne "@fixed" ||
 	     $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) {
 		my $newfile = $filename;
@@ -7918,7 +7970,7 @@ EOM
 		}
 	}
 
-	if ($quiet == 0) {
+	if (!$json && $quiet == 0) {
 		print "\n";
 		if ($clean == 1) {
 			print "$vname has no obvious style problems and is ready for submission.\n";
-- 
2.53.0
Re: [PATCH v2] checkpatch: add --json output mode
Posted by Joe Perches 2 months, 1 week ago
On Wed, 2026-04-08 at 13:24 -0400, Sasha Levin wrote:

Adding --json seems sensible but some of the
added checkpatch code seems odd to me.

> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> @@ -2395,6 +2400,18 @@ sub report {
>  
>  	push(our @report, $output);
>  
> +	if ($json) {
> +		our ($realfile, $realline);

Seems an odd way to check if $realfile/$readline is set

> +		my %issue = (
> +			level => $level,
> +			type => $type,
> +			message => $msg,
> +		);
> +		$issue{file} = $realfile if (defined $realfile && $realfile ne '');
> +		$issue{line} = $realline + 0 if (defined $realline && $realline);

All the uses of + 0 seem unnecessary, but I gather it's for
string/decimal conversions.

> +sub json_print_result {
> +	my ($filename, $total_errors, $total_warnings, $total_checks,
> +	    $total_lines, $issues, $used_types, $ignored_types) = @_;
> +	my %result = (
> +		filename       => $filename,
> +		total_errors   => $total_errors + 0,
> +		total_warnings => $total_warnings + 0,
> +		total_checks   => $total_checks + 0,
> +		total_lines    => $total_lines + 0,
> +		issues         => $issues,
> +	);
> +	$result{used_types} = $used_types if (defined $used_types);
> +	$result{ignored_types} = $ignored_types if (defined $ignored_types);
> +	my $json_encoder = JSON::PP->new->canonical->utf8;

Maybe add JSON pretty too?

> +	print $json_encoder->encode(\%result) . "\n";

Still missing parentheses around print args.
I do know  that not all existing print uses have parentheses.
I just prefer them to be more like C readable.

> +}
> +
>  sub fixup_current_range {
>  	my ($lineRef, $offset, $length) = @_;
>  
> @@ -2690,14 +2724,15 @@ sub process {
>  	my $last_coalesced_string_linenr = -1;
>  
>  	our @report = ();
> +	our @json_issues = ();
>  	our $cnt_lines = 0;
>  	our $cnt_error = 0;
>  	our $cnt_warn = 0;
>  	our $cnt_chk = 0;
>  
>  	# Trace the real file/line as we go.
> -	my $realfile = '';
> -	my $realline = 0;
> +	our $realfile = '';
> +	our $realline = 0;

?

> @@ -7791,18 +7826,27 @@ sub process {
>  	# If we have no input at all, then there is nothing to report on
>  	# so just keep quiet.
>  	if ($#rawlines == -1) {
> +		if ($json) {
> +			json_print_result($filename, 0, 0, 0, 0, []);
> +		}
>  		exit(0);
>  	}
>  
>  	# In mailback mode only produce a report in the negative, for
>  	# things that appear to be patches.
>  	if ($mailback && ($clean == 1 || !$is_patch)) {
> +		if ($json) {
> +			json_print_result($filename, 0, 0, 0, 0, []);
> +		}
>  		exit(0);
>  	}
>  
>  	# This is not a patch, and we are in 'no-patch' mode so
>  	# just keep quiet.
>  	if (!$chk_patch && !$is_patch) {
> +		if ($json) {
> +			json_print_result($filename, 0, 0, 0, 0, []);
> +		}
>  		exit(0);
>  	}


Duplicated code, maybe use a function or consolidate the code?
Something like:

 	if (($#rawlines == -1) ||
			# If we have no input, there's nothing to report
 	    ($mailback && ($clean == 1 || !$is_patch)) ||
			# In mailback mode only produce a report for what seems to be a patch
 	    (!$chk_patch && !$is_patch)) {
			# This is not a patch, and we are in 'no-patch' mode.
		json_print_result($filename, 0, 0, 0, 0, []) if ($json);
 		exit(0);
 	}

>  
> @@ -7850,6 +7894,13 @@ sub process {
>  		}
>  	}
>  
> +	if ($json) {
> +		my @used = sort keys %use_type;
> +		my @ignored = sort keys %ignore_type;
> +		json_print_result($filename, $cnt_error, $cnt_warn,
> +				  $cnt_chk, $cnt_lines, \@json_issues,
> +				  \@used, \@ignored);
> +	} else {
>  	print report_dump();
>  	if ($summary && !($clean == 1 && $quiet == 1)) {
>  		print "$filename " if ($summary_file);
> @@ -7878,8 +7929,9 @@ NOTE: Whitespace errors detected.
>  EOM
>  		}
>  	}
> +	} # end !$json

I quite dislike misleading indentation.

Perhaps it's  unnecessary here and simpler to use an
exit in the new block at line 7850

>  
> -	if ($clean == 0 && $fix &&
> +	if (!$json && $clean == 0 && $fix &&
>  	    ("@rawlines" ne "@fixed" ||
>  	     $#fixed_inserted >= 0 || $#fixed_deleted >= 0)) {
>  		my $newfile = $filename;
> @@ -7918,7 +7970,7 @@ EOM
>  		}
>  	}
>  
> -	if ($quiet == 0) {
> +	if (!$json && $quiet == 0) {
>  		print "\n";
>  		if ($clean == 1) {
>  			print "$vname has no obvious style problems and is ready for submission.\n";
> 
[PATCH v3] checkpatch: add --json output mode
Posted by Sasha Levin 1 month, 3 weeks ago
Add a --json flag to checkpatch.pl that emits structured JSON output,
making results machine-parseable for CI systems, IDE integrations, and
AI-assisted code review tools.

The JSON output includes per-file totals (errors, warnings, checks,
lines) and an array of individual issues with structured fields for
level, type, message, file path, and line number.

A separate --json-pretty flag emits the same JSON in a pretty-printed
(indented, multi-line) form for human reading.

The --json (and --json-pretty) flags are mutually exclusive with
--terse and --emacs.  Normal text output behaviour is completely
unchanged when --json is not specified.

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
v3:
  - Report the same line numbers text mode prints (matches --emacs
    and --showfile).  Fixes wrong locations on commit-message issues.
  - Drop redundant defined() checks and `+ 0` coercions in the JSON
    code; the values are already numeric and always defined.
  - Add --json-pretty for indented output.
  - Add parens around print() arguments.
  - Consolidate the three empty-result early exits into one block.
  - Return at the JSON branch instead of wrapping the rest of
    process() in an else, so multi-file runs emit one document per
    file and the indentation is no longer misleading.
v2: https://lore.kernel.org/all/20260408172435.1268067-1-sashal@kernel.org/
v1: https://lore.kernel.org/all/20260406170039.4034716-1-sashal@kernel.org/

 Documentation/dev-tools/checkpatch.rst | 13 ++++
 scripts/checkpatch.pl                  | 86 +++++++++++++++++++-------
 2 files changed, 78 insertions(+), 21 deletions(-)

diff --git a/Documentation/dev-tools/checkpatch.rst b/Documentation/dev-tools/checkpatch.rst
index dccede68698ca..8a7c7742b23fa 100644
--- a/Documentation/dev-tools/checkpatch.rst
+++ b/Documentation/dev-tools/checkpatch.rst
@@ -64,6 +64,19 @@ Available options:
 
    Output only one line per report.
 
+ - --json
+
+   Output results as a JSON object.  The object includes total error,
+   warning, and check counts, plus an array of individual issues with
+   structured fields for level, type, message, file, and line number.
+   Output is one compact JSON document per input file, suitable for CI
+   and scripted post-processing.  Cannot be used with --terse or --emacs.
+
+ - --json-pretty
+
+   Like --json, but emit pretty-printed (indented, multi-line) JSON for
+   human reading.
+
  - --showfile
 
    Show the diffed file position instead of the input file position.
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0492d6afc9a1f..181bd10b046b7 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -14,6 +14,7 @@ use File::Basename;
 use Cwd 'abs_path';
 use Term::ANSIColor qw(:constants);
 use Encode qw(decode encode);
+use JSON::PP;
 
 my $P = $0;
 my $D = dirname(abs_path($P));
@@ -33,6 +34,8 @@ my $chk_patch = 1;
 my $tst_only;
 my $emacs = 0;
 my $terse = 0;
+my $json = 0;
+my $json_pretty = 0;
 my $showfile = 0;
 my $file = 0;
 my $git = 0;
@@ -93,6 +96,8 @@ Options:
   --patch                    treat FILE as patchfile (default)
   --emacs                    emacs compile window format
   --terse                    one line per report
+  --json                     output results as JSON
+  --json-pretty              like --json, but pretty-printed
   --showfile                 emit diffed file position, not input file position
   -g, --git                  treat FILE as a single commit or git revision range
                              single git commit with:
@@ -320,6 +325,8 @@ GetOptions(
 	'patch!'	=> \$chk_patch,
 	'emacs!'	=> \$emacs,
 	'terse!'	=> \$terse,
+	'json!'		=> \$json,
+	'json-pretty!'	=> \$json_pretty,
 	'showfile!'	=> \$showfile,
 	'f|file!'	=> \$file,
 	'g|git!'	=> \$git,
@@ -380,6 +387,9 @@ help($help - 1) if ($help);
 die "$P: --git cannot be used with --file or --fix\n" if ($git && ($file || $fix));
 die "$P: --verbose cannot be used with --terse\n" if ($verbose && $terse);
 
+$json = 1 if ($json_pretty);
+die "$P: --json cannot be used with --terse or --emacs\n" if ($json && ($terse || $emacs));
+
 if ($color =~ /^[01]$/) {
 	$color = !$color;
 } elsif ($color =~ /^always$/i) {
@@ -1352,7 +1362,7 @@ for my $filename (@ARGV) {
 	}
 	close($FILE);
 
-	if ($#ARGV > 0 && $quiet == 0) {
+	if (!$json && $#ARGV > 0 && $quiet == 0) {
 		print '-' x length($vname) . "\n";
 		print "$vname\n";
 		print '-' x length($vname) . "\n";
@@ -1373,7 +1383,7 @@ for my $filename (@ARGV) {
 	$file = $oldfile if ($is_git_file);
 }
 
-if (!$quiet) {
+if (!$quiet && !$json) {
 	hash_show_words(\%use_type, "Used");
 	hash_show_words(\%ignore_type, "Ignored");
 
@@ -2396,6 +2406,19 @@ sub report {
 
 	push(our @report, $output);
 
+	if ($json) {
+		our ($realfile, $realline, $linenr);
+		my $line = ($file || $showfile) ? $realline : $linenr;
+		my %issue = (
+			level   => $level,
+			type    => $type,
+			message => $msg,
+		);
+		$issue{file} = $realfile if ($realfile ne '');
+		$issue{line} = $line if ($line);
+		push(our @json_issues, \%issue);
+	}
+
 	return 1;
 }
 
@@ -2403,6 +2426,24 @@ sub report_dump {
 	our @report;
 }
 
+sub json_print_result {
+	my ($filename, $total_errors, $total_warnings, $total_checks,
+	    $total_lines, $issues, $used_types, $ignored_types) = @_;
+	my %result = (
+		filename       => $filename,
+		total_errors   => $total_errors,
+		total_warnings => $total_warnings,
+		total_checks   => $total_checks,
+		total_lines    => $total_lines,
+		issues         => $issues,
+	);
+	$result{used_types}    = $used_types    if (defined $used_types);
+	$result{ignored_types} = $ignored_types if (defined $ignored_types);
+	my $json_encoder = JSON::PP->new->canonical->utf8;
+	$json_encoder->pretty if ($json_pretty);
+	print($json_encoder->encode(\%result), "\n");
+}
+
 sub fixup_current_range {
 	my ($lineRef, $offset, $length) = @_;
 
@@ -2653,7 +2694,7 @@ sub is_userspace {
 sub process {
 	my $filename = shift;
 
-	my $linenr=0;
+	our $linenr=0;
 	my $prevline="";
 	my $prevrawline="";
 	my $stashline="";
@@ -2691,14 +2732,15 @@ sub process {
 	my $last_coalesced_string_linenr = -1;
 
 	our @report = ();
+	our @json_issues = ();
 	our $cnt_lines = 0;
 	our $cnt_error = 0;
 	our $cnt_warn = 0;
 	our $cnt_chk = 0;
 
 	# Trace the real file/line as we go.
-	my $realfile = '';
-	my $realline = 0;
+	our $realfile = '';
+	our $realline = 0;
 	my $realcnt = 0;
 	my $here = '';
 	my $context_function;		#undef'd unless there's a known function
@@ -7806,21 +7848,14 @@ sub process {
 		}
 	}
 
-	# If we have no input at all, then there is nothing to report on
-	# so just keep quiet.
-	if ($#rawlines == -1) {
-		exit(0);
-	}
-
-	# In mailback mode only produce a report in the negative, for
-	# things that appear to be patches.
-	if ($mailback && ($clean == 1 || !$is_patch)) {
-		exit(0);
-	}
-
-	# This is not a patch, and we are in 'no-patch' mode so
-	# just keep quiet.
-	if (!$chk_patch && !$is_patch) {
+	# Bail out early without producing a normal report when there is no
+	# input at all, when we are in mailback mode and either the patch is
+	# clean or the input does not appear to be a patch, or when the input
+	# is not a patch and we are in 'no-patch' mode.
+	if ($#rawlines == -1 ||
+	    ($mailback && ($clean == 1 || !$is_patch)) ||
+	    (!$chk_patch && !$is_patch)) {
+		json_print_result($filename, 0, 0, 0, 0, []) if ($json);
 		exit(0);
 	}
 
@@ -7868,7 +7903,16 @@ sub process {
 		}
 	}
 
-	print report_dump();
+	if ($json) {
+		my @used    = sort keys %use_type;
+		my @ignored = sort keys %ignore_type;
+		json_print_result($filename, $cnt_error, $cnt_warn,
+				  $cnt_chk, $cnt_lines, \@json_issues,
+				  \@used, \@ignored);
+		return $clean;
+	}
+
+	print(report_dump());
 	if ($summary && !($clean == 1 && $quiet == 1)) {
 		print "$filename " if ($summary_file);
 		print "total: $cnt_error errors, $cnt_warn warnings, " .
-- 
2.53.0
Re: [PATCH v3] checkpatch: add --json output mode
Posted by Joe Perches 1 month, 3 weeks ago
On Sat, 2026-04-25 at 16:04 -0400, Sasha Levin wrote:

> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
[]
> @@ -2403,6 +2426,24 @@ sub report_dump {
>  	our @report;
>  }
>  
> +sub json_print_result {
> +	my ($filename, $total_errors, $total_warnings, $total_checks,
> +	    $total_lines, $issues, $used_types, $ignored_types) = @_;
> +	my %result = (
> +		filename       => $filename,
> +		total_errors   => $total_errors,
> +		total_warnings => $total_warnings,
> +		total_checks   => $total_checks,
> +		total_lines    => $total_lines,
> +		issues         => $issues,
> +	);
> +	$result{used_types}    = $used_types    if (defined $used_types);
> +	$result{ignored_types} = $ignored_types if (defined $ignored_types);
> +	my $json_encoder = JSON::PP->new->canonical->utf8;

Maybe canonical isn't great as it outputs keys in alphabetic order.
The output may be more sensible in the defined order.
Re: [PATCH v3] checkpatch: add --json output mode
Posted by Joe Perches 1 month, 3 weeks ago
On 2026-04-25 13:04, Sasha Levin wrote:
> Add a --json flag to checkpatch.pl that emits structured JSON output,
> making results machine-parseable for CI systems, IDE integrations, and
> AI-assisted code review tools.
[]
> A separate --json-pretty flag emits the same JSON in a pretty-printed
> (indented, multi-line) form for human reading

Why not just always use pretty?
Would a script care?
Re: [PATCH v3] checkpatch: add --json output mode
Posted by Sasha Levin 1 month, 3 weeks ago
On Sat, Apr 25, 2026 at 02:52:35PM -0700, Joe Perches wrote:
>On 2026-04-25 13:04, Sasha Levin wrote:
>>Add a --json flag to checkpatch.pl that emits structured JSON output,
>>making results machine-parseable for CI systems, IDE integrations, and
>>AI-assisted code review tools.
>[]
>>A separate --json-pretty flag emits the same JSON in a pretty-printed
>>(indented, multi-line) form for human reading
>
>Why not just always use pretty?
>Would a script care?

Who's the intended consumer for the --json-pretty?

I my mind, --json is there to make it easier for tooling to process the output.

A user can already achieve the same result by piping the json output through jq
or other similar tools:

$ ./scripts/checkpatch.pl --json 0001-checkpatch-add-json-output-mode.patch 
{"filename":"0001-checkpatch-add-json-output-mode.patch","ignored_types":[],"issues":[],"total_checks":0,"total_errors":0,"total_lines":189,"total_warnings":0,"used_types":[]}
$ ./scripts/checkpatch.pl --json 0001-checkpatch-add-json-output-mode.patch | jq
{
   "filename": "0001-checkpatch-add-json-output-mode.patch",
   "ignored_types": [],
   "issues": [],
   "total_checks": 0,
   "total_errors": 0,
   "total_lines": 189,
   "total_warnings": 0,
   "used_types": []
}

-- 
Thanks,
Sasha
Re: [PATCH v3] checkpatch: add --json output mode
Posted by Joe Perches 1 month, 3 weeks ago
On Sat, 2026-04-25 at 20:07 -0400, Sasha Levin wrote:
> On Sat, Apr 25, 2026 at 02:52:35PM -0700, Joe Perches wrote:
> On 2026-04-25 13:04, Sasha Levin wrote:
> Add a --json flag to checkpatch.pl that emits structured JSON output,
> > > making results machine-parseable for CI systems, IDE integrations, and
> > > AI-assisted code review tools.
> > []
> > > A separate --json-pretty flag emits the same JSON in a pretty-printed
> > > (indented, multi-line) form for human reading
> > Why not just always use pretty?
> > Would a script care?
> 
> Who's the intended consumer for the --json-pretty?
> 
> I my mind, --json is there to make it easier for tooling to process the output.

Agree, but does the pretty output make it harder for tooling?
Re: [PATCH v3] checkpatch: add --json output mode
Posted by Sasha Levin 1 month, 3 weeks ago
On Sat, Apr 25, 2026 at 06:12:13PM -0700, Joe Perches wrote:
>On Sat, 2026-04-25 at 20:07 -0400, Sasha Levin wrote:
>> On Sat, Apr 25, 2026 at 02:52:35PM -0700, Joe Perches wrote:
>> On 2026-04-25 13:04, Sasha Levin wrote:
>> Add a --json flag to checkpatch.pl that emits structured JSON output,
>> > > making results machine-parseable for CI systems, IDE integrations, and
>> > > AI-assisted code review tools.
>> > []
>> > > A separate --json-pretty flag emits the same JSON in a pretty-printed
>> > > (indented, multi-line) form for human reading
>> > Why not just always use pretty?
>> > Would a script care?
>>
>> Who's the intended consumer for the --json-pretty?
>>
>> I my mind, --json is there to make it easier for tooling to process the output.
>
>Agree, but does the pretty output make it harder for tooling?

For real JSON parsers, no - they handle either form fine.
                                                                                                                                                                           
The one issue is multi-file invocations: --json emits one compact document per
file per line (NDJSON), which lets plain-shell consumers do `while read line;
do ...` or pipe through grep/awk/head. Pretty mode loses that property because
each document spans multiple lines, so consumers need a
streaming JSON parser.

-- 
Thanks,
Sasha