SPDX support for checkpatch

* Mandate use of SPDX-License-Identifier in new files
 * Validate SPDX license choices
 * Forbid other SPDX tags
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmfB2bYACgkQvobrtBUQ
 T9/XMhAAmfGQpHmr5cMBFkJwcSO7CnmggK+UM+BYP/2Zv6LdzdT3G1n9PzGuvPuv
 bXA2iYzFzZbD3uFYUi1MDHkQPvCY0skGZTIw6FPFv83a9aFTpM571L2wtpcPpBf/
 F+Fa6Thb//rgzB0eUSY+ZE7BVIyqB6Lpgq6eclePF+Q8hpv9e6/pW5LxwK4eYPev
 ELzIdOUUVkTH4PkBKL/HJGpCG4YUP6ORXSCJylU3s74OudjhLX5CXf3hGRbgXLpK
 t3jyl14CipZPtvNOAxW3AvzjkvqEWb4+ZxHGXJCypCscKOrM/SG0m1HpUOrLx2z3
 O9liRSl3yenSmN8gXghPhS346+jLMihocvD6NFJNzJLYq+JgIq3xPM2U3b3AXIUn
 TUaVE92vp90YusCyu/J+4iyMu7gwir7pLSAzKudmRQJLbA8Uxiq6GeQmCPV+Rj65
 eq6YAcxQeH+sgZud5I3fJ1tiupAsbzha+T+kCyEos3vE7qof+a1W9NhnhGGfZd/y
 lsukf/wT9ukX7aw61geiVdGDrwLtMbcfA7fRyLxI5WZkH6qFW+WMX2bpZaEOv0wb
 z+MH21cr0e56hbRwh7PdxwYrXW/sorvyi4sZgTh79ch8O3Hed9pBa2K2VkDJ4LKU
 joqc0vXwKJXbDZe0KLzD0LnajfiJnduCOsZgP5e93PndjL1fHzg=
 =eGL+
 -----END PGP SIGNATURE-----

Merge tag 'spdx-check-pull-request' of https://gitlab.com/berrange/qemu into staging

SPDX support for checkpatch

* Mandate use of SPDX-License-Identifier in new files
* Validate SPDX license choices
* Forbid other SPDX tags

# -----BEGIN PGP SIGNATURE-----
#
# iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmfB2bYACgkQvobrtBUQ
# T9/XMhAAmfGQpHmr5cMBFkJwcSO7CnmggK+UM+BYP/2Zv6LdzdT3G1n9PzGuvPuv
# bXA2iYzFzZbD3uFYUi1MDHkQPvCY0skGZTIw6FPFv83a9aFTpM571L2wtpcPpBf/
# F+Fa6Thb//rgzB0eUSY+ZE7BVIyqB6Lpgq6eclePF+Q8hpv9e6/pW5LxwK4eYPev
# ELzIdOUUVkTH4PkBKL/HJGpCG4YUP6ORXSCJylU3s74OudjhLX5CXf3hGRbgXLpK
# t3jyl14CipZPtvNOAxW3AvzjkvqEWb4+ZxHGXJCypCscKOrM/SG0m1HpUOrLx2z3
# O9liRSl3yenSmN8gXghPhS346+jLMihocvD6NFJNzJLYq+JgIq3xPM2U3b3AXIUn
# TUaVE92vp90YusCyu/J+4iyMu7gwir7pLSAzKudmRQJLbA8Uxiq6GeQmCPV+Rj65
# eq6YAcxQeH+sgZud5I3fJ1tiupAsbzha+T+kCyEos3vE7qof+a1W9NhnhGGfZd/y
# lsukf/wT9ukX7aw61geiVdGDrwLtMbcfA7fRyLxI5WZkH6qFW+WMX2bpZaEOv0wb
# z+MH21cr0e56hbRwh7PdxwYrXW/sorvyi4sZgTh79ch8O3Hed9pBa2K2VkDJ4LKU
# joqc0vXwKJXbDZe0KLzD0LnajfiJnduCOsZgP5e93PndjL1fHzg=
# =eGL+
# -----END PGP SIGNATURE-----
# gpg: Signature made Fri 28 Feb 2025 23:43:50 HKT
# gpg:                using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF
# gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full]
# gpg:                 aka "Daniel P. Berrange <berrange@redhat.com>" [full]
# Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E  8E3F BE86 EBB4 1510 4FDF

