Skip to content
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
18 changes: 17 additions & 1 deletion lib/src/Gren.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ const TAGS_LIMIT = 30;
// The data sources whose releases are built from the commits each release contains.
const MEMBERSHIP_DATA_SOURCES = ["prs", "prs-with-issues"];

// Where a release section starts. The preamble a changelog opens with ends here, and a
// changelog written without a separator is split here; the two have to agree on the answer.
const RELEASE_HEADING = "#{1,6} +v?\\d+\\.\\d+\\.\\d+";
const PREAMBLE_END = new RegExp(`^${RELEASE_HEADING}`, "m");
const SECTION_SPLIT = new RegExp(`(?<=\\n)(?=${RELEASE_HEADING})`);

/**
* Get the semver version a tag or release name stands for
*
Expand Down Expand Up @@ -350,12 +356,22 @@ class Gren {
content = content.slice(changelogTitle.length);
}

// The title in the file is not always the one in the configuration: a banner is added to
// it, or its wording changes. Whatever stands before the first release is title too, and
// leaving it in makes the preamble's first line the heading of the release under it, which
// drops that release from the file this run is about to write over it.
const firstRelease = content.search(PREAMBLE_END);

if (firstRelease > 0) {
content = content.slice(firstRelease);
}

let current = null;
// A changelog written with nothing between its releases can only be split on the headings,
// at the start of each one so that the release before it keeps its last line.
const chunks = releaseSeparator
? content.split(releaseSeparator)
: content.split(/(?<=\n)(?=#{1,6} +v?\d+\.\d+\.\d+)/);
: content.split(SECTION_SPLIT);

chunks.forEach((chunk) => {
const heading = chunk.trimStart().split("\n")[0];
Expand Down
36 changes: 36 additions & 0 deletions test/Gren.membership.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,42 @@ describe("Gren release membership", () => {
});
});

it("Should read the first release under a title the configuration does not spell", () => {
// A banner, or any title edited since the file was written, is still title. Keying the
// first section off the configured changelogTitle alone leaves the leftover preamble
// attached to the release under it, and that release is then dropped from the file the
// next run writes.
fs.writeFileSync(
path.join(repo.dir, "CHANGELOG.md"),
"# Changelog\n\n> Sponsor this project.\n\n" + Object.values(sections).join(separator),
);

const gren = createGren({ frozenBefore: "2020-01-16", changelogFilename: "CHANGELOG.md" });
const read = gren._readChangelogSections();

assert.equal(read.get("2.0.0"), sections["2.0.0"]);
assert.equal(read.get("1.2.0"), sections["1.2.0"]);
});

it("Should read the first release under an unknown title without a separator", () => {
const plain = { "2.0.0": sections["2.0.0"], "1.2.0": sections["1.2.0"] };

fs.writeFileSync(
path.join(repo.dir, "CHANGELOG.md"),
"Release history\n===============\n\n" + Object.values(plain).join(""),
);

const gren = createGren({
frozenBefore: "2020-01-16",
changelogFilename: "CHANGELOG.md",
template: { releaseSeparator: "" },
});
const read = gren._readChangelogSections();

assert.equal(read.get("2.0.0"), plain["2.0.0"]);
assert.equal(read.get("1.2.0"), plain["1.2.0"]);
});

it("Should read a changelog with nothing between its releases", async () => {
const plain = { "2.0.0": sections["2.0.0"], "1.2.0": sections["1.2.0"] };

Expand Down
Loading