-
-
Notifications
You must be signed in to change notification settings - Fork 158
/
releases.js
118 lines (109 loc) · 3.3 KB
/
releases.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import semver from 'semver'
import { niceDate } from './utils'
const MERGE_COMMIT_PATTERN = /^Merge (remote-tracking )?branch '.+'/
const COMMIT_MESSAGE_PATTERN = /\n+([\S\s]+)/
export function parseReleases (commits, remote, latestVersion, options) {
let release = newRelease(latestVersion)
const releases = []
for (let commit of commits) {
if (commit.tag) {
if (release.tag || options.unreleased) {
releases.push({
...release,
href: getCompareLink(
`${options.tagPrefix}${commit.tag}`,
release.tag ? `${options.tagPrefix}${release.tag}` : 'HEAD',
remote
),
commits: sliceCommits(release.commits.sort(sortCommits), options, release),
major: !options.tagPattern && commit.tag && release.tag && semver.diff(commit.tag, release.tag) === 'major'
})
}
const summary = getSummary(commit.message, options.releaseSummary)
release = newRelease(commit.tag, commit.date, summary)
}
if (commit.merge) {
release.merges.push(commit.merge)
} else if (commit.fixes) {
release.fixes.push({
fixes: commit.fixes,
commit
})
} else if (filterCommit(commit, release, options.commitLimit)) {
release.commits.push(commit)
}
}
releases.push(release)
return releases
}
export function sortReleases (a, b) {
if (a.tag && b.tag) return semver.rcompare(a.tag, b.tag)
if (a.tag) return 1
if (b.tag) return -1
return 0
}
function newRelease (tag = null, date = new Date().toISOString(), summary = null) {
return {
commits: [],
fixes: [],
merges: [],
tag,
date,
summary,
title: tag || 'Unreleased',
niceDate: niceDate(date),
isoDate: date.slice(0, 10)
}
}
function filterCommit (commit, release, limit) {
if (commit.breaking) {
return true
}
if (semver.valid(commit.subject)) {
// Filter out version commits
return false
}
if (MERGE_COMMIT_PATTERN.test(commit.subject)) {
// Filter out merge commits
return false
}
if (release.merges.findIndex(m => m.message === commit.subject) !== -1) {
// Filter out commits with the same message as an existing merge
return false
}
return true
}
function getCompareLink (from, to, remote) {
if (!remote) {
return null
}
if (/bitbucket/.test(remote.hostname)) {
return `${remote.url}/compare/${to}..${from}`
}
if (/dev\.azure/.test(remote.hostname) || /visualstudio/.test(remote.hostname)) {
return `${remote.url}/branches?baseVersion=GT${to}&targetVersion=GT${from}&_a=commits`
}
return `${remote.url}/compare/${from}...${to}`
}
function getSummary (message, releaseSummary) {
if (!message || !releaseSummary) {
return null
}
if (COMMIT_MESSAGE_PATTERN.test(message)) {
return message.match(COMMIT_MESSAGE_PATTERN)[1]
}
return null
}
function sortCommits (a, b) {
if (!a.breaking && b.breaking) return -1
if (a.breaking && !b.breaking) return 1
return (b.insertions + b.deletions) - (a.insertions + a.deletions)
}
function sliceCommits (commits, options, release) {
if (options.commitLimit === false) {
return commits
}
const emptyRelease = release.fixes.length === 0 && release.merges.length === 0
const limit = emptyRelease ? options.backfillLimit : options.commitLimit
return commits.slice(0, limit)
}