Skip to content

Commit

Permalink
Automatically Generate Release Notes Based on GitHub Releases (#124)
Browse files Browse the repository at this point in the history
# Automatically Generate Release Notes Based on GitHub Releases

## ♻️ Current situation & Problem
- Currently one has to manually set a release not in App Store Connect
to finalize an application update.

## ⚙️ Release Notes 
- Parses the release notes based on the GitHub release tag that is
formatted to fit the Apple release notes format.

### Code of Conduct & Contributing Guidelines 

By submitting creating this pull request, you agree to follow our [Code
of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md):
- [x] I agree to follow the [Code of
Conduct](https://github.com/StanfordBDHG/.github/blob/main/CODE_OF_CONDUCT.md)
and [Contributing
Guidelines](https://github.com/StanfordBDHG/.github/blob/main/CONTRIBUTING.md).
  • Loading branch information
PSchmiedmayer authored Jan 10, 2025
1 parent ed34e80 commit 5c57ffd
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 3 deletions.
17 changes: 16 additions & 1 deletion .github/workflows/deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ on:
The semantic version of the app that should be released.
required: true
type: string
releasenotes:
description: |
Release notes of what changed in this version.
required: false
type: string
default: Bug fixes and performance improvements.
workflow_call:
inputs:
environment:
Expand All @@ -42,6 +48,12 @@ on:
The semantic version of the app that should be released.
required: true
type: string
releasenotes:
description: |
Release notes of what changed in this version.
required: false
type: string
default: Bug fixes and performance improvements.

concurrency:
group: deployment
Expand All @@ -61,8 +73,10 @@ jobs:
run: |
if [[ -z "${{ inputs.environment }}" ]]; then
echo "environment=staging" >> $GITHUB_OUTPUT
echo "environment: staging"
else
echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT
echo "environment: ${{ inputs.environment }}"
fi
vars:
name: Inject Environment Variables In Deployment Workflow
Expand Down Expand Up @@ -92,6 +106,7 @@ jobs:
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
echo "version: ${{ inputs.version }}"
fi
echo "releasenotes: ${{ inputs.releasenotes }}"
buildandtest:
name: Build and Test
needs: determineenvironment
Expand All @@ -110,5 +125,5 @@ jobs:
environment: ${{ needs.determineenvironment.outputs.environment }}
googleserviceinfoplistpath: 'ENGAGEHF/Supporting Files/GoogleService-Info.plist'
setupsigning: true
fastlanelane: deploy environment:"${{ needs.determineenvironment.outputs.environment }}" appidentifier:"${{ needs.vars.outputs.appidentifier }}" provisioningProfile:"${{ needs.vars.outputs.provisioningProfileName }}" versionname:"${{ needs.vars.outputs.version }}"
fastlanelane: deploy environment:"${{ needs.determineenvironment.outputs.environment }}" appidentifier:"${{ needs.vars.outputs.appidentifier }}" provisioningProfile:"${{ needs.vars.outputs.provisioningProfileName }}" versionname:"${{ needs.vars.outputs.version }}" releasenotes:"${{ inputs.releasenotes }}"
secrets: inherit
73 changes: 72 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,79 @@ concurrency:
cancel-in-progress: false

jobs:
formatreleasenotes:
name: Format Release Notes
runs-on: ubuntu-latest
outputs:
releasenotes: ${{ steps.releasenotes.outputs.releasenotes }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Install Dependencies
run: pip install requests
- name: Fetch and Process releasenotes
id: releasenotes
run: |
python <<EOF
import re
import os
import requests
# Fetch release notes from the GitHub API
RELEASE_TAG = "${{ github.event.release.tag_name }}"
REPO = "${{ github.repository }}"
URL = f"https://api.github.com/repos/{REPO}/releases/tags/{RELEASE_TAG}"
response = requests.get(URL)
release = response.json()
releasenotes = release.get('body', '')
# Extract the "What's Changed" section
match = re.search(r"(## What's Changed.*?)(\n##|$)", releasenotes, flags=re.DOTALL)
if match:
releasenotes = match.group(1)
else:
releasenotes = "Bug fixes and performance improvements."
# Remove bold (**text**), italics (*text* or _text_), and underline (__text__)
releasenotes = re.sub(r'\*\*(.*?)\*\*', r'\1', releasenotes) # Remove **bold**
releasenotes = re.sub(r'\*(.*?)\*', r'\1', releasenotes) # Remove *italics*
releasenotes = re.sub(r'_(.*?)_', r'\1', releasenotes) # Remove _italics/underline_
releasenotes = re.sub(r'__(.*?)__', r'\1', releasenotes) # Remove __underline__
# Remove all headers (e.g., ## What's Changed)
releasenotes = re.sub(r'^#+\s*', '', releasenotes, flags=re.MULTILINE)
# Remove inline links but keep text (e.g., [text](url) → text)
releasenotes = re.sub(r'\[(.*?)\]\((.*?)\)', r'\1', releasenotes)
# Shorten pull request URLs to reference IDs (e.g., #123)
releasenotes = re.sub(r'https://github\.com/[^/]+/[^/]+/pull/(\d+)', r'#\1', releasenotes)
# Replace list items "*" with "-"
releasenotes = re.sub(r'^\s*\*\s+', '- ', releasenotes, flags=re.MULTILINE)
# Remove excess blank lines
releasenotes = re.sub(r'\n\s*\n', '\n', releasenotes).strip()
# Replace quotation marks with single quotes and line breaks
releasenotes = releasenotes.replace('"', "’")
releasenotes = releasenotes.replace("'", "’")
releasenotes = releasenotes.replace("\n", "\\n")
# Write cleaned releasenotes to GITHUB_OUTPUT
with open(os.environ['GITHUB_OUTPUT'], 'a') as output_file:
output_file.write(f"releasenotes<<EOF\n{releasenotes}\nEOF\n")
EOF
- name: Formatted Release Notes
run: |
echo "Formatted Release Notes:"
echo "${{ steps.releasenotes.outputs.releasenotes }}"
build-and-test:
name: Build and Test
uses: ./.github/workflows/deployment.yml
needs: formatreleasenotes
permissions:
contents: read
checks: write
Expand All @@ -28,4 +98,5 @@ jobs:
secrets: inherit
with:
environment: production
version: ${{ github.event.release.tag_name }}
version: ${{ github.event.release.tag_name }}
releasenotes: ${{ needs.formatreleasenotes.outputs.releasenotes }}
8 changes: 7 additions & 1 deletion fastlane/Fastfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ APP_CONFIG = {
default_environment: "staging",
default_app_identifier: "edu.stanford.bdh.engagehf",
default_provisioningProfile: "Stanford BDHG ENGAGE-HF",
default_version_name: "2.0.1"
default_version_name: "2.0.1",
default_release_notes: "Bug fixes and performance improvements."
}.freeze

platform :ios do
Expand Down Expand Up @@ -130,11 +131,13 @@ platform :ios do
appidentifier = options[:appidentifier].to_s.strip.empty? ? APP_CONFIG[:default_app_identifier] : options[:appidentifier]
provisioningProfile = options[:provisioningProfile].to_s.strip.empty? ? APP_CONFIG[:default_provisioningProfile] : options[:provisioningProfile]
versionname = options[:versionname].to_s.strip.empty? ? APP_CONFIG[:default_version_name] : options[:versionname]
releasenotes = options[:releasenotes].to_s.strip.empty? ? APP_CONFIG[:default_release_notes] : options[:releasenotes]

UI.message("Using environment: #{environment}")
UI.message("Using app identifier: #{appidentifier}")
UI.message("Using provisioning profile: #{provisioningProfile}")
UI.message("Using version name: #{versionname}")
UI.message("Using release notes: #{releasenotes}")

if environment == "production"
increment_version_number(
Expand All @@ -158,6 +161,9 @@ platform :ios do
if environment == "production"
deliver(
app_identifier: appidentifier,
release_notes: ({
'default' => releasenotes
}),
submit_for_review: true,
force: true,
reject_if_possible: true,
Expand Down

0 comments on commit 5c57ffd

Please sign in to comment.