From 81865828a275ba384bc96fe10493cb1f7ee03f91 Mon Sep 17 00:00:00 2001 From: Titus Fortner Date: Mon, 29 Jan 2024 10:00:22 -0500 Subject: [PATCH] [build] move copyright from rake task to a bazel target (#13512) * [build] move copyright from rake task to a bazel target * [ci] add copyright check to linter --- Rakefile | 34 ----------- rake_tasks/copyright.rb | 89 ----------------------------- scripts/BUILD.bazel | 5 ++ scripts/format.sh | 3 + scripts/update_copyright.py | 111 ++++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 123 deletions(-) delete mode 100644 rake_tasks/copyright.rb create mode 100755 scripts/update_copyright.py diff --git a/Rakefile b/Rakefile index 0ca5ee746621e..9c4d1f2d4b16e 100644 --- a/Rakefile +++ b/Rakefile @@ -45,7 +45,6 @@ require 'rake_tasks/bazel/task' # These are the final items mixed into the global NS # These need moving into correct namespaces, and not be globally included require 'rake_tasks/bazel' -require 'rake_tasks/copyright' require 'rake_tasks/python' $DEBUG = orig_verbose != Rake::FileUtilsExt::DEFAULT @@ -440,39 +439,6 @@ task :authors do sh "(git log --use-mailmap --format='%aN <%aE>' ; cat .OLD_AUTHORS) | sort -uf > AUTHORS" end -namespace :copyright do - desc 'Update Copyright notices on all files in repo' - task :update do - Copyright.new.update( - FileList['javascript/**/*.js'].exclude( - 'javascript/atoms/test/jquery.min.js', - 'javascript/jsunit/**/*.js', - 'javascript/node/selenium-webdriver/node_modules/**/*.js', - 'javascript/selenium-core/lib/**/*.js', - 'javascript/selenium-core/scripts/ui-element.js', - 'javascript/selenium-core/scripts/ui-map-sample.js', - 'javascript/selenium-core/scripts/user-extensions.js', - 'javascript/selenium-core/scripts/xmlextras.js', - 'javascript/selenium-core/xpath/**/*.js', - 'javascript/grid-ui/node_modules/**/*.js' - ) - ) - Copyright.new.update(FileList['javascript/**/*.tsx']) - Copyright.new(comment_characters: '#').update(FileList['py/**/*.py'].exclude( - 'py/selenium/webdriver/common/bidi/cdp.py', - 'py/generate.py', - 'py/selenium/webdriver/common/devtools/**/*', - 'py/venv/**/*' - )) - Copyright.new(comment_characters: '#', prefix: ["# frozen_string_literal: true\n", "\n"]) - .update(FileList['rb/**/*.rb']) - Copyright.new.update(FileList['java/**/*.java']) - Copyright.new.update(FileList['rust/**/*.rs']) - - sh './scripts/format.sh' - end -end - namespace :side do task atoms: [ '//javascript/atoms/fragments:find-element' diff --git a/rake_tasks/copyright.rb b/rake_tasks/copyright.rb deleted file mode 100644 index 10b1aeab6c1f5..0000000000000 --- a/rake_tasks/copyright.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -class Copyright - def initialize(comment_characters: '//', prefix: nil) - @comment_characters = comment_characters - @prefix = prefix - end - - def update(files) - files.each do |file| - lines = IO.readlines(file) - - index = -1 - lines.any? do |line| - done = true - if starts_with_comment_character?(line) || valid_copyright_notice_line?(line, index) - index += 1 - done = false - end - done - end - - if index == -1 - write_update_notice(file, lines, copyright_notice) - else - current = lines.shift(index + 1).join('') - if current != copyright_notice - write_update_notice(file, lines, copyright_notice) - end - end - end - end - - def starts_with_comment_character?(line) - line.index(@comment_characters)&.zero? - end - - def valid_copyright_notice_line?(line, index) - copyright_notice_lines[index + 1] && - line.index(copyright_notice_lines[index + 1])&.zero? - end - - def copyright_notice - copyright_notice_lines.join('') - end - - def copyright_notice_lines - @copyright_notice_lines ||= Array(@prefix) + commented_notice_lines - end - - def commented_notice_lines - notice_lines.map do |line| - "#{@comment_characters} #{line}".rstrip + "\n" - end - end - - def notice_lines - notice.split(/\n/) - end - - def write_update_notice(file, lines, notice) - puts "Adding notice to #{file}" - File.open(file, 'w') do |f| - f.write(notice + "\n") - lines.each { |line| f.write(line) } - end - end - - def notice - <<~eos - Licensed to the Software Freedom Conservancy (SFC) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The SFC licenses this file - to you 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 - - http://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. - eos - end -end diff --git a/scripts/BUILD.bazel b/scripts/BUILD.bazel index 2fb476346ffd1..1e038be4e52c8 100644 --- a/scripts/BUILD.bazel +++ b/scripts/BUILD.bazel @@ -27,6 +27,11 @@ py_binary( ], ) +py_binary( + name = "update_copyright", + srcs = ["update_copyright.py"], +) + java_binary( name = "google-java-format", jvm_flags = [ diff --git a/scripts/format.sh b/scripts/format.sh index 6800b0eb18279..0f632a340f4f9 100755 --- a/scripts/format.sh +++ b/scripts/format.sh @@ -19,3 +19,6 @@ find "$PWD/java" -type f -name '*.java' | xargs "$GOOGLE_JAVA_FORMAT" --replace section "Rust" echo " rustfmt" >&2 bazel run @rules_rust//:rustfmt + +section "Copyright" +bazel run //scripts:update_copyright diff --git a/scripts/update_copyright.py b/scripts/update_copyright.py new file mode 100755 index 0000000000000..9ca241b65789b --- /dev/null +++ b/scripts/update_copyright.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python + +import glob +import os +from pathlib import Path + +class Copyright: + NOTICE = """Licensed to the Software Freedom Conservancy (SFC) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The SFC licenses this file +to you 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 + + http://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.""" + + def __init__(self, comment_characters='//', prefix=None): + self._comment_characters = comment_characters + self._prefix = prefix or [] + + def update(self, files): + for file in files: + with open(file, 'r') as f: + lines = f.readlines() + + index = -1 + for i, line in enumerate(lines): + if line.startswith(self._comment_characters) or \ + self.valid_copyright_notice_line(line, index): + index += 1 + else: + break + + if index == -1: + self.write_update_notice(file, lines) + else: + current = ''.join(lines[:index + 1]) + if current != self.copyright_notice: + self.write_update_notice(file, lines[index + 1:]) + + def valid_copyright_notice_line(self, line, index): + return index + 1 < len(self.copyright_notice_lines) and \ + line.startswith(self.copyright_notice_lines[index + 1]) + + @property + def copyright_notice(self): + return ''.join(self.copyright_notice_lines) + + @property + def copyright_notice_lines(self): + return self._prefix + self.commented_notice_lines + + @property + def commented_notice_lines(self): + return [f"{self._comment_characters} {line}".rstrip() + "\n" for line in self.NOTICE.split('\n')] + + def write_update_notice(self, file, lines): + print(f"Adding notice to {file}") + with open(file, 'w') as f: + f.write(self.copyright_notice + "\n") + f.writelines(lines) + +ROOT = Path(os.path.realpath(__file__)).parent.parent + +JS_EXCLUSIONS = [ + f"{ROOT}/javascript/atoms/test/jquery.min.js", + f"{ROOT}/javascript/jsunit/**/*.js", + f"{ROOT}/javascript/node/selenium-webdriver/node_modules/**/*.js", + f"{ROOT}/javascript/selenium-core/lib/**/*.js", + f"{ROOT}/javascript/selenium-core/scripts/ui-element.js", + f"{ROOT}/javascript/selenium-core/scripts/ui-map-sample.js", + f"{ROOT}/javascript/selenium-core/scripts/user-extensions.js", + f"{ROOT}/javascript/selenium-core/scripts/xmlextras.js", + f"{ROOT}/javascript/selenium-core/xpath/**/*.js", + f"{ROOT}/javascript/grid-ui/node_modules/**/*.js" +] + +PY_EXCLUSIONS = [ + f"{ROOT}/py/selenium/webdriver/common/bidi/cdp.py", + f"{ROOT}/py/generate.py", + f"{ROOT}/py/selenium/webdriver/common/devtools/**/*", + f"{ROOT}/py/venv/**/*" +] + + +def update_files(file_pattern, exclusions, comment_characters='//', prefix=None): + included = set(glob.glob(file_pattern, recursive=True)) + excluded = set() + for pattern in exclusions: + excluded.update(glob.glob(pattern, recursive=True)) + files = included - excluded + + copyright = Copyright(comment_characters, prefix) + copyright.update(files) + + +if __name__ == "__main__": + update_files(f"{ROOT}/javascript/**/*.js", JS_EXCLUSIONS) + update_files(f"{ROOT}/javascript/**/*.tsx", []) + update_files(f"{ROOT}/py/**/*.py", PY_EXCLUSIONS, comment_characters="#") + update_files(f"{ROOT}/rb/**/*.rb", [], comment_characters="#", prefix=["# frozen_string_literal: true\n", "\n"]) + update_files(f"{ROOT}/java/**/*.java", []) + update_files(f"{ROOT}/rust/**/*.rs", [])