Last active
April 24, 2025 12:41
-
-
Save jeremybenaim/7ee9f1835e5973773bdefccb51d0fae9 to your computer and use it in GitHub Desktop.
Automate your changelog thanks to ChatGPT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# .github/workflows/changelog_generator.yml | |
name: Generate Changelog and Post to Slack | |
on: | |
schedule: | |
# This will run every Friday at 3 PM UTC | |
- cron: "0 15 * * 5" | |
jobs: | |
generate_changelog: | |
runs-on: ubuntu-latest | |
steps: | |
- name: Checkout code | |
uses: actions/checkout@v2 | |
- name: Set up Python | |
uses: actions/setup-python@v2 | |
with: | |
python-version: "3.x" | |
- name: Install dependencies | |
run: | | |
python -m pip install --upgrade pip | |
pip install requests openai | |
- name: Generate Changelog and Post to Slack | |
run: python ./scripts/generate_changelog.py | |
env: | |
TOKEN: ${{ secrets.MACHINE_USER_TOKEN }} | |
SLACK_WEBHOOK_URL: ${{ secrets.CHANGELOG_SLACK_WEBHOOK_URL }} | |
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# scripts/generate_changelog.py | |
import os | |
import requests | |
import re | |
import openai | |
from datetime import datetime, timedelta | |
# Constants | |
REPO_OWNER = "YOUR_USERNAME" | |
REPO_NAME = "YOUR_REPOSITORY_NAME" | |
TOKEN = os.environ["TOKEN"] | |
SLACK_WEBHOOK_URL = os.environ["SLACK_WEBHOOK_URL"] | |
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"] | |
DAYS_AGO = 7 | |
LINEAR_BASE_URL = "https://linear.app/photoroom/issue/" | |
SLACK_MSG_COLOR = "#36a64f" | |
headers = { | |
"Authorization": f"Bearer {TOKEN}", | |
"Accept": "application/vnd.github+json", | |
"X-GitHub-Api-Version": "2022-11-28", | |
} | |
def fetch_recent_merged_prs(): | |
end_date = datetime.utcnow() | |
start_date = end_date - timedelta(days=DAYS_AGO) | |
response = requests.get( | |
f"https://api.github.com/repos/{REPO_OWNER}/{REPO_NAME}/pulls?state=closed&since={start_date.isoformat()}Z", | |
headers=headers, | |
) | |
if response.status_code != 200: | |
raise Exception("Error fetching PRs from GitHub API!") | |
return [pr for pr in response.json() if pr["merged_at"]] | |
def extract_commit_details_from_prs(prs): | |
commit_details = [] | |
for pr in prs: | |
commit_message = pr["title"] | |
commit_url = pr["html_url"] | |
pr_number = pr["number"] | |
branch_name = pr["head"]["ref"] | |
issue_numbers = re.findall(r"(www-\d+|web-\d+)", branch_name) | |
# If no issue numbers are found, add the PR details without issue numbers and URLs | |
if not issue_numbers: | |
commit_details.append( | |
{ | |
"message": commit_message, | |
"pr_number": pr_number, | |
"pr_url": commit_url, | |
"issue_number": None, | |
"issue_url": None, | |
} | |
) | |
continue | |
for issue in issue_numbers: | |
commit_details.append( | |
{ | |
"message": commit_message, | |
"pr_number": pr_number, | |
"pr_url": commit_url, | |
"issue_number": issue, | |
"issue_url": f"{LINEAR_BASE_URL}{issue}/", | |
} | |
) | |
return commit_details | |
def generate_changelog_with_openai(commit_details): | |
commit_messages = [] | |
for details in commit_details: | |
base_message = f"{details['pr_url']} - {details['message']}" | |
# Add the issue URL if available | |
if details["issue_url"]: | |
base_message += f" (Linear Issue: {details['issue_url']})" | |
commit_messages.append(base_message) | |
commit_list = "\n".join(commit_messages) | |
prompt = """ | |
Generate a changelog for the web version of the PhotoRoom app, which offers AI-driven image editing capabilities such as background removal, retouching, resizing, and more, detailing recent updates. | |
The changelog should: | |
1. Be Informative: Using the provided list of GitHub commits, break them down into categories such as Features, Fixes & Improvements, and Technical Updates. Summarize each commit concisely, ensuring the key points are highlighted. | |
2. Have a Professional yet Friendly tone: The tone should be balanced, not too corporate or too informal. | |
3. Celebratory Introduction and Conclusion: Start the changelog with a celebratory note acknowledging the team's hard work and progress. End with a shoutout to the team and wishes for a pleasant weekend. | |
4. Formatting: you cannot use Markdown formatting, and you can only use emojis for the introductory paragraph or the conclusion paragraph, nowhere else. | |
5. Links: the syntax to create links is the following: `<http://www.example.com|This message is a link>`. | |
6. Linear Links: note that the Linear link is optional, include it only if provided. | |
7. Do not wrap your answer in a codeblock. Just output the text, nothing else | |
Here's a good example to follow, please try to match the formatting as closely as possible, only changing the content of the changelog and have some liberty with the introduction and conclusion paragraphs. Notice the importance of the formatting of a changelog item: | |
``` | |
- <https://github.com/facebook/react/pull/27304/|#27304>: We optimize our ci to strip comments and minify production builds. (<https://linear.app/example/issue/WEB-1234/|WEB-1234>)) | |
``` | |
And here's an example of the full changelog: | |
``` | |
The PhotoRoom web team has been working diligently to bring you the latest updates and improvements to enhance your editing experience. We are thrilled to share the following changes with you. Let's dive in! :diving_mask: | |
*Features* | |
• <https://github.com/facebook/react/pull/27304/|#27304>: We optimize our ci to strip comments and minify production builds. (<https://linear.app/example/issue/WEB-1234/|WEB-1234>) | |
*Fixes & Improvements* | |
• <https://github.com/facebook/react/pull/27304/|#27304>: We optimize our ci to strip comments and minify production builds. (<https://linear.app/example/issue/WEB-1234/|WEB-1234>) | |
*Technical Updates* | |
• <https://github.com/facebook/react/pull/27304/|#27304>: We optimize our ci to strip comments and minify production builds. (<https://linear.app/example/issue/WEB-1234/|WEB-1234>) | |
These updates wouldn't be possible without the hard work and dedication of our incredible PhotoRoom web team. We are grateful for their commitment to delivering a top-notch editing experience for our users. Wishing everyone a delightful and restful weekend! | |
Stay tuned for more exciting updates coming soon! | |
``` | |
And here are the commits: | |
{} | |
""".format( | |
commit_list | |
) | |
openai.api_key = OPENAI_API_KEY | |
messages = [{"role": "user", "content": prompt}] | |
response = openai.ChatCompletion.create(model="gpt-4", messages=messages) | |
if "error" in response.choices[0].message: | |
raise Exception("Error generating changelog with OpenAI!") | |
return response.choices[0].message["content"].strip() | |
def post_changelog_to_slack(changelog, end_date): | |
slack_payload = { | |
"text": "Hey team, it's changelog time! :wave:", | |
"attachments": [ | |
{ | |
"color": SLACK_MSG_COLOR, | |
"title": f"🗓️ PhotoRoom Web Update - {end_date.strftime('%B %d, %Y')}", | |
"text": changelog, | |
} | |
], | |
} | |
response = requests.post(SLACK_WEBHOOK_URL, json=slack_payload) | |
if response.status_code != 200: | |
raise Exception("Failed to post changelog to Slack.") | |
if __name__ == "__main__": | |
try: | |
print("⏳ Generating changelog, it can take a few minutes...") | |
prs = fetch_recent_merged_prs() | |
commit_details = extract_commit_details_from_prs(prs) | |
changelog = generate_changelog_with_openai(commit_details) | |
post_changelog_to_slack(changelog, datetime.utcnow()) | |
print("✅ Changelog successfully posted to Slack!") | |
except Exception as e: | |
print(str(e)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Read the full story on our blog 🙂