diff --git a/.config/cliff.toml b/.config/cliff.toml new file mode 100644 index 0000000..1a38ec0 --- /dev/null +++ b/.config/cliff.toml @@ -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 = "โœจ Features" }, + { message = "^fix", group = "๐Ÿ› Fixes" }, + { message = "^refactor", group = "โ™ป๏ธ Refactor" }, + { message = "^docs", group = "๐Ÿ“ Documentation" }, + { message = "^perf", group = "โšก Performance" }, + { message = "^style", group = "๐Ÿ’„ Styling" }, + { message = "^test", group = "๐Ÿงช Tests" }, + { message = "^ci", group = "๐Ÿ‘ท CI/CD" }, + { message = "^chore|^build", group = "๐Ÿ‘ฉโ€๐Ÿ’ป Miscellaneous" }, + { message = "^revert", group = "โช Revert" }, + { message = ".*", skip = true }, +] diff --git a/.config/cog.toml b/.config/cog.toml new file mode 100644 index 0000000..ec6313e --- /dev/null +++ b/.config/cog.toml @@ -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 } diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9186ec5..d8d774e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -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. @@ -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 diff --git a/CHANGELOG.md b/CHANGELOG.md index d51dce6..f6dd49c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,413 +1 @@ -# Changelog - -Since we follow -[Conventional Commits](https://decisions.seedcase-project.org/why-conventional-commits/) -we're able to automatically create formal "releases" of the workshop -based on our commit messages. Releases in the context of workshops are -simply snapshots in time of the workshop content. The releases are -published to Zenodo for easier discovery, archival, and citation -purposes. We use -[Commitizen](https://decisions.seedcase-project.org/why-semantic-release-with-commitizen/) -to automatically create these releases using -[SemVer](https://semverdoc.org) as the version numbering scheme. - -Because releases are created based on commit messages, a new release can -be 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. - -If you attended a workshop or used the workshop material as some point -in time, you can always refer to this changelog page to find out what -has been changed since you last used it. - -## 0.11.0 (2026-06-04) - -## 0.10.0 (2026-05-03) - -## 0.9.1 (2026-04-25) - -## 0.9.0 (2026-04-25) - -### Feat - -- ๐Ÿ”จ create soft link to extension in justfile -- ๐Ÿ”ง add URN for eventual `zen-do` PDF upload -- ๐Ÿ”จ include styler recipe in justfile, to format R in `.qmd` - -### Fix - -- ๐Ÿ› fix issues found during testing -- โœ๏ธ update path to release workflow - -### Refactor - -- โฌ†๏ธ update Quarto theme -- ๐ŸŽจ reformat files -- ๐Ÿ”ง change format of slides if its for rostools or not -- ๐Ÿšš move explanation of files into CONTRIBUTING -- ๐Ÿ“ small improvements to text in CODEOWNERS -- ๐Ÿ”ง `_publish.yaml` should only be added for Netlify projects -- ๐Ÿ‘ท set auto-release files only for rostools templates -- ๐Ÿ’„ rostools extension only added for rostools projects -- ๐Ÿง‘โ€๐Ÿ’ป set some vscode settings only for R workshops -- ๐Ÿ”ง sync files to template -- ๐Ÿ”ง sync extensions and snippets with template -- ๐Ÿง‘โ€๐Ÿ’ป simplify VS Code settings -- ๐Ÿ‘ท don't use reusable workflows, include full steps -- ๐Ÿ”ง simplify the Copier questions asked, removing unnecessary ones -- ๐Ÿ”ง simplify metadata values to match t-squared -- ๐ŸŽจ small formatting fixes to pre-workshop tasks files -- โœ๏ธ shorten recipe to `just install-deps` -- โฌ†๏ธ update pre-commit versions -- ๐Ÿ”จ sort contributors in tool script - -## 0.8.2 (2026-04-07) - -### Fix - -- :pencil2: small corrections to installing R packages doc -- :bug: need to use two `##`, not three for panel-tabset - -## 0.8.1 (2026-04-06) - -### Fix - -- :pencil2: solution chunk should be a callout and collapsed - -## 0.8.0 (2026-04-06) - -### Feat - -- :sparkles: link to r-universe, don't need RTools/pak -- :wrench: include "solution chunk" snippet into VS Code settings - -### Fix - -- :pencil2: forgot to include a `#sec-` tag in `for-teachers.qmd` -- :pencil2: workflow job should be called `release-project` - -### Refactor - -- :recycle: simplify learning design and use headers rather than list -- :fire: no longer need the `workshop_level` metadata item -- :wrench: explicitly use Posit Air for R formatting in VS Code settings -- small edits to justfile recipe docs -- :arrow_up: update `rostools-theme` extension - -## 0.7.0 (2026-03-30) - -### Feat - -- :sparkles: add badges to landing page -- :sparkles: standardize table widths of schedule -- :see_no_evil: some `.vdoc.*` type files are created by Quarto, ignore - them -- :sparkles: include hidden contributor list sections in README and - index - -### Fix - -- :pencil2: match `#sec-` with filename -- :bug: don't format on save for `qmd`, creates `.vdoc` files everywhere -- :art: resolve Markdown formatting issues -- :pencil2: correct URL in `copier.yaml` -- :pencil2: correct URLs from lychee check - -### Refactor - -- :hammer: rename `style` to `format-r` in justfile -- :pencil2: use quotes around values in `_quarto.yml` -- :recycle: include `@sec-` links to chapters along with a link -- :technologist: simplify pull request template after Markdown formatter - added -- :wrench: indent by 2 in Markdown files in `.editorconfig` -- :recycle: install uv directly, rather than first pipx -- :arrow_up: update pre-commit hook versions -- :arrow_up: update `rostools-theme` Quarto extension - -## 0.6.0 (2026-03-26) - -### Feat - -- :sparkles: add rumdl Markdown formatter - -### Fix - -- :pencil2: replace 'course' with 'workshop' -- :pencil2: clarify that RTools needs to match R - -### Refactor - -- :memo: clarify that instructors are learning (in intro) -- :see_no_evil: ignore auto-generated Quarto ipynb files -- :recycle: revise contributor list tool to match Markdown formatter -- :recycle: ensure URLs are checked in `just run-all` -- :fire: don't need to explicitly use `theme` in `_quarto.yml` - -## 0.5.0 (2026-02-07) - -### Feat - -- :sparkles: add lychee URL checking to justfile -- :sparkles: exclude latex output files from typos - -### Refactor - -- :recycle: simplify code of conduct text - -## 0.4.15 (2025-09-17) - -### Refactor - -- :memo: explain how releases work in CHANGELOG (#27) - -## 0.4.14 (2025-09-08) - -### Fix - -- :pencil2: can use `svg` in License badge -- :wrench: need to include `theme: brand` in `_quarto.yml` -- :pencil2: remove duplicate sentence in pre-workshop overview - -### Refactor - -- :art: strip empty Jinja lines correctly - -## 0.4.13 (2025-09-03) - -### Fix - -- :bug: move `github_repo` as question to fix update issue - -### Refactor - -- :recycle: output `get-contributors.sh` as text, send to file in - justfile - -## 0.4.12 (2025-09-03) - -### Refactor - -- :recycle: minor text edits to pre-workshop code of conduct (#26) - -## 0.4.11 (2025-09-03) - -### Fix - -- :bug: `dst_path` isn't good to use when running updates - -## 0.4.10 (2025-09-03) - -### Refactor - -- :truck: save `_contributors.yml` to `includes/` - -## 0.4.9 (2025-09-03) - -### Refactor - -- :pencil2: minor text edit to improve flow (#24) - -## 0.4.8 (2025-09-03) - -### Fix - -- :bug: correctly strip empty jinja lines - -### Refactor - -- :pencil2: should be `isIdenticalTo` and `lesson` in `.zenodo.json` - -## 0.4.7 (2025-09-03) - -### Refactor - -- :recycle: minor rewrite of star-us (#23) - -## 0.4.6 (2025-09-03) - -### Refactor - -- :recycle: minor rewrites in learning design (#22) - -## 0.4.5 (2025-09-02) - -### Fix - -- :bug: need to check for existence of `github_repo` first - -## 0.4.4 (2025-09-02) - -### Fix - -- :pencil2: this badge is default `svg`, don't end with it - -## 0.4.3 (2025-09-02) - -### Refactor - -- :wrench: include `revert` as a branch tag -- :hammer: ignore irrelevant dirs when listing TODOs -- :pencil2: remove trailing `/` from URL - -## 0.4.2 (2025-09-02) - -### Fix - -- :pencil2: no spaces around em-dashes - -### Refactor - -- :memo: simplify some text of the README -- :recycle: replace ending of `_contributors.yml` with newline for - pre-commit styling -- :hammer: exclude justfile when listing TODOs -- :hammer: use `quarto update` to match recipe name -- :arrow_up: update pre-commit hook versions - -## 0.4.1 (2025-08-29) - -### Fix - -- :pencil2: should say "teach", not "instruct" -- :fire: removed left over note in `justfile` -- :pencil2: CONTRIBUTING in template shouldn't refer to "template" - -### Refactor - -- :lipstick: use less emojis and a specific star in `star-us` includes -- :recycle: mention that some files are for development too - -## 0.4.0 (2025-08-29) - -### Feat - -- :sparkles: add GoatCounter HTML script - -### Refactor - -- :lipstick: strip empty Jinja lines -- :truck: `Rproj` file should only be added for R workshops - -## 0.3.2 (2025-08-29) - -### Refactor - -- :lipstick: wrap text in README in a callout block for separation - -## 0.3.1 (2025-08-28) - -### Fix - -- :pencil2: forgot to include commas in `.zenodo.json` fields -- :pencil2: should be `>-` for validating -- :pencil2: should be `knitr` in the `Rproj` file, not `Sweave` - -### Refactor - -- :fire: abbrev `meta` isn't used anywhere - -## 0.3.0 (2025-08-28) - -### Feat - -- :wrench: include changelog in website, plus add more text in it - -### Fix - -- :hammer: point contributor script to generated template repo -- :bug: need to store `github_repo` in answers file - -### Refactor - -- :recycle: add TODO item in slides -- :pencil2: use shorter link to LICENSE in README -- :hammer: build contributor list in justfile, not Quarto config -- :lipstick: use `svg` for copier badge -- :fire: keep assignee empty in Dependabot PRs - -## 0.2.0 (2025-08-24) - -### Feat - -- :wrench: add all pages to `_quarto.yml` -- :sparkles: add a "is this for you" page -- :sparkles: create Jinja templated version of the landing page -- :sparkles: include a survey includes file -- :sparkles: output `README.qmd` to GFM Markdown version -- :sparkles: create starting URL for workshop on copy -- :sparkles: add (empty) CODEOWNERS -- :sparkles: add author name questions -- :sparkles: add empty objectives includes file -- :sparkles: add a post-copy message and tasks - -### Fix - -- :bug: actually have to insert `_metadata.yml` file in `_quarto.yml` -- :bug: include shortcode should always use root `/` -- :bug: Jinja strip empty lines needs a specific format -- :bug: Quarto `{#` need to be escaped in Jinja -- :bug: need to escape Quarto shortcodes if in Jinja file -- :pencil2: includes of file should have `_` -- :bug: Jinja else if needs to be `elif` -- :bug: can't have spaces between `%}` - -### Refactor - -- :recycle: don't update template in `run-all` of justfile -- :truck: includes need to be prefixed with `_` -- :fire: clean up leftover `vscode` setting files -- :recycle: make intro slides a bit more generic -- :recycle: include snippets of all possible sections in session -- :truck: rename to `_star-us.qmd`, not "follow" -- :truck: prefix includes with `_` -- :recycle: stylistic and editing changes to installing R packages page -- :fire: remove duplicate text in survey page -- :recycle: check that board number is a number -- :recycle: switch to using bash in `check-commits` justfile -- :memo: fix link to instructor guide -- :fire: don't need the update from template workflow -- :recycle: switch to using `github_user` and `github_repo` for project - naming -- :recycle: use lowercase for workshop type naming -- :recycle: set Zenodo upload type to `lesson` -- :recycle: moved version information for installing into - `_metadata.yml` -- :recycle: match syllabus structure to that done in GitHub Intro -- :fire: session isn't always an R workshop, don't need code chunk - -## 0.1.0 (2025-08-24) - -### Feat - -- :sparkles: add initial, though empty, CHANGELOG file -- :sparkles: fill out templating in `_quarto.yml` file -- :sparkles: add `_metadata.yml` file to hold common text -- :hammer: justfile recipe to build readme in template -- :sparkles: update template's README -- :sparkles: set of default badges for template README and landing page -- :sparkles: standalone page for learning design -- :sparkles: add includes for "follow us" block -- :sparkles: add justfile to template -- :sparkles: add `.zenodo.json` to the template - -### Fix - -- :bug: wrap `${{ }}` in `{{` to escape them -- :bug: should be `{{ }}`, without the % - -### Refactor - -- :fire: no need for generic "installing-programs" doc -- :recycle: include "reading-website" into overview page -- :truck: simplify includes to all be in `includes/` -- :truck: converted includes into own pages in template -- :recycle: remove social time from schedule -- :recycle: include a starting URL for Quarto website in Netlify -- :construction_worker: merge template website build workflow into one - file -- :recycle: expand on template's CONTRIBUTING doc -- :truck: move code of conduct out of includes as own page -- :recycle: use only one `.cz.toml`, but use internal 'if' statements - inside +