Skip to content

Commit

Permalink
feat: Basic copyright script and CI integration
Browse files Browse the repository at this point in the history
This PR adds a script to do basic copyright notice checks, and will be used
to add the necessary features in issue #7690.  It reads the list of files
from stdin or argv[], and exits with a useful return status. Use the -h
flag for a terse summary.

This PR also creates a copyright CI workflow
  • Loading branch information
richsalz committed Nov 3, 2024
1 parent 1b4f481 commit 9cf68db
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/check-copyright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright The IETF Trust 2024. All Rights Reserved.
name: Copyright years
on: [pull_request, push]
permissions:
contents: read

jobs:
copyright-notice:
runs-on: ubuntu-latest
name: Test changed-files
steps:
- name: Get changed files
id: changed-files
uses: tj-actions/changed-files@v44
- uses: actions/checkout@v4
- name: Check changed files
env:
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
run: perl ./ietf/check-copyright -lv -f ${ALL_CHANGED_FILES};
141 changes: 141 additions & 0 deletions ietf/check-copyright
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/env perl
# Copyright The IETF Trust 2024. All Rights Reserved.

use strict;
use warnings;
use POSIX qw/strftime/;
use Getopt::Std;

# Number of errors found; exit status
my $ERRORS = 0;

# Convenience variables, for the copyright year regexp patterns.
my $this_year = strftime("%Y", localtime);
my $some_year = "[12][0-9][0-9][0-9]";
my $year_range = "(${some_year})(-${some_year})?";
my $copyright = "Copyright The IETF Trust *${year_range}";

# Things to skip
my @skiplist = (
"\.zip",
"vzic/",
"patches/",
"\.gitignore",
"\.json"
);

# Getopt settings.
our($opt_h, $opt_f, $opt_v, $opt_c, $opt_l, $opt_m);

sub
usage()
{
my $retcode = pop();

print STDERR "Options:\n";
print STDERR " -h This help message\n";
print STDERR " -f Read filenames from argv\n";
print STDERR " -v List files as processed\n";
print STDERR " -c Modify files that should be changed\n";
print STDERR " (Does not do a git commit)\n";
print STDERR " -l List files that need to be changed\n";
print STDERR " -m List files missing copyright\n";
exit $retcode;
}


## Get list of files changed during this year.
sub
collect_files
{
# Get last commit of the of the previous year/
my $FIRST=`git rev-list -1 --before=$this_year-01-01 HEAD`;
chop $FIRST;

# Get every file changed since then, ignoring deleted files.
open(my $FH, "-|", "git diff-tree -r --name-status $FIRST..HEAD")
|| die "Can't open diff-tree, $!";
my @FILES = ();
my @FIELDS;
while ( <$FH> ) {
@FIELDS = split();
next if $FIELDS[0] =~ /D/; # ignore deleted files
push(@FILES, $FIELDS[1]);
}
close($FH) || die "Can't close diff-tree";
return @FILES;
}

## Process file, notice if copyright is missing or outdated.
sub
process()
{
my $NAME = pop();
my $NEW = "";
my $found = 0;
my $changed = 0;
my $SAVE;

print "# Processing $NAME\n" if defined $opt_v;

# ignore ZIP files
foreach my $pat ( @skiplist ) {
return if $NAME =~ /$pat/;
}

# Read the file, copying to $NEW and changing copyright
# along the way.
open my $FH, '<', $NAME || die "Can't open $NAME, $!";
while ( <$FH> ) {
$SAVE = $_;
if ( /$copyright/io ) {
$found = 1;
$SAVE =~ s|${year_range}|$1-${this_year}|;
$SAVE =~ s|(${some_year})-$1|$1|;
$changed = 1 if $SAVE ne $_;
}
$NEW .= $SAVE;
}
close($FH) || die "Can't close $NAME, $!";

# Copyright missing?
if ( defined $opt_m ) {
print "$NAME\n" if ! $found;
$ERRORS++;
return;
}

# Unchanged file?
return if ! $changed;

if ( defined $opt_l ) {
print "$NAME\n";
$ERRORS++;
} else {
# Write the new file
open my $FH, '>', $NAME || die "Can't close-write $NAME, $!";
print $FH $NEW;
close($FH) || die "Can't close-write $NAME, $!";
}
}

## Parse JCL.
getopts('hfvclm') || &usage(1);
&usage(0) if $opt_h;
if ( defined($opt_m) + defined($opt_l) + defined($opt_c) != 1 ) {
print STDERR "Must have exactly one of m/l/c options\n";
exit 1;
}

## Do the work.
my @FILES = ();
if ( defined($opt_f) ) {
@FILES = @ARGV;
} else {
@FILES = &collect_files();
}

foreach my $F ( @FILES ) {
&process($F);
}
exit $ERRORS;

0 comments on commit 9cf68db

Please sign in to comment.