Skip to content

Commit bb48fa4

Browse files
authored
Merge pull request #12437 from 0xc0170/dev_travis_scancode
travis: add PR license check for missing/not-valid license files
2 parents 9205bdf + a0248c1 commit bb48fa4

File tree

2 files changed

+165
-2
lines changed

2 files changed

+165
-2
lines changed

Diff for: .travis.yml

+32-2
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,40 @@ matrix:
5555
- <<: *basic-vm
5656
name: "license check"
5757
env: NAME=licence_check
58+
language: python
59+
python: 3.6.8 # scancode-toolkit v3.1.1 requires v3.6.8
60+
install:
61+
- pip install scancode-toolkit==3.1.1
62+
before_script:
63+
- mkdir -p SCANCODE
64+
# Fetch remaining information needed for branch comparison
65+
- git fetch --all --unshallow --tags
66+
- git fetch origin "${TRAVIS_BRANCH}"
5867
script:
68+
# scancode does not support list of files, only one file or directory
69+
# we use SCANCODE directory for all changed files (their copies with full tree)
70+
- >-
71+
git diff --name-only --diff-filter=d FETCH_HEAD..HEAD \
72+
| ( grep '.\(c\|cpp\|h\|hpp\|py\)$' || true ) \
73+
| ( grep -v '^tools/test/toolchains/api_test.py') \
74+
| while read file; do cp --parents "${file}" SCANCODE; done
75+
- scancode -l --json-pp scancode.json SCANCODE
76+
- python ./tools/test/travis-ci/scancode-evaluate.py -f scancode.json || true
77+
after_success:
78+
- python ./tools/test/travis-ci/scancode-evaluate.py -f scancode.json
79+
- cat scancode-evaluate.log
80+
- retval=$?
5981
- |
60-
! grep --recursive --max-count=100 --ignore-case --exclude .travis.yml \
61-
"gnu general\|gnu lesser\|lesser general\|public license"
82+
if [ $retval == 0 ]; then
83+
echo "License check OK";
84+
else
85+
echo "License check failed, please review license issues found";
86+
COUNT=$(cat scancode-evaluate.log | grep File: | wc -l)
87+
STATUSM="Needs review, ${COUNT} license issues found";
88+
set_status "success" "$STATUSM";
89+
fi
90+
91+
6292
6393
- <<: *basic-vm
6494
name: "include check"

Diff for: tools/test/travis-ci/scancode-evaluate.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
"""
2+
SPDX-License-Identifier: Apache-2.0
3+
4+
Copyright (c) 2020 Arm Limited. All rights reserved.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations
17+
"""
18+
19+
# Asumptions for this script:
20+
# 1. directory_name is scanned directory.
21+
# Files are copied to this directory with full tree. As result, if we find
22+
# license offender, we can have full path (just scrape directory_name). We do this
23+
# magic because scancode allows to scan directories/one file.
24+
# 2. SPDX and license text is a must for all code files
25+
26+
import json
27+
import argparse
28+
import sys
29+
import os.path
30+
import logging
31+
import re
32+
33+
userlog = logging.getLogger("scancode-evaluate")
34+
userlog.setLevel(logging.INFO)
35+
logfile = os.path.join(os.getcwd(), 'scancode-evaluate.log')
36+
log_file_handler = logging.FileHandler(logfile, mode='w')
37+
userlog.addHandler(log_file_handler)
38+
39+
MISSING_LICENSE_TEXT = "Missing license header"
40+
MISSING_PERMISIVE_LICENSE_TEXT = "Non-permissive license"
41+
MISSING_SPDX_TEXT = "Missing SPDX license identifier"
42+
43+
def license_check(directory_name, file):
44+
""" Check licenses in the scancode json file for specified directory
45+
46+
This function does not verify if file exists, should be done prior the call.
47+
48+
Args:
49+
directory_name - where scancode was run, used to scrape this from paths
50+
file - scancode json output file (output from scancode --license --json-pp)
51+
52+
Returns:
53+
0 if nothing found
54+
>0 - count how many license isses found
55+
-1 if any error in file licenses found
56+
"""
57+
58+
offenders = []
59+
try:
60+
# find all licenses in the files, must be licensed and permissive
61+
with open(file, 'r') as scancode_output:
62+
results = json.load(scancode_output)
63+
except ValueError:
64+
userlog.warning("JSON could not be decoded")
65+
return -1
66+
67+
try:
68+
for file in results['files']:
69+
license_offender = {}
70+
license_offender['file'] = file
71+
# ignore directory, not relevant here
72+
if license_offender['file']['type'] == 'directory':
73+
continue
74+
if not license_offender['file']['licenses']:
75+
license_offender['reason'] = MISSING_LICENSE_TEXT
76+
offenders.append(license_offender)
77+
continue
78+
79+
found_spdx = False
80+
for i in range(len(license_offender['file']['licenses'])):
81+
if license_offender['file']['licenses'][i]['category'] != 'Permissive':
82+
license_offender['reason'] = MISSING_PERMISIVE_LICENSE_TEXT
83+
offenders.append(license_offender)
84+
# find SPDX, it shall be one of licenses found
85+
if license_offender['file']['licenses'][i]['matched_rule']['identifier'].find("spdx") != -1:
86+
found_spdx = True
87+
88+
if not found_spdx:
89+
try:
90+
# Issue reported here https://github.com/nexB/scancode-toolkit/issues/1913
91+
# We verify here if SPDX is not really there as SDPX is part of the license text
92+
# scancode has some problems detecting it properly
93+
with open(os.path.join(os.path.abspath(license_offender['file']['path'])), 'r') as spdx_file_check:
94+
filetext = spdx_file_check.read()
95+
matches = re.findall("SPDX-License-Identifier:?", filetext)
96+
if matches:
97+
continue
98+
license_offender['reason'] = MISSING_SPDX_TEXT
99+
offenders.append(license_offender)
100+
except UnicodeDecodeError:
101+
# not valid file for license check
102+
continue
103+
except KeyError:
104+
userlog.warning("Invalid scancode json file")
105+
return -1
106+
107+
if offenders:
108+
userlog.warning("Found files with missing license details, please review and fix")
109+
for offender in offenders:
110+
userlog.warning("File: " + offender['file']['path'][len(directory_name):] + " " + "reason: " + offender['reason'])
111+
return len(offenders)
112+
113+
def parse_args():
114+
parser = argparse.ArgumentParser(
115+
description="License check.")
116+
parser.add_argument('-f', '--file',
117+
help="scancode-toolkit output json file")
118+
parser.add_argument('-d', '--directory_name', default="SCANCODE",
119+
help='Directory name where are files being checked')
120+
return parser.parse_args()
121+
122+
if __name__ == "__main__":
123+
124+
args = parse_args()
125+
if args.file and os.path.isfile(args.file):
126+
count = license_check(args.directory_name, args.file)
127+
if count == 0:
128+
sys.exit(0)
129+
else:
130+
sys.exit(-1)
131+
else:
132+
userlog.warning("Could not find the scancode json file")
133+
sys.exit(-1)

0 commit comments

Comments
 (0)