-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
129 lines (115 loc) · 3.69 KB
/
index.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
119
120
121
122
123
124
125
126
127
128
129
'use strict'
const path = require('path')
const semver = require('semver')
const { parser } = require('@conventional-commits/parser')
const visit = require('unist-util-visit-parents')
const git = require('./lib/git')
const UNKNOWN_TYPE = Symbol('UNKNOWN_TYPE')
/**
* @TODO There are many features and improvements I think
* we can add. Here are a few:
*
* - options for tab parsing to support lerna style tags
* - footer conventional commits
* - revert commit handling
* - suggest pre-release version when not on main/master
* - add option for existingVersions to check against
*/
module.exports = async function gitRecommendedBump (opts = {}) {
const cwd = path.resolve(opts.path || process.cwd())
const gitRoot = opts.gitRoot || await git.root(cwd)
// const primaryBranch = opts.primaryBranch || 'main'
const commitFilter = typeof opts.commitFilter === 'function' ? opts.commitFilter : () => true
const revertCommit = typeof opts.revertCommit === 'function' ? opts.revertCommit : () => false
const tagPrefix = 'v'
const currentVersion = opts.currentVersion || null
const parse = opts.parse || parser
const types = Object.entries(opts.types || {
fix: 'patch',
feat: 'minor'
}).reduce((t, [key, bump]) => {
if (bump !== 'patch' && bump !== 'minor') {
throw new TypeError('types.bump must be either patch or minor')
}
t[key] = { bump, commits: new Set() }
return t
}, {
[UNKNOWN_TYPE]: {
bump: 'patch',
commits: new Set()
}
})
const commits = []
let minors = 0
let majors = 0
// eslint-disable-next-line no-labels
gitLogLoop:
for await (const commit of git.paginatedLog({ cwd: gitRoot, subpath: cwd })) {
if (!commitFilter(commit)) {
// @TODO
continue
}
const revert = revertCommit(commit)
if (revert) {
// @TODO
continue
}
// Check tags, if we have a version tag, optionally back to
// currentVersion, then we can stop reading git log
for (let tag of commit.tags) {
if (tagPrefix) {
tag = tag.replace(tagPrefix, '')
}
if (!tag || !semver.valid(tag)) {
continue
}
if (!currentVersion || tag === currentVersion) {
// eslint-disable-next-line no-labels
break gitLogLoop
}
}
// Parse as conventional commit
try {
const parsedBody = parse(commit.message)
if (parsedBody) {
visit(parsedBody, ['summary', 'type', 'scope', 'text', 'breaking-change'], (node, ancestors) => {
switch (node.type) {
case 'summary':
// eslint-disable-next-line no-return-assign
commit.summary = node.children.reduce((s, n) => s += n.value, '')
break
case 'type':
commit.type = node.value
if (types[node.value]) {
types[node.value].commits.add(commit.hash)
if (types[node.value].bump === 'minor') {
minors++
}
} else {
types[UNKNOWN_TYPE].commits.add(commit.hash)
}
break
case 'scope':
commit.scope = node.value
break
case 'breaking-change':
commit.breakingChange = true
majors++
break
}
})
commit.parsedBody = parsedBody
}
} catch (e) {
types[UNKNOWN_TYPE].commits.add(commit.hash)
}
// @TODO parse nested commits
// https://github.com/googleapis/release-please/blob/master/src/util/to-conventional-changelog-format.ts#L204
commits.push(commit)
}
const releaseType = majors ? 'major' : minors ? 'minor' : 'patch'
return {
releaseType,
commits
}
}