Skip to content

feat: Add Git-related constants and functions, update changelog handl…#51

Merged
97gamjak merged 19 commits intodevfrom
feature/DEV-21-retrieve-last-release-and-or-tag-from-git-github
Dec 20, 2025
Merged

feat: Add Git-related constants and functions, update changelog handl…#51
97gamjak merged 19 commits intodevfrom
feature/DEV-21-retrieve-last-release-and-or-tag-from-git-github

Conversation

@97gamjak
Copy link
Copy Markdown
Owner

…ing, and enhance linting rules

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request refactors Git and GitHub-related functionality by introducing a new Constants module for centralized configuration, adding Git tag handling capabilities, and updating the changelog management to remove dependency on environment variables. The changes also include linting rule adjustments and test updates to align with the new architecture.

  • Introduces a centralized Constants module with GitConstants for GitHub URLs
  • Adds comprehensive Git tag functionality with version comparison and parsing
  • Removes get_github_repo() function in favor of static constants

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/devops/config/constants.py Adds new Constants and GitConstants classes for centralized GitHub URL management
src/devops/config/__init__.py Exports the new Constants class
src/devops/git/tag.py Introduces GitTag dataclass and functions for Git tag parsing, comparison, and retrieval
src/devops/git/__init__.py Adds module docstring for Git-related functionality
src/devops/git/github.py Removes get_github_repo() function that relied on environment variables
src/devops/files/update_changelog.py Updates to use Constants instead of get_github_repo(), renames exception from MSTD to DevOps
src/devops/utils/utils.py Updates error message to reference Constants.github.github_devops_issues_url
src/devops/enums/__init__.py Adds LogLevel to exports
tests/files/test_update_changelog.py Updates tests to remove mocking of get_github_repo() and use Constants, renames exception references
ruff.toml Moves PLR2004 (magic numbers) rule from test-specific ignores to global ignores
.gitignore Adds specific test notebook file to ignore list
Comments suppressed due to low confidence (1)

src/devops/config/constants.py:3

  • Import of 'dataclass' is not used.
from dataclasses import dataclass

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +241
"""Module for Git tag-related constants and functions."""

from __future__ import annotations

import subprocess
from dataclasses import dataclass


# TODO(97gamjak): centralize exception handling
# https://github.com/97gamjak/devops/issues/24
class GitTagError(Exception):
"""Exception raised for Git tag-related errors in devops checks."""

def __init__(self, message: str) -> None:
"""Initialize the exception with a message."""
super().__init__(f"GitTagError: {message}")
self.message = message


@dataclass(frozen=True)
class GitTag:
"""Class representing a Git tag."""

major: int = 0
minor: int = 0
patch: int = 0

def __str__(self) -> str:
"""Return the string representation of the Git tag.

Returns
-------
str
The string representation of the Git tag
in the format 'v<major>.<minor>.<patch>'.

"""
return f"v{self.major}.{self.minor}.{self.patch}"

def __eq__(self, other: object) -> bool:
"""Check equality between two GitTag instances.

Parameters
----------
other: object
The other GitTag instance to compare with.

Returns
-------
bool
True if both GitTag instances are equal, False otherwise.

"""
if not isinstance(other, GitTag):
return NotImplemented
return (self.major, self.minor, self.patch) == (
other.major,
other.minor,
other.patch,
)

def __hash__(self) -> int:
"""Return the hash of the GitTag instance.

Returns
-------
int
The hash value of the GitTag instance.

"""
return hash((self.major, self.minor, self.patch))

def __lt__(self, other: GitTag) -> bool:
"""Check if this GitTag is less than another GitTag.

Parameters
----------
other: GitTag
The other GitTag instance to compare with.

Returns
-------
bool
True if this GitTag is less than the other GitTag,
False otherwise.

"""
version_self = (self.major, self.minor, self.patch)
version_other = (other.major, other.minor, other.patch)
return version_self < version_other

def __gt__(self, other: GitTag) -> bool:
"""Check if this GitTag is greater than another GitTag.

Parameters
----------
other: GitTag
The other GitTag instance to compare with.

Returns
-------
bool
True if this GitTag is greater than the other GitTag,
False otherwise.

"""
version_self = (self.major, self.minor, self.patch)
version_other = (other.major, other.minor, other.patch)
return version_self > version_other

def __le__(self, other: GitTag) -> bool:
"""Check if this GitTag is less than or equal to another GitTag.

Parameters
----------
other: GitTag
The other GitTag instance to compare with.

Returns
-------
bool
True if this GitTag is less than or equal to the other GitTag,
False otherwise.

"""
version_self = (self.major, self.minor, self.patch)
version_other = (other.major, other.minor, other.patch)
return version_self <= version_other

def __ge__(self, other: GitTag) -> bool:
"""Check if this GitTag is greater than or equal to another GitTag.

Parameters
----------
other: GitTag
The other GitTag instance to compare with.

Returns
-------
bool
True if this GitTag is greater than or equal to the other GitTag,
False otherwise.

"""
version_self = (self.major, self.minor, self.patch)
version_other = (other.major, other.minor, other.patch)
return version_self >= version_other

@staticmethod
def from_string(tag: str) -> GitTag:
"""Create a GitTag instance from a string.

Parameters
----------
tag: str
The Git tag string in the format 'v<major>.<minor>.<patch>'.

Returns
-------
GitTag
The GitTag instance created from the string.

Raises
------
GitTagError
If the tag string is not in the correct format.

"""
tag = tag.removeprefix("v")
parts = tag.split(".")

# TODO(97gamjak): implement support for different version schemes
# https://97gamjak.atlassian.net/browse/DEV-49
if len(parts) != 3: # noqa: PLR2004 this will be removed and cleaned up with further naming schemes
msg = f"Invalid tag format: {tag}"
raise GitTagError(msg)

try:
major, minor, patch = map(int, parts)
except ValueError as exc:
msg = f"Invalid numeric components in tag: {tag}"
raise GitTagError(msg) from exc
return GitTag(major, minor, patch)


def get_all_tags(*, empty_tag_list_allowed: bool = True) -> list[GitTag]:
"""Get all Git tags in the repository.

Parameters
----------
empty_tag_list_allowed: bool
Whether to allow an empty tag list without raising an error.

Returns
-------
list[GitTag]
A list of all Git tags.

Raises
------
GitTagError
If there is an error retrieving the Git tags and
empty_tag_list_allowed is False.

"""
try:
tags_output = subprocess.check_output(
["git", "tag", "--list"],
stderr=subprocess.DEVNULL,
text=True,
).strip()
except subprocess.CalledProcessError as e:
if not empty_tag_list_allowed:
msg = "Failed to retrieve Git tags."
raise GitTagError(msg) from e
return []

tags = []
for tag_str in tags_output.splitlines():
tag = GitTag.from_string(tag_str)
tags.append(tag)

return tags


def get_latest_tag() -> GitTag:
"""Get the latest Git tag in the repository.

Returns
-------
GitTag
The latest Git tag. If no tags exist, returns GitTag(0, 0, 0).

"""
tags = get_all_tags()
if not tags:
return GitTag(0, 0, 0)

sorted_tags = sorted(tags, reverse=True)

return sorted_tags[0]
Copy link

Copilot AI Dec 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new Git tag functionality in src/devops/git/tag.py lacks test coverage. Other modules in the project, such as src/devops/files/update_changelog.py and src/devops/config/config.py, have corresponding test files. The GitTag class and functions like get_all_tags and get_latest_tag should have comprehensive unit tests to cover tag parsing, comparison operations, and edge cases (e.g., empty tag lists, invalid tag formats).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback

97gamjak and others added 6 commits December 20, 2025 09:58
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…t-github' of github.com:97gamjak/devops into feature/DEV-21-retrieve-last-release-and-or-tag-from-git-github
Copy link
Copy Markdown
Contributor

Copilot AI commented Dec 20, 2025

@97gamjak I've opened a new pull request, #53, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 4 commits December 20, 2025 09:07
Add 39 comprehensive unit tests for src/devops/git/tag.py covering:
- GitTag class initialization and string representation
- GitTag.from_string() with valid and invalid inputs
- GitTag ordering and comparison operations
- get_all_tags() with various scenarios and edge cases
- get_latest_tag() with version ordering logic
- GitTagError exception handling

All tests pass and follow project conventions.

Co-authored-by: 97gamjak <77228802+97gamjak@users.noreply.github.com>
Add test coverage for git tag module
@97gamjak 97gamjak merged commit bedef73 into dev Dec 20, 2025
4 checks passed
@97gamjak 97gamjak deleted the feature/DEV-21-retrieve-last-release-and-or-tag-from-git-github branch December 20, 2025 09:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants