[PM-34709] Create workflow to categorize changes on PR for the release notes#696
[PM-34709] Create workflow to categorize changes on PR for the release notes#696djsmith85 wants to merge 5 commits into
Conversation
…ating release notes This workflow has been copied from bitwarden/android.
…y prefixing them with a exclamation point
…attern matching labels)
|
|
New Issues (1)Checkmarx found the following issues in this Pull Request
|
| payload = json.dumps({"labels": labels}) | ||
| subprocess.run( | ||
| ["gh", "api", "repos/{owner}/{repo}/issues/" + pr_number, "-X", "PATCH", "--silent", "--input", "-"], | ||
| input=payload, |
There was a problem hiding this comment.
@djsmith85 pr_number is a script argument, but we should still change this to set a good example. Thought we could change the argument type, update all of these methods to receive an int and then convert it back to string for the gh commands.
diff --git forkSrcPrefix/.github/scripts/label-pr.py forkDstPrefix/.github/scripts/label-pr.py
index 4e803df447ce5f5edee45d01d6f91dfd8e38d55d..bfae9220e4b58fe1d02a7cc34efac8c0322a9ce9 100644
--- forkSrcPrefix/.github/scripts/label-pr.py
+++ forkDstPrefix/.github/scripts/label-pr.py
@@ -62,11 +62,11 @@ def load_config_json(config_file: str) -> dict:
print(f"❌ Unexpected error loading label-pr.json config: {e}")
sys.exit(1)
-def gh_get_changed_files(pr_number: str) -> list[str]:
+def gh_get_changed_files(pr_number: int) -> list[str]:
"""Get list of changed files in a pull request."""
try:
result = subprocess.run(
- ["gh", "pr", "diff", pr_number, "--name-only"],
+ ["gh", "pr", "diff", str(pr_number), "--name-only"],
capture_output=True,
text=True,
check=True
@@ -77,11 +77,11 @@ def gh_get_changed_files(pr_number: str) -> list[str]:
print(f"::error::Error getting changed files: {e}")
return []
-def gh_get_pr_title(pr_number: str) -> str:
+def gh_get_pr_title(pr_number: int) -> str:
"""Get the title of a pull request."""
try:
result = subprocess.run(
- ["gh", "pr", "view", pr_number, "--json", "title", "--jq", ".title"],
+ ["gh", "pr", "view", str(pr_number), "--json", "title", "--jq", ".title"],
capture_output=True,
text=True,
check=True
@@ -91,19 +91,19 @@ def gh_get_pr_title(pr_number: str) -> str:
print(f"::error::Error getting PR title: {e}")
return ""
-def gh_add_labels(pr_number: str, labels: list[str]) -> None:
+def gh_add_labels(pr_number: int, labels: list[str]) -> None:
"""Add labels to a pull request (doesn't remove existing labels)."""
gh_labels = ','.join(labels)
subprocess.run(
- ["gh", "pr", "edit", pr_number, "--add-label", gh_labels],
+ ["gh", "pr", "edit", str(pr_number), "--add-label", gh_labels],
check=True
)
-def gh_replace_labels(pr_number: str, labels: list[str]) -> None:
+def gh_replace_labels(pr_number: int, labels: list[str]) -> None:
"""Replace all labels on a pull request with the specified labels."""
payload = json.dumps({"labels": labels})
subprocess.run(
- ["gh", "api", "repos/{owner}/{repo}/issues/" + pr_number, "-X", "PATCH", "--silent", "--input", "-"],
+ ["gh", "api", f"repos/{{owner}}/{{repo}}/issues/{pr_number}", "-X", "PATCH", "--silent", "--input", "-"],
input=payload,
text=True,
check=True
@@ -181,6 +181,7 @@ def parse_args():
)
parser.add_argument(
"pr_number",
+ type=int,
help="The pull request number"
)
| "app:authenticator": [ | ||
| "authenticator/" | ||
| ], | ||
| "t:feature": [ |
There was a problem hiding this comment.
fyi we're planning to remove setting t: (Change Type) labels based on changed files, relying exclusively on the PR title convention for that (or devs manually setting them), leaving path matching for the app: labels alone. This can match multiple labels, but GitHub's Release Categories system will only match one category which may not be the most relevant one for the PR, reason why sdlc-enforce-labels.yml ensures there's only a single t: label present. Ultimately, the PR title convention has been working better for the team.
There was a problem hiding this comment.
hm okay, I had extended the categorization for changed files especially for clients, which android/ios would also benefit from (app:password-manager/app:authenticator). I agree that match per title guides the dev to choose a better category, if there's no auto-category per file-change set.
One thing you haven't seen yet, is that I don't rely on the Github generate release notes feature for clients. I wanted to ensure that change on one app would only show for that app-release, unless the change applies to all clients. This also means a single change could occur in multiple categories if we wanted them to.
I kept the release.yml as definition as it was already there, well-known, documented and wouldn't involve changing the scripts. I was thinking of extending the release.yml-standard with a bw-description-tag, which we could use to add a message to each category. For example staged feature rollout (cloud vs self-host).





🎟️ Tracking
https://bitwarden.atlassian.net/browse/PM-34709
📔 Objective
Originally built by @vvolkgang to categorize PRs by change type and applying labels accordingly (t:feature, t:bugfix, t:deps, etc).
It uses PR title (conventional commits) and changed files to identify and categorize.
This is already in use on the bitwarden/android and bitwarden/ios, but now that it will also be needed on the bitwarden/clients and bitwarden/server repos.
Goal is to centralize the workflow/scripts and to simplify the existing workflows and easily use them in the other two.