Conversation
| if: ${{ github.event_name != 'merge_group' }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - uses: actions/setup-node@v4 | ||
| if: ${{ github.event_name != 'merge_group' }} | ||
| with: | ||
| node-version: 22 | ||
| fetch-depth: 0 | ||
|
|
||
| - run: npm install js-yaml@4.1.0 | ||
| if: ${{ github.event_name != 'merge_group' }} | ||
|
|
||
| - name: Fail if PR changelog is not correct | ||
| if: ${{ github.event_name != 'merge_group' }} | ||
| uses: actions/github-script@v8 | ||
| id: check-changelog | ||
| - uses: cachix/install-nix-action@v30 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const yaml = require('js-yaml'); | ||
| const fs = require('fs'); | ||
| const execSync = require('child_process').execSync; | ||
|
|
||
| const prDescription = await github.rest.pulls.get({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: context.issue.number | ||
| }); | ||
|
|
||
| const changelogRegex = /# Changelog[\s\S]*?```yaml([\s\S]*?)```/; | ||
| const changelogMatch = prDescription.data.body.match(changelogRegex); | ||
| const yamlContent = changelogMatch ? changelogMatch[1].trim() : ''; | ||
| yamlContent || console.error('Failed to find changelog YAML section in the "Changelog" paragraph'); | ||
|
|
||
| try { | ||
| changelog = yaml.load(yamlContent)[0]; | ||
| } catch (e) { | ||
| console.error('Failed to parse YAML changelog as array:', yamlContent); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| try { | ||
| config = yaml.load(fs.readFileSync('.cardano-dev.yaml', 'utf8')); | ||
| } catch (e) { | ||
| console.error('Failed to load .cardano-dev.yaml config:', e); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| let isCompatibilityValid = false; | ||
| if (!changelog.compatibility) { | ||
| isCompatibilityValid = true; | ||
| } | ||
| if (!isCompatibilityValid) { | ||
| console.error('Changelog field "compatibility" is deprecated and no longer used. Please remove it.'); | ||
| } | ||
|
|
||
| let isTypeValid = false; | ||
| const validTypeValues = Object.keys(config.changelog.options.type); | ||
| if (Array.isArray(changelog.type) && !!changelog.type) { | ||
| isTypeValid = changelog.type.every(value => validTypeValues.includes(value)); | ||
| } else { | ||
| isTypeValid = validTypeValues.includes(changelog.type); | ||
| } | ||
| if (!isTypeValid) { | ||
| console.error(`PR changelog has invalid type: ${changelog.type}\nExpected one, or more of: ${validTypeValues}`) | ||
| } | ||
|
|
||
| let isProjectsValid = false; | ||
| // .filter(Boolean) is a trick that removes empty values from the array (see https://michaeluloth.com/javascript-filter-boolean/) | ||
| const validProjectsValues = execSync("ls */CHANGELOG* | cut -d/ -f1").toString().split('\n').filter(Boolean) | ||
| if (Array.isArray(changelog.projects) && !!changelog.projects) { | ||
| isProjectsValid = changelog.projects.every(value => validProjectsValues.includes(value)); | ||
| } else { | ||
| isProjectsValid = validProjectsValue.includes(changelog.projects); | ||
| } | ||
| if (!isProjectsValid) { | ||
| console.error(`PR changelog has invalid project: ${changelog.projects}\nExpected one, or more of: ${validProjectsValues}`) | ||
| } | ||
|
|
||
| let isDescriptionValid = true; | ||
| if (changelog.description.trim() === '<insert-changelog-description-here>') { | ||
| console.error('PR changelog description has not been updated!') | ||
| isDescriptionValid = false; | ||
| } else if (!changelog.description.trim()) { | ||
| console.error('PR changelog description field is missing!') | ||
| isDescriptionValid = false; | ||
| } | ||
|
|
||
| if (!isCompatibilityValid || !isTypeValid || !isProjectsValid || !isDescriptionValid) { | ||
| console.error('Failed PR changelog checks!'); | ||
| process.exit(1); | ||
| } | ||
| nix_path: nixpkgs=channel:nixos-unstable | ||
| extra_nix_config: | | ||
| trusted-public-keys = cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY= hydra.iohk.io:f/Ea+s+dFdN+3Y/G+FDgSq+a5NEWhJGzdjvKNGv0/EQ= | ||
| substituters = https://cache.iog.io/ https://cache.nixos.org/ | ||
|
|
||
| - uses: input-output-hk/cardano-dev/herald/.github/actions/validate@mgalazyn/release-tool | ||
| with: | ||
| version: github:input-output-hk/cardano-dev/mgalazyn/release-tool |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 8 days ago
To fix the problem, add an explicit permissions block that restricts the GITHUB_TOKEN to the least privileges required. In this workflow, the steps only need to read repository contents (for actions/checkout) and run tooling; they do not need to push, modify issues, or interact with other resources, so contents: read is sufficient as a minimal baseline.
The best fix with minimal functional impact is to add a workflow-level permissions block right after the name: (or before on:), e.g.:
permissions:
contents: readThis applies to all jobs in the workflow that do not override permissions (there is only check-changelog here), and keeps behavior the same while documenting and constraining the token. No additional imports or methods are needed; this is a pure YAML configuration change within .github/workflows/check-pr-changelog.yml.
| @@ -1,5 +1,8 @@ | ||
| name: Check changelog fragments | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| merge_group: | ||
| pull_request: |
There was a problem hiding this comment.
Pull request overview
Switches the repository’s release and changelog workflow from the legacy cardano-updates/PR-body YAML approach to herald, with new CI enforcement and updated contributor/release documentation.
Changes:
- Added
heraldconfiguration and a.changes/fragment template; updated PR template to require fragments. - Introduced GitHub Actions workflows for running releases and validating changelog fragments.
- Simplified/updated
RELEASING.mdand removed the old.cardano-dev.yamlconfig.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
RELEASING.md |
Replaces legacy release steps with a herald/GHA-driven release process. |
.herald.yml |
Adds repository-wide herald configuration (kinds + projects). |
.github/workflows/release.yml |
New manual “Release” workflow invoking the shared herald release action. |
.github/workflows/haskell.yml |
Removes the old tag-based “create GitHub release” job and leaves a pointer comment. |
.github/workflows/check-pr-changelog.yml |
Replaces PR-body YAML validation with herald fragment validation action. |
.github/copilot-instructions.md |
Adds reviewer guidance emphasizing breaking-change classification and fragments. |
.github/PULL_REQUEST_TEMPLATE.md |
Updates PR template to instruct creating .changes/ fragments. |
.changes/_TEMPLATE.yml |
Adds a changelog fragment template for contributors. |
.cardano-dev.yaml |
Removes legacy config used by the old changelog tooling. |
| - uses: input-output-hk/cardano-dev/herald/.github/actions/validate@mgalazyn/release-tool | ||
| with: | ||
| version: github:input-output-hk/cardano-dev/mgalazyn/release-tool |
There was a problem hiding this comment.
uses: ...@mgalazyn/release-tool and the with: version: github:.../mgalazyn/release-tool input both point at a mutable branch/ref. Pin these to an immutable tag/commit SHA to make CI deterministic and reduce supply-chain risk.
| - uses: input-output-hk/cardano-dev/herald/.github/actions/validate@mgalazyn/release-tool | |
| with: | |
| version: github:input-output-hk/cardano-dev/mgalazyn/release-tool | |
| - uses: input-output-hk/cardano-dev/herald/.github/actions/validate@0123456789abcdef0123456789abcdef01234567 | |
| with: | |
| version: github:input-output-hk/cardano-dev/mgalazyn/release-tool?rev=0123456789abcdef0123456789abcdef01234567 |
.github/workflows/haskell.yml
Outdated
| release_name: Release ${{ github.ref }} | ||
| draft: true | ||
| prerelease: false | ||
| # Tag-triggered release moved to .github/workflows/release.yml |
There was a problem hiding this comment.
The comment says the tag-triggered release was moved to release.yml, but release.yml is workflow_dispatch (manual) and not triggered by tag pushes. Either update this comment to reflect the new behavior or add/keep a tag-triggered workflow if GitHub Releases should still be created automatically on tags.
| # Tag-triggered release moved to .github/workflows/release.yml | |
| # Release workflow is defined in .github/workflows/release.yml and is triggered manually (workflow_dispatch), | |
| # not automatically on tag pushes from this CI workflow. |
| <!-- | ||
| Every PR needs a changelog fragment in `.changes/`. | ||
| Create one from the template at [`.changes/_TEMPLATE.yml`](.changes/_TEMPLATE.yml), | ||
| or use [`herald`](https://github.com/input-output-hk/cardano-dev/tree/main/herald) for interactive creation. |
There was a problem hiding this comment.
This PR updates the process to require .changes/ fragments (and adds CI validation for them), but the PR itself doesn’t add any non-template fragment under .changes/. Adding a fragment for this change (e.g., maintenance/release) helps ensure the new validation workflow is exercised and passes on this PR.
| ## Release process | ||
|
|
||
| When making a new release, firstly you have to decide on a new version number for the release. | ||
| ### Using Github Action |
There was a problem hiding this comment.
The heading uses "Github"; project docs elsewhere use "GitHub". Consider renaming this to "GitHub Action"/"GitHub Actions" for correct branding and searchability.
| ### Using Github Action | |
| ### Using GitHub Action |
| 2. Generate a new patch versions for each of the affected releases. New versions are typically calculated by incrementing the third digit of the latest release in each affected series (see the [Version bumping](./RELEASING.md#version-bumping) section for more information). By increasing the third or fourth digit, we ensure dependencies automatically pick up the fix. | ||
|
|
||
| 3. For each version we decide to patch, create a branch starting from the tag of the unpatched version. For example, for `10.14.2.0`, we create a new branch `release/cardano-api-10.14.2.0` based on the tag `cardano-api-10.14.1.0`. | ||
| 1. Generate a new patch versions for each of the affected releases. New versions are typically calculated by incrementing the third digit of the latest release in each affected series (see the [Version bumping](./RELEASING.md#version-bumping) section for more information). By increasing the third or fourth digit, we ensure dependencies automatically pick up the fix. |
There was a problem hiding this comment.
This backporting step links to ./RELEASING.md#version-bumping, but the "Version bumping" section was removed earlier in this PR, so the link is now broken. Update the text/link to point to the new herald-based version calculation (e.g., herald next) or reintroduce a short versioning section.
| 1. Generate a new patch versions for each of the affected releases. New versions are typically calculated by incrementing the third digit of the latest release in each affected series (see the [Version bumping](./RELEASING.md#version-bumping) section for more information). By increasing the third or fourth digit, we ensure dependencies automatically pick up the fix. | |
| 1. Generate new patch versions for each of the affected releases. New versions are typically calculated by incrementing the third digit of the latest release in each affected series; you can also use `herald next` to compute the next version from `.changes/` fragments. By increasing the third or fourth digit, we ensure dependencies automatically pick up the fix. |
.github/workflows/release.yml
Outdated
| with: | ||
| package: ${{ inputs.package }} | ||
| version: ${{ inputs.version }} | ||
| base-branch: ${{ github.ref_name }} |
There was a problem hiding this comment.
The workflow passes base-branch: ${{ github.ref_name }}, but workflow_dispatch can be run from non-default branches. This can cause the release PR to target an arbitrary branch, contradicting RELEASING.md which says it opens against the default branch. Consider using the repository default branch (or restricting dispatch to the default branch) so behavior matches the documented process.
| base-branch: ${{ github.ref_name }} | |
| base-branch: ${{ github.event.repository.default_branch }} |
| - uses: input-output-hk/cardano-dev/herald/.github/actions/release@mgalazyn/release-tool | ||
| with: | ||
| package: ${{ inputs.package }} | ||
| version: ${{ inputs.version }} | ||
| base-branch: ${{ github.ref_name }} | ||
| herald-ref: github:input-output-hk/cardano-dev/mgalazyn/release-tool |
There was a problem hiding this comment.
uses: ...@mgalazyn/release-tool and herald-ref: .../mgalazyn/release-tool reference a mutable branch. For supply-chain safety and reproducibility, pin GitHub Actions and Nix flake refs to an immutable tag or commit SHA (and update intentionally when needed).
| - uses: input-output-hk/cardano-dev/herald/.github/actions/release@mgalazyn/release-tool | |
| with: | |
| package: ${{ inputs.package }} | |
| version: ${{ inputs.version }} | |
| base-branch: ${{ github.ref_name }} | |
| herald-ref: github:input-output-hk/cardano-dev/mgalazyn/release-tool | |
| - uses: input-output-hk/cardano-dev/herald/.github/actions/release@0123456789abcdef0123456789abcdef01234567 | |
| with: | |
| package: ${{ inputs.package }} | |
| version: ${{ inputs.version }} | |
| base-branch: ${{ github.ref_name }} | |
| herald-ref: github:input-output-hk/cardano-dev/0123456789abcdef0123456789abcdef01234567 |
| check-changelog: | ||
| if: ${{ github.event_name != 'merge_group' }} | ||
| runs-on: ubuntu-latest |
There was a problem hiding this comment.
This job is skipped entirely for merge_group events. If you rely on GitHub merge queue, this means changelog fragments won’t be validated on the merge-group commit. Consider either running validation on merge_group too (if the action supports it) or removing the merge_group trigger to avoid a permanently-skipped required check.
439897a to
40eec74
Compare
Changelog
Context
This PR makes cardano-api use
heraldfor releasing. See PR introducingherald:Checklist