Exemple #1
0
 def extract_zip_file(file: str, path: str):
     # Apparently, ZipFile does not resolve symlinks so let's do it manually
     if os.path.islink(file):
         file = os.path.realpath(file)
     FileUtils.ensure_file_exists(file)
     zip_file = zipfile.ZipFile(file, "r")
     zip_file.extractall(path)
Exemple #2
0
    def _validate_args(self, parser, args):
        if args.gsheet and (args.gsheet_client_secret is None
                            or args.gsheet_spreadsheet is None
                            or args.gsheet_worksheet is None):
            parser.error(
                "--gsheet requires the following arguments: "
                "--gsheet-client-secret, --gsheet-spreadsheet and --gsheet-worksheet."
            )

        if args.do_print:
            self.operation_mode = OperationMode.PRINT
        elif args.gsheet:
            self.operation_mode = OperationMode.GSHEET
            self.gsheet_options = GSheetOptions(args.gsheet_client_secret,
                                                args.gsheet_spreadsheet,
                                                worksheet=None)
            self.gsheet_jira_table = getattr(args,
                                             "gsheet_compare_with_jira_table",
                                             None)
        if self.operation_mode not in VALID_OPERATION_MODES:
            raise ValueError(
                f"Unknown state! "
                f"Operation mode should be any of {VALID_OPERATION_MODES}, but it is set to: {self.operation_mode}"
            )
        if hasattr(args, "gmail_credentials_file"):
            FileUtils.ensure_file_exists(args.gmail_credentials_file)
    def run(self):
        LOG.info(
            f"Starting sending latest command data in email.\n Config: {str(self.config)}"
        )

        zip_extract_dest = FileUtils.join_path(os.sep, "tmp", "extracted_zip")
        ZipFileUtils.extract_zip_file(self.config.email.attachment_file,
                                      zip_extract_dest)

        # Pick file from zip that will be the email's body
        email_body_file = FileUtils.join_path(os.sep, zip_extract_dest,
                                              self.config.email_body_file)
        FileUtils.ensure_file_exists(email_body_file)
        email_body_contents: str = FileUtils.read_file(email_body_file)

        body_mimetype: EmailMimeType = self._determine_body_mimetype_by_attachment(
            email_body_file)
        email_service = EmailService(self.config.email.email_conf)
        try:
            email_service.send_mail(
                self.config.email.sender,
                self.config.email.subject,
                email_body_contents,
                self.config.email.recipients,
                self.config.email.attachment_file,
                body_mimetype=body_mimetype,
                override_attachment_filename=self.config.email.
                attachment_filename,
            )
        except SMTPAuthenticationError as smtpe:
            ignore_smpth_auth_env: str = OsUtils.get_env_value(
                EnvVar.IGNORE_SMTP_AUTH_ERROR.value, "")
            LOG.info(
                f"Recognized env var '{EnvVar.IGNORE_SMTP_AUTH_ERROR.value}': {ignore_smpth_auth_env}"
            )
            if not ignore_smpth_auth_env:
                raise smtpe
            else:
                # Swallow exeption
                LOG.exception(
                    f"SMTP auth error occurred but env var "
                    f"'{EnvVar.IGNORE_SMTP_AUTH_ERROR.value}' was set",
                    exc_info=True,
                )
        LOG.info("Finished sending email to recipients")
    def send_mail(self, sender: str, subject: str, body: str, recipients: List[str],
                  attachment_file=None,
                  override_attachment_filename: str = None,
                  body_mimetype: EmailMimeType = EmailMimeType.PLAIN):
        self._validate_config(recipients)

        email_msg = None
        if attachment_file:
            FileUtils.ensure_file_exists(attachment_file)
            # https://stackoverflow.com/a/169406/1106893
            email_msg = MIMEMultipart()
            email_msg.attach(MIMEText(str(body), body_mimetype.value))
            if override_attachment_filename:
                attachment = self._create_attachment(attachment_file, attachment_name=override_attachment_filename)
            else:
                attachment = self._create_attachment(attachment_file)
            email_msg.attach(attachment)
        else:
            email_msg = MIMEText(str(body))
        recipients_comma_separated = self._add_common_email_data(email_msg, recipients, sender, subject)
        self._connect_to_server_and_send(email_msg, recipients, recipients_comma_separated, sender)
    def write_all_changes_files(self):
        """
        Iterate over changed files, print all matching changes to the particular file
        Create changes file for each touched file
        :return:
        """
        LOG.info("Recording changes of individual files...")
        for idx, changed_file in enumerate(self.data.list_of_changed_files):
            target_file = FileUtils.join_path(
                self.config.umbrella_result_basedir, "changes",
                os.path.basename(changed_file))
            FileUtils.ensure_file_exists(target_file, create=True)

            # NOTE: It seems impossible to call the following command with gitpython:
            # git log --follow --oneline -- <file>
            # Use a simple CLI command instead

            # TODO check if change file exists - It can happen that it was deleted
            cli_command = (
                f"cd {self.upstream_repo.repo_path} && "
                f"git log {ORIGIN_TRUNK} --follow --oneline -- {changed_file} | "
                f'egrep "{self.data.piped_jira_ids}"')
            LOG.info("[%d / %d] CLI command: %s", idx + 1,
                     len(self.data.list_of_changed_files), cli_command)
            cmd, output = CommandRunner.run_cli_command(
                cli_command,
                fail_on_empty_output=False,
                print_command=False,
                fail_on_error=False)

            if output:
                LOG.info("Saving changes result to file: %s", target_file)
                FileUtils.save_to_file(target_file, output)
            else:
                LOG.error(
                    f"Failed to detect changes of file: {changed_file}. CLI command was: {cli_command}. "
                    f"This seems to be a programming error. Exiting...")
                FileUtils.save_to_file(target_file, "")
                sys.exit(1)
    def run(self):
        patch_file = self.args.patch_file

        FileUtils.ensure_file_exists(patch_file, create=False)
        patch_file_name = FileUtils.path_basename(patch_file)
        matches = RegexUtils.ensure_matches_pattern(patch_file_name, YARN_PATCH_FILENAME_REGEX)
        if not matches:
            raise ValueError(
                f"Filename '{patch_file_name}' (full path: {patch_file}) "
                f"does not match usual patch file pattern: '{YARN_PATCH_FILENAME_REGEX}'!"
            )

        orig_branch = self.upstream_repo.get_current_branch_name()
        LOG.info("Current branch: %s", orig_branch)

        target_branch = BRANCH_PREFIX + RegexUtils.get_matched_group(patch_file, YARN_PATCH_FILENAME_REGEX, 1)
        LOG.info("Target branch: %s", target_branch)

        clean = self.upstream_repo.is_working_directory_clean()
        if not clean:
            raise ValueError("git working directory is not clean, please stash or drop your changes")

        self.upstream_repo.checkout_branch(self.base_branch)
        self.upstream_repo.pull(ORIGIN)
        diff = self.upstream_repo.diff_between_refs(self.remote_base_branch, self.base_branch)
        if diff:
            raise ValueError(
                f"There is a diff between local {self.base_branch} and {self.remote_base_branch}! "
                f"Run 'git reset {self.remote_base_branch} --hard' and re-run the script!"
            )

        apply_result = self.upstream_repo.apply_check(patch_file, raise_exception=False)
        if not apply_result:
            self.upstream_repo.checkout_previous_branch()
            cmd = "git apply " + patch_file
            raise ValueError(
                f"Patch does not apply to {self.base_branch}, please resolve the conflicts manually. "
                f"Run this command to apply the patch again: {cmd}"
            )

        LOG.info("Patch %s applies cleanly to %s", patch_file, self.base_branch)
        branch_exists = self.upstream_repo.is_branch_exist(target_branch)
        base_ref = self.base_branch
        if not branch_exists:
            success = self.upstream_repo.checkout_new_branch(target_branch, base_ref)
            if not success:
                raise ValueError(f"Cannot checkout new branch {target_branch} based on ref {base_ref}")
            LOG.info("Checked out branch %s based on ref %s", target_branch, base_ref)
        else:
            branch_pattern = target_branch + "*"
            branches = self.upstream_repo.list_branches(branch_pattern)
            LOG.info("Found existing review branches for this patch: %s", branches)
            target_branch = PatchUtils.get_next_review_branch_name(branches)
            LOG.info("Creating new version of review branch as: %s", target_branch)
            success = self.upstream_repo.checkout_new_branch(target_branch, base_ref)
            if not success:
                raise ValueError(f"Cannot checkout new branch {target_branch} based on ref {base_ref}")

        self.upstream_repo.apply_patch(patch_file, include_check=False)
        LOG.info("Successfully applied patch: %s", patch_file)
        commit_msg = f"patch file: {patch_file}"
        self.upstream_repo.add_all_and_commit(commit_msg)
        LOG.info("Committed changes of patch: %s with message: %s", patch_file, commit_msg)