Skip to content
Open
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
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ When committing changes, please try to follow
[Conventional Commits](https://decisions.seedcase-project.org/why-conventional-commits/)
as Git messages. Using this convention allows us to be able to
automatically create a release based on the commit message by using
[Commitizen](https://decisions.seedcase-project.org/why-semantic-release-with-commitizen/).
[Cocogitto](https://decisions.seedcase-project.org/why-semantic-release-with-cocogitto/).
If you don't use Conventional Commits when making a commit, we will
revise the pull request title to follow that format, as we use squash
merges when merging pull requests, so all other commits in the pull
Expand Down
10 changes: 4 additions & 6 deletions index.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,10 @@ including for developing the package.
- Uses [Quarto](https://quarto.org/) Markdown for the website content,
allowing for easy integration of code, text, and figures.
- Uses
[Commitizen](https://decisions.seedcase-project.org/why-changelog-with-commitizen/)
to
[check](https://decisions.seedcase-project.org/why-lint-with-commitizen/)
commit messages and automatically create the changelog.
- Automated Git tagging and GitHub releases with
[commitizen](https://decisions.seedcase-project.org/why-semantic-release-with-commitizen/)
[git-cliff](https://decisions.seedcase-project.org/why-changelog-with-git-cliff/)
to automatically create the changelog.
- Automates Git tagging and GitHub releases with
[Cocogitto](https://decisions.seedcase-project.org/why-semantic-release-with-cocogitto/)
that are based on messages following
[Conventional Commits](https://decisions.seedcase-project.org/why-conventional-commits/).
- Uses a [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)
Expand Down
134 changes: 134 additions & 0 deletions template/.config/cliff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
[remote]
# Strictly don't connect to the internet to generate the changelog.
offline = false

[remote.github]
# TODO: Fill in the owner and repo so that the links in the changelog work correctly.
owner = ""
repo = ""
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to be filled out by each person using this repo as a template? Should we provide instructions for this somewhere else in addition to this comment so that it gets more visibility?


[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/)
for commit messages, we can automatically create
releases of the Python package based on those messages. The
releases are also published to Zenodo for easier discovery, archiving,
and citation.

We use
[Cocogitto](https://decisions.seedcase-project.org/why-semantic-release-with-cocogitto/)
to automate 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 from commit messages.

Because releases are generated automatically, new versions are released
often---sometimes several times in a day---
and each release usually contains only a small number of changes. Below
is a list of the releases and the changes
within each one.

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

body = """
Comment thread
lwjohnst86 marked this conversation as resolved.
{%- 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 = [
# TODO: Replace OWNER and REPO with actual owner and repo
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above, it might be difficult for someone to see these even if they are marked TODO unless we point it out in some instructions separately.

# Replace pull request numbers with links to GitHub.
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "[#${2}](https://github.com/OWNER/REPO/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" },
Comment thread
lwjohnst86 marked this conversation as resolved.
{ message = "^docs", group = "<!-- 3 -->📝 Documentation" },
{ message = "^perf", group = "<!-- 4 -->⚡ Performance" },
{ message = "^style", group = "<!-- 5 -->💄 Style" },
{ message = "^test", group = "<!-- 6 -->🧪 Tests" },
{ message = "^ci", group = "<!-- 7 -->👷 CI/CD" },
{ message = "^build", group = "<!-- 8 -->🧱 Build system" },
{ message = "^chore", group = "<!-- 9 -->🧹 Chores" },
{ message = "^revert", group = "<!-- 10 -->⏪ Revert" },
{ message = ".*", skip = true },
]
18 changes: 18 additions & 0 deletions template/.config/cog.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
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 rumdl fmt CHANGELOG.md --silent",
"uv version {{version}}",
"git commit CHANGELOG.md pyproject.toml uv.lock -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 }
Comment thread
lwjohnst86 marked this conversation as resolved.
fix = { bump_patch = true }
feat = { bump_minor = true }
Comment thread
lwjohnst86 marked this conversation as resolved.
6 changes: 0 additions & 6 deletions template/.cz.toml

This file was deleted.

61 changes: 0 additions & 61 deletions template/.github/workflows/release-package.yml

This file was deleted.

137 changes: 137 additions & 0 deletions template/.github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
name: Release

on:
push:
branches:
- main

# Limit token permissions for security
permissions: read-all

jobs:
github-release:
if: "!startsWith(github.event.head_commit.message, 'build: 🔖 update version')"
runs-on: ubuntu-latest
# To generate releases, this job needs write access to the repository contents.
permissions:
contents: write
# Can only release one version at a time, so need to stop any other jobs that
# are also trying to release, to prevent conflicts.
concurrency:
group: release-group
cancel-in-progress: true
# Used by the publishing job
outputs:
has_changes: ${{ steps.check_changes.outputs.has_changes }}
current_version: ${{ steps.create_release.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.
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@20cf305ff2072d973412fa9b1e3a4f227bda3c76 # v2.14.0
with:
egress-policy: audit

# Using this security pattern for GitHub Apps is recommended by GitHub and ensures that
# the token is only available for a short time and has limited permissions. Check out
# <https://guidebook.seedcase-project.org/operations/security> for more details.
- uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3 # v3.1.1
id: app-token
with:
client-id: ${{ vars.UPDATE_VERSION_APP_ID }}
private-key: ${{ secrets.UPDATE_VERSION_TOKEN }}

- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
# Only need the last commit from the repo.
fetch-depth: 0
# Requires the token in order to push changes to the repo for the release.
token: ${{ steps.app-token.outputs.token }}

# Set this for the bot user who will make the release commit.
- name: Set bot user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"

- name: Install Cocogitto
uses: cocogitto/cocogitto-action@9a9fe03b31c47444290c0d7f9b1ee1b44ee13f20 # v4.1.0
with:
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 bump --auto --dry-run --config .config/cog.toml) != 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 bump --auto --config .config/cog.toml

- name: Create GitHub release
id: create_release
if: steps.check_changes.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
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
echo "current_version=${version}" >> $GITHUB_OUTPUT

pypi-publish:
name: Publish to PyPI
runs-on: ubuntu-latest
# Only give permissions for this job.
permissions:
# IMPORTANT: Mandatory for trusted publishing.
id-token: write
environment:
name: pypi
needs:
- github-release
if: ${{ needs.github-release.outputs.has_changes }}
steps:
- name: Harden the runner (Audit all outbound calls)
uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0
with:
egress-policy: audit

- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# Need to explicitly get the current version, otherwise it defaults to current commit
# (which is not the same as the release/version commit).
ref: ${{ needs.github-release.outputs.current_version }}

# This workflow and the publish workflows are based on:
# - https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
# - https://www.andrlik.org/dispatches/til-use-uv-for-build-and-publish-github-actions/
# - https://github.com/astral-sh/trusted-publishing-examples
- name: Set up uv
uses: astral-sh/setup-uv@bd01e18f51369d5a26f1651c3cb451d3417e3bba # v6.3.1

- name: Build distributions
# Builds dists from source and stores them in the dist/ directory.
run: uv build

- name: Publish 📦 to PyPI
# Only publish if the option is explicitly set in the calling workflow.
run: uv publish --trusted-publishing always
5 changes: 0 additions & 5 deletions template/.pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ repos:
- id: check-merge-conflict
args: [--assume-in-merge]

- repo: https://github.com/commitizen-tools/commitizen
rev: v4.13.7
hooks:
- id: commitizen

# Use the mirror since the main `typos` repo has tags for different
# sub-packages, which confuses pre-commit when it tries to find the latest
# version
Expand Down
Loading
Loading