Skip to content
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

Release process - Generate release notes from PRs #1898

Merged
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 .github/.release_notes_allowed_labels_list
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Breaking changes,New,Fixed,Improved,Changed,Removed,Deprecated
11 changes: 11 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,14 @@
- [ ] Related issues are linked

COAND-XXX

## Release notes
[//]: # (Use the headers listed below to organize your release notes. Each section should begin with ### followed by a valid label)
[//]: # (Allowed labels: `Breaking changes`, `New`, `Fixed`, `Improved`, `Changed`, `Removed`, `Deprecated`)
[//]: # (Content will be grouped under a specific label until the next header #, ##, or ### is found)
[//]: # (### New)
[//]: # (List any new features or enhancements)
[//]: # (e.g. - Added functionality for user authentication)
[//]: # (### Fixed)
[//]: # (List fixes here)
[//]: # (e.g. - Fixed issue with incorrect data rendering)
65 changes: 65 additions & 0 deletions .github/workflows/generate_release_notes.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: Generate release notes

on:
workflow_call:
inputs:
version-name:
required: true
type: string

jobs:
get_allowed_labels:
runs-on: ubuntu-latest

outputs:
allowed-labels: ${{ steps.get_allowed_labels.outputs.allowed_labels }}

steps:
- uses: actions/checkout@v4

- name: Get the list of allowed pull request labels
id: get_allowed_labels
env:
PROJECT_ROOT: ${{ github.workspace }}
run: |
RED='\033[0;31m'
FILE_NAME=.release_notes_allowed_labels_list
GITHUB_DIR=.github
FILE_PATH=$PROJECT_ROOT/$GITHUB_DIR/$FILE_NAME
if [[ ! -f "$FILE_PATH" ]]; then
echo -e "${RED}$FILE_NAME file doesn't exist in $GITHUB_DIR/"
exit 1
fi
ALLOWED_LABELS=$(cat $FILE_PATH)
echo -e "allowed_labels=$ALLOWED_LABELS" >> $GITHUB_OUTPUT
echo -e "Allowed labels are: $ALLOWED_LABELS"

generate_release_notes:
runs-on: ubuntu-latest
needs: get_allowed_labels

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Generate release notes
id: generate_release_notes
env:
ALLOWED_LABELS: ${{ needs.get_allowed_labels.outputs.allowed-labels }}
VERSION_NAME: ${{ inputs.version-name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPO: ${{ github.repository }}
run: |
chmod +x scripts/generate_release_notes.sh
RELEASE_NOTES_FILE_NAME="release-notes-${VERSION_NAME}.md"
scripts/generate_release_notes.sh $RELEASE_NOTES_FILE_NAME

- name: Upload release notes artifact
uses: actions/upload-artifact@v3
env:
VERSION_NAME: ${{ inputs.version-name }}
with:
name: "release-notes-${{ env.VERSION_NAME }}"
path: "release-notes-${{ env.VERSION_NAME }}.md"
overwrite: true
95 changes: 95 additions & 0 deletions scripts/generate_release_notes.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/bin/bash

# Fetch latest release tag
fetch_latest_release_tag() {
LATEST_TAG=$(git describe --tags --abbrev=0)
echo "$LATEST_TAG"
}

# Fetch recent commits since the last release tag
fetch_recent_commits() {
LATEST_TAG=$1

COMMITS=$(git log --oneline "$LATEST_TAG"..HEAD)
echo -e "$COMMITS"
}

# Generate release notes from PRs
generate_release_notes_from_prs() {
LATEST_TAG="$(fetch_latest_release_tag)"
COMMITS="$(fetch_recent_commits "$LATEST_TAG")"
echo -e "Commits between the $LATEST_TAG and HEAD\n$COMMITS"

# Initialize variables to hold content for each label
IFS=',' read -r -a LABELS <<< "$ALLOWED_LABELS"
declare -A LABEL_CONTENTS
for LABEL in "${LABELS[@]}"; do
LABEL_CONTENTS["$LABEL"]=""
done

# Iterate over each commit to find PR numbers, fetch PR body and extract release notes
while IFS= read -r COMMIT; do
if [[ $COMMIT =~ Merge\ pull\ request\ \#([0-9]+) ]]; then
PR_NUMBER="${BASH_REMATCH[1]}"
echo -e "Processing PR #$PR_NUMBER"

# Fetch PR content and extract body
API_URL="https://api.github.com/repos/$GITHUB_REPO/pulls/$PR_NUMBER"
PR_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "$API_URL")
PR_BODY=$(echo "$PR_RESPONSE" | jq -r '.body')

# Extract release notes for each label
for LABEL in "${LABELS[@]}"; do
HEADER="### $LABEL"
LABEL_CONTENT=$(echo "$PR_BODY" | awk -v header="$HEADER" '
$0 ~ header { capture = 1; next } # Start capturing after the specified header
capture && /^[#]+[ ]/ { exit } # Stop at lines starting with one or more # followed by a space
capture { print $0 } # Continue capturing until a stopping condition
')
if [ -n "$LABEL_CONTENT" ]; then
LABEL_CONTENTS["$LABEL"]="${LABEL_CONTENTS[$LABEL]}$LABEL_CONTENT\n"
echo -e "Generated notes for $LABEL:\n$LABEL_CONTENT"
fi
done
fi
done <<< "$COMMITS"

# Combine notes by labels
OUTPUT=""
for LABEL in "${LABELS[@]}"; do
if [ -n "${LABEL_CONTENTS[$LABEL]}" ]; then
OUTPUT="${OUTPUT}### $LABEL\n${LABEL_CONTENTS[$LABEL]}\n"
fi
done

# Save release notes in a file
if [ -n "$OUTPUT" ]; then
printf "Generated release notes:\n$OUTPUT"
printf "$OUTPUT" >> "$RELEASE_NOTES_FILE_NAME"
printf "$OUTPUT" >> "$GITHUB_STEP_SUMMARY"
fi
}

# Main Execution
generate_release_notes() {
if [ -z "$ALLOWED_LABELS" ]; then
echo "ALLOWED_LABELS is not provided. Please provide it in env list. Exiting..."
exit 1
fi

if [ -z "$GITHUB_TOKEN" ]; then
echo "GITHUB_TOKEN is not provided. Please provide it in env list. Exiting..."
exit 1
fi

if [ -z "$GITHUB_REPO" ]; then
echo "GITHUB_REPO is not provided. Please provide it in env list. Exiting..."
exit 1
fi

generate_release_notes_from_prs
}

RELEASE_NOTES_FILE_NAME=$1

generate_release_notes