mafw.scripts.new_release

Release automation script for maintainers.

This module provides a Click-based command line interface that prepares a new MAFw release by bumping the version, updating NOTICE.txt, regenerating the changelog, optionally generating release notes, committing tracked release artifacts, creating the git tag, and optionally pushing to the remote repository.

author:

Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)

Module Attributes

VALID_HATCH_SEGMENTS

Allowed Hatch version segments supported by this script.

VERSION_PATTERN

Regular expression used to parse local version strings (stable/alpha/beta/rc).

STABLE_TAG_PATTERN

Regular expression used to identify stable git tags in the form vX.Y.Z.

ABOUT_FILE

Path to the version source file managed by hatch version.

CHANGELOG_FILE

Path to the changelog file that is regenerated for each release.

NOTICE_FILE

Path to the notice file containing the public project version.

RELEASE_TEMPLATE_FILE

Path to the markdown template used to build release notes.

RELEASE_SECTION_HEADERS

Release note section headers used in the markdown template.

CONTEXT_SETTINGS

Click context settings for command line help aliases.

NOTICE_VERSION_PATTERN

Pattern used to update the version block in NOTICE.txt.

VersionKind

Supported release kinds used to drive changelog and release-note behavior.

Functions

bump_version(segment, *, dry_run)

Compute or execute the version bump depending on dry-run mode.

check_main_branch()

Ensure the release process is executed from the main branch.

check_missing_release(current_version)

Prevent creating a new release when a stable release is already missing a tag.

classify_version(version)

Classify a version string into stable/rc/alpha/beta.

cmd(command, *[, dry_run])

Execute a subprocess command and always return a completed process object.

commit_changes(version, dry_run, *[, ...])

Commit tracked release artifacts for the target version.

create_release_note(version, dry_run)

Create the release note markdown file for the given version.

create_tag(version, dry_run)

Create the local git tag for the target version.

ensure_clean_git()

Ensure the git working tree is clean (excluding untracked files).

extract_change_sections_from_changelog(version)

Extract release change sections from CHANGELOG.md.

extract_change_sections_from_changelog_block(...)

Extract release change sections from a changelog block.

extract_version_changelog_block(...)

Extract the changelog block associated with the target version.

generate_changelog(version, dry_run)

Generate the project changelog for the target release.

get_contributors(since_ref)

Collect contributor names since the baseline reference.

get_last_stable_tag()

Return the latest stable tag matching vX.Y.Z.

get_release_note_base_ref()

Determine the git reference used as baseline for release-note metadata.

get_release_statistics(since_ref)

Collect release statistics since the baseline reference.

normalize_hatch_segments(segments)

Normalize the user-provided segment selector to a Hatch-compatible token list.

parse_stable_tag(tag)

Parse a stable tag in the form vX.Y.Z.

parse_version(version)

Parse a version string in the form X.Y.Z or with a pre-release suffix.

prevent_duplicate_tag(version)

Ensure the target release tag does not already exist.

push_changes(dry_run)

Push commits and tags to the remote repository.

read_current_version()

Read the project version using hatch version.

render_release_note_section(content, header, ...)

Replace a release-note section in the markdown template.

run_stdout(command, *[, dry_run])

Execute a command and return stripped standard output.

update_notice_version(version, dry_run)

Update the version in NOTICE.txt to match the release version.

mafw.scripts.new_release._classify_changelog_subsection(subsection_heading: str) str | None[source]

Map a changelog subsection heading to a release-note category key.

Parameters:

subsection_heading (str) – Raw level-3 heading from changelog.

Returns:

Category key, or None if the heading is not mappable.

Return type:

str | None

mafw.scripts.new_release._to_command_line(command: str | list[str]) str[source]

Convert a command into a printable shell-like string.

Parameters:

command (str | list[str]) – Command expressed as a string or tokenized list.

Returns:

Human-readable command line.

Return type:

str

