Shared GitHub workflows and actions for DFINITY repositories.
- Bump version
- Check commit messages
- Check pull request title
- Create pull request
- Generate changelog
- Generate release notes
- Is beta tag
- NPM publish
- Setup Commitizen
- Setup Deno
- Setup pnpm
- Setup Python
Name files using kebab-case and use the .yaml extension instead of .yml.
Name jobs and workflows using snake_case.
Name steps using natural language. Do not use quotes for the step name.
Explicitly name every step, even if it's a reusable action.
Suffix required actions with :required to make it easier to determine which actions are required and which aren't.
Example:
name: my_action:requiredA JavaScript action (using: node24) is executed by GitHub straight from the committed file its main points at, with no install or build step beforehand. Its dependencies therefore have to be committed too, which is why they are bundled into a single dist/index.js.
Mark that output as generated so it collapses in pull request diffs instead of burying the source changes:
actions/*/dist/** linguist-generated=truePair it with a job that rebuilds the bundles and fails on any difference. That check is what makes collapsing the diff safe, because it proves the committed output is exactly what the reviewed source compiles to.
When referencing 3rd party actions, use a specific commit SHA to lock the version. This ensures that the action will not change unexpectedly, which could lead to breaking changes in your workflows.
name: checkout_repo
on:
push:
branches:
- main
jobs:
checkout_repo:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2A reusable workflow that other repositories call must reference the actions in its own repository the same fully qualified, pinned way. A relative ./ path resolves against the caller's workspace rather than the repository the workflow lives in, so it fails there, and silently runs the caller's own file if one happens to sit at that path. Pinning keeps a single reference from a consuming repository resolving to a coherent set of workflows and actions.
The cost is that those pins do not move when an action changes, which leaves a workflow running an older copy of an action than the one beside it in the tree. That failure is quiet: a newly added input handed to an action pinned from before it existed is reported as a warning, not an error, so the run stays green while the new behaviour does nothing. Pair the convention with a job that fails when a pin has fallen behind:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# Each pin is resolved against local history, which the default shallow
# checkout does not have.
fetch-depth: 0
- name: Check workflow self references
run: script/bump-self-refsRun that job on pushes to the default branch rather than on pull requests. While an action is being changed there is no commit yet to pin to, so the pin can only be moved in a follow-up change, which also means the job cannot serve as a required status check.
The script in this repository resolves its own pins against its own history, so it checks this repository only. A repository that consumes these workflows has the same problem with its own pins, but solving it means comparing against a different repository's releases, which is what Dependabot's github-actions ecosystem is for.
For workflows that run on pull requests, use the concurrency key to ensure that only one workflow runs at a time for a given pull request. This prevents multiple workflows from running simultaneously and potentially causing conflicts.
name: commitizen
on:
merge_group:
pull_request:
concurrency:
group: pr-${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: trueFor workflows that perform deployments or releases, setup concurrency to ensure that only one deployment or release is in progress at a time. This prevents multiple deployments or releases from being triggered simultaneously, which could lead to inconsistencies.
name: release
on:
push:
branches:
- main
concurrency:
group: production
cancel-in-progress: falseCreate a .cz.yaml file and add the following content, replacing 0.11.0 with the current version of your repo:
---
commitizen:
name: cz_conventional_commits
tag_format: $version
version: 0.11.0
version_files:
- Cargo.toml
- packages/example/package.json:versionThe root Cargo.toml file holds the version number for each crate in the repo. Packages within the repo should reference the root workspace:
[package]
name = "example_crate"
version.workspace = truepackage.json files cannot share versions with their corresponding workspace, so they must be listed individually.
Create the .github/repo_policies/BOT_APPROVED_FILES file and add the following content:
# List of approved files that can be changed by a bot via an automated PR.
# This is to increase security and prevent accidentally updating files that shouldn't be changed by a bot.
.cz.yaml
CHANGELOG.md
Cargo.lock
Cargo.toml
packages/example/package.json
Disallow merge commits and rebase merging. Enable squash merging and set the default commit message to be Pull request title and description. This setting can alternatively be set to one of the other available options depending on the project's requirements, but take care to make sure that the rest of the recommendations here are adjusted to suit the chosen setting.
To support developers creating PR descriptions with the correct format, a pull request template can be used. This is not necessary if the PR description is not included in the merged commit message.
Create the .github/PULL_REQUEST_TEMPLATE.md file and add the following content:
<!-- Provide additional contextual information about the code changes below this line, then remove this line. -->
<!-- If relevant, provide additional information about breaking changes after the `BREAKING CHANGE` prefix on the following line, then remove this line. Remove the following line if there are no breaking changes. -->
<!--
BREAKING CHANGE:
-->
<!-- If relevant, add a reference to an issue on the following line, then remove this line. Remove the following line if there are no relevant issues. -->
<!--
Ref: #<issue number>
-->Branch targetting criteria:
Default.main.master.
Merge queue settings:
- Enable
Require merge queue. - Set the
Merge methodto beSquash and merge. - Enable
Require all queue entries to pass required checks.
Status checks:
- Enable
Require status checks to pass. - Add all required status checks in the
Status checks that are requiredsection.
Merge queues are currently not picking up the status report from reusable workflows on GitHub correctly. To work around this, we need to add an additional job to the pipeline that checks if the reusable workflows have passed or were skipped.
On PRs, the Check pull request title workflow is run. On merge groups, the Check commit messages workflow is run. The commitizen job is run after both of these jobs have completed. The commitizen job checks if the previous jobs have passed or were skipped. If they have, the commitizen job runs. If they haven't, the commitizen job fails.
name: commitizen
on:
merge_group:
pull_request:
concurrency:
group: pr-${{ github.workflow }}-${{ github.head_ref }}
cancel-in-progress: true
jobs:
check_pr_title:
name: check_pr_title
if: github.event_name == 'pull_request'
uses: dfinity/ci-tools/.github/workflows/check-pr-title.yaml@main
check_commit_messages:
name: check_commit_messages
if: github.event_name == 'merge_group'
uses: dfinity/ci-tools/.github/workflows/check-commit-messages.yaml@main
commitizen:
name: commitizen:required
runs-on: ubuntu-latest
needs: [check_pr_title, check_commit_messages]
if: always()
steps:
- name: Check previous jobs
run: |
if [[ "${{ needs.check_pr_title.result }}" == "success" || "${{ needs.check_pr_title.result }}" == "skipped" ]] &&
[[ "${{ needs.check_commit_messages.result }}" == "success" || "${{ needs.check_commit_messages.result }}" == "skipped" ]]; then
echo "All required jobs passed or were skipped."
else
echo "One or more jobs failed."
exit 1
fiContributions are welcome! Please refer to CONTRIBUTING.md, where you can find all you need to know to contribute to this project.
This project is licensed under the Apache-2.0 License.