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
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,11 @@
- [Update package.json](https://github.com/cjbarth/github-release-notes/commit/f2fea79abb3300381744faed0d11ef539ddf676c) - @cjbarth
- [Add release-it](https://github.com/cjbarth/github-release-notes/commit/5f4b37dcf1c3bb7a02f5a69b29f989cae803757c) - @cjbarth
- [Fix tests](https://github.com/cjbarth/github-release-notes/commit/ecceb7ca1d1e80a5ba88b4fbf9863dd673b05bde) - @cjbarth
- [Track PRs, commits by branch, not date](https://github.com/cjbarth/github-release-notes/commit/acef232efa2f0e66bf5bdd8f28310584fc3b1e7f) - @cjbarth
- [Fix tests](https://github.com/cjbarth/github-release-notes/commit/718b9aea68980bcdb49a3436414de58ae9832230) - @cjbarth
- [Correctly compare dates for PR retrieval; fix tests](https://github.com/cjbarth/github-release-notes/commit/0b306da3c19adeef4781a3042488f9b53462fe3a) - @cjbarth
- [Track PRs, commits by branch, not date](https://github.com/cjbarth/github-release-notes/commit/acef232efa2f0e66bf5bdd8f28310584fc3b1e7f) - @cjbarth
- [Use commit date as tag date](https://github.com/cjbarth/github-release-notes/commit/ed9fc746a3e7256c8cadb02571e606d0645cb7d9) - @cjbarth
- [Correctly compare dates for PR retrieval](https://github.com/cjbarth/github-release-notes/commit/e53f9e7f6aff4b32dc3f7e6ccdca1f9d767eaf1a) - @cjbarth
- [Correctly compare dates for PR retrieval; fix tests](https://github.com/cjbarth/github-release-notes/commit/0b306da3c19adeef4781a3042488f9b53462fe3a) - @cjbarth
- [Update supported NodeJS versions to current (#291)](https://github.com/cjbarth/github-release-notes/commit/ff0ddae3938db3cfcca5ef317d74eee034c32cc5) - @cjbarth
- [docs: add viatrix as a contributor (#297)](https://github.com/cjbarth/github-release-notes/commit/8beb6f013cdfe410a0c20cd48291efe4c92a8ace) - @allcontributors[bot]
- [Return exit code 1 on error for gren changelog (#294)](https://github.com/cjbarth/github-release-notes/commit/69b77665dddb1135a81ce856a7c8edb1003dbc45) - @viatrix
Expand Down
84 changes: 46 additions & 38 deletions lib/src/Gren.js
Original file line number Diff line number Diff line change
Expand Up @@ -1288,63 +1288,71 @@ class Gren {
}));
}

commits = commits.filter((commit) => branchCommitShas.includes(commit.sha));
commits = this._sortCommitsByParent(commits);
releaseRange.push(commits);
const filteredCommits = commits.filter((commit) => branchCommitShas.includes(commit.sha));
const sortedCommits = this._sortCommitsByParent(filteredCommits);
releaseRange.push(sortedCommits);
}
loadedCommits("Commits acquired");

return dataSource[this.options.dataSource](releaseRanges);
}

_sortCommitsByParent(commits, dateOrder = "desc") {
// 1) Map SHAs -> commit object for O(1) lookups
// 1) Map sha -> commit
const commitMap = new Map(commits.map((c) => [c.sha, c]));

// 2) Build parent -> [children] adjacency
const childrenMap = new Map();
for (const commit of commits) {
// find the first parent in our set (if any)
const parentSha = (commit.parents || []).map((p) => p.sha).find((sha) => commitMap.has(sha));
if (parentSha) {
if (!childrenMap.has(parentSha)) childrenMap.set(parentSha, []);
childrenMap.get(parentSha).push(commit);
// 2) Compute parents for each commit
const parentMap = new Map();
for (const c of commits) {
const parentList = (c.parents || []).map((p) => p.sha).filter((sha) => commitMap.has(sha));
parentMap.set(c.sha, parentList);
}

// 3) Compute which SHAs appear as a parent -> those that have children
const hasChild = new Set();
for (const parents of parentMap.values()) {
for (const p of parents) {
hasChild.add(p);
}
}

// 3) Identify "roots": commits whose first parent is not in our list
const roots = commits.filter(
(c) => !(c.parents || []).map((p) => p.sha).some((sha) => commitMap.has(sha)),
);
// 4) Heads = commits that never appear as anyone's parent
const heads = commits.filter((c) => !hasChild.has(c.sha)).map((c) => c.sha);

// 4) Date-based comparator
const cmpDate = (a, b) => {
const da = new Date(a.committer.date);
const db = new Date(b.committer.date);
return dateOrder === "asc" ? da - db : db - da;
// 5) A helper to compare by newest date
const compareDateDesc = (shaA, shaB) => {
const da = new Date(
commitMap.get(shaA).commit.committer.date || commitMap.get(shaA).commit.author.date,
);
const db = new Date(
commitMap.get(shaB).commit.committer.date || commitMap.get(shaB).commit.author.date,
);
return db - da;
};

// 5) Sort roots by date
roots.sort(cmpDate);

// 6) DFS-like traversal to produce the final list
// 6) Candidate pool & result
const result = [];
const visit = (commit) => {
result.push(commit);
const kids = childrenMap.get(commit.sha) || [];
// within the same parent, sort by date too
kids.sort(cmpDate);
for (const child of kids) {
visit(child);
}
};
const seen = new Set();
const pool = [...heads];

while (pool.length) {
// pick the newest SHA
pool.sort((a, b) => compareDateDesc(a, b));
const sha = pool.shift();

for (const root of roots) {
visit(root);
if (seen.has(sha)) continue;
seen.add(sha);

// emit that commit
result.push(commitMap.get(sha));

// add its parents to the pool
for (const p of parentMap.get(sha) || []) {
if (!seen.has(p)) pool.push(p);
}
}

// This was done parent first, we want the child at the top
return result.reverse();
return result;
}

_transformTagsIntoReleaseObjects(tags) {
Expand Down
Loading