diff --git a/Jenkinsfile b/Jenkinsfile index d9f9f21..e353334 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -106,4 +106,4 @@ spec: } } } -} \ No newline at end of file +} diff --git a/Makefile b/Makefile index 74e0d69..5d17398 100644 --- a/Makefile +++ b/Makefile @@ -71,4 +71,4 @@ check_trailing_whitespace: .PHONY: check_headers check_headers: @echo "Checking file headers" - @python test/verify_boilerplate.py + @python3.7 test/verify_boilerplate.py diff --git a/test/boilerplate/boilerplate.BUILD.txt b/test/boilerplate/boilerplate.BUILD.txt new file mode 100644 index 0000000..b0c7da3 --- /dev/null +++ b/test/boilerplate/boilerplate.BUILD.txt @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/boilerplate/boilerplate.WORKSPACE.txt b/test/boilerplate/boilerplate.WORKSPACE.txt new file mode 100644 index 0000000..b0c7da3 --- /dev/null +++ b/test/boilerplate/boilerplate.WORKSPACE.txt @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/boilerplate/boilerplate.bazel.txt b/test/boilerplate/boilerplate.bazel.txt new file mode 100644 index 0000000..b0c7da3 --- /dev/null +++ b/test/boilerplate/boilerplate.bazel.txt @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/boilerplate/boilerplate.bzl.txt b/test/boilerplate/boilerplate.bzl.txt new file mode 100644 index 0000000..b0c7da3 --- /dev/null +++ b/test/boilerplate/boilerplate.bzl.txt @@ -0,0 +1,13 @@ +# Copyright 2018 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. diff --git a/test/boilerplate/boilerplate.css.txt b/test/boilerplate/boilerplate.css.txt new file mode 100644 index 0000000..9275aed --- /dev/null +++ b/test/boilerplate/boilerplate.css.txt @@ -0,0 +1,13 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/test/boilerplate/boilerplate.go.preamble b/test/boilerplate/boilerplate.go.preamble new file mode 100644 index 0000000..a417fec --- /dev/null +++ b/test/boilerplate/boilerplate.go.preamble @@ -0,0 +1 @@ +// +build diff --git a/test/boilerplate/boilerplate.html.preamble b/test/boilerplate/boilerplate.html.preamble new file mode 100644 index 0000000..f360152 --- /dev/null +++ b/test/boilerplate/boilerplate.html.preamble @@ -0,0 +1 @@ + diff --git a/test/boilerplate/boilerplate.java.txt b/test/boilerplate/boilerplate.java.txt new file mode 100644 index 0000000..9275aed --- /dev/null +++ b/test/boilerplate/boilerplate.java.txt @@ -0,0 +1,13 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/test/boilerplate/boilerplate.js.txt b/test/boilerplate/boilerplate.js.txt new file mode 100644 index 0000000..9275aed --- /dev/null +++ b/test/boilerplate/boilerplate.js.txt @@ -0,0 +1,13 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/test/boilerplate/boilerplate.py.preamble b/test/boilerplate/boilerplate.py.preamble new file mode 100644 index 0000000..7218afe --- /dev/null +++ b/test/boilerplate/boilerplate.py.preamble @@ -0,0 +1 @@ +#! diff --git a/test/boilerplate/boilerplate.scss.txt b/test/boilerplate/boilerplate.scss.txt new file mode 100644 index 0000000..9275aed --- /dev/null +++ b/test/boilerplate/boilerplate.scss.txt @@ -0,0 +1,13 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/test/boilerplate/boilerplate.sh.preamble b/test/boilerplate/boilerplate.sh.preamble new file mode 100644 index 0000000..7218afe --- /dev/null +++ b/test/boilerplate/boilerplate.sh.preamble @@ -0,0 +1 @@ +#! diff --git a/test/boilerplate/boilerplate.ts.txt b/test/boilerplate/boilerplate.ts.txt new file mode 100644 index 0000000..9275aed --- /dev/null +++ b/test/boilerplate/boilerplate.ts.txt @@ -0,0 +1,13 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. diff --git a/test/boilerplate/boilerplate.xml.preamble b/test/boilerplate/boilerplate.xml.preamble new file mode 100644 index 0000000..b2f4ead --- /dev/null +++ b/test/boilerplate/boilerplate.xml.preamble @@ -0,0 +1 @@ + len(data): return False - # trim our file to the same number of lines as the reference file + # truncate our file to the same number of lines as the reference file data = data[:len(ref)] - year = regexs["year"] - for datum in data: - if year.search(datum): - return False # if we don't match the reference at this point, fail if ref != data: return False - return True + return True -def get_file_extension(filename): - """Extracts the extension part of a filename. +def get_file_parts(filename): + """Extracts the basename and extension parts of a filename. Identifies the extension as everything after the last period in filename. - Args: filename: string containing the filename - Returns: - A string containing the extension in lowercase + A tuple of: + A string containing the basename + A string containing the extension in lowercase """ - return os.path.splitext(filename)[1].split(".")[-1].lower() - - -# These directories will be omitted from header checks -SKIPPED_DIRS = [ - 'Godeps', 'third_party', '_gopath', '_output', - '.git', 'vendor', '__init__.py', 'node_modules' -] + extension = os.path.splitext(filename)[1].split(".")[-1].lower() + basename = os.path.basename(filename) + return basename, extension -def normalize_files(files): +def normalize_files(files, args): """Extracts the files that require boilerplate checking from the files argument. - A new list will be built. Each path from the original files argument will be added unless it is within one of SKIPPED_DIRS. All relative paths will be converted to absolute paths by prepending the root_dir path parsed from the command line, or its default value. - Args: files: a list of file path strings - Returns: A modified copy of the files list where any any path in a skipped directory is removed, and all paths have been made absolute. """ - newfiles = [] - for pathname in files: - if any(x in pathname for x in SKIPPED_DIRS): - continue - newfiles.append(pathname) + newfiles = [f for f in files if not any(s in f for s in SKIPPED_PATHS)] + for idx, pathname in enumerate(newfiles): if not os.path.isabs(pathname): - newfiles[idx] = os.path.join(ARGS.rootdir, pathname) + newfiles[idx] = os.path.join(args.rootdir, pathname) return newfiles -def get_files(extensions, ARGS): +def get_files(extensions, args): """Generates a list of paths whose boilerplate should be verified. - If a list of file names has been provided on the command line, it will be treated as the initial set to search. Otherwise, all paths within rootdir will be discovered and used as the initial set. - Once the initial set of files is identified, it is normalized via normalize_files() and further stripped of any file name whose extension is not in extensions. - Args: extensions: a list of file extensions indicating which file types should have their boilerplate verified - Returns: A list of absolute file paths """ files = [] - if ARGS.filenames: - files = ARGS.filenames + if args.filenames: + files = args.filenames else: - for root, dirs, walkfiles in os.walk(ARGS.rootdir): + for root, dirs, walkfiles in os.walk(args.rootdir): # don't visit certain dirs. This is just a performance improvement # as we would prune these later in normalize_files(). But doing it # cuts down the amount of filesystem walking we do and cuts down # the size of the file list - for dpath in SKIPPED_DIRS: + for dpath in SKIPPED_PATHS: if dpath in dirs: dirs.remove(dpath) for name in walkfiles: pathname = os.path.join(root, name) files.append(pathname) - files = normalize_files(files) + files = normalize_files(files, args) outfiles = [] for pathname in files: - basename = os.path.basename(pathname) - extension = get_file_extension(pathname) - if extension in extensions or basename in extensions: + basename, extension = get_file_parts(pathname) + extension_present = extension in extensions or basename in extensions + if args.force_extension or extension_present: outfiles.append(pathname) return outfiles -def get_regexs(): - """Builds a map of regular expressions used in boilerplate validation. - - There are two scenarios where these regexes are used. The first is in - validating the date referenced is the boilerplate, by ensuring it is an - acceptable year. The second is in identifying non-boilerplate elements, - like shebangs and compiler hints that should be ignored when validating - headers. - - Returns: - A map of compiled regular expression objects, keyed by mnemonic. - """ - regexs = {} - # Search for "YEAR" which exists in the boilerplate, but shouldn't in the - # real thing - regexs["year"] = re.compile('YEAR') - # dates can be 2014, 2015, 2016 or 2017, company holder names can be - # anything - regexs["date"] = re.compile('(2014|2015|2016|2017|2018)') - # strip // +build \n\n build constraints - regexs["go_build_constraints"] = re.compile(r"^(// \+build.*\n)+\n", - re.MULTILINE) - # strip #!.* from shell/python scripts - regexs["shebang"] = re.compile(r"^(#!.*\n)\n*", re.MULTILINE) - return regexs - - def main(args): """Identifies and verifies files that should have the desired boilerplate. - Retrieves the lists of files to be validated and tests each one in turn. If all files contain correct boilerplate, this function terminates normally. Otherwise it prints the name of each non-conforming file and exists with a non-zero status code. """ - regexs = get_regexs() - refs = get_refs(args) + refs = get_references(args) + preambles = get_preambles(args) filenames = get_files(refs.keys(), args) nonconforming_files = [] for filename in filenames: - if not has_valid_header(filename, refs, regexs): + if not has_valid_header(filename, refs, preambles, REGEXES, args): nonconforming_files.append(filename) if nonconforming_files: print('%d files have incorrect boilerplate headers:' % len( @@ -272,6 +306,8 @@ def main(args): for filename in sorted(nonconforming_files): print(os.path.relpath(filename, args.rootdir)) sys.exit(1) + else: + print('All files examined have correct boilerplate.') if __name__ == "__main__":