API

Code Docstrings

Actions

Prune YAML

brassy.actions.prune_yaml.direct_pruning_of_files(input_files_or_folders, console, working_dir)[source]

Prune empty values from YAML files specified by input paths.

Parameters:
  • input_files_or_folders (list of str) – A list of file paths or directories containing YAML files to prune.

  • console (Console) – An object used for printing messages to the console.

  • working_dir (str) – The working directory path.

Return type:

None

Notes

This function collects YAML files from the specified input paths and prunes each file using prune_yaml_file.

Examples

>>> direct_pruning_of_files(['configs/'], console, '/home/user')
Pruned configs/config1.yaml
Pruned configs/config2.yaml
brassy.actions.prune_yaml.prune_empty(data, prune_lists=True, key='')[source]

Recursively remove empty values from a nested dictionary or list.

Parameters:
  • data (dict or list) – The data structure to prune.

  • prune_lists (bool, optional) – Indicates whether to prune empty lists. Currently unused.

  • key (str, optional) – The key associated with the current data item, used for special cases.

Returns:

The pruned data structure, or None if it is empty.

Return type:

dict or list or None

Notes

The function considers the following values as empty: None, empty strings, empty dictionaries, and empty lists. If a value is 0 and the key is “number”, it is also considered empty to address the related issues field which was previously set to 0 instead of null.

Examples

>>> data = {'a': None, 'b': '', 'c': {'d': [], 'e': 'value'}}
>>> prune_empty(data)
{'c': {'e': 'value'}}
brassy.actions.prune_yaml.prune_yaml_file(yaml_file_path, console)[source]

Prune empty values from a YAML file and overwrite it with the pruned content.

Parameters:
  • yaml_file_path (str) – The file path to the YAML file to be pruned.

  • console (Console) – An object used for printing messages to the console.

Return type:

None

Notes

This function reads the YAML file, prunes empty values using prune_empty, and writes the pruned content back to the same file.

Examples

>>> prune_yaml_file('config.yaml', console)
Pruned config.yaml

Build Release Notes

brassy.actions.build_release_notes.build_release_notes(input_files_or_folders, console, rich_open, version=None, release_date=None, header_file=None, footer_file=None, working_dir='.')[source]

Build release notes from YAML data.

Parameters:
  • data (dict) – Parsed content of YAML files.

  • version (str, optional) – Version number of the release, by default ‘1.1’.

  • release_date (str, optional) – Release date, by default None, which uses today’s date.

  • header_file (str, optional) – A header file to prepend to the release notes.

  • footer_file (str, optional) – A footer file to suffix to the release notes.

Returns:

Formatted release notes in .rst format.

Return type:

str

brassy.actions.build_release_notes.find_duplicate_titles(data)[source]

Check if there are any duplicate titles in dictionaries of lists of dictionaries.

Parameters:

data (dict) – A dictionary containing lists of dictionaries with items indexed by “title”.

Returns:

True if there are duplicate “title” values, False otherwise.

Return type:

bool

brassy.actions.build_release_notes.format_files_changed_entry(detailed, entry)[source]
brassy.actions.build_release_notes.format_release_notes(data, version, release_date=None, header=None, footer=None)[source]

Format the parsed YAML data into release notes in .rst format.

Parameters:
  • data (dict) – Parsed content of YAML files.

  • version (str, optional) – Version number of the release, by default ‘1.1’.

  • release_date (str, optional) – Release date, by default None, which uses today’s date.

Returns:

Formatted release notes in .rst format.

Return type:

str

brassy.actions.build_release_notes.generate_file_change_section_list_of_strings(entry, line, category, title, description)[source]
brassy.actions.build_release_notes.generate_section_string(section_lines, changelog_entries, release_date, version, footer, header)[source]

Adds a header and/or footer to the given content.

Parameters:
  • content (str) – The content to which the header and/or footer will be added.

  • rich_open (function) – A function used to open files.

  • header_file (str, optional) – The file containing the header content. Defaults to None.

  • footer_file (str, optional) – The file containing the footer content. Defaults to None.

Returns:

The content with the header and/or footer added.

Return type:

str

Initialize

brassy.actions.init.init()[source]