mafw.scripts.new_release.bump_version(segment: str, *, dry_run: bool) str[source]

Compute or execute the version bump depending on dry-run mode.

Hatch is used as single source of truth for the resolved target version. In dry-run mode, the __about__.py file is temporarily rewritten by Hatch and restored afterwards so the git worktree remains unchanged.

Parameters:
  • segment (str) – Hatch selector segments (comma-separated).

  • dry_run (bool) – Whether command execution is disabled.

Returns:

New version string.

Return type:

str

mafw.scripts.new_release.check_main_branch() None[source]

Ensure the release process is executed from the main branch.

Raises:

click.ClickException – If the current branch is not main.

mafw.scripts.new_release.check_missing_release(current_version: str) None[source]

Prevent creating a new release when a stable release is already missing a tag.

If the current project version is stable and ahead of the last stable git tag, the release is aborted to avoid skipping the untagged stable release.

Parameters:

current_version (str) – Current project version.

Raises:

click.ClickException – If a missing stable release is detected.

mafw.scripts.new_release.classify_version(version: str) Literal['stable', 'rc', 'alpha', 'beta'][source]

Classify a version string into stable/rc/alpha/beta.

Parameters:

version (str) – Version string to classify.

Returns:

Classified version kind.

Return type:

VersionKind

Raises:

click.ClickException – If the version cannot be parsed.

mafw.scripts.new_release.cmd(command: str | list[str], *, dry_run: bool = False, **kwargs: Any) CompletedProcess[Any][source]

Execute a subprocess command and always return a completed process object.

The command line is always printed. In dry-run mode, execution is skipped and a successful synthetic CompletedProcess is returned.

Parameters:
  • command (str | list[str]) – Command to execute.

  • dry_run (bool) – If True, print the command without executing it.

  • kwargs (Any) – Additional keyword arguments forwarded to subprocess.run.

Returns:

Completed process produced by the command execution.

Return type:

subprocess.CompletedProcess[Any]

mafw.scripts.new_release.commit_changes(version: str, dry_run: bool, *, include_changelog: bool = True) None[source]

Commit tracked release artifacts for the target version.

The generated release note is intentionally not staged and remains untracked as requested.

Parameters:
  • version (str) – Target release version.

  • dry_run (bool) – Whether command execution is disabled.

  • include_changelog (bool) – Whether CHANGELOG.md should be staged and committed as part of the release artifacts.

mafw.scripts.new_release.create_release_note(version: str, dry_run: bool) Path[source]

Create the release note markdown file for the given version.

Change sections are copied from the generated changelog for the same version to ensure release notes stay aligned with changelog content.

Parameters:
  • version (str) – Target release version.

  • dry_run (bool) – Whether command execution is disabled.

Returns:

Path to the release note markdown file.

Return type:

Path

Raises:

click.ClickException – If the template is missing.

mafw.scripts.new_release.create_tag(version: str, dry_run: bool) str[source]

Create the local git tag for the target version.

Parameters:
  • version (str) – Target release version.

  • dry_run (bool) – Whether command execution is disabled.

Returns:

Created tag name.

Return type:

str

mafw.scripts.new_release.ensure_clean_git() None[source]

Ensure the git working tree is clean (excluding untracked files).

Raises:

click.ClickException – If tracked changes are present.

mafw.scripts.new_release.extract_change_sections_from_changelog(version: str) dict[str, str][source]

Extract release change sections from CHANGELOG.md.

Parameters:

version (str) – Target release version without leading v.

Returns:

Mapping from release-note category key to markdown content.

Return type:

dict[str, str]

Raises:

click.ClickException – If changelog file does not exist or the requested section is missing.

mafw.scripts.new_release.extract_change_sections_from_changelog_block(changelog_block: str) dict[str, str][source]

Extract release change sections from a changelog block.

