Module continuous_delivery_scripts.assert_news
Checks if valid news files are created for changes in the project.
Functions
def find_news_files(git: GitWrapper,
root_dir: str,
news_dir: str) ‑> List[str]-
Expand source code
def find_news_files(git: GitWrapper, root_dir: str, news_dir: str) -> List[str]: """Determines a list of all the news files which were added as part of the PR. Args: git: Instance of GitWrapper. root_dir: Root directory of the project. news_dir: Relative path to news directory. Returns: list: list of absolute paths to news files """ files_changed = git.list_files_added_to_current_commit() # To speed up the process, we first look at files added to the current commit. # If no news files were added, then we check for addition on the branch. # Relies on the fact GitWrapper returns paths that are always relative # to the project root. news_prefix = news_dir.replace("\\", "/").rstrip("/") + "/" added_news_files = [file_path for file_path in files_changed if file_path.startswith(news_prefix)] if len(added_news_files) == 0: files_changed = git.list_files_added_on_current_branch() added_news_files = [file_path for file_path in files_changed if file_path.startswith(news_prefix)] return [str(pathlib.Path(root_dir, file_path)) for file_path in added_news_files]Determines a list of all the news files which were added as part of the PR.
- Args
- -----=
git- Instance of GitWrapper.
root_dir- Root directory of the project.
news_dir- Relative path to news directory.
- Returns
- -----=
list- list of absolute paths to news files
def generate_news_file(git: GitWrapper,
news_dir: pathlib.Path) ‑> pathlib.Path-
Expand source code
def generate_news_file(git: GitWrapper, news_dir: pathlib.Path) -> pathlib.Path: """Adds a news file if the branch corresponds to an dependency update. Args: git: Instance of GitWrapper. news_dir: path to news directory. """ current_branch = str(git.get_current_branch()) is_dependency_update, groups = git.is_current_branch_of_type( str(configuration.get_value(ConfigurationVariable.DEPENDENCY_UPDATE_BRANCH_PATTERN)) ) if not is_dependency_update: raise EnvironmentError(f"Branch {current_branch} must contain a news file.") if not configuration.get_value(ConfigurationVariable.AUTOGENERATE_NEWS_FILE_ON_DEPENDENCY_UPDATE): raise EnvironmentError(f"Branch {current_branch} must contain a news file.") list_groups = _convert_to_string_iter(groups) message = str(configuration.get_value(ConfigurationVariable.DEPENDENCY_UPDATE_NEWS_MESSAGE)).format( message=", ".join(list_groups) ) logger.info(f"Generating a news file with content: {message}...") return create_news_file( str(news_dir), None, message, configuration.get_value(ConfigurationVariable.DEPENDENCY_UPDATE_NEWS_TYPE), )Adds a news file if the branch corresponds to an dependency update.
- Args
- -----=
git- Instance of GitWrapper.
news_dir- path to news directory.
def main() ‑> None-
Expand source code
def main() -> None: """Asserts the new PR comprises at least one news file and it adheres to the required standard.""" parser = argparse.ArgumentParser(description="Check correctly formatted news files exist on feature branch.") parser.add_argument("-b", "--current-branch", help="Name of the current branch", nargs="?") parser.add_argument("-l", "--local", action="store_true", help="perform checks directly on local repository") parser.add_argument("-v", "--verbose", action="count", default=0, help="Verbosity, by default errors are reported.") args = parser.parse_args() set_log_level(args.verbose) repository: ContextManager[GitWrapper] if args.local: repository = LocalProjectRepository() else: repository = ProjectTempClone(desired_branch_name=args.current_branch) with repository as git: if git.is_current_branch_feature(): root_dir = configuration.get_value(ConfigurationVariable.PROJECT_ROOT) absolute_news_dir = configuration.get_value(ConfigurationVariable.NEWS_DIR) news_dir = str(pathlib.Path(absolute_news_dir).relative_to(root_dir)) try: validate_news_files(git=git, news_dir=news_dir, root_dir=str(git.root)) except MissingNewsFileError as e: log_exception(logger, e) try: news_file = generate_news_file(git, git.get_corresponding_path(pathlib.Path(news_dir))) _commit_news_file(git, news_file, args.local) except Exception as e2: log_exception(logger, e2) sys.exit(1) except Exception as e: log_exception(logger, e) sys.exit(1)Asserts the new PR comprises at least one news file and it adheres to the required standard.
def validate_news_file(absolute_path: pathlib.Path | str) ‑> None-
Expand source code
def validate_news_file(absolute_path: Union[pathlib.Path, str]) -> None: """Applies NewsFileValidator validation logic to news file.""" NewsFileValidator(absolute_path).validate()Applies NewsFileValidator validation logic to news file.
def validate_news_files(git: GitWrapper,
root_dir: str,
news_dir: str) ‑> None-
Expand source code
def validate_news_files(git: GitWrapper, root_dir: str, news_dir: str) -> None: """Checks that news files exist and pass validation checks. Args: git: Instance of GitWrapper. root_dir: Root directory of the project. news_dir: Relative path to news directory. """ added_news_files = find_news_files(git=git, news_dir=news_dir, root_dir=root_dir) if not added_news_files: raise MissingNewsFileError(f"PR must contain a news file in {news_dir}. See README.md.") for absolute_file_path in added_news_files: validate_news_file(absolute_file_path)Checks that news files exist and pass validation checks.
- Args
- -----=
git- Instance of GitWrapper.
root_dir- Root directory of the project.
news_dir- Relative path to news directory.
Classes
class MissingNewsFileError (*args, **kwargs)-
Expand source code
class MissingNewsFileError(FileNotFoundError): """The branch contains no added news file."""The branch contains no added news file.
Ancestors
- builtins.FileNotFoundError
- builtins.OSError
- builtins.Exception
- builtins.BaseException
class NewsFileValidator (absolute_path: pathlib.Path | str)-
Expand source code
class NewsFileValidator: """Verifies individual news files.""" def __init__(self, absolute_path: Union[pathlib.Path, str]) -> None: """Creates a new instance of NewsFileValidator. Args: absolute_path: the absolute path to the news file """ self._news_file_path = pathlib.Path(absolute_path) self._basename = self._news_file_path.name def validate_file_name(self) -> None: """Ensures the news file follows the naming rules.""" if re.match(NEWS_FILE_NAME_REGEX, self._basename) is None: raise ValueError( f'Incorrect news file name "{self._basename}".' f' It doesn\'t match the following regex: "{NEWS_FILE_NAME_REGEX}".' ) def validate_file_contents(self) -> None: """Ensures the news file is not empty and not longer than one line.""" file_content = self._news_file_path.read_text() if file_content.strip() == "": raise ValueError(f'Empty news file "{self._basename}".') if len(file_content.splitlines()) > 1: raise ValueError(f'News file "{self._basename}" contains more than one line.') def validate(self) -> None: """Runs all validators.""" logger.info(f"Verifying {self._basename}") self.validate_file_name() self.validate_file_contents()Verifies individual news files.
Creates a new instance of NewsFileValidator.
- Args
- -----=
absolute_path- the absolute path to the news file
Methods
def validate(self) ‑> None-
Expand source code
def validate(self) -> None: """Runs all validators.""" logger.info(f"Verifying {self._basename}") self.validate_file_name() self.validate_file_contents()Runs all validators.
def validate_file_contents(self) ‑> None-
Expand source code
def validate_file_contents(self) -> None: """Ensures the news file is not empty and not longer than one line.""" file_content = self._news_file_path.read_text() if file_content.strip() == "": raise ValueError(f'Empty news file "{self._basename}".') if len(file_content.splitlines()) > 1: raise ValueError(f'News file "{self._basename}" contains more than one line.')Ensures the news file is not empty and not longer than one line.
def validate_file_name(self) ‑> None-
Expand source code
def validate_file_name(self) -> None: """Ensures the news file follows the naming rules.""" if re.match(NEWS_FILE_NAME_REGEX, self._basename) is None: raise ValueError( f'Incorrect news file name "{self._basename}".' f' It doesn\'t match the following regex: "{NEWS_FILE_NAME_REGEX}".' )Ensures the news file follows the naming rules.