Initialize configuration files for the application.

This function creates site and user configuration files, and optionally a project configuration file based on user input.

Return type:

None

Examples

>>> init()
Do you want to create a project config file? [y/N]: y

Templates

Release YAML

class brassy.templates.release_yaml_template.ChangeItem(*, title: Annotated[str | None, MinLen(min_length=1)], description: Annotated[str | None, MinLen(min_length=1)], files: Files, related_issue: RelatedIssue | RelatedInternalIssue | None = None, date: DateRange | None = None)[source]

Bases: BaseModel

date: DateRange | None
description: str | None
empty_str_to_none()[source]
files: Files
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'date': FieldInfo(annotation=Union[DateRange, NoneType], required=False, default=None), 'description': FieldInfo(annotation=Union[str, NoneType], required=True, json_schema_extra={'strip_whitespace': True}, metadata=[MinLen(min_length=1)]), 'files': FieldInfo(annotation=Files, required=True), 'related_issue': FieldInfo(annotation=Union[RelatedIssue, RelatedInternalIssue, NoneType], required=False, default=None, alias='related-issue', alias_priority=2, json_schema_extra={'exclude_unset': True}), 'title': FieldInfo(annotation=Union[str, NoneType], required=True, json_schema_extra={'strip_whitespace': True}, metadata=[MinLen(min_length=1)])}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

related_issue: RelatedIssue | RelatedInternalIssue | None
title: str | None
class brassy.templates.release_yaml_template.DateRange(*, start: date | None, finish: date | None)[source]

Bases: BaseModel

finish: date | None
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'finish': FieldInfo(annotation=Union[date, NoneType], required=True, validate_default=True), 'start': FieldInfo(annotation=Union[date, NoneType], required=True, validate_default=True)}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

classmethod parse_date(value)[source]
start: date | None
class brassy.templates.release_yaml_template.Files(*, deleted: List[str] = [], moved: List[str] = [], added: List[str] = [], modified: List[str] = [])[source]

Bases: BaseModel

added: List[str]
check_at_least_one_field()[source]
deleted: List[str]
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'added': FieldInfo(annotation=List[str], required=False, default=[]), 'deleted': FieldInfo(annotation=List[str], required=False, default=[]), 'modified': FieldInfo(annotation=List[str], required=False, default=[]), 'moved': FieldInfo(annotation=List[str], required=False, default=[])}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

modified: List[str]
moved: List[str]
class brassy.templates.release_yaml_template.RelatedInternalIssue(*, internal: Annotated[str | None, _PydanticGeneralMetadata(pattern='[A-Za-z]+#\\d+ - .+')] = None)[source]

Bases: BaseModel

internal: str | None
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'internal': FieldInfo(annotation=Union[str, NoneType], required=False, default=None, metadata=[_PydanticGeneralMetadata(pattern='[A-Za-z]+#\\d+ - .+')])}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

class brassy.templates.release_yaml_template.RelatedIssue(*, number: int | None = None, repo_url: Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)] | None = None)[source]

Bases: BaseModel

blank_string(field)[source]
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'number': FieldInfo(annotation=Union[int, NoneType], required=False, default=None), 'repo_url': FieldInfo(annotation=Union[Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)], NoneType], required=False, default=None)}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

number: int | None
repo_url: Annotated[Url, UrlConstraints(max_length=2083, allowed_schemes=['http', 'https'], host_required=None, default_host=None, default_port=None, default_path=None)] | None
class brassy.templates.release_yaml_template.ReleaseNote(root: RootModelRootType = PydanticUndefined)[source]

Bases: RootModel[Dict[str, List[ChangeItem]]]

ReleaseNote is a root model containing a dictionary that maps category names to lists of ChangeItems.

model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'root': FieldInfo(annotation=Dict[str, List[ChangeItem]], required=True)}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

Settings

class brassy.templates.settings_template.ReleaseTemplate(*, release_template: List[Dict[str, List[str]]] | None = None)[source]

Bases: BaseModel

class Config[source]

Bases: object

populate_by_name = True
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {'populate_by_name': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'release_template': FieldInfo(annotation=Union[List[Dict[str, List[str]]], NoneType], required=False, default=None, alias='release-template', alias_priority=2)}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