The parsing logic expects the block to contain level-3 headings (###) with standardized labels (e.g. “New Features”, “Bug Fixes”, …).

Parameters:

changelog_block (str) – Changelog markdown block to parse.

Returns:

Mapping from release-note category key to markdown content.

Return type:

dict[str, str]

mafw.scripts.new_release.extract_version_changelog_block(changelog_content: str, version: str) str[source]

Extract the changelog block associated with the target version.

Parameters:
  • changelog_content (str) – Complete changelog markdown text.

  • version (str) – Target release version without leading v.

Returns:

Markdown block for the selected release.

Return type:

str

Raises:

click.ClickException – If no section for the target version is found.

mafw.scripts.new_release.generate_changelog(version: str, dry_run: bool) None[source]

Generate the project changelog for the target release.

Parameters:
  • version (str) – Target release version.

  • dry_run (bool) – Whether command execution is disabled.

mafw.scripts.new_release.get_contributors(since_ref: str) list[str][source]

Collect contributor names since the baseline reference.

Parameters:

since_ref (str) – Baseline reference to compare against HEAD.

Returns:

Ordered list of contributor names.

Return type:

list[str]

mafw.scripts.new_release.get_last_stable_tag() str | None[source]

Return the latest stable tag matching vX.Y.Z.

Returns:

Latest stable tag or None when no stable tags are present.

Return type:

str | None

mafw.scripts.new_release.get_release_note_base_ref() str[source]

Determine the git reference used as baseline for release-note metadata.

Returns:

Last stable tag if available, otherwise the first commit hash.

Return type:

str

mafw.scripts.new_release.get_release_statistics(since_ref: str) tuple[str, str][source]

Collect release statistics since the baseline reference.

Parameters:

since_ref (str) – Baseline reference to compare against HEAD.

Returns:

Commit count and short diff statistics.

Return type:

tuple[str, str]

mafw.scripts.new_release.normalize_hatch_segments(segments: str) str[source]

Normalize the user-provided segment selector to a Hatch-compatible token list.

The selector supports comma-separated segments and follows Hatch semantics. Examples:

  • minor,rc: bump minor and create/reset an RC suffix.

  • rc: increment the release-candidate counter only.

  • alpha / beta: create alpha/beta pre-release suffix.

  • release: remove any pre-release suffix (stable release).

Parameters:

segments (str) – Raw selector as passed on the command line.

Returns:

Normalized Hatch selector (comma-separated, lowercase, no whitespace).

Return type:

str

Raises:

click.ClickException – If the selector is empty or contains unsupported segments.

mafw.scripts.new_release.parse_stable_tag(tag: str) tuple[int, int, int][source]

Parse a stable tag in the form vX.Y.Z.

Parameters:

tag (str) – Stable tag value.

Returns:

Parsed stable version tuple.

Return type:

tuple[int, int, int]

Raises:

click.ClickException – If the tag does not match vX.Y.Z.

mafw.scripts.new_release.parse_version(version: str) tuple[int, int, int, int | None][source]

Parse a version string in the form X.Y.Z or with a pre-release suffix.

Supported suffixes follow Hatch/PEP 440 conventions:

  • Release candidates: X.Y.ZrcN

  • Alpha releases: X.Y.ZaN

  • Beta releases: X.Y.ZbN

Parameters:

version (str) – Version string to parse.

Returns:

Parsed major, minor, micro, and optional pre-release index.

Return type:

tuple[int, int, int, int | None]

Raises:

click.ClickException – If the version format is unsupported.

mafw.scripts.new_release.prevent_duplicate_tag(version: str) None[source]

Ensure the target release tag does not already exist.

Parameters:

version (str) – Target release version.

Raises:

click.ClickException – If v<version> already exists.

mafw.scripts.new_release.push_changes(dry_run: bool) None[source]

Push commits and tags to the remote repository.

Parameters:

dry_run (bool) – Whether command execution is disabled.

mafw.scripts.new_release.read_current_version() str[source]

Read the project version using hatch version.

Returns:

Current project version string.

Return type:

str

Raises:

click.ClickException – If the version cannot be extracted.

mafw.scripts.new_release.render_release_note_section(content: str, header: str, section_markdown: str) str[source]

Replace a release-note section in the markdown template.

If the provided section markdown is empty, the entire section (header and placeholder) is removed from the content.

Parameters:
  • content (str) – Current release note markdown text.

  • header (str) – Section header to replace.

  • section_markdown (str) – Markdown content to insert under the section header.

Returns:

Updated markdown text.

Return type:

str

Raises:

click.ClickException – If the section header cannot be matched in template.

mafw.scripts.new_release.run_stdout(command: str | list[str], *, dry_run: bool = False, **kwargs: Any) str[source]

Execute a command and return stripped standard output.

Parameters:
  • command (str | list[str]) – Command to execute.

  • dry_run (bool) – If True, do not execute the command.

  • kwargs (Any) – Additional keyword arguments forwarded to cmd.

Returns:

Standard output stripped of leading and trailing whitespace.

Return type:

str

mafw.scripts.new_release.update_notice_version(version: str, dry_run: bool) None[source]

Update the version in NOTICE.txt to match the release version.

Parameters:
  • version (str) – Target release version.

  • dry_run (bool) – Whether filesystem changes are disabled.

Raises:

click.ClickException – If NOTICE.txt is missing or has unexpected format.

mafw.scripts.new_release.ABOUT_FILE = PosixPath('src/mafw/__about__.py')

Path to the version source file managed by hatch version.

mafw.scripts.new_release.CHANGELOG_FILE = PosixPath('CHANGELOG.md')

Path to the changelog file that is regenerated for each release.

mafw.scripts.new_release.CONTEXT_SETTINGS = {'help_option_names': ['-h', '--help']}

Click context settings for command line help aliases.

mafw.scripts.new_release.NOTICE_FILE = PosixPath('NOTICE.txt')

Path to the notice file containing the public project version.

mafw.scripts.new_release.NOTICE_VERSION_PATTERN = re.compile('MAFw - Modular Analysis Framework\\n\\nversion:\\s*V[0-9]+\\.[0-9]+\\.[0-9]+(?:[-a-zA-Z0-9\\.\\-_]+)?', re.MULTILINE)

Pattern used to update the version block in NOTICE.txt.

mafw.scripts.new_release.RELEASE_SECTION_HEADERS = {'bug_fixes': '## 🐛 Bug Fixes', 'deprecated': '## ⚠️ Deprecated', 'new_features': '## 🚀 New Features', 'other_changes': '## ️*️⃣    Other Changes', 'refactorings': '## ♻️ Refactorings', 'removed': '## 🗑️ Removals', 'security': '## 🔒 Security'}

Release note section headers used in the markdown template.

mafw.scripts.new_release.RELEASE_TEMPLATE_FILE = PosixPath('.gitlab/release_templates/Default.md')

Path to the markdown template used to build release notes.

mafw.scripts.new_release.STABLE_TAG_PATTERN = re.compile('^v(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<micro>\\d+)$')

Regular expression used to identify stable git tags in the form vX.Y.Z.

mafw.scripts.new_release.VALID_HATCH_SEGMENTS: Final[tuple[str, ...]] = ('major', 'minor', 'micro', 'rc', 'alpha', 'beta', 'release')

Allowed Hatch version segments supported by this script.

mafw.scripts.new_release.VERSION_PATTERN = re.compile('^(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<micro>\\d+)(?:(?P<suffix>rc|a|b)(?P<suffix_num>\\d+))?$')

Regular expression used to parse local version strings (stable/alpha/beta/rc).

mafw.scripts.new_release.VersionKind

Supported release kinds used to drive changelog and release-note behavior.

alias of Literal[‘stable’, ‘rc’, ‘alpha’, ‘beta’]