diff --git a/Dockerfile b/Dockerfile index 509957f..1830e03 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,5 +4,6 @@ COPY *.sh / COPY *.py / COPY *.ini / COPY gitlint /.gitlint +COPY *.txt / ENTRYPOINT [ "/entrypoint.sh" ] diff --git a/action.yml b/action.yml index 341f640..72ede70 100644 --- a/action.yml +++ b/action.yml @@ -16,6 +16,18 @@ inputs: patchwork_token: description: Patchwork token required: true + config: + description: Configuration file or URL + required: false + default: /config.ini + email_message: + description: Email message file or URL + required: false + default: /default-email-message.txt + user: + description: User ID + required: false + default: 104215 runs: using: 'docker' @@ -26,3 +38,6 @@ runs: GITHUB_TOKEN: ${{ inputs.github_token }} EMAIL_TOKEN: ${{ inputs.email_token }} PATCHWORK_TOKEN: ${{ inputs.patchwork_token }} + CONFIG: ${{ inputs.config }} + EMAIL: ${{ inputs.email_message }} + USER: ${{ inputs.user }} diff --git a/default-email-message.txt b/default-email-message.txt new file mode 100644 index 0000000..d3d6e83 --- /dev/null +++ b/default-email-message.txt @@ -0,0 +1,15 @@ +This is automated email and please do not reply to this email! + +Dear submitter, + +Thank you for submitting the patches to the linux bluetooth mailing list. +This is a CI test results with your patch series: +PW Link:{} + +---Test result--- + +{} + +--- +Regards, +Linux Bluetooth diff --git a/entrypoint.sh b/entrypoint.sh index 9f030be..0464417 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -11,6 +11,9 @@ echo "SHA: $GITHUB_SHA" echo "REF: $GITHUB_REF" echo "HEAD-REF: $GITHUB_HEAD_REF" echo "BASE-REF: $GITHUB_BASE_REF" +echo "CONFIG: $CONFIG" +echo "EMAIL: $EMAIL" +echo "USER: $USER" echo "PWD: $(pwd)" git config --global user.name "$GITHUB_ACTOR" @@ -32,4 +35,4 @@ git clone --depth=1 https://git.kernel.org/pub/scm/libs/ell/ell.git $ELL_PATH PR=${GITHUB_REF#"refs/pull/"} PR=${PR%"/merge"} -/run-ci.py -c /config.ini -p $PR -r $GITHUB_REPOSITORY -s $SRC_PATH -e $ELL_PATH -v +/run-ci.py -c $CONFIG -m $EMAIL -p $PR -r $GITHUB_REPOSITORY -s $SRC_PATH -e $ELL_PATH -v -u $USER diff --git a/run-ci.py b/run-ci.py index 87ff7dc..f88507b 100755 --- a/run-ci.py +++ b/run-ci.py @@ -17,6 +17,8 @@ from github import Github from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText +from urllib.request import urlretrieve + # Globals logger = None @@ -40,24 +42,8 @@ test_suite = {} PW_BASE_URL = "https://patchwork.kernel.org/api/1.1" - -EMAIL_MESSAGE = '''This is automated email and please do not reply to this email! - -Dear submitter, - -Thank you for submitting the patches to the linux bluetooth mailing list. -This is a CI test results with your patch series: -PW Link:{} - ----Test result--- - -{} - ---- -Regards, -Linux Bluetooth - -''' +PW_USER = None +EMAIL_MESSAGE = '' def requests_url(url): """ Helper function to requests WEB API GET with URL """ @@ -154,7 +140,7 @@ def patchwork_post_checks(url, state, target_url, context, description): headers['Authorization'] = f'Token {token}' content = { - 'user': 104215, + 'user': PW_USER, 'state': state, 'target_url': target_url, 'context': context, @@ -248,6 +234,9 @@ def config_submit_pw(config, name): Return True if it is specified and value is "yes" """ + if not config_enable(config, name): + return False + if name in config: if 'submit_pw' in config[name]: if config[name]['submit_pw'] == 'yes': @@ -399,14 +388,16 @@ class CiBase: name = None display_name = None desc = None - enable = True start_time = 0 end_time = 0 - submit_pw = False verdict = Verdict.PENDING output = "" + def __init__(self): + self.enable = config_enable(config, self.name) + self.submit_pw = config_submit_pw(config, self.name) + def success(self): self.end_timer() self.verdict = Verdict.PASS @@ -484,15 +475,15 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - if self.name in config: if 'bin_path' in config[self.name]: self.checkpatch_pl = config[self.name]['bin_path'] logger.debug("checkpatch_pl = %s" % self.checkpatch_pl) + if 'no_signoff' not in config['checkpatch']: + config['checkpatch']['no_signoff'] = False + def run(self): logger.debug("##### Run CheckPatch Test #####") self.start_timer() @@ -512,7 +503,8 @@ def run(self): patch = patchwork_get_patch(str(patch_item["id"])) # Run checkpatch - (output, error) = self.run_checkpatch(patch) + (output, error) = self.run_checkpatch(patch, + no_sob=config['checkpatch']['no_signoff']) # Failed / Warning if error != None: @@ -540,7 +532,7 @@ def run(self): if self.verdict != Verdict.FAIL: self.success() - def run_checkpatch(self, patch): + def run_checkpatch(self, patch, no_sob=False): """ Run checkpatch script with patch from the patchwork. It saves to file first and run checkpatch with the saved patch file. @@ -548,18 +540,23 @@ def run_checkpatch(self, patch): On success, it returns None. On failure, it returns the stderr output string """ + args = [ self.checkpatch_pl, '--no-tree' ] output = None error = None + if no_sob: + args.append('--no-signoff') + # Save the patch content to file filename = os.path.join(src_dir, str(patch['id']) + ".patch") logger.debug("Save patch: %s" % filename) patch_file = patchwork_save_patch(patch, filename) + args.append(patch_file) + try: - output = subprocess.check_output((self.checkpatch_pl, '--no-tree', - patch_file), + output = subprocess.check_output(args, stderr=subprocess.STDOUT, cwd=src_dir) output = output.decode("utf-8") @@ -585,9 +582,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - if self.name in config: if 'config_path' in config[self.name]: self.gitlint_config = config[self.name]['config_path'] @@ -669,9 +663,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, "build") - self.submit_pw = config_submit_pw(config, "build") - def run(self): logger.debug("##### Run Build: Setup ELL #####") self.start_timer() @@ -720,9 +711,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, "build") - self.submit_pw = config_submit_pw(config, "build") - def run(self): logger.debug("##### Run Build: Prep #####") self.start_timer() @@ -756,9 +744,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - def run(self): logger.debug("##### Run Build Test #####") self.start_timer() @@ -796,9 +781,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - def run(self): logger.debug("##### Run Build Make Test #####") self.start_timer() @@ -841,9 +823,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - def run(self): logger.debug("##### Run MakeCheck Test #####") self.start_timer() @@ -886,9 +865,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - def run(self): logger.debug("##### Run MakeCheck w/ Valgrind Test #####") self.start_timer() @@ -948,9 +924,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - def run(self): logger.debug("##### Run Make Distcheck Test #####") self.start_timer() @@ -996,9 +969,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, self.name) - self.submit_pw = config_submit_pw(config, self.name) - def run(self): logger.debug("##### Run Build w/exteranl ell - configure Test #####") self.start_timer() @@ -1037,9 +1007,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, 'build_extell') - self.submit_pw = config_submit_pw(config, 'build_extell') - def run(self): logger.debug("##### Run Build w/exteranl ell - make Test #####") self.start_timer() @@ -1083,9 +1050,6 @@ def config(self): """ logger.debug("Parser configuration") - self.enable = config_enable(config, 'incremental_build') - self.submit_pw = config_submit_pw(config, 'incremental_build') - def run(self): logger.debug("##### Run Incremental Build Test #####") self.start_timer() @@ -1108,6 +1072,8 @@ def run(self): # If there is only one patch, no need to run and just return success if github_pr.commits == 1: logger.debug("Only 1 patch and no need to run here") + self.submit_result(pw_series_patch_1, Verdict.PASS, + "Incremental build not run PASS") self.success() return @@ -1206,12 +1172,15 @@ def run_ci(args): print(testcase.name) return 0 - # Run tests + # Initialize patchwork checks as 'pending' for testcase in CiBase.__subclasses__(): test = testcase() - test_suite[test.name] = test + test.submit_result(pw_series_patch_1, Verdict.PENDING, + "%s PENDING" % test.display_name) + # Run tests + for test in test_suite.values(): try: test.run() except EndTest: @@ -1223,8 +1192,10 @@ def run_ci(args): num_fails += 1 logger.info(test.name + " result: " + test.verdict.name) - logger.debug("Post message to github: " + test.output) - github_pr_post_comment(test) + + if test.enable: + logger.debug("Post message to github: " + test.output) + github_pr_post_comment(test) return num_fails @@ -1289,13 +1260,7 @@ def report_ci(): result='ERROR', elapsed=test.elapsed()) if test.verdict == Verdict.SKIP: - results += TEST_REPORT_FAIL.format(test.display_name, - "SKIPPED", - test.desc, - test.output) - summary += ONELINE_RESULT.format(test=test.display_name, - result='ERROR', - elapsed=test.elapsed()) + continue body = EMAIL_MESSAGE.format(pw_series["web_url"], summary + '\n' + results) @@ -1379,7 +1344,7 @@ def parse_args(): parser = argparse.ArgumentParser( description="Check patch style in the pull request") parser.add_argument('-c', '--config-file', default='config.ini', - help='Configuration file') + help='Configuration file or URL') parser.add_argument('-l', '--show-test-list', action='store_true', help='Display supported CI tests') parser.add_argument('-p', '--pr-num', required=True, type=int, @@ -1392,15 +1357,37 @@ def parse_args(): help='Path to ELL source') parser.add_argument('-v', '--verbose', action='store_true', help='Display debugging info') + parser.add_argument('-m', '--email-message', + default='/default-email-message.txt') + parser.add_argument('-u', '--user', type=int, required=True) return parser.parse_args() +def is_url(config: str) -> bool: + prefixes = ('http://', 'https://') + + return config.startswith(prefixes) + def main(): global src_dir, src2_dir, src3_dir, src4_dir, ell_dir, base_dir + global EMAIL_MESSAGE args = parse_args() + if is_url(args.config_file): + urlretrieve(args.config_file, '/tmp/config.ini') + args.config_file = '/tmp/config.ini' + + if is_url(args.email_message): + urlretrieve(args.email_message, '/tmp/email-message.txt') + args.email_message = '/tmp/email-message.txt' + + with open(args.email_message, 'r') as f: + EMAIL_MESSAGE = f.read() + + PW_USER = args.user + init_logging(args.verbose) init_config(args.config_file, args.verbose)