release_template: List[Dict[str, List[str]]] | None
class brassy.templates.settings_template.SettingsTemplate(*, use_color: bool = True, default_yaml_path: Path | None = None, change_categories: List[str] = ['bug fix', 'enhancement', 'deprecation', 'removal', 'performance', 'documentation', 'continuous integration'], default_title: str = 'NO TITLE', default_description: str = 'NO DESCRIPTION', fail_on_empty_dir: bool = True, description_populates_with_pipe: bool = False, valid_fields: List[str] = ['title', 'description', 'files', 'related-issue'], valid_changes: List[str] = ['deleted', 'moved', 'added', 'modified'], enable_experimental_features: bool = False, templates: ReleaseTemplate | None = ReleaseTemplate(release_template=[{'header': ['{prefix_file}', '']}, {'title': ['', 'Version {release_version} ({release_date})', '**************************', '']}, {'summary': [' * *{change_type}*: {title}']}, {'entry': ['', '{change_type}', '===========', '', '{title}', '-------------------------', '', '{description}', '', '::', '', '     {file_change}: {file}']}, {'footer': ['', '{suffix_file}']}]))[source]

Bases: BaseModel

change_categories: List[str]
default_description: str
default_title: str
default_yaml_path: Path | None
description_populates_with_pipe: bool
enable_experimental_features: bool
fail_on_empty_dir: bool
model_computed_fields: ClassVar[Dict[str, ComputedFieldInfo]] = {}

A dictionary of computed field names and their corresponding ComputedFieldInfo objects.

model_config: ClassVar[ConfigDict] = {}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_fields: ClassVar[Dict[str, FieldInfo]] = {'change_categories': FieldInfo(annotation=List[str], required=False, default=['bug fix', 'enhancement', 'deprecation', 'removal', 'performance', 'documentation', 'continuous integration']), 'default_description': FieldInfo(annotation=str, required=False, default='NO DESCRIPTION'), 'default_title': FieldInfo(annotation=str, required=False, default='NO TITLE'), 'default_yaml_path': FieldInfo(annotation=Union[Path, NoneType], required=False, default=None), 'description_populates_with_pipe': FieldInfo(annotation=bool, required=False, default=False), 'enable_experimental_features': FieldInfo(annotation=bool, required=False, default=False), 'fail_on_empty_dir': FieldInfo(annotation=bool, required=False, default=True), 'templates': FieldInfo(annotation=Union[ReleaseTemplate, NoneType], required=False, default=ReleaseTemplate(release_template=[{'header': ['{prefix_file}', '']}, {'title': ['', 'Version {release_version} ({release_date})', '**************************', '']}, {'summary': [' * *{change_type}*: {title}']}, {'entry': ['', '{change_type}', '===========', '', '{title}', '-------------------------', '', '{description}', '', '::', '', '     {file_change}: {file}']}, {'footer': ['', '{suffix_file}']}])), 'use_color': FieldInfo(annotation=bool, required=False, default=True), 'valid_changes': FieldInfo(annotation=List[str], required=False, default=['deleted', 'moved', 'added', 'modified']), 'valid_fields': FieldInfo(annotation=List[str], required=False, default=['title', 'description', 'files', 'related-issue'])}

Metadata about the fields defined on the model, mapping of field names to [FieldInfo][pydantic.fields.FieldInfo] objects.

This replaces Model.__fields__ from Pydantic V1.

templates: ReleaseTemplate | None
use_color: bool
valid_changes: List[str]
valid_fields: List[str]

Utils

CLI

brassy.utils.CLI.exit_on_invalid_arguments(args, parser, console)[source]

Validate the argparse arguments.

This function validates the provided argparse arguments to ensure that the required input files/folders and output file are provided. If arguments are invalid, it prints an error message and exits the program.

Parameters:
  • args (argparse.Namespace) – Parsed arguments.

  • parser (argparse.ArgumentParser) – The ArgumentParser object used to parse the command-line arguments.

brassy.utils.CLI.get_file_list_from_cli_input(input_files_or_folders, console, working_dir='.')[source]
brassy.utils.CLI.get_parser()[source]

