Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
51c08a6
BACKPORT-CONFLICT: manual resolution required for commit 6b621df
naspirato Nov 18, 2025
44c18f8
Enhance cherry-pick script with changelog extraction and improved PR …
naspirato Nov 18, 2025
a34a0ac
Enhance cherry-pick script to avoid branch name conflicts and improve…
naspirato Nov 18, 2025
75ae221
Enhance cherry-pick script to include detailed conflict resolution in…
naspirato Nov 18, 2025
410e32c
Add PR template and category definitions for validation
naspirato Nov 18, 2025
4a5f696
Enhance cherry-pick script with improved error handling and conflict …
naspirato Nov 18, 2025
b40ea66
Enhance cherry-pick script with improved conflict handling and logging
naspirato Nov 18, 2025
a8e8e1c
Refactor changelog extraction in cherry-pick script
naspirato Nov 18, 2025
3f4601a
Enhance cherry-pick script with improved diff link generation
naspirato Nov 18, 2025
b839d34
Enhance cherry-pick script with improved backport comment management
naspirato Nov 18, 2025
b862fb5
Refactor cherry-pick script for improved PR validation and changelog …
naspirato Nov 18, 2025
37f7702
Update cherry-pick script to change cherry-pick command options
naspirato Nov 18, 2025
3b57e26
Refactor cherry-pick command in script to simplify handling of empty …
naspirato Nov 18, 2025
028e364
Refactor cherry-pick script to streamline commit existence checks and…
naspirato Nov 18, 2025
d2d64db
Enhance cherry-pick script to improve conflict message handling and l…
naspirato Nov 18, 2025
ae45047
Enhance cherry-pick script to improve conflict summary generation
naspirato Nov 18, 2025
ddd3d78
Refine conflict message extraction in cherry-pick script
naspirato Nov 19, 2025
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
60 changes: 60 additions & 0 deletions .github/actions/validate_pr_description/pr_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
"""
PR template and categories definitions for YDB project.
Used by both validate_pr_description.py and cherry_pick.py to ensure consistency.
"""

# Issue reference patterns for validation
ISSUE_PATTERNS = [
r"https://github.com/ydb-platform/[a-z\-]+/issues/\d+",
r"https://st.yandex-team.ru/[a-zA-Z]+-\d+",
r"#\d+",
r"[a-zA-Z]+-\d+"
]

# Full PR template
PULL_REQUEST_TEMPLATE = """### Changelog entry <!-- a user-readable short description of the changes that goes to CHANGELOG.md and Release Notes -->

...

### Changelog category <!-- remove all except one -->

* New feature
* Experimental feature
* Improvement
* Performance improvement
* User Interface
* Bugfix
* Backward incompatible change
* Documentation (changelog entry is not required)
* Not for changelog (changelog entry is not required)"""

# Categories that require changelog entry
FOR_CHANGELOG_CATEGORIES = [
"New feature",
"Experimental feature",
"User Interface",
"Improvement",
"Performance improvement",
"Bugfix",
"Backward incompatible change"
]

# Categories that don't require changelog entry
NOT_FOR_CHANGELOG_CATEGORIES = [
"Documentation (changelog entry is not required)",
"Not for changelog (changelog entry is not required)"
]

# All valid categories
ALL_CATEGORIES = FOR_CHANGELOG_CATEGORIES + NOT_FOR_CHANGELOG_CATEGORIES


def get_category_section_template() -> str:
"""Get the category section template as a string (for cherry_pick.py)"""
return "\n".join([f"* {cat}" for cat in ALL_CATEGORIES])


def get_category_section_for_selected(category: str) -> str:
"""Get category section with only selected category marked"""
return f"* {category}"

Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
import sys
import re
from typing import Tuple

issue_patterns = [
r"https://github.com/ydb-platform/[a-z\-]+/issues/\d+",
r"https://st.yandex-team.ru/[a-zA-Z]+-\d+",
r"#\d+",
r"[a-zA-Z]+-\d+"
]

pull_request_template = """
### Changelog entry <!-- a user-readable short description of the changes that goes to CHANGELOG.md and Release Notes -->

...

### Changelog category <!-- remove all except one -->

* New feature
* Experimental feature
* Improvement
* Performance improvement
* User Interface
* Bugfix
* Backward incompatible change
* Documentation (changelog entry is not required)
* Not for changelog (changelog entry is not required)
"""
from pr_template import (
ISSUE_PATTERNS,
PULL_REQUEST_TEMPLATE,
FOR_CHANGELOG_CATEGORIES,
NOT_FOR_CHANGELOG_CATEGORIES,
ALL_CATEGORIES
)

def validate_pr_description(description, is_not_for_cl_valid=True) -> bool:
try:
Expand All @@ -44,7 +26,7 @@ def check_pr_description(description, is_not_for_cl_valid=True) -> Tuple[bool, s
if "### Changelog category" not in description and "### Changelog entry" not in description:
return is_not_for_cl_valid, "Changelog category and entry sections are not found."

if pull_request_template.strip() in description.strip():
if PULL_REQUEST_TEMPLATE.strip() in description.strip():
return is_not_for_cl_valid, "Pull request template as is."

# Extract changelog category section
Expand All @@ -62,34 +44,18 @@ def check_pr_description(description, is_not_for_cl_valid=True) -> Tuple[bool, s
return False, txt

category = categories[0]
for_cl_categories = [
"New feature",
"Experimental feature",
"User Interface",
"Improvement",
"Performance improvement",
"Bugfix",
"Backward incompatible change"
]

not_for_cl_categories = [
"Documentation (changelog entry is not required)",
"Not for changelog (changelog entry is not required)"
]

valid_categories = for_cl_categories + not_for_cl_categories

if not any(cat.startswith(category) for cat in valid_categories):
if not any(cat.startswith(category) for cat in ALL_CATEGORIES):
txt = f"Invalid Changelog category: {category}"
print(f"::warning::{txt}")
return False, txt

if not is_not_for_cl_valid and any(cat.startswith(category) for cat in not_for_cl_categories):
if not is_not_for_cl_valid and any(cat.startswith(category) for cat in NOT_FOR_CHANGELOG_CATEGORIES):
txt = f"Category is not for changelog: {category}"
print(f"::notice::{txt}")
return False, txt

if not any(cat.startswith(category) for cat in not_for_cl_categories):
if not any(cat.startswith(category) for cat in NOT_FOR_CHANGELOG_CATEGORIES):
entry_section = re.search(r"### Changelog entry.*?\n(.*?)(\n###|$)", description, re.DOTALL)
if not entry_section or len(entry_section.group(1).strip()) < 20:
txt = "The changelog entry is less than 20 characters or missing."
Expand All @@ -100,7 +66,7 @@ def check_pr_description(description, is_not_for_cl_valid=True) -> Tuple[bool, s
def check_issue_pattern(issue_pattern):
return re.search(issue_pattern, description)

if not any(check_issue_pattern(issue_pattern) for issue_pattern in issue_patterns):
if not any(check_issue_pattern(issue_pattern) for issue_pattern in ISSUE_PATTERNS):
txt = "Bugfix requires a linked issue in the changelog entry"
print(f"::warning::{txt}")
return False, txt
Expand Down
Loading