Skip to content
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
131 changes: 131 additions & 0 deletions .config/cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
[remote]
# Strictly don't connect to the internet to generate the changelog.
offline = false

[remote.github]
owner = "rostools"
repo = "template-workshop"

[changelog]
# A Tera template to be rendered for each release in the changelog.
header = """
# Changelog

Since we follow
[Conventional Commits](https://decisions.seedcase-project.org/why-conventional-commits/)
when writing commit messages, we're able to automatically create formal
"releases" of the template based on the commit messages. Releases in the
context of template are when changes occur to the `template/` files or
to the `copier.yaml` files. The releases are also published to Zenodo
for easier discovery, archival, and citation purposes. We use
[Cocogitto](https://decisions.seedcase-project.org/why-semantic-release-with-cocogitto/)
to be able to automatically create these releases, which uses
[SemVar](https://semverdoc.org) as the version numbering scheme,
and [Git Cliff](https://decisions.seedcase-project.org/why-changelog-with-git-cliff/)
to generate the changelog based on the commit messages.

Because releases are created based on commit messages, a new release is
created quite often---sometimes several times in a day. This also means
that any individual release will not have many changes within it. Below
is a list of the releases we've made so far, along with what was changed
within each release.

Commits from bots, like `dependabot` or `pre-commit-ci`, are not included in
the changelog.

"""

body = """
{%- macro remote_url() -%}
https://github.com/{{ remote.github.owner }}/{{ remote.github.repo }}
{%- endmacro -%}

{%- macro print_commit(commit) -%}
- {% if commit.scope %}*({{ commit.scope }})* {% endif %}\
{% if commit.breaking %}**breaking** {% endif %}\
{{ commit.message | upper_first }} \
{% if commit.remote.username %} by \
{% if commit.remote.username is containing("[bot]") %}
`@{{ commit.remote.username }}`\
{% else %}\
[`@{{ commit.remote.username }}`](https://github.com/{{ commit.remote.username }})\
{% endif %}\
{% endif %} \
([{{ commit.id | truncate(length=7, end="") }}]({{ self::remote_url() }}/commit/{{ commit.id }}))\
{%- endmacro -%}

{% if version %}
{% if previous.version %}
## [{{ version | trim_start_matches(pat="v") }}]\
({{ self::remote_url() }}/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% endif %}
{% else %}
## [unreleased]
{% 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::print_commit(commit=commit) }}
{% endfor %}
{% for commit in commits %}
{% if not commit.scope %}
{{ self::print_commit(commit=commit) }}
{% endif %}
{% endfor %}
{% endfor %}

{% if github %}
{% 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) %}
{% if contributor.username is containing("[bot]") %}
- `@{{ contributor.username }}` started making automated contributions\
{% else %}
- [`@{{ contributor.username }}`](https://github.com/{{ contributor.username }}) made their first contribution
{% if contributor.pr_number %} in \
[#{{ contributor.pr_number }}]({{ self::remote_url() }}/pull/{{ contributor.pr_number }})\
{% endif %}
{% endif %}\
{% endfor %}
{% endif %}

"""

# Remove leading and trailing whitespaces from the changelog's body.
trim = true
output = "CHANGELOG.md"

[git]
commit_preprocessors = [
# Replace pull request numbers with links to GitHub.
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "[#${2}](https://github.com/rostools/template-workshop/pull/${2})" },
# Check spelling of the commit message using https://github.com/crate-ci/typos.
# If the spelling is incorrect, it will be fixed automatically.
{ pattern = '.*', replace_command = 'uvx typos --write-changes -' },
# Remove gitmoji, both actual UTF emoji and :emoji:
{ pattern = ' *(:\w+:|[\p{Emoji_Presentation}\p{Extended_Pictographic}](?:\u{FE0F})?\u{200D}?) *', replace = "" },
]

commit_parsers = [
# Don't include commits from bots.
{ field = "author.name", pattern = ".*(dependabot|github-actions|pre-commit-ci).*", skip = true },
# Don't include the version update commits.
{ message = ".*update version", skip = true },
{ message = "^feat", group = "<!-- 0 -->✨ Features" },
{ message = "^fix", group = "<!-- 1 -->🐛 Fixes" },
{ message = "^refactor", group = "<!-- 2 -->♻️ Refactor" },
{ message = "^docs", group = "<!-- 3 -->📝 Documentation" },
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
{ message = "^style", group = "<!-- 5 -->💄 Styling" },
{ message = "^test", group = "<!-- 6 -->🧪 Tests" },
{ message = "^ci", group = "<!-- 7 -->👷 CI/CD" },
{ message = "^chore|^build", group = "<!-- 8 -->👩‍💻 Miscellaneous" },
{ message = "^revert", group = "<!-- 9 -->⏪ Revert" },
{ message = ".*", skip = true },
]
17 changes: 17 additions & 0 deletions .config/cog.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from_latest_tag = true
disable_changelog = true
disable_bump_commit = true
branch_whitelist = ["main"]
pre_bump_hooks = [
# Quiet the log output of git-cliff, it is noisy.
"RUST_LOG='none' uvx git-cliff --tag {{version}}",
"uvx --from panache-cli panache format CHANGELOG.md --quiet",
"git commit CHANGELOG.md -m 'build: 🔖 update version to {{version}} [skip ci]'",
]
post_bump_hooks = ["git push", "git push --tags"]

[commit_types]
refactor = { bump_patch = true }
perf = { bump_patch = true }
fix = { bump_patch = true }
feat = { bump_minor = true }
54 changes: 32 additions & 22 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ jobs:
concurrency:
group: release-group
cancel-in-progress: true
# Outputs for potential next jobs.
outputs:
previous_version: ${{ steps.version-var.outputs.previous_version }}
current_version: ${{ steps.version-var.outputs.current_version }}
steps:
# This is a useful security step to check for unexpected outbound calls from the runner,
# which could indicate a compromised token or runner.
Expand Down Expand Up @@ -55,27 +51,41 @@ jobs:
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

# This step outputs `REVISION` and `PREVIOUS_REVISION` env variables.
- id: cz
name: Update version and changelog
uses: commitizen-tools/commitizen-action@338bbd841b75aaee6bf5340e1fa12f6ab58ff9ff # 0.27.1
- name: Install Cocogitto
uses: cocogitto/cocogitto-action@9a9fe03b31c47444290c0d7f9b1ee1b44ee13f20 # v4.1.0
with:
github_token: ${{ steps.app-token.outputs.token }}
changelog: true
command: check

# Install uv to use git-cliff and rumdl
- name: Set up uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
enable-cache: true

- name: Check if there are releasable changes
continue-on-error: true
id: check_changes
run: |
# Determine if a bump is possible.
if [[ $(cog --config .config/cog.toml bump --auto --dry-run) != No* ]]; then
echo "has_changes=true" >> $GITHUB_OUTPUT
else
echo "has_changes=false" >> $GITHUB_OUTPUT
fi

- name: Create tag and update changelog
if: steps.check_changes.outputs.has_changes == 'true'
run: |
cog --config .config/cog.toml bump --auto

- name: Create GitHub release
if: ${{ env.PREVIOUS_REVISION != env.REVISION }}
if: steps.check_changes.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create $REVISION \
--generate-notes \
--fail-on-no-commits \
--verify-tag

# Need to output this to tell any potential next job that a release was made.
- id: version-var
name: Output version variable
run: |
echo "previous_version=$PREVIOUS_REVISION" >> "$GITHUB_OUTPUT"
echo "current_version=$REVISION" >> "$GITHUB_OUTPUT"
version=$(cog get-version)
# Remove logging from git-cliff.
RUST_LOG='none' uvx git-cliff --latest --output RELEASE_NOTES.md --strip all
gh release create "${version}" \
--title "Release ${version}" \
--notes-file RELEASE_NOTES.md
Loading
Loading