Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add release-notes output #28

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
Loading