Skip to content

Switch to herald for releasing#1164

Open
carbolymer wants to merge 1 commit intomasterfrom
mgalazyn/chore/use-herald-for-changelogs
Open

Switch to herald for releasing#1164
carbolymer wants to merge 1 commit intomasterfrom
mgalazyn/chore/use-herald-for-changelogs

Conversation

@carbolymer
Copy link
Copy Markdown
Contributor

@carbolymer carbolymer commented Mar 27, 2026

Changelog

- description: |
    Switch to `herald` for releasing.
# uncomment types applicable to the change:
  type:
  # - feature        # introduces a new feature
  # - breaking       # the API has changed in a breaking way
  # - compatible     # the API has changed but is non-breaking
  # - optimisation   # measurable performance improvements
  # - refactoring    # QoL changes
  # - bugfix         # fixes a defect
  # - test           # fixes/modifies tests
  # - maintenance    # not directly related to the code
  # - release        # related to a new release preparation
  # - documentation  # change in code docs, haddocks...
# uncomment at least one main project this PR is associated with
  projects:
   - cardano-api
   - cardano-api-gen
   - cardano-rpc
   - cardano-wasm

Context

This PR makes cardano-api use herald for releasing. See PR introducing herald:

Checklist

  • Commit sequence broadly makes sense and commits have useful messages
  • New tests are added if needed and existing tests are updated. See Running tests for more details
  • Self-reviewed the diff

Comment on lines +10 to +26
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

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {contents: read}

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: read

This 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.

Suggested changeset 1
.github/workflows/check-pr-changelog.yml

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/.github/workflows/check-pr-changelog.yml b/.github/workflows/check-pr-changelog.yml
--- a/.github/workflows/check-pr-changelog.yml
+++ b/.github/workflows/check-pr-changelog.yml
@@ -1,5 +1,8 @@
 name: Check changelog fragments
 
+permissions:
+  contents: read
+
 on:
   merge_group:
   pull_request:
EOF
@@ -1,5 +1,8 @@
name: Check changelog fragments

permissions:
contents: read

on:
merge_group:
pull_request:
Copilot is powered by AI and may make mistakes. Always verify output.
@carbolymer carbolymer self-assigned this Mar 27, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 herald configuration 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.md and removed the old .cardano-dev.yaml config.

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.

Comment on lines +24 to +26
- uses: input-output-hk/cardano-dev/herald/.github/actions/validate@mgalazyn/release-tool
with:
version: github:input-output-hk/cardano-dev/mgalazyn/release-tool
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
- 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

Copilot uses AI. Check for mistakes.
release_name: Release ${{ github.ref }}
draft: true
prerelease: false
# Tag-triggered release moved to .github/workflows/release.yml
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
# 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.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +4
<!--
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.
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
## Release process

When making a new release, firstly you have to decide on a new version number for the release.
### Using Github Action
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The heading uses "Github"; project docs elsewhere use "GitHub". Consider renaming this to "GitHub Action"/"GitHub Actions" for correct branding and searchability.

Suggested change
### Using Github Action
### Using GitHub Action

Copilot uses AI. Check for mistakes.
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.
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
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.

Copilot uses AI. Check for mistakes.
with:
package: ${{ inputs.package }}
version: ${{ inputs.version }}
base-branch: ${{ github.ref_name }}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
base-branch: ${{ github.ref_name }}
base-branch: ${{ github.event.repository.default_branch }}

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +44
- 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
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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).

Suggested change
- 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

Copilot uses AI. Check for mistakes.
Comment on lines 9 to 11
check-changelog:
if: ${{ github.event_name != 'merge_group' }}
runs-on: ubuntu-latest
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants