Skip to content

commit ¤

Module containing the commit logic.

Classes:

AngularConvention ¤

Bases: CommitConvention

Angular commit message convention.

Methods:

  • is_major

    Tell if this commit is worth a major bump.

  • is_minor

    Tell if this commit is worth a minor bump.

  • parse_subject

    Parse the subject of the commit (<type>[(scope)]: Subject).

is_major ¤

is_major(commit_message: str) -> bool

Tell if this commit is worth a major bump.

Parameters:

  • commit_message (str) –

    The commit message.

Returns:

  • bool

    Whether it's a major commit.

Source code in src/git_changelog/commit.py
385
386
387
388
389
390
391
392
393
394
def is_major(self, commit_message: str) -> bool:
    """Tell if this commit is worth a major bump.

    Arguments:
        commit_message: The commit message.

    Returns:
        Whether it's a major commit.
    """
    return bool(self.BREAK_REGEX.search(commit_message))

is_minor ¤

is_minor(commit_type: str) -> bool

Tell if this commit is worth a minor bump.

Parameters:

  • commit_type (str) –

    The commit type.

Returns:

  • bool

    Whether it's a minor commit.

Source code in src/git_changelog/commit.py
374
375
376
377
378
379
380
381
382
383
def is_minor(self, commit_type: str) -> bool:
    """Tell if this commit is worth a minor bump.

    Arguments:
        commit_type: The commit type.

    Returns:
        Whether it's a minor commit.
    """
    return commit_type == self.TYPES["feat"]

parse_subject ¤

parse_subject(commit_subject: str) -> dict[str, str]

Parse the subject of the commit (<type>[(scope)]: Subject).

Parameters:

  • commit_subject (str) –

    The commit message subject.

Returns:

Source code in src/git_changelog/commit.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
def parse_subject(self, commit_subject: str) -> dict[str, str]:
    """Parse the subject of the commit (`<type>[(scope)]: Subject`).

    Arguments:
        commit_subject: The commit message subject.

    Returns:
        The parsed data.
    """
    subject_match = self.SUBJECT_REGEX.match(commit_subject)
    if subject_match:
        dct = subject_match.groupdict()
        dct["type"] = self.TYPES[dct["type"]]
        return dct
    return {"type": "", "scope": "", "subject": commit_subject}

BasicConvention ¤

Bases: CommitConvention

Basic commit message convention.

Methods:

  • is_major

    Tell if this commit is worth a major bump.

  • is_minor

    Tell if this commit is worth a minor bump.

  • parse_type

    Parse the type of the commit given its subject.

is_major ¤

is_major(commit_message: str) -> bool

Tell if this commit is worth a major bump.

Parameters:

  • commit_message (str) –

    The commit message.

Returns:

  • bool

    Whether it's a major commit.

Source code in src/git_changelog/commit.py
295
296
297
298
299
300
301
302
303
304
def is_major(self, commit_message: str) -> bool:
    """Tell if this commit is worth a major bump.

    Arguments:
        commit_message: The commit message.

    Returns:
        Whether it's a major commit.
    """
    return bool(self.BREAK_REGEX.search(commit_message))

is_minor ¤

is_minor(commit_type: str) -> bool

Tell if this commit is worth a minor bump.

Parameters:

  • commit_type (str) –

    The commit type.

Returns:

  • bool

    Whether it's a minor commit.

Source code in src/git_changelog/commit.py
284
285
286
287
288
289
290
291
292
293
def is_minor(self, commit_type: str) -> bool:
    """Tell if this commit is worth a minor bump.

    Arguments:
        commit_type: The commit type.

    Returns:
        Whether it's a minor commit.
    """
    return commit_type == self.TYPES["add"]

parse_type ¤

parse_type(commit_subject: str) -> str

Parse the type of the commit given its subject.

Parameters:

  • commit_subject (str) –

    The commit message subject.

Returns:

  • str

    The commit type.

Source code in src/git_changelog/commit.py
270
271
272
273
274
275
276
277
278
279
280
281
282
def parse_type(self, commit_subject: str) -> str:
    """Parse the type of the commit given its subject.

    Arguments:
        commit_subject: The commit message subject.

    Returns:
        The commit type.
    """
    type_match = self.TYPE_REGEX.match(commit_subject)
    if type_match:
        return self.TYPES.get(type_match.groupdict()["type"].lower(), "")
    return ""

Commit ¤

Commit(
    commit_hash: str,
    author_name: str = "",
    author_email: str = "",
    author_date: str | datetime = "",
    committer_name: str = "",
    committer_email: str = "",
    committer_date: str | datetime = "",
    refs: str = "",
    subject: str = "",
    body: list[str] | None = None,
    url: str = "",
    *,
    parse_trailers: bool = False,
    parent_hashes: str | list[str] = "",
    commits_map: dict[str, Commit] | None = None,
    version_parser: (
        Callable[[str], tuple[ParsedVersion, str]] | None
    ) = None
)

A class to represent a commit.

Parameters:

  • commit_hash (str) –

    The commit hash.

  • author_name (str, default: '' ) –

    The author name.

  • author_email (str, default: '' ) –

    The author email.

  • author_date (str | datetime, default: '' ) –

    The authoring date (datetime or UTC timestamp).

  • committer_name (str, default: '' ) –

    The committer name.

  • committer_email (str, default: '' ) –

    The committer email.

  • committer_date (str | datetime, default: '' ) –

    The committing date (datetime or UTC timestamp).

  • refs (str, default: '' ) –

    The commit refs.

  • subject (str, default: '' ) –

    The commit message subject.

  • body (list[str] | None, default: None ) –

    The commit message body.

  • url (str, default: '' ) –

    The commit URL.

  • parse_trailers (bool, default: False ) –

    Whether to parse Git trailers.

Methods:

Attributes:

Source code in src/git_changelog/commit.py
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
def __init__(
    self,
    commit_hash: str,
    author_name: str = "",
    author_email: str = "",
    author_date: str | datetime = "",
    committer_name: str = "",
    committer_email: str = "",
    committer_date: str | datetime = "",
    refs: str = "",
    subject: str = "",
    body: list[str] | None = None,
    url: str = "",
    *,
    parse_trailers: bool = False,
    parent_hashes: str | list[str] = "",
    commits_map: dict[str, Commit] | None = None,
    version_parser: Callable[[str], tuple[ParsedVersion, str]] | None = None,
):
    """Initialization method.

    Arguments:
        commit_hash: The commit hash.
        author_name: The author name.
        author_email: The author email.
        author_date: The authoring date (datetime or UTC timestamp).
        committer_name: The committer name.
        committer_email: The committer email.
        committer_date: The committing date (datetime or UTC timestamp).
        refs: The commit refs.
        subject: The commit message subject.
        body: The commit message body.
        url: The commit URL.
        parse_trailers: Whether to parse Git trailers.
    """
    if not author_date:
        author_date = datetime.now()  # noqa: DTZ005
    elif isinstance(author_date, str):
        author_date = datetime.fromtimestamp(float(author_date), tz=timezone.utc)
    if not committer_date:
        committer_date = datetime.now()  # noqa: DTZ005
    elif isinstance(committer_date, str):
        committer_date = datetime.fromtimestamp(float(committer_date), tz=timezone.utc)

    self.hash: str = commit_hash
    self.author_name: str = author_name
    self.author_email: str = author_email
    self.author_date: datetime = author_date
    self.committer_name: str = committer_name
    self.committer_email: str = committer_email
    self.committer_date: datetime = committer_date
    self.subject: str = subject
    self.body: list[str] = _clean_body(body) if body else []
    self.url: str = url

    tag = ""
    for ref in refs.split(","):
        ref = ref.strip()  # noqa: PLW2901
        if ref.startswith("tag: "):
            ref = ref.replace("tag: ", "")  # noqa: PLW2901
            if version_parser is None or _is_valid_version(ref, version_parser):
                tag = ref
                break
    self.tag: str = tag
    self.version: str = tag

    if isinstance(parent_hashes, str):
        parent_hashes = parent_hashes.split()
    self.parent_hashes = parent_hashes
    self._commits_map = commits_map

    self.text_refs: dict[str, list[Ref]] = {}
    self.convention: dict[str, Any] = {}

    self.trailers: dict[str, str] = {}
    self.body_without_trailers = self.body

    if parse_trailers:
        self._parse_trailers()

parent_commits property ¤

parent_commits: list[Commit]

Parent commits of this commit.

update_with_convention ¤

update_with_convention(
    convention: CommitConvention,
) -> None

Apply the convention-parsed data to this commit.

Parameters:

Source code in src/git_changelog/commit.py
125
126
127
128
129
130
131
def update_with_convention(self, convention: CommitConvention) -> None:
    """Apply the convention-parsed data to this commit.

    Arguments:
        convention: The convention to use.
    """
    self.convention.update(convention.parse_commit(self))

