Skip to content

chore: add release note script #5327

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ result-*
# Exclude rust build directories
*target/
Cargo.lock
uv.lock
1 change: 1 addition & 0 deletions scripts/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.12
18 changes: 18 additions & 0 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
`uv` will automatically configure dependencies. Some run some `script.py` you can use `uv run script.py`.

### Release Script
To run the release script you need to pass in a github token through an environment variable. This is because unauthenticated users are limited to 60 API calls per _hour_.

```
GITHUB_TOKEN=<token> uv run generate_release_notes.py --release-commit <release commit>
```

You can generate personal access tokens here: https://github.com/settings/personal-access-tokens, which should result in something that looks like
```
github_pat_11A098uas3kuA78daawj_hkaj987987QWERTYUIOPkjhkjha8and8A8Andjw
```

Example script run
```
GITHUB_TOKEN=github_pat_11A098uas3kuA78daawj_hkaj987987QWERTYUIOPkjhkjha8and8A8Andjw uv run generate_release_notes.py --release-commit 92f7827c8487eb2a99b443aec6ee7d1df031b1bf
```
102 changes: 102 additions & 0 deletions scripts/generate_release_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import argparse
import subprocess
from github import Github
import os

REPO_NAME = "aws/s2n-tls"


def get_release_summaries(pr) -> None | str:

Check notice

Code scanning / CodeQL

Explicit returns mixed with implicit (fall through) returns Note

Mixing implicit and explicit returns may indicate an error as implicit returns always return None.
"""Extract release summaries from PRs that have them."""
body = pr.body or ""
if "### Release Summary:" in body:
# get everything between "### Release Summary:" and the next heading
summary = body.split("### Release Summary:")[1].split("###")[0].strip()
# make sure it's not the default HTML comment
if summary and "<!--" not in summary:
return summary


def format_pr_entry(pr) -> str:
"""Format a PR into the desired changelog entry format."""
return f"{pr.title} by @{pr.user.login} in {pr.html_url}"


def get_last_release_commit(repo):
"""Get the commit SHA of the last release."""
latest_release = repo.get_latest_release()
tag = repo.get_git_ref(f"tags/{latest_release.tag_name}")
return tag.object.sha


def get_commits_in_release(previous_commit: str, new_commit: str) -> list[str]:
"""Get all of the commits between the previous release commit and the new release commit"""
# make sure we are currently on the main branch
current_branch = subprocess.check_output(
["git", "branch", "--show-current"], text=True
)
assert "main" in current_branch

log_output = subprocess.check_output(
["git", "log", f"{previous_commit}..{new_commit}", "--pretty=format:%s"],
text=True,
)
return [commit for commit in log_output.splitlines()]


def get_pr_from_commit_description(description: str) -> int:
"""Given 'chore: Bump nixpkgs version to 24.11 (#5294)' return '5294'"""
assert "(#" in description

number_start = description.find("(#") + len("#(")
number_end = description.find(")", number_start)
number = description[number_start:number_end]

return int(number)


def main():
parser = argparse.ArgumentParser(prog="s2n-tls release note generator")
parser.add_argument("--release-commit", required=True)
args = parser.parse_args()

token = os.getenv("GITHUB_TOKEN")
if not token:
print("Please set the GITHUB_TOKEN environment variable")
return

g = Github(token)
repo = g.get_repo(REPO_NAME)
last_release_commit = get_last_release_commit(repo)

print(
f"generating release notes from ({last_release_commit}, {args.release_commit}]"
)
commits = get_commits_in_release(last_release_commit, args.release_commit)
prs = [get_pr_from_commit_description(description) for description in commits]

changelog = []
release_summaries = []

for pr_number in prs:
pr = repo.get_pull(pr_number)
changelog.append(format_pr_entry(pr))
maybe_release_note = get_release_summaries(pr)
if maybe_release_note is not None:
release_summaries.append(maybe_release_note)

# generate markdown release notes
print("\n\n")
print("## Release Summary:")
for summary in release_summaries:
print(f"* {summary}")
print("")

print("## What's Changed:")
for change in changelog:
print(f"* {change}")
print("")


if __name__ == "__main__":
main()
10 changes: 10 additions & 0 deletions scripts/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[project]
name = "scripts"
version = "0.1.0"
description = "This project contains various utility script for the s2n-tls codebase"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"pygithub>=2.6.1",
"ruff>=0.11.10",
]
Loading