* tag 'spdx-check-pull-request' of https://gitlab.com/berrange/qemu:
  scripts: forbid use of arbitrary SPDX tags besides license identifiers
  scripts: validate SPDX license choices
  scripts: mandate that new files have SPDX-License-Identifier

Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
Stefan Hajnoczi 2025-03-03 10:21:09 +08:00
commit 354925d422

View File

@ -1353,6 +1353,70 @@ sub checkfilename {
}
}
sub checkspdx {
my ($file, $expr) = @_;
# Imported Linux headers probably have SPDX tags, but if they
# don't we're not requiring contributors to fix this, as these
# files are not expected to be modified locally in QEMU.
# Also don't accidentally detect own checking code.
if ($file =~ m,include/standard-headers, ||
$file =~ m,linux-headers, ||
$file =~ m,checkpatch.pl,) {
return;
}
my $origexpr = $expr;
# Flatten sub-expressions
$expr =~ s/\(|\)/ /g;
$expr =~ s/OR|AND/ /g;
# Merge WITH exceptions to the license
$expr =~ s/\s+WITH\s+/-WITH-/g;
# Cull more leading/trailing whitespace
$expr =~ s/^\s*//g;
$expr =~ s/\s*$//g;
my @bits = split / +/, $expr;
my $prefer = "GPL-2.0-or-later";
my @valid = qw(
GPL-2.0-only
LGPL-2.1-only
LGPL-2.1-or-later
BSD-2-Clause
BSD-3-Clause
MIT
);
my $nonpreferred = 0;
my @unknown = ();
foreach my $bit (@bits) {
if ($bit eq $prefer) {
next;
}
if (grep /^$bit$/, @valid) {
$nonpreferred = 1;
} else {
push @unknown, $bit;
}
}
if (@unknown) {
ERROR("Saw unacceptable licenses '" . join(',', @unknown) .
"', valid choices for QEMU are:\n" . join("\n", $prefer, @valid));
}
if ($nonpreferred) {
WARN("Saw acceptable license '$origexpr' but note '$prefer' is " .
"preferred for new files unless the code is derived from a " .
"source file with an existing declared license that must be " .
"retained. Please explain the license choice in the commit " .
"message.");
}
}
sub process {
my $filename = shift;
@ -1378,6 +1442,8 @@ sub process {
my $in_imported_file = 0;
my $in_no_imported_file = 0;
my $non_utf8_charset = 0;
my $expect_spdx = 0;
my $expect_spdx_file;
our @report = ();
our $cnt_lines = 0;
@ -1615,6 +1681,51 @@ sub process {
WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
}
# All new files should have a SPDX-License-Identifier tag
if ($line =~ /^new file mode\s*\d+\s*$/) {
if ($expect_spdx) {
if ($expect_spdx_file =~
/\.(c|h|py|pl|sh|json|inc|Makefile)$/) {
# source code files MUST have SPDX license declared
ERROR("New file '$expect_spdx_file' requires " .
"'SPDX-License-Identifer'");
} else {
# Other files MAY have SPDX license if appropriate
WARNING("Does new file '$expect_spdx_file' need " .
"'SPDX-License-Identifer'?");
}
}
$expect_spdx = 1;
$expect_spdx_file = undef;
} elsif ($expect_spdx) {
$expect_spdx_file = $realfile unless
defined $expect_spdx_file;
# SPDX tags may occurr in comments which were
# stripped from '$line', so use '$rawline'
if ($rawline =~ /SPDX-License-Identifier/) {
$expect_spdx = 0;
$expect_spdx_file = undef;
}
}
# Check SPDX-License-Identifier references a permitted license
if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) {
&checkspdx($realfile, $1);
}
if ($rawline =~ m,(SPDX-[a-zA-Z0-9-_]+):,) {
my $tag = $1;
my @permitted = qw(
SPDX-License-Identifier
);
unless (grep { /^$tag$/ } @permitted) {
ERROR("Tag $tag not permitted in QEMU code, valid " .
"choices are: " . join(", ", @permitted));
}
}
# Check for wrappage within a valid hunk of the file
if ($realcnt != 0 && $line !~ m{^(?:\+|-| |\\ No newline|$)}) {
ERROR("patch seems to be corrupt (line wrapped?)\n" .