Skip to content

Commit

Permalink
Add release-notes output (#28)
Browse files Browse the repository at this point in the history
Closes: #27.
  • Loading branch information
nbusseneau authored Jul 20, 2024
1 parent 77ac767 commit 0d79fe3
Show file tree
Hide file tree
Showing 15 changed files with 189 additions and 63 deletions.
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Use LF as default EOL marker
* text=auto eol=lf
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'
13 changes: 10 additions & 3 deletions dist/index.js

Large diffs are not rendered by default.

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
60 changes: 1 addition & 59 deletions src/updateChangelog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,65 +3,7 @@ import markdown from "remark-parse";
import stringify from "remark-stringify";
import { VFile } from "vfile";
import { Node, Position } from "unist";

type MarkdownRootNode = {
type: "root";
children: MarkdownNode[];
};

interface HeadingNode {
type: "heading";
depth: number;
children: MarkdownNode[];
position: Position;
}

interface DefinitionNode {
type: "definition";
identifier: string;
label: string;
url: string;
position?: Position;
}

interface ListNode {
type: "list";
ordered: boolean;
start: any;
spread: boolean;
url: string;
children: object[];
position: Position;
}

interface ParagraphNode {
type: "paragraph";
children: object[];
position: Position;
}

interface LinkReferenceNode {
type: "linkReference";
identifier: string;
label: string;
referenceType: string;
children: TextNode[];
position?: Position;
}

interface TextNode {
type: "text";
value: string;
position?: Position;
}

type MarkdownNode =
| HeadingNode
| DefinitionNode
| ListNode
| ParagraphNode
| LinkReferenceNode
| TextNode;
import { MarkdownRootNode, HeadingNode, DefinitionNode, LinkReferenceNode, TextNode } from "markdown-nodes";

interface Options {
tag: string;
Expand Down
62 changes: 62 additions & 0 deletions types/markdown-nodes/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
declare module "markdown-nodes" {
import { Position } from "unist";

type MarkdownRootNode = {
type: "root";
children: MarkdownNode[];
};

interface HeadingNode {
type: "heading";
depth: number;
children: MarkdownNode[];
position: Position;
}

interface DefinitionNode {
type: "definition";
identifier: string;
label: string;
url: string;
position?: Position;
}

interface ListNode {
type: "list";
ordered: boolean;
start: any;
spread: boolean;
url: string;
children: object[];
position: Position;
}

interface ParagraphNode {
type: "paragraph";
children: object[];
position: Position;
}

interface LinkReferenceNode {
type: "linkReference";
identifier: string;
label: string;
referenceType: string;
children: TextNode[];
position?: Position;
}

interface TextNode {
type: "text";
value: string;
position?: Position;
}

type MarkdownNode =
| HeadingNode
| DefinitionNode
| ListNode
| ParagraphNode
| LinkReferenceNode
| TextNode;
}

0 comments on commit 0d79fe3

Please sign in to comment.