Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions examples/.github-webhook-server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,27 @@ can-be-merged-required-labels:
- "tests-passed"
- "security-reviewed"

# Conventional commit configuration
conventional-title: "feat,fix,docs,style,refactor,test,chore"
# Conventional Commits validation
# Enforces Conventional Commits v1.0.0 specification for PR titles
# Format: <type>[optional scope]: <description>
#
# Standard types (recommended):
# - feat: New features (triggers MINOR version bump in semver)
# - fix: Bug fixes (triggers PATCH version bump in semver)
# - build, chore, ci, docs, style, refactor, perf, test, revert
#
# Custom types: You can define your own types! The spec allows any noun.
# Examples: my-title, hotfix, release, custom
#
# Valid PR title examples:
# - feat: add user authentication
# - fix(parser): handle edge case in XML parsing
# - feat!: breaking API change to authentication
# - my-title: custom type example
# - hotfix(api): resolve production issue
#
# Resources: https://www.conventionalcommits.org/en/v1.0.0/
conventional-title: "feat,fix,build,chore,ci,docs,style,refactor,perf,test,revert"

# Minimum LGTM count required
minimum-lgtm: 2
Expand Down
22 changes: 21 additions & 1 deletion examples/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,27 @@ repositories:
- my-label1
- my-label2

conventional-title: "ci,docs,feat,fix,refactor,test,release" # Check PR title start with any of these words + :
# Conventional Commits validation
# Enforces Conventional Commits v1.0.0 specification for PR titles
# Format: <type>[optional scope]: <description>
#
# Standard types (recommended):
# - feat: New features (triggers MINOR version bump in semver)
# - fix: Bug fixes (triggers PATCH version bump in semver)
# - build, chore, ci, docs, style, refactor, perf, test, revert
#
# Custom types: You can define your own types! The spec allows any noun.
# Examples: my-title, hotfix, release, custom
#
# Valid PR title examples:
# - feat: add user authentication
# - fix(parser): handle edge case in XML parsing
# - feat!: breaking API change to authentication
# - my-title: custom type example
# - hotfix(api): resolve production issue
#
# Resources: https://www.conventionalcommits.org/en/v1.0.0/
conventional-title: "feat,fix,build,chore,ci,docs,style,refactor,perf,test,revert"
branch-protection:
strict: True
require_code_owner_reviews: True
Expand Down
29 changes: 28 additions & 1 deletion webhook_server/config/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,34 @@ properties:
description: Required labels for PR to be marked as can-be-merged
conventional-title:
type: string
description: Comma-separated list of conventional commit prefixes
description: |
Comma-separated list of allowed commit types for Conventional Commits validation.

Enforces Conventional Commits v1.0.0 specification: <type>[optional scope]: <description>

Standard types (recommended):
- feat: New features (MINOR in semver)
- fix: Bug fixes (PATCH in semver)
- build, chore, ci, docs, style, refactor, perf, test, revert

Custom types: The specification allows custom types (any noun).
Examples: my-title, hotfix, release, custom

Format requirements:
- Type from configured list
- Optional scope in parentheses: (scope)
- Optional breaking change indicator: !
- Mandatory colon + space: ": "
- Non-empty description

Valid examples:
- feat: add authentication
- fix(api): handle edge case
- feat!: breaking change
- my-title: custom type

Resources: https://www.conventionalcommits.org/en/v1.0.0/
example: "feat,fix,build,chore,ci,docs,style,refactor,perf,test,revert"
minimum-lgtm:
type: integer
description: Minimum number of LGTM required before approving PR
Expand Down
51 changes: 44 additions & 7 deletions webhook_server/libs/handlers/runner_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,9 +602,13 @@ async def run_conventional_title_check(self, pull_request: PullRequest) -> None:
)

output: dict[str, str] = {
"title": "Conventional Title",
"summary": "",
"text": "",
"title": "✅ Conventional Title",
"summary": "PR title follows Conventional Commits format",
"text": (
f"**Format:** `<type>[optional scope]: <description>`\n\n"
f"**Your title:** `{pull_request.title}`\n\n"
f"This title complies with the Conventional Commits v1.0.0 specification."
),
}

if await self.check_run_handler.is_check_run_in_progress(check_run=CONVENTIONAL_TITLE_STR):
Expand All @@ -615,11 +619,11 @@ async def run_conventional_title_check(self, pull_request: PullRequest) -> None:
f"Setting conventional title check status to in-progress",
)
await self.check_run_handler.set_conventional_title_in_progress()
allowed_names = self.github_webhook.conventional_title.split(",")
allowed_names = [name.strip() for name in self.github_webhook.conventional_title.split(",") if name.strip()]
title = pull_request.title

self.logger.debug(f"{self.log_prefix} Conventional title check for title: {title}, allowed: {allowed_names}")
if any([re.search(rf"{_name}(.*):", title) for _name in allowed_names]):
if any([re.match(rf"^{re.escape(_name)}(\([^)]+\))?!?: .+", title) for _name in allowed_names]):
self.logger.step( # type: ignore[attr-defined]
f"{self.log_prefix} {format_task_fields('runner', 'ci_check', 'completed')} "
f"Conventional title check completed successfully",
Expand All @@ -631,8 +635,41 @@ async def run_conventional_title_check(self, pull_request: PullRequest) -> None:
f"{format_task_fields('runner', 'ci_check', 'failed')} "
f"Conventional title check failed"
)
output["summary"] = "Failed"
output["text"] = f"Pull request title must starts with allowed title: {': ,'.join(allowed_names)}"
output["title"] = "❌ Conventional Title"
output["summary"] = "Conventional Commit Format Violation"
output["text"] = f"""## Conventional Commits Validation Failed

**Your PR title:**
> {title}

**Required format:**
```
<type>[optional scope]: <description>
```

**Configured types for this repository:**
{", ".join(f"`{t}`" for t in allowed_names)}

**Valid examples:**
- `feat: add user authentication`
- `fix(parser): handle edge case in URL parsing`
- `feat!: breaking change in API response`
- `refactor(core)!: major architectural change`
- `docs: update installation guide`

**Format rules:**
- Type must be one of the configured types
- Optional scope in parentheses: `(scope)`
- Optional breaking change indicator: `!`
- **Mandatory**: colon followed by space `: `
- **Mandatory**: non-empty description after the space

**Note:** The Conventional Commits specification allows custom types beyond the standard recommendations.
Your team can configure additional types in the repository settings.

**Resources:**
- [Conventional Commits v1.0.0 Specification](https://www.conventionalcommits.org/en/v1.0.0/)
"""
await self.check_run_handler.set_conventional_title_failure(output=output)

async def is_branch_exists(self, branch: str) -> Branch:
Expand Down
Loading