Returns an ArgumentParser object with predefined arguments for generating release notes from YAML files.

Returns:

The ArgumentParser object with predefined arguments.

Return type:

argparse.ArgumentParser

brassy.utils.CLI.get_yaml_files_from_input(input_files_or_folders)[source]

Get a list of YAML files from the given input files or folders.

Parameters:

input_files_or_folders (list) – List of paths to input files or folders.

Returns:

List of paths to YAML files.

Return type:

list

Raises:

ValueError – If a file is not a YAML file or if no YAML files are found in a directory.

brassy.utils.CLI.parse_arguments()[source]

Parse command line arguments for input folder and output file.

Returns:

Parsed arguments containing input_folder and output_file.

Return type:

argparse.Namespace

brassy.utils.CLI.print_version_and_exit()[source]
brassy.utils.CLI.run_from_CLI()[source]

Main function to generate release notes from YAML files and write to an output file.

git_handler

brassy.utils.git_handler.get_current_git_branch()[source]

Get the current dirs git branch name.

Returns:

The name of the current git branch.

Return type:

str

brassy.utils.git_handler.get_git_status(repo_path='.')[source]

Retrieve the status of files in the specified Git repository.

Parameters:

repo_path (str, optional) – The path to the Git repository. Defaults to the current directory.

Returns:

A dictionary with the following keys:

  • ’added’: list of str

    List of file paths for files that have been added.

  • ’modified’: list of str

    List of file paths for files that have been modified.

  • ’deleted’: list of str

    List of file paths for files that have been deleted.

  • ’renamed’: list of str

    List of file paths for files that have been renamed.

Return type:

dict

brassy.utils.git_handler.print_out_git_changed_files(print_function, repo_path='.')[source]

Messages

brassy.utils.messages.get_boolean_prompt_function(format=True)[source]
brassy.utils.messages.get_rich_opener(no_format=False)[source]

Returns the appropriate opener function for rich progress bar.

Parameters:

no_format (bool, optional) – If True, returns the opener function without any formatting. If False, returns the opener function with formatting. Defaults to False.

Returns:

The opener function for rich progress bar.

Return type:

function

brassy.utils.messages.init_logger(use_rich)[source]

Initialize and configure the logger.

Parameters:

use_rich (bool) – If True, sets up rich logging else use standard stream logging

Returns:

logger – The configured logger instance

Return type:

logging.Logger

brassy.utils.messages.setup_console(no_format=False, quiet=False)[source]

Set up and return the console for printing messages.

Parameters:
  • no_format (bool, optional) – Whether to disable formatting. Defaults to False.

  • quiet (bool, optional) – Whether to suppress console output. Defaults to False.

Returns:

The configured rich console object.

Return type:

Console

brassy.utils.messages.setup_messages(format, quiet)[source]

Settings Manager

brassy.utils.settings_manager.create_config_file(config_file)[source]

Create a configuration file with default settings.

Parameters:

config_file (str) – Path where the configuration file will be created.

brassy.utils.settings_manager.get_config_files(app_name)[source]

Get a list of configuration file paths in order of increasing precedence.

Parameters:

app_name (str) – Name of the application.

Returns:

List of configuration file paths.

Return type:

list of str

brassy.utils.settings_manager.get_git_repo_root(path='.')[source]

Get the root directory of the Git repository containing the given path.

Parameters:

path (str, optional) – A path within the Git repository. Defaults to the current directory.

Returns:

Absolute path to the root of the Git repository. This is usually the path containing the .git folder.

Return type:

str

brassy.utils.settings_manager.get_project_config_file_path(app_name)[source]

Retrieve the project-specific configuration file path for the application.

Parameters:

app_name (str) – Name of the application.

Returns:

Path to the project’s configuration file.

Return type:

str

brassy.utils.settings_manager.get_settings(app_name)[source]

Return application settings from config files and environment variables.

Parameters:

app_name (str) – Name of the application.

Returns:

An instance of the Settings model with all configurations applied.

Return type:

Settings

Raises:

ValidationError – If the final settings do not conform to the Settings model.

brassy.utils.settings_manager.get_settings_from_config_files(app_name)[source]

