diff --git a/cliff.toml b/cliff.toml new file mode 100644 index 00000000..c8d7d1b8 --- /dev/null +++ b/cliff.toml @@ -0,0 +1,130 @@ +# git-cliff ~ default configuration file +# https://git-cliff.org/docs/configuration +# +# Lines starting with "#" are comments. +# Configuration options are organized into tables and keys. +# See documentation for more information on available options. + +[changelog] +# template for the changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% if version -%} + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} +{% else -%} + ## [Unreleased] +{% endif -%} + +{% for group, commits in commits | filter(attribute="merge_commit", value=false) | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {%- for commit in commits | unique(attribute="message") %} + - {{ commit.message | split(pat="\n") | first | upper_first | trim }}\ + {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif -%} + {% if commit.remote.pr_number %} in \ + [#{{ commit.remote.pr_number }}]({{ self::remote_url() }}/pull/{{ commit.remote.pr_number }}) \ + {%- endif -%} + {% endfor %} +{% endfor %} + +{%- if github.contributors | filter(attribute="is_first_time", value=true) | length != 0 %} + ## New Contributors +{%- endif -%} + +{% for contributor in github.contributors | filter(attribute="is_first_time", value=true) %} + * @{{ contributor.username }} made their first contribution + {%- if contributor.pr_number %} in \ + [#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }}) \ + {%- endif %} +{%- endfor %}\n\n +""" +# template for the changelog footer +footer = """ +{%- macro remote_url() -%} + https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }} +{%- endmacro -%} + +{% for release in releases -%} + {% if release.version -%} + {% if release.previous.version -%} + [{{ release.version | trim_start_matches(pat="v") }}]: \ + {{ self::remote_url() }}/compare/{{ release.previous.version }}..{{ release.version }} + {% endif -%} + {% else -%} + [unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}..HEAD + {% endif -%} +{% endfor %} + +""" +# remove the leading and trailing s +trim = true +# postprocessors +postprocessors = [ + # { pattern = '', replace = "https://github.com/orhun/git-cliff" }, # replace repository URL +] +# render body even when there are no releases to process +# render_always = true +# output file path +# output = "test.md" + +#[remote.github] +#owner = "spacecowboy" +#repo = "feeder" + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = false +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # Replace issue numbers + #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](/issues/${2}))"}, + # Check spelling of the commit with https://github.com/crate-ci/typos + # If the spelling is incorrect, it will be automatically fixed. + #{ pattern = '.*', replace_command = 'typos --write-changes -' }, +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "^test", skip = true }, + { message = "^chore", skip = true }, + { message = "^ci", skip = true }, + { message = ".*renovate", skip = true }, + { message = ".*circleci", skip = true }, + { message = "^Bump", skip = true }, + { message = "^build", skip = true }, + { message = "^deps", skip = true }, + { message = "^fix(deps)", skip = true }, + { message = "^Releasing", skip = true }, + { message = "^feat", group = "🚀 Features" }, + { message = "^fix", group = "🐛 Bug Fixes & Minor Changes" }, + { message = "^added", group = "🐛 Bug Fixes & Minor Changes" }, + { message = "^refactor", group = "🚜 Refactoring" }, + { message = "^doc", group = "📚 Documentation" }, + { message = "^perf", group = "⚡ Performance" }, + { message = "^lang", group = "🌐 Translations" }, + { message = ".*Weblate", group = "🌐 Translations" }, + { body = ".*security", group = "🛡️ Security" }, + { message = "^revert", group = "◀️ Revert" }, +# { message = ".*", group = "💼 Other" }, + { message = ".*", group = "🐛 Bug Fixes & Minor Changes" }, +] +# filter out the commits that are not matched by commit parsers +filter_commits = true +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" diff --git a/release.sh b/release.sh index 69ab0431..44b69b79 100755 --- a/release.sh +++ b/release.sh @@ -4,16 +4,9 @@ TARGET="${1:-HEAD}" current_default="$(git describe --tags --abbrev=0 "${TARGET}")" -echo >&2 -n "Current version [${current_default}]: " -read -r current_in +echo >&2 -n "Current version [${current_default}]" -if [ -z "${current_in}" ]; then - CURRENT_VERSION="${current_default}" -else - CURRENT_VERSION="${current_in}" -fi - -next_default="$(grep "versionName" app/build.gradle.kts | sed "s|\s*versionName = \"\(.*\)\"|\\1|")" +next_default="$(git cliff --bumped-version)" echo >&2 -n "Next version [${next_default}]: " read -r next_in @@ -47,36 +40,10 @@ then git add app/src/main/res/xml/locales_config.xml fi -CL="# ${NEXT_VERSION} -$(git shortlog -w76,2,9 --max-parents=1 --format='* [%h] %s' "${CURRENT_VERSION}..HEAD") -" - -tmpfile="$(mktemp)" - -echo "${CL}" > "${tmpfile}" - -sensible-editor "${tmpfile}" +git cliff --tag "${NEXT_VERSION}" -o CHANGELOG.md echo >&2 "Changelog for [${NEXT_VERSION}]:" -cat >&2 "${tmpfile}" - -read -r -p "Write changelog? [y/N] " response -if [[ "$response" =~ ^[yY]$ ]] -then - # Playstore has a limit - head --bytes=500 "${tmpfile}" >"fastlane/metadata/android/en-US/changelogs/${NEXT_CODE}.txt" - - PREV="" - if [ -f CHANGELOG.md ]; then - PREV="$(cat CHANGELOG.md)" - fi - - cat >CHANGELOG.md <&2 read -r -p "Update gradle versions? [y/N] " response if [[ "$response" =~ ^[yY]$ ]] @@ -91,19 +58,19 @@ echo "Verifying build" read -r -p "Commit changes? [y/N] " response if [[ "$response" =~ ^[yY]$ ]] then - git add "fastlane/metadata/android/en-US/changelogs/${NEXT_CODE}.txt" git add app/build.gradle.kts git add CHANGELOG.md git diff --staged - git commit -m "Releasing ${NEXT_VERSION}" + git commit -m "chore: releasing ${NEXT_VERSION}" fi read -r -p "Make tag? [y/N] " response if [[ "$response" =~ ^[yY]$ ]] then - git tag -asm "$(cat "${tmpfile}")" "${NEXT_VERSION}" + git tag -asm "$(git cliff --tag "${NEXT_VERSION}" --unreleased)" "${NEXT_VERSION}" fi +# Undo the changes to locales_config.xml git checkout app/src/main/res fastlane/metadata/android read -r -p "Post to feed? [y/N] " response diff --git a/scripts/changelog-to-hugo.main.kts b/scripts/changelog-to-hugo.main.kts index c05a11ad..e1b250ce 100755 --- a/scripts/changelog-to-hugo.main.kts +++ b/scripts/changelog-to-hugo.main.kts @@ -12,6 +12,8 @@ import java.util.concurrent.TimeUnit val flavour = CommonMarkFlavourDescriptor() +val versionPattern = Regex("""(\d+\.\d+\.\d+[\.\-_0-9a-zA-Z]*)""") + data class ChangelogEntry( val version: String, val content: String, @@ -56,6 +58,11 @@ fun recurseMarkdown( } MarkdownElementTypes.ATX_1 -> { + // Keep going directly + ignoreContent = true + } + + MarkdownElementTypes.ATX_2 -> { // Header marks boundary between entries if (sb.isNotBlank()) { entries.add( @@ -67,7 +74,11 @@ fun recurseMarkdown( sb.clear() } val textNode = node.children.last() - return src.slice(textNode.startOffset until textNode.endOffset).trim() + // [2.9.0] - 2025-02-07 released + val title = src.slice(textNode.startOffset until textNode.endOffset).trim() + // Extract version from title using regex + newVersion = versionPattern.find(title)?.groupValues?.get(1) ?: error("Failed to extract version from: $title") + return newVersion } }