mirror of
https://github.com/lvgl/lvgl.git
synced 2026-05-31 07:56:23 +08:00
chore(commit_message): allow ! in commit message to indicate breaking change (#10140)
This commit is contained in:
@@ -52,13 +52,16 @@ Format](https://github.com/angular/angular/blob/main/CONTRIBUTING.md#-commit-mes
|
|||||||
The following structure should be used:
|
The following structure should be used:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
<type>(<scope>): <subject>
|
<type>(<scope>)!: <subject>
|
||||||
<--- blank line
|
<--- blank line
|
||||||
<body>
|
<body>
|
||||||
<--- blank line
|
<--- blank line
|
||||||
<footer>
|
<footer>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The `!` after the scope is optional and is used to flag breaking changes
|
||||||
|
(see [Breaking Changes](#breaking-changes) below).
|
||||||
|
|
||||||
Possible `<type>`s:
|
Possible `<type>`s:
|
||||||
|
|
||||||
- `feat` new feature
|
- `feat` new feature
|
||||||
@@ -97,7 +100,38 @@ change.
|
|||||||
(See [Linking a pull request to an issue](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue)
|
(See [Linking a pull request to an issue](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue)
|
||||||
for details.)
|
for details.)
|
||||||
|
|
||||||
Some examples:
|
### Breaking Changes
|
||||||
|
|
||||||
|
If your commit introduces a change that breaks backward compatibility (e.g. removes or
|
||||||
|
renames a public API, changes a function signature, or alters existing behavior in a
|
||||||
|
way that requires callers to update their code), it must be flagged the following ways:
|
||||||
|
|
||||||
|
**1. Add `!` after the scope in the subject line** to make the breaking change immediately
|
||||||
|
visible in the commit history:
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat(drm)!: replace lv_drm_init() arguments
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Add a `BREAKING CHANGE` entry in the footer** to describe what changed and how to
|
||||||
|
migrate:
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat(drm)!: replace lv_drm_init() arguments
|
||||||
|
|
||||||
|
The card and connector arguments have been merged into a single
|
||||||
|
device path string for consistency with other driver APIs.
|
||||||
|
|
||||||
|
BREAKING CHANGE: lv_drm_init(card, connector) is now
|
||||||
|
lv_drm_init(device). Replace calls like lv_drm_init(0, 1) with
|
||||||
|
lv_drm_init("/dev/dri/card0").
|
||||||
|
```
|
||||||
|
|
||||||
|
Using both `!` and `BREAKING CHANGE` together is recommended for maximum clarity,
|
||||||
|
the `!` signals at a glance that the commit is breaking, while the footer explains
|
||||||
|
exactly what callers need to update.
|
||||||
|
|
||||||
|
### Commit Message Examples
|
||||||
|
|
||||||
```text
|
```text
|
||||||
fix(image): update size when a new source is set
|
fix(image): update size when a new source is set
|
||||||
@@ -126,6 +160,14 @@ docs(porting): fix typo
|
|||||||
chore: bump version to release candidate tag
|
chore: bump version to release candidate tag
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```text
|
||||||
|
feat(drm)!: replace lv_drm_init() arguments
|
||||||
|
|
||||||
|
BREAKING CHANGE: lv_drm_init(card, connector) is now
|
||||||
|
lv_drm_init(device). Replace calls like lv_drm_init(0, 1) with
|
||||||
|
lv_drm_init("/dev/dri/card0").
|
||||||
|
```
|
||||||
|
|
||||||
### PR Title
|
### PR Title
|
||||||
|
|
||||||
Since the repository uses squash merge by default, the PR title becomes
|
Since the repository uses squash merge by default, the PR title becomes
|
||||||
|
|||||||
@@ -56,13 +56,13 @@ TYPE_TYPOS = {
|
|||||||
VALID_TYPES_RE = "|".join(VALID_TYPES)
|
VALID_TYPES_RE = "|".join(VALID_TYPES)
|
||||||
|
|
||||||
# type(scope): description (chore/docs/ci allow omitting scope)
|
# type(scope): description (chore/docs/ci allow omitting scope)
|
||||||
FULL_PATTERN = re.compile(rf"^({VALID_TYPES_RE})\(([a-zA-Z0-9_/-]+)\): (.+)$")
|
FULL_PATTERN = re.compile(rf"^({VALID_TYPES_RE})\(([a-zA-Z0-9_/-]+)\)(!?): (.+)$")
|
||||||
|
|
||||||
# Types that allow omitting scope
|
# Types that allow omitting scope
|
||||||
SCOPE_OPTIONAL_TYPES = {"chore", "docs", "ci"}
|
SCOPE_OPTIONAL_TYPES = {"chore", "docs", "ci"}
|
||||||
|
|
||||||
# type: description (no scope, for scope-optional types)
|
# type: description (no scope, for scope-optional types)
|
||||||
NO_SCOPE_PATTERN = re.compile(rf"^({'|'.join(SCOPE_OPTIONAL_TYPES)}): (.+)$")
|
NO_SCOPE_PATTERN = re.compile(rf"^({'|'.join(SCOPE_OPTIONAL_TYPES)})(!?): (.+)$")
|
||||||
|
|
||||||
# type( or type:
|
# type( or type:
|
||||||
TYPE_ONLY_PATTERN = re.compile(r"^([a-zA-Z_]+)")
|
TYPE_ONLY_PATTERN = re.compile(r"^([a-zA-Z_]+)")
|
||||||
@@ -138,13 +138,13 @@ def check_commit_msg(msg):
|
|||||||
type_with_paren = re.compile(rf"^({VALID_TYPES_RE})\(")
|
type_with_paren = re.compile(rf"^({VALID_TYPES_RE})\(")
|
||||||
if not type_with_paren.match(msg):
|
if not type_with_paren.match(msg):
|
||||||
# type: desc (missing scope)
|
# type: desc (missing scope)
|
||||||
type_with_colon = re.compile(rf"^({VALID_TYPES_RE}):")
|
type_with_colon = re.compile(rf"^({VALID_TYPES_RE})!?:")
|
||||||
if type_with_colon.match(msg):
|
if type_with_colon.match(msg):
|
||||||
# Allow scope-optional types (chore, docs, ci) without scope
|
# Allow scope-optional types (chore, docs, ci) without scope
|
||||||
if type_lower in SCOPE_OPTIONAL_TYPES:
|
if type_lower in SCOPE_OPTIONAL_TYPES:
|
||||||
no_scope_match = NO_SCOPE_PATTERN.match(msg)
|
no_scope_match = NO_SCOPE_PATTERN.match(msg)
|
||||||
if no_scope_match:
|
if no_scope_match:
|
||||||
desc = no_scope_match.group(2)
|
desc = no_scope_match.group(3)
|
||||||
if desc and desc[0].isupper():
|
if desc and desc[0].isupper():
|
||||||
errors.append(
|
errors.append(
|
||||||
f"Description should start with lowercase: '{desc[:30]}...'"
|
f"Description should start with lowercase: '{desc[:30]}...'"
|
||||||
@@ -173,8 +173,8 @@ def check_commit_msg(msg):
|
|||||||
if not full:
|
if not full:
|
||||||
# Diagnose specific issues
|
# Diagnose specific issues
|
||||||
empty_scope = re.compile(rf"^({VALID_TYPES_RE})\(\)")
|
empty_scope = re.compile(rf"^({VALID_TYPES_RE})\(\)")
|
||||||
no_space = re.compile(rf"^({VALID_TYPES_RE})\([^)]*\):[^ ]")
|
no_space = re.compile(rf"^({VALID_TYPES_RE})\([^)]*\)!?:[^ ]")
|
||||||
no_colon = re.compile(rf"^({VALID_TYPES_RE})\([^)]*\)[^:]")
|
no_colon = re.compile(rf"^({VALID_TYPES_RE})\([^)]*\)!?[^:!]")
|
||||||
|
|
||||||
if empty_scope.match(msg):
|
if empty_scope.match(msg):
|
||||||
errors.append("Scope cannot be empty")
|
errors.append("Scope cannot be empty")
|
||||||
@@ -184,7 +184,7 @@ def check_commit_msg(msg):
|
|||||||
errors.append("Missing colon after scope. Use 'type(scope): description'")
|
errors.append("Missing colon after scope. Use 'type(scope): description'")
|
||||||
else:
|
else:
|
||||||
# Check if scope contains filename or PR reference
|
# Check if scope contains filename or PR reference
|
||||||
scope_match = re.match(rf"^({VALID_TYPES_RE})\(([^)]+)\): .+", msg)
|
scope_match = re.match(rf"^({VALID_TYPES_RE})\(([^)]+)\)!?: .+", msg)
|
||||||
if scope_match:
|
if scope_match:
|
||||||
scope = scope_match.group(2)
|
scope = scope_match.group(2)
|
||||||
if re.search(r"\.[a-zA-Z]+$", scope):
|
if re.search(r"\.[a-zA-Z]+$", scope):
|
||||||
@@ -205,7 +205,7 @@ def check_commit_msg(msg):
|
|||||||
return errors
|
return errors
|
||||||
|
|
||||||
# Validate description
|
# Validate description
|
||||||
desc = full.group(3)
|
desc = full.group(4)
|
||||||
|
|
||||||
if desc and desc[0].isupper():
|
if desc and desc[0].isupper():
|
||||||
errors.append(f"Description should start with lowercase: '{desc[:30]}...'")
|
errors.append(f"Description should start with lowercase: '{desc[:30]}...'")
|
||||||
|
|||||||
Reference in New Issue
Block a user