Retrieve settings from configuration files without environment overrides.

Parameters:

app_name (str) – Name of the application.

Returns:

Configuration settings merged from files.

Return type:

dict

brassy.utils.settings_manager.get_site_config_file_path(app_name)[source]

Retrieve the site-specific configuration file path for the application.

Parameters:

app_name (str) – Name of the application.

Returns:

Path to the site’s configuration file.

Return type:

str

brassy.utils.settings_manager.get_user_config_file_path(app_name)[source]

Retrieve the user-specific configuration file path for the application.

Parameters:

app_name (str) – Name of the application.

Returns:

Path to the user’s configuration file.

Return type:

str

brassy.utils.settings_manager.merge_and_validate_config_files(config_files)[source]

Merge settings from multiple configuration files and validate them.

Parameters:

config_files (list of str) – List of configuration file paths. The order of the files matters. Each file overwrites the values of the previous.

Returns:

Merged and validated configuration settings.

Return type:

dict

Raises:

ValidationError – If any of the settings do not conform to the Settings model.

brassy.utils.settings_manager.override_dict_with_environmental_variables(input_dict)[source]

Override dict values with case insensitive environment variables when available.

Parameters:

input_dict (dict) – Original settings dictionary.

Returns:

Updated settings dictionary with environment variable overrides.

Return type:

dict

brassy.utils.settings_manager.read_config_file(config_file, create_file_if_not_exist=False)[source]

Read and parse a YAML configuration file.

Parameters:
  • config_file (str) – Path to the configuration file.

  • create_file_if_not_exist (bool) – Creates file if it doesn’t exist

Returns:

Parsed configuration settings.

Return type:

dict

File Handler

brassy.utils.file_handler.create_blank_template_yaml_file(file_path_arg, console, working_dir='.')[source]

Creates a blank YAML template file with a predefined structure.

This function generates a YAML file at the specified path with a default template. It handles special characters required for YAML compatibility and writes the file to disk.

Parameters:
  • file_path_arg (str) – The file path of the YAML template as passed via the CLI.

  • console (rich.console.Console) – A Rich Console object used for displaying messages and errors to the user.

  • working_dir (str, optional) – The working directory path. Defaults to the current directory “.”.

Raises:

SystemExit – If a Git repo is not found in the current working directory and no file path is provided, the program exits with an error message.

Notes

This function performs a string replacement to insert a “|” due to an issue with YAML’s handling of pipe symbols. For more details, see: https://github.com/yaml/pyyaml/pull/822

brassy.utils.file_handler.get_yaml_template_path(file_path_arg, working_dir='/workspaces/yaml-to-release-note/sphinx')[source]

Returns the path of the YAML template file based on the given file path argument.

Parameters:

file_path_arg (str) – The file path argument provided by the user.

Returns:

The path of the YAML template file.

Return type:

str

brassy.utils.file_handler.read_yaml_files(input_files, rich_open)[source]

Read and parse the given list of YAML files.

Parameters:

input_files (list) – List of paths to the YAML files.

Returns:

Parsed content of all YAML files categorized by type of change.

Return type:

dict

Examples

>>> read_yaml_files(["file1.yaml", "file2.yaml"])
{'bug-fix': [
    {'title': 'fixed explosions',
      'description': 'This fixed the explosion mechanism'},
    {'title': 'fixed cats not being cute',
      'description': 'This made the cats WAY cuter'}
    ]
}
brassy.utils.file_handler.value_error_on_invalid_yaml(content, file_path)[source]

Check if the YAML content follows the correct schema.

Parameters:
  • content (dict) – Parsed content of the YAML file.

  • file_path (str) – Path to the YAML file.

Raises:

ValueError – If the YAML content does not follow the correct schema.

brassy.utils.file_handler.write_output_file(output_file, content)[source]

Write the formatted release notes to the output file.

Parameters:
  • output_file (str) – Path to the output .rst file.

  • content (str) – Formatted release notes.

Main Module

This module provides functionality to generate release notes from YAML files. It reads YAML files, parses their content, and formats the parsed data into release notes in .rst format. The release notes can be written to an output file.

brassy.brassy.run_from_CLI()[source]