#!/usr/bin/env bash # Bash script to prepare a release using git-cliff. # Inspired by https://github.com/orhun/git-cliff/blob/main/release.sh set -eu VERSION_FORMAT="^v[0-9]+\.[0-9]+\.[0-9]+$" # Check for a clean working directory. if [ -n "$(git status --porcelain)" ]; then echo "Your working directory is dirty. Commit or stash your changes before running this script." exit 1 fi # Check if a version tag is provided. if [ "$#" -eq 1 ]; then VERSION_TAG=$1 else # After git-cliff version 1.4.0 it should be possible to run `git cliff --bumped-version`. suggested_version=$(git cliff --unreleased --bump --context | jq -r .[0].version) echo -n "No version tag provided. git-cliff suggests $suggested_version. Proceed? [Y/n] " read user_input # Check if input is empty or a variation of "yes". if [[ -z "$user_input" || "$user_input" =~ ^[Yy](es)?$ ]]; then echo "Proceeding with version $suggested_version." VERSION_TAG=$suggested_version else echo "Release preparation cancelled." exit 1 fi fi # Verify that the version tag matches the expected format. if ! [[ $VERSION_TAG =~ $VERSION_FORMAT ]]; then echo "Version tag $VERSION_TAG does not match the expected format ${VERSION_FORMAT}." exit 1 fi echo "Preparing release ${VERSION_TAG}…" echo # Update CHANGELOG. git cliff --tag "$VERSION_TAG" -o CHANGELOG.md # Add all changes and commit. git add -A git commit -m "🔖 chore(release): prepare for $VERSION_TAG" # Template for the tag description. export GIT_CLIFF_TEMPLATE="\ {%- set breaking_header_shown = false -%} {% for commit in commits -%} {%- if commit.breaking and not breaking_header_shown %} 💥 BREAKING CHANGES 💥 {% set_global breaking_header_shown = true -%} {%- endif %} {%- if commit.breaking %} - {{ commit.message | upper_first -}} {% endif -%} {% endfor %} {% for group, group_commits in commits | group_by(attribute=\"group\") %} {{ group | striptags | trim | upper_first }} {% for commit in group_commits %} - {% if commit.breaking %}[‼️BREAKING‼️] {% endif %}{{ commit.message | upper_first }} {%- endfor %} {% endfor %}" # Cleaner template for the tag description. export GIT_CLIFF__CHANGELOG__BODY=$(cat <<'EOF' {% if version %}\ ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} {% else %}\ ## unreleased {% endif %}\ {% macro commit(commit, in_breaking_section=false) -%} - {% if commit.scope %}*({{ commit.scope }})* {% endif %}{% if commit.breaking and not in_breaking_section %}[**‼️BREAKING‼️**] {% endif %}\ {{ commit.message | upper_first }} - ({{ commit.id | truncate(length=7, end="") }})\ {% endmacro -%} {%- set breaking_header_shown = false -%} {% for commit in commits -%} {% if commit.breaking and not breaking_header_shown -%} {% raw %}\n### 💥 BREAKING CHANGES 💥\n{% endraw %} {% set_global breaking_header_shown = true %} {%- endif -%} {%- if commit.breaking -%} {{ self::commit(commit=commit, in_breaking_section=true) -}} {% endif -%} {%- endfor -%} {%- if breaking_header_shown == true -%} {% raw %}\n{% endraw %}\ {%- endif -%} {% for group, commits in commits | group_by(attribute="group") %} ### {{ group | striptags | trim | upper_first }} {% for commit in commits | filter(attribute="scope") | sort(attribute="scope") %} {{ self::commit(commit=commit) }} {%- endfor -%} {% raw %}\n{% endraw %}\ {%- for commit in commits %} {%- if not commit.scope -%} {{ self::commit(commit=commit) }} {% endif -%} {% endfor -%} {% endfor %}\n EOF ) # Generate the tag description. changelog=$(git cliff --tag "$VERSION_TAG" --unreleased --strip all) # Undo the pre_processing that adds PR links. changelog=$(echo "$changelog" | sed -E 's/\[\#([0-9]+)\]\(https:\/\/github\.com\/welpo\/[^\/]+\/issues\/([0-9]+)\)/#\1/g') # Create a signed and annotated tag. git tag -s -a "$VERSION_TAG" -m "Release $VERSION_TAG" -m "$changelog" echo "Most recent commit:" git log -1 echo echo "Information for tag $VERSION_TAG:" git show $VERSION_TAG echo echo "Release $VERSION_TAG is ready. Don't forget to push the changes and the tag:" remote_url=$(git remote get-url origin) # Check if the URL is in SSH format (git@). if [[ "$remote_url" == git@github.com:* ]]; then https_url="https://github.com/${remote_url#git@github.com:}" https_url="${https_url%.git}" else https_url="${remote_url%.git}" fi echo "git push && git push --tags && open ${https_url}/tags"