update_with_provider ¤

update_with_provider(
    provider: ProviderRefParser, parse_refs: bool = True
) -> None

Apply the provider-parsed data to this commit.

Parameters:

  • provider (ProviderRefParser) –

    The provider to use.

  • parse_refs (bool, default: True ) –

    Whether to parse references for this provider.

Source code in src/git_changelog/commit.py
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
def update_with_provider(
    self,
    provider: ProviderRefParser,
    parse_refs: bool = True,  # noqa: FBT001,FBT002
) -> None:
    """Apply the provider-parsed data to this commit.

    Arguments:
        provider: The provider to use.
        parse_refs: Whether to parse references for this provider.
    """
    # set the commit url based on provider
    # FIXME: hardcoded 'commits'
    if "commits" in provider.REF:
        self.url = provider.build_ref_url("commits", {"ref": self.hash})
    else:
        # use default "commit" url (could be wrong)
        self.url = f"{provider.url}/{provider.namespace}/{provider.project}/commit/{self.hash}"

    # build commit text references from its subject and body
    if parse_refs:
        for ref_type in provider.REF:
            self.text_refs[ref_type] = provider.get_refs(
                ref_type,
                "\n".join([self.subject, *self.body]),
            )

        if "issues" in self.text_refs:
            self.text_refs["issues_not_in_subject"] = []
            for issue in self.text_refs["issues"]:
                if issue.ref not in self.subject:
                    self.text_refs["issues_not_in_subject"].append(issue)

CommitConvention ¤

Bases: ABC

A base class for a convention of commit messages.

Methods:

parse_commit abstractmethod ¤

parse_commit(commit: Commit) -> dict[str, str | bool]

Parse the commit to extract information.

Parameters:

  • commit (Commit) –

    The commit to parse.

Returns:

Source code in src/git_changelog/commit.py
193
194
195
196
197
198
199
200
201
202
203
@abstractmethod
def parse_commit(self, commit: Commit) -> dict[str, str | bool]:
    """Parse the commit to extract information.

    Arguments:
        commit: The commit to parse.

    Returns:
        A dictionary containing the parsed data.
    """
    raise NotImplementedError

ConventionalCommitConvention ¤

Bases: AngularConvention

Conventional commit message convention.

Methods:

  • is_major

    Tell if this commit is worth a major bump.

  • is_minor

    Tell if this commit is worth a minor bump.

  • parse_subject

    Parse the subject of the commit (<type>[(scope)]: Subject).

is_major ¤

is_major(commit_message: str) -> bool

Tell if this commit is worth a major bump.

Parameters:

  • commit_message (str) –

    The commit message.

Returns:

  • bool

    Whether it's a major commit.

Source code in src/git_changelog/commit.py
385
386
387
388
389
390
391
392
393
394
def is_major(self, commit_message: str) -> bool:
    """Tell if this commit is worth a major bump.

    Arguments:
        commit_message: The commit message.

    Returns:
        Whether it's a major commit.
    """
    return bool(self.BREAK_REGEX.search(commit_message))

is_minor ¤

is_minor(commit_type: str) -> bool

Tell if this commit is worth a minor bump.

Parameters:

  • commit_type (str) –

    The commit type.

Returns:

  • bool

    Whether it's a minor commit.

Source code in src/git_changelog/commit.py
374
375
376
377
378
379
380
381
382
383
def is_minor(self, commit_type: str) -> bool:
    """Tell if this commit is worth a minor bump.

    Arguments:
        commit_type: The commit type.

    Returns:
        Whether it's a minor commit.
    """
    return commit_type == self.TYPES["feat"]

parse_subject ¤

parse_subject(commit_subject: str) -> dict[str, str]

Parse the subject of the commit (<type>[(scope)]: Subject).

Parameters:

  • commit_subject (str) –

    The commit message subject.

Returns:

Source code in src/git_changelog/commit.py
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
def parse_subject(self, commit_subject: str) -> dict[str, str]:
    """Parse the subject of the commit (`<type>[(scope)]: Subject`).

    Arguments:
        commit_subject: The commit message subject.

    Returns:
        The parsed data.
    """
    subject_match = self.SUBJECT_REGEX.match(commit_subject)
    if subject_match:
        dct = subject_match.groupdict()
        dct["type"] = self.TYPES[dct["type"]]
        return dct
    return {"type": "", "scope": "", "subject": commit_subject}