Skip to content

Commit

Permalink
Draft guide with release template and aggregator script automation
Browse files Browse the repository at this point in the history
  • Loading branch information
riverma committed Mar 26, 2024
1 parent 4016bf6 commit d9c3457
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 0 deletions.
93 changes: 93 additions & 0 deletions docs/guides/documentation/releases/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Releases

<pre align="center">Streamline software releases through consistent templates, automated aggregation and notifications.</pre>

## Introduction

**Background**: Making releases can be a chore. From ensuring the release notes have helpful information to aggregating many updates and notifying your users - doing the process right can be time consuming and fraught with misunderstandings. In this guide we recommend a standardized, automated way to notify your users of new releases. For example, we recommend using a `.github/release.yml` template to allow for more readable release notes, showcasing the importance of each update. We also provide automation for aggregating releases from many repositories into a super-release that provides a holistic view of project progress. Finally, we recommend automated notifications through GitHub integrations to help keep everyone informed.

**Use Cases**:
- Automating release notes generation with a readable template
- Aggregating multiple repository releases for projects with many repositories
- Streamlining release notifications to keep teams and users informed automatically

---

## Prerequisites
* A GitHub account and repository
* Basic understanding of GitHub Actions and workflows
* Access to IM channels like Slack for integration

---

## Quick Start
**[⬇️ Recommended GitHub release.yml Template](release.yml.md)**

_A customizable GitHub-specific release template. Customize it to fit your project's labeling scheme and presentation preferences for release notes and place it in your GitHub repository's `.github/release.yml` path._

**[⬇️ Python Script to Aggregate GitHub Releases](gh_aggregate_release_notes.py)**

_A Python script that aggregates release notes from many repositories and generates a "super" release text._

NOTE: You'll need a configuration file to use the above Python script. See step 2.2 below for an example file that you can customize for your project.


---

## Step-by-Step Guide

1. **Customize Release Notes**:
- Create a `.github/release.yml` file in your repository.
- Download our [GitHub release notes template](release.yml) and place the contents into your `.github/release.yml` file.
- Customize our recommended template as a baseline and to configure how release notes are generated based on your project's issue labels.

2. **Aggregate Releases**:
We recommend using a script to automatically aggregate release notes from multiple repositories. Details below.

2.1 Download our script
- Copy/download our script to your local machine
```
curl -o gh_aggregate_release_notes.py https://...
```

2.2 Create a configuration file with your project's release information. Save the file with extension `.yml` A sample is provided below:
```
github_token: <INSERT YOUR GH PERSONAL TOKEN>
urls:
- https://github.com/NASA-AMMOS/slim/releases/tag/v1.3.0
- https://github.com/your-org/your-repo/releases/tag/v1.0.0
```
2.3 Run the script to generate aggregated release notes
```
$ python gh_aggregate_release_notes.py your_configuration_file.yml
```

2.3 Review your aggregated release notes
- Your aggregated release notes should be printed to standard out

3. **Set Up Notifications**:
- Integrate GitHub with your IM channels, such as Slack, for example installing and configuring extensions like: [GitHub's Slack integration](https://slack.github.com).
- Conduct individual outreach to your customers/users to encourage them to watch your repository for release updates to stay informed about new releases through GitHub's notification system.

---

## Frequently Asked Questions (FAQ)

- Q: Can I customize which pull requests or issues appear in the release notes?
- A: Yes, by using labels and the `exclude-labels` field in the `.github/release.yml` file, you can control the inclusion of pull requests and issues in your release notes.

---

## Credits

**Authorship**:
- [@riverma](https://www.github.com/riverma)

**Acknowledgements**:
* @hookhua for inspiration to make this guide.

---

## Feedback and Contributions

We welcome feedback and contributions to help improve and grow this page. Please see our [contribution guidelines](https://github.com/YOUR_REPOSITORY/contributing.md).
99 changes: 99 additions & 0 deletions docs/guides/documentation/releases/gh_aggregate_release_notes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import requests
import yaml
import argparse
from urllib.parse import urlparse
from time import sleep
from tqdm import tqdm
import random

def read_config(file_path):
"""
Reads the YAML configuration file and returns its contents.
Args:
file_path (str): The path to the YAML configuration file.
Returns:
dict: The contents of the YAML file if successful, None otherwise.
"""
with open(file_path, 'r') as stream:
try:
return yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
return None

def get_release_notes(url, github_token):
"""
Extracts the owner, repo, and tag from the given GitHub URL and retrieves the release notes using the GitHub API.
Implements retries with exponential backoff and jitter for handling API rate limits and network issues.
Args:
url (str): The URL of the GitHub release tag page.
github_token (str): The GitHub token used for authentication.
Returns:
str: The release notes text if successful, empty string otherwise.
"""
parsed_url = urlparse(url)
hostname = parsed_url.hostname
path_parts = parsed_url.path.split('/')
owner, repo, tag = path_parts[1], path_parts[2], path_parts[-1]

# Be agnostic to GitHub.com or GitHub Enterprise repo URLs
api_url_prefix = f"https://api.github.com/repos/{owner}/{repo}" if hostname == "github.com" else f"https://{hostname}/api/v3/repos/{owner}/{repo}"
api_url = f"{api_url_prefix}/releases/tags/{tag}"
headers = {
"Authorization": f"token {github_token}",
"Accept": "application/vnd.github.v3+json"
}

max_retries = 5
retry_num = 0
backoff_factor = 2
while retry_num < max_retries:
response = requests.get(api_url, headers=headers)
if response.status_code == 200:
return response.json().get("body", "")
else:
print(f"Error fetching release notes for {url}: {response.status_code}. Retrying...")
sleep_time = backoff_factor * (2 ** retry_num) + random.uniform(0, 1)
sleep(sleep_time)
retry_num += 1

print(f"Failed to fetch release notes after {max_retries} attempts.")
return ""

def main(config_file):
"""
Main function to aggregate GitHub release notes.
It reads a YAML configuration file for GitHub repository URLs and a GitHub token,
then retrieves and prints the release notes for each repository URL listed.
Args:
config_file (str): The path to the YAML configuration file containing the GitHub token and URLs.
"""
config = read_config(config_file)
if not config:
print("Failed to read configuration.")
return

github_token = config.get("github_token")
urls = config.get("urls", [])

release_notes = ""

for url in tqdm(urls, desc="Downloading release notes"):
notes = get_release_notes(url, github_token)
if notes:
repo_name = url.split("/")[4] # Assumes a specific URL structure.
release_notes += f"# {repo_name}\n\n{notes}\n\n"

print(release_notes)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Aggregates GitHub release notes from a configuration file.")
parser.add_argument('config_file', type=str, help="Path to the YAML configuration file")
args = parser.parse_args()

main(args.config_file)
36 changes: 36 additions & 0 deletions docs/guides/documentation/releases/release.yml.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
title: Release Template (GitHub)
sidebar_label: Release Template (GitHub)
---

```yaml
# place in .github/release.yml

changelog:
exclude: # exclude any PRs labels we don't want in the changelog
labels:
- ignore-for-release
- skip-changelog
categories: # group PRs by your most important labels. Add / customize as needed.
- title: "πŸš€ Features"
labels:
- enhancement
- title: "πŸ› Bug Fixes"
labels:
- bug
- title: "πŸ“š Documentation"
labels:
- documentation
- title: πŸ“¦ Dependencies
labels:
- dependencies
- title: πŸ’» Other Changes
labels:
- "*"
exclude: # place the list of all labels you've categorized aboved to avoid duplication!
labels:
- enhancement
- bug
- documentation
- dependencies
```

0 comments on commit d9c3457

Please sign in to comment.