Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save motss/d9d6c58ca7b064982dcdbb5e663f047f to your computer and use it in GitHub Desktop.
Save motss/d9d6c58ca7b064982dcdbb5e663f047f to your computer and use it in GitHub Desktop.
How to get a list of merged PRs after the last release tag then format for changelog using Github CLI
#!/bin/sh
# Ensure a reelase tag is provided
if [ -z "$1" ]; then
printf "Please provide a release tag!\n"
exit 1
fi
RELEASES=$(gh release list --limit 1)
# Ensure there is at least one release tag in the repository
if [ -z "$RELEASES" ]; then
printf "No release found!\n"
exit 1
fi
# Get the timestamp of the last release tag
# By default, Github CLI or gh list all release tags in descending order
# Apply limit=1 to get the last release tag
TIMESTAMP=$(
gh release list \
--limit 1 \
--json tagName,publishedAt \
--jq ".[0].publishedAt | fromdateiso8601"
)
PRS=$(gh pr list --state merged --limit 1)
# Ensure there is at least one merged PR in the repository
if [ -z "$PRS" ]; then
printf "No merged PRs found!\n"
exit 1
fi
# To format the merged PRs for changelog, we only need:
# 1. PR number - via .number
# 1. PR title - via .title
# 1. PR author - via .author.login
# 1. PR merged at - via .mergedAt
# 1. PR merge commit - via .mergeCommit.oid
# 1. PR URL - via .url
#
# Github CLI does not support filter so limit=999 is used here to get a huge number of PRs as a stopgap solution.
# 999 is a large enough number but feel free to tweak this to suit you the best. Larger value means Github CLI
# has to fetch more data which might slow things down.
#
# Then, use jq expressions to filter the list of merged PRs that has timestamp > timestamp of last release tag.
#
# Finally format them for changelog with linkable author and PR.
#
# Note that this assumes no merged PRs has the same timestamp as the last release tag.
MERGED_PRS=$(
gh pr list \
--state merged \
--json author,number,mergeCommit,mergedAt,url,title \
--limit 999 \
--jq ".[] | \
select (.mergedAt | fromdateiso8601 > $TIMESTAMP) | \
\"- [\`\(.mergeCommit.oid[0:7])\`](\(.url | split(\"/pull/\")[0])/commit/\(.mergeCommit.oid)) \(.title) by [@\(.author.login)](https://github.com/\(.author.login)) ([#\(.number)](\(.url)))\""
)
# Get the last release tag and the repository URL
OLD_RELEASE_TAG=$(gh release list --limit 1 --json tagName --jq ".[] | .tagName")
# Define your own release tag format
NEW_RELEASE_TAG="$1"
# Get the repository URL
REPO_URL=$(gh repo view --json url --jq ".url")
# Define the header of the changelog
HEADER="## What's changed"
# Define the footer of the changelog
FOOTER="Full changelog: $REPO_URL/compare/$OLD_RELEASE_TAG...$NEW_RELEASE_TAG"
# Define the changelog
CHANGELOG="$HEADER\n\n$MERGED_PRS\n\n$FOOTER\n"
# Print the changelog for the release
printf "%s" "$CHANGELOG"
# Define the new release tag
# todo: use semver instead
$TAG="$(date '+%Y-%m-%d')-$(git rev-parse --short HEAD)"
gh release create $TAG --notes "$CHANGELOG" --title "$TAG"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment