Skip to content

Commit

Permalink
add release-notes output
Browse files Browse the repository at this point in the history
Add a new `release-notes` output to the action containing the release
notes for the newly released versions, allowing consumers to leverage it
in their workflows (e.g. by passing it down to the GitHub Release API).
  • Loading branch information
nbusseneau committed Jul 2, 2024
1 parent 64c61ea commit 92915a2
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add a new `release-notes` output to the action containing the release notes for the newly released versions.

## [3.0.0] - 2024-04-08

### Fixed
Expand Down
Empty file.
3 changes: 3 additions & 0 deletions __tests__/fixtures/first_release/release-notes.expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Added

- Everything since the beginning!
Empty file.
3 changes: 3 additions & 0 deletions __tests__/fixtures/standard/release-notes.expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Changed

- Our main theme is now blue instead of red.
3 changes: 3 additions & 0 deletions __tests__/fixtures/tag_on_tag/release-notes.expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Changed

- Our main theme is now blue instead of red.
3 changes: 3 additions & 0 deletions __tests__/fixtures/tag_release/release-notes.expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Changed

- Our main theme is now blue instead of red.
35 changes: 35 additions & 0 deletions __tests__/getReleaseNotes.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import getReleaseNotes from "../src/getReleaseNotes";
import { read } from "to-vfile";

interface Fixture {
tag: string;
version: string;
date: string;
genesisHash: string;
owner: string;
repo: string;
}

it.each(["empty_release", "standard", "first_release", "lowercase_link_reference", "tag_release", "tag_on_tag"])(
`should extract %s release-notes output`,
async function(testcase) {
const expectedChangelog = await read(
`./__tests__/fixtures/${testcase}/CHANGELOG.expected.md`,
{
encoding: "utf-8"
}
);
const release: Fixture = await import(
`./fixtures/${testcase}/fixture`
).then(module => module.default);

const expectedReleaseNotes = await read(
`./__tests__/fixtures/${testcase}/release-notes.expected.md`,
{
encoding: "utf-8"
}
).then(expected => expected.toString("utf-8"));
const actualReleaseNotes = getReleaseNotes(expectedChangelog, release.version);
expect(actualReleaseNotes).toEqual(expectedReleaseNotes);
}
);
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ inputs:
changelogPath:
description: 'The path to the changelog file. Defaults to `./CHANGELOG.md`'
required: false
outputs:
release-notes:
description: 'The release notes of the newly released version'
runs:
using: 'node20'
main: 'dist/index.js'
55 changes: 55 additions & 0 deletions src/getReleaseNotes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import unified, { Transformer } from "unified";
import markdown from "remark-parse";
import stringify from "remark-stringify";
import { VFile } from "vfile";
import { Node } from "unist";
import { MarkdownRootNode } from "markdown-nodes";

function releaseNotesExtraction(version: string) {
return transformer as unknown as Transformer;

function transformer(tree: MarkdownRootNode, _file: VFile) {
const children = tree.children;

const firstNodeIndex = children.findIndex(
node => node.type === "heading" && node.depth === 2 &&
node.children.length > 1 && node.children[0].type === "linkReference" &&
node.children[0].identifier === version
) + 1;
const firstNode = children.slice(firstNodeIndex);

let lastNodeIndex = firstNode.findIndex(
node => node.type === "heading" && node.depth === 2
);
// special case: release notes for first release will not end with another
// section, instead they end with the compare URLs
if (lastNodeIndex === -1) {
lastNodeIndex = firstNode.findIndex(
node => node.type === "definition" && node.identifier === "unreleased"
);
}

const releaseNotesNodes = firstNode.slice(0, lastNodeIndex);
tree.children = releaseNotesNodes;
return tree as Node;
}
}

export default function getReleaseNotes(
file: VFile,
version: string
): string {
// @ts-ignore
return unified()
.use(markdown)
.use(releaseNotesExtraction, version)
.data("settings", {
listItemIndent: "1",
tightDefinitions: true,
bullet: "-"
})
.use(stringify)
.processSync(file)
.toString("utf-8")
.trim();
}
6 changes: 5 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { setFailed } from "@actions/core";
import { setOutput } from "@actions/core/lib/core";
import { read, write } from "to-vfile";
import updateChangelog from "./updateChangelog";
import getInputs from "./getInputs";
import getGenesisHash from "./getGenesisHash";
import getReleaseNotes from "./getReleaseNotes";

async function run(): Promise<void> {
try {
Expand All @@ -20,8 +22,10 @@ async function run(): Promise<void> {
owner,
repo
);

await write(newChangelog, { encoding: "utf-8" });

const releaseNotes = getReleaseNotes(newChangelog, version);
setOutput("release-notes", releaseNotes);
} catch (error) {
setFailed(error.message);
}
Expand Down

0 comments on commit 92915a2

Please sign in to comment.