Skip to content

Commit 11953f2

Browse files
chmouelclaude
andcommitted
feat: improve pr-labeler
- Limit suggested labels to maximum of 3 (configurable via max_labels, default -1 for unlimited) - Only suggest "documentation" label when docs/ files are modified - Only suggest "e2e" label when test/ files are modified - Add validation logic to enforce these restrictions - Add "hack" to excluded labels list to avoid self-labeling - Update pipeline template to pass MAX_LABELS environment variable - Improve label limit logic to support unlimited labeling when max_labels <= 0 Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com>
1 parent 717b4a0 commit 11953f2

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

.tekton/pr-labeler.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ spec:
2323
- name: gemini_model
2424
value: "gemini-2.5-flash"
2525
- name: excluded_labels
26-
value: "good-first-issue,help-wanted,wontfix"
26+
value: "good-first-issue,help-wanted,wontfix,hack"
27+
- name: max_labels
28+
value: "3"
2729
pipelineSpec:
2830
params:
2931
- name: repo_url
@@ -33,6 +35,7 @@ spec:
3335
- name: repo_name
3436
- name: gemini_model
3537
- name: excluded_labels
38+
- name: max_labels
3639
tasks:
3740
- name: pr-labeler
3841
taskSpec:
@@ -44,6 +47,7 @@ spec:
4447
- name: repo_name
4548
- name: gemini_model
4649
- name: excluded_labels
50+
- name: max_labels
4751
workspaces:
4852
- name: source
4953
steps:
@@ -86,6 +90,8 @@ spec:
8690
value: "$(params.gemini_model)"
8791
- name: EXCLUDED_LABELS
8892
value: "$(params.excluded_labels)"
93+
- name: MAX_LABELS
94+
value: "$(params.max_labels)"
8995
command:
9096
- ./hack/pr-labeler.py
9197
params:
@@ -103,6 +109,8 @@ spec:
103109
value: "$(params.gemini_model)"
104110
- name: excluded_labels
105111
value: "$(params.excluded_labels)"
112+
- name: max_labels
113+
value: "$(params.max_labels)"
106114
workspaces:
107115
- name: source
108116
workspace: source

hack/pr-labeler.py

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def get_paginated_data(url, headers, timeout=300):
3939
def get_excluded_labels():
4040
"""Get excluded labels from environment variable or use default"""
4141
excluded_env = os.environ.get(
42-
"EXCLUDED_LABELS", "good-first-issue,help-wanted,wontfix"
42+
"EXCLUDED_LABELS", "good-first-issue,help-wanted,wontfix,hack"
4343
)
4444
# Split by comma and strip whitespace, filter out empty strings
4545
return {label.strip() for label in excluded_env.split(",") if label.strip()}
@@ -131,7 +131,14 @@ def analyze_with_gemini(
131131
IMPORTANT: You can ONLY suggest labels from this list of available labels in the repository:
132132
{labels_text}
133133
134-
Based on the PR title, description, files changed, and commit messages, suggest 2-4 relevant labels from the available labels list above. Use the label descriptions to understand their intended purpose.
134+
Based on the PR title, description, files changed, and commit messages, suggest up to 3 relevant labels from the available labels list above. Use the label descriptions to understand their intended purpose.
135+
136+
IMPORTANT RESTRICTIONS:
137+
- Only suggest "documentation" label if files in the docs/ directory are modified
138+
- Only suggest "e2e" label if files in the test/ directory are modified for e2e tests
139+
- Only suggest provider labels ("github", "gitlab", "bitbucket", "gitea") if files in the pkg/provider/ directory are modified
140+
- Provider labels should match the specific provider subdirectory modified (e.g., "github" only if pkg/provider/github/ files are changed)
141+
- Maximum 3 labels total
135142
136143
Respond with only a JSON array of label names that exist in the available labels list, like: ["enhancement", "backend"]
137144
"""
@@ -277,6 +284,14 @@ def main():
277284
print(f"Files changed: {len(files_changed)} files")
278285
print(f"Commits: {len(commit_messages)} commits")
279286

287+
# Skip if PR already has max_labels or more labels (unless unlimited)
288+
max_labels = int(os.environ.get("MAX_LABELS", "-1"))
289+
if max_labels > 0 and len(current_labels) >= max_labels:
290+
print(
291+
f"PR already has {len(current_labels)} labels (max: {max_labels}), skipping label addition"
292+
)
293+
return
294+
280295
# Analyze with Gemini
281296
suggested_labels = analyze_with_gemini(
282297
pr_title, pr_description, files_changed, commit_messages, available_labels
@@ -301,9 +316,71 @@ def main():
301316
]
302317
print(f"Warning: Gemini suggested invalid labels: {invalid_labels}")
303318

319+
# Apply restrictions based on files changed
320+
has_docs_files = any(
321+
file.split("\t")[1].startswith("docs/") for file in files_changed
322+
)
323+
has_test_files = any(
324+
file.split("\t")[1].startswith("test/") for file in files_changed
325+
)
326+
has_provider_files = any(
327+
file.split("\t")[1].startswith("pkg/provider/") for file in files_changed
328+
)
329+
330+
# Detect specific provider subdirectories modified
331+
provider_types = set()
332+
if has_provider_files:
333+
for file in files_changed:
334+
file_path = file.split("\t")[1]
335+
if file_path.startswith("pkg/provider/"):
336+
path_parts = file_path.split("/")
337+
if len(path_parts) >= 3: # pkg/provider/[subdir]/...
338+
subdir = path_parts[2]
339+
if subdir in [
340+
"github",
341+
"gitlab",
342+
"bitbucketcloud",
343+
"bitbucketdatacenter",
344+
"gitea",
345+
]:
346+
if subdir.startswith("bitbucket"):
347+
provider_types.add("bitbucket")
348+
else:
349+
provider_types.add(subdir)
350+
351+
# Filter out restricted labels
352+
filtered_labels = []
353+
for label in valid_suggested_labels:
354+
if label == "documentation" and not has_docs_files:
355+
print("Skipping 'documentation' label - no docs/ files modified")
356+
continue
357+
if label == "e2e" and not has_test_files:
358+
print("Skipping 'e2e' label - no test/ files modified")
359+
continue
360+
# Provider-specific label restrictions
361+
if (
362+
label in ["github", "gitlab", "bitbucket", "gitea"]
363+
and not has_provider_files
364+
):
365+
print(f"Skipping '{label}' label - no pkg/provider/ files modified")
366+
continue
367+
if (
368+
label in ["github", "gitlab", "bitbucket", "gitea"]
369+
and label not in provider_types
370+
):
371+
print(f"Skipping '{label}' label - no pkg/provider/{label}/ files modified")
372+
continue
373+
filtered_labels.append(label)
374+
375+
# Limit to maximum labels (unless unlimited)
376+
max_labels = int(os.environ.get("MAX_LABELS", "-1"))
377+
if max_labels > 0 and len(filtered_labels) > max_labels:
378+
print(f"Limiting labels from {len(filtered_labels)} to {max_labels}")
379+
filtered_labels = filtered_labels[:max_labels]
380+
304381
# Filter out labels that already exist
305382
new_labels = [
306-
label for label in valid_suggested_labels if label not in existing_labels_set
383+
label for label in filtered_labels if label not in existing_labels_set
307384
]
308385

309386
if new_labels:

0 commit comments

Comments
 (0)