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
475
476
477
478
479
480
481
482
483
484
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
464
465
466
467
468
469
470
471
472
473
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
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
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
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["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
360
361
362
363
364
365
366
367
368
369
370
371
372
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
125
126
127
128
129
130
131
132
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
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] = {}

    # YORE: Bump 3: Replace `_Trailers()` with `[]` within line.
    self.trailers: list[tuple[str, str]] = _Trailers()
    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
215
216
217
218
219
220
221
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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
283
284
285
286
287
288
289
290
291
292
293
@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
475
476
477
478
479
480
481
482
483
484
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
464
465
466
467
468
469
470
471
472
473
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
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
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}