mirror of https://github.com/apache/druid.git
193 lines
7.6 KiB
Python
Executable File
193 lines
7.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
# contributor license agreements. See the NOTICE file distributed with
|
|
# this work for additional information regarding copyright ownership.
|
|
# The ASF 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.
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
|
|
# this script does some primitive examination of git diff to determine if a test suite needs to be run or not
|
|
|
|
# these jobs should always be run, no matter what
|
|
always_run_jobs = ['license checks', '(openjdk17) packaging check']
|
|
|
|
# ignore changes to these files completely since they don't impact CI, if the changes are only to these files then all
|
|
# of CI can be skipped. however, jobs which are always run will still be run even if only these files are changed
|
|
ignore_prefixes = ['.github', '.idea', '.asf.yaml', '.backportrc.json', '.codecov.yml', '.dockerignore', '.gitignore',
|
|
'.lgtm.yml', 'CONTRIBUTING.md', 'setup-hooks.sh', 'upload.sh', 'dev', 'distribution/docker',
|
|
'distribution/asf-release-process-guide.md',
|
|
'owasp-dependency-check-suppressions.xml', 'licenses']
|
|
|
|
script_prefixes = ['check_test_suite.py', 'check_test_suite_test.py']
|
|
script_job = ['script checks']
|
|
|
|
# these files are docs changes
|
|
# if changes are limited to this set then we can skip web-console and java
|
|
# if no changes in this set we can skip docs
|
|
docs_prefixes = ['docs/', 'website/']
|
|
# travis docs job name
|
|
docs_jobs = ['docs']
|
|
# these files are web-console changes
|
|
# if changes are limited to this set then we can skip docs and java
|
|
# if no changes in this set we can skip web-console
|
|
web_console_prefixes = ['web-console/']
|
|
# travis web-console job name
|
|
web_console_jobs = ['web console', 'web console end-to-end test']
|
|
web_console_still_run_for_java_jobs = ['web console end-to-end test']
|
|
|
|
|
|
def check_ignore(file):
|
|
is_always_ignore = True in (file.startswith(prefix) for prefix in ignore_prefixes)
|
|
if is_always_ignore:
|
|
print("found ignorable file change: {}".format(file))
|
|
return is_always_ignore
|
|
|
|
def check_testable_script(file):
|
|
is_script = True in (file.startswith(prefix) for prefix in script_prefixes)
|
|
if is_script:
|
|
print("found script file change: {}".format(file))
|
|
return is_script
|
|
|
|
def check_docs(file):
|
|
is_docs = True in (file.startswith(prefix) for prefix in docs_prefixes)
|
|
if is_docs:
|
|
print("found docs file change: {}".format(file))
|
|
return is_docs
|
|
|
|
|
|
def check_console(file):
|
|
is_console = True in (file.startswith(prefix) for prefix in web_console_prefixes)
|
|
if is_console:
|
|
print("found web-console file change: {}".format(file))
|
|
return is_console
|
|
|
|
|
|
def check_should_run_suite(suite, diff_files):
|
|
"""
|
|
try to determine if a test suite should run or not given a set files in a diff
|
|
|
|
:param suite: travis job name
|
|
:param diff_files: files changed in git diff
|
|
:return: True if the supplied suite needs to run, False otherwise
|
|
"""
|
|
|
|
if suite in always_run_jobs:
|
|
# you gotta do what you gotta do
|
|
return True
|
|
|
|
all_ignore = True
|
|
any_docs = False
|
|
all_docs = True
|
|
any_console = False
|
|
all_console = True
|
|
any_java = False
|
|
any_testable_script = False
|
|
all_testable_script = True
|
|
|
|
# go over all of the files in the diff and collect some information about the diff contents, we'll use this later
|
|
# to decide whether or not to run the suite
|
|
for f in diff_files:
|
|
is_ignore = check_ignore(f)
|
|
all_ignore = all_ignore and is_ignore
|
|
is_docs = check_docs(f)
|
|
any_docs = any_docs or is_docs
|
|
all_docs = all_docs and is_docs
|
|
is_console = check_console(f)
|
|
any_console = any_console or is_console
|
|
all_console = all_console and is_console
|
|
is_script = check_testable_script(f)
|
|
any_testable_script = any_testable_script or is_script
|
|
all_testable_script = all_testable_script and is_script
|
|
any_java = any_java or (not is_ignore and not is_docs and not is_console and not is_script)
|
|
|
|
# if everything is ignorable, we can skip this suite
|
|
if all_ignore:
|
|
return False
|
|
# if the test suite is a doc job, return true if any of the files changed were docs
|
|
if suite in docs_jobs:
|
|
return any_docs
|
|
# if all of the changes are docs paths, but the current suite is not a docs job, we can skip
|
|
if all_docs:
|
|
return False
|
|
if suite in web_console_still_run_for_java_jobs:
|
|
return any_console or any_java
|
|
# if the test suite is a web console job, return true if any of the changes are web console files
|
|
if suite in web_console_jobs:
|
|
return any_console
|
|
# if all of the changes are web console paths, but the current suite is not a web console job, we can skip
|
|
if all_console:
|
|
return False
|
|
if suite in script_job:
|
|
return any_testable_script
|
|
if all_testable_script:
|
|
return False
|
|
|
|
# if all of the files belong to known non-java groups, we can also skip java
|
|
# note that this should probably be reworked to much more selectively run the java jobs depending on the diff
|
|
if not any_java:
|
|
return False
|
|
|
|
# we don't know we can skip for sure, so lets run it
|
|
return True
|
|
|
|
|
|
def failWithUsage():
|
|
sys.stderr.write("usage: check_test_suite.py <test-suite-name>\n")
|
|
sys.stderr.write(" e.g., check_test_suite.py docs")
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
suite_name = ""
|
|
|
|
# when run by travis, we run this script without arguments, so collect the test suite name from environment
|
|
# variables. if it doesn't exist, fail
|
|
if len(sys.argv) == 1:
|
|
if 'TRAVIS_JOB_NAME' in os.environ:
|
|
suite_name = os.environ['TRAVIS_JOB_NAME']
|
|
else:
|
|
failWithUsage()
|
|
elif len(sys.argv) == 2:
|
|
# to help with testing, can explicitly pass a test suite name
|
|
suite_name = sys.argv[1]
|
|
else:
|
|
failWithUsage()
|
|
|
|
# we only selectively run CI for PR builds, branch builds such as master and releases will always run all suites
|
|
is_pr = False
|
|
if 'TRAVIS_PULL_REQUEST' in os.environ and os.environ['TRAVIS_PULL_REQUEST'] != 'false':
|
|
is_pr = True
|
|
|
|
if not is_pr:
|
|
print("Not a pull request build, need to run all test suites")
|
|
sys.exit(1)
|
|
|
|
# this looks like it only gets the last commit, but the way travis PR builds work this actually gets the complete
|
|
# diff (since all commits from the PR are rebased onto the target branch and added as a single commit)
|
|
all_changed_files_string = subprocess.check_output("git diff --name-only HEAD~1", shell=True).decode('UTF-8')
|
|
all_changed_files = all_changed_files_string.splitlines()
|
|
print("Checking if suite '{}' needs to run test on diff:\n{}".format(suite_name, all_changed_files_string))
|
|
|
|
# we should always run all test suites for builds that are not for a pull request
|
|
needs_run = check_should_run_suite(suite_name, all_changed_files)
|
|
|
|
if needs_run:
|
|
print("Changes detected, need to run test suite '{}'".format(suite_name))
|
|
sys.exit(1)
|
|
|
|
print("No applicable changes detected, can skip test suite '{}'".format(suite_name))
|
|
sys.exit(0)
|