zx-bulk-release 2.2.0 → 2.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/src/main/js/analyze.js +1 -1
- package/src/main/js/changelog.js +1 -1
- package/src/main/js/{publish.js → gh.js} +7 -21
- package/src/main/js/{repo.js → git.js} +11 -2
- package/src/main/js/log.js +63 -3
- package/src/main/js/meta.js +2 -3
- package/src/main/js/processor.js +63 -89
- package/src/main/js/build.js +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## [2.2.2](https://github.com/semrel-extra/zx-bulk-release/compare/v2.2.1...v2.2.2) (2023-03-24)
|
|
2
|
+
|
|
3
|
+
### Fixes & improvements
|
|
4
|
+
* fix: fix gitPush retry ([268da72](https://github.com/semrel-extra/zx-bulk-release/commit/268da727036b0d3bf20b1ef10053440c5f56dad0))
|
|
5
|
+
|
|
6
|
+
## [2.2.1](https://github.com/semrel-extra/zx-bulk-release/compare/v2.2.0...v2.2.1) (2023-03-23)
|
|
7
|
+
|
|
8
|
+
### Fixes & improvements
|
|
9
|
+
* perf: make parallel internal `publish` tasks ([87f388e](https://github.com/semrel-extra/zx-bulk-release/commit/87f388ea2ff5cce96cca600903d80260f13f0908))
|
|
10
|
+
* refactor: improve internal reporter ([cc62df7](https://github.com/semrel-extra/zx-bulk-release/commit/cc62df762c0581db159ddd2fae8d90b085911884))
|
|
11
|
+
|
|
1
12
|
## [2.2.0](https://github.com/semrel-extra/zx-bulk-release/compare/v2.1.6...v2.2.0) (2023-03-23)
|
|
2
13
|
|
|
3
14
|
### Fixes & improvements
|
package/package.json
CHANGED
package/src/main/js/analyze.js
CHANGED
|
@@ -2,7 +2,7 @@ import {semver} from 'zx-extra'
|
|
|
2
2
|
import {updateDeps} from './deps.js'
|
|
3
3
|
import {formatTag} from './meta.js';
|
|
4
4
|
import {log} from './log.js'
|
|
5
|
-
import {getCommits} from './
|
|
5
|
+
import {getCommits} from './git.js'
|
|
6
6
|
|
|
7
7
|
export const analyze = async (pkg, packages) => {
|
|
8
8
|
const semanticChanges = await getSemanticChanges(pkg.absPath, pkg.latest.tag?.ref)
|
package/src/main/js/changelog.js
CHANGED
|
@@ -1,23 +1,9 @@
|
|
|
1
|
-
import {fs, path, $} from 'zx-extra'
|
|
2
|
-
import {formatTag, pushTag} from './meta.js'
|
|
3
|
-
import {pushCommit, getRepo} from './repo.js'
|
|
4
|
-
import {npmPublish} from './npm.js'
|
|
5
|
-
import {pushChangelog, formatReleaseNotes} from './changelog.js'
|
|
6
|
-
import {msgJoin} from './util.js'
|
|
7
|
-
import {runCmd} from './processor.js'
|
|
8
1
|
import {log} from './log.js'
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
await pushMeta(pkg)
|
|
15
|
-
await pushChangelog(pkg)
|
|
16
|
-
await npmPublish(pkg)
|
|
17
|
-
await ghRelease(pkg)
|
|
18
|
-
await ghPages(pkg)
|
|
19
|
-
await run(pkg, 'publishCmd')
|
|
20
|
-
}
|
|
2
|
+
import {getRepo, pushCommit} from './git.js'
|
|
3
|
+
import {formatTag} from './meta.js'
|
|
4
|
+
import {formatReleaseNotes} from './changelog.js'
|
|
5
|
+
import {$, path} from 'zx-extra'
|
|
6
|
+
import {msgJoin} from './util.js'
|
|
21
7
|
|
|
22
8
|
export const ghRelease = async (pkg) => {
|
|
23
9
|
log({pkg})(`create gh release`)
|
|
@@ -35,10 +21,10 @@ export const ghRelease = async (pkg) => {
|
|
|
35
21
|
body: releaseNotes
|
|
36
22
|
})
|
|
37
23
|
|
|
38
|
-
await $.o({cwd})`curl -H
|
|
24
|
+
await $.o({cwd})`curl -H 'Authorization: token ${ghToken}' -H 'Accept: application/vnd.github.v3+json' https://api.github.com/repos/${repoName}/releases -d ${releaseData}`
|
|
39
25
|
}
|
|
40
26
|
|
|
41
|
-
const ghPages = async (pkg) => {
|
|
27
|
+
export const ghPages = async (pkg) => {
|
|
42
28
|
const {config: {ghPages: opts, gitCommitterEmail, gitCommitterName, ghBasicAuth: basicAuth}} = pkg
|
|
43
29
|
if (!opts) return
|
|
44
30
|
|
|
@@ -30,7 +30,6 @@ export const pushCommit = async ({cwd, from, to, branch, origin, msg, ignoreFile
|
|
|
30
30
|
|
|
31
31
|
while (retries > 0) {
|
|
32
32
|
try {
|
|
33
|
-
|
|
34
33
|
_cwd = await fetchRepo({cwd, branch, origin, basicAuth})
|
|
35
34
|
|
|
36
35
|
for (let {relpath, contents} of files) {
|
|
@@ -54,8 +53,12 @@ export const pushCommit = async ({cwd, from, to, branch, origin, msg, ignoreFile
|
|
|
54
53
|
return await $.raw`git push origin HEAD:refs/heads/${branch}`
|
|
55
54
|
} catch (e) {
|
|
56
55
|
retries -= 1
|
|
56
|
+
log({level: 'error'})('git push failed', 'branch', branch, 'retries left', retries, e)
|
|
57
57
|
branches[keyByValue(branches, _cwd)] = null
|
|
58
|
-
|
|
58
|
+
|
|
59
|
+
if (retries === 0) {
|
|
60
|
+
throw e
|
|
61
|
+
}
|
|
59
62
|
}
|
|
60
63
|
}
|
|
61
64
|
})
|
|
@@ -65,6 +68,7 @@ export const getRepo = async (_cwd, {basicAuth} = {}) => {
|
|
|
65
68
|
const cwd = await getRoot(_cwd)
|
|
66
69
|
if (repos[cwd]) return repos[cwd]
|
|
67
70
|
|
|
71
|
+
console.log('!!! has basic auth', !!basicAuth)
|
|
68
72
|
const originUrl = await getOrigin(cwd)
|
|
69
73
|
const [, , repoHost, repoName] = originUrl.replace(':', '/').replace(/\.git/, '').match(/.+(@|\/\/)([^/]+)\/(.+)$/) || []
|
|
70
74
|
const repoPublicUrl = `https://${repoHost}/${repoName}`
|
|
@@ -109,3 +113,8 @@ export const getCommits = async (cwd, from, to = 'HEAD') => ctx(async ($) => {
|
|
|
109
113
|
return {subj, body, short, hash}
|
|
110
114
|
})
|
|
111
115
|
})
|
|
116
|
+
|
|
117
|
+
export const getTags = async (cwd, ref = '') =>
|
|
118
|
+
(await $.o({cwd})`git tag -l ${ref}`)
|
|
119
|
+
.toString()
|
|
120
|
+
.split('\n')
|
package/src/main/js/log.js
CHANGED
|
@@ -1,9 +1,69 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {$, fs} from 'zx-extra'
|
|
2
|
+
import {get, set, tpl} from './util.js'
|
|
2
3
|
|
|
3
4
|
export const log = (ctx) => {
|
|
4
|
-
if ($.
|
|
5
|
-
return $.
|
|
5
|
+
if ($.report) {
|
|
6
|
+
return $.report.log(ctx)
|
|
6
7
|
}
|
|
7
8
|
|
|
8
9
|
return console.log
|
|
9
10
|
}
|
|
11
|
+
|
|
12
|
+
export const createReport = ({logger = console, file = null} = {}) => ({
|
|
13
|
+
logger,
|
|
14
|
+
file,
|
|
15
|
+
status: 'initial',
|
|
16
|
+
queue: [],
|
|
17
|
+
packages: {},
|
|
18
|
+
events: [],
|
|
19
|
+
setPackages(packages) {
|
|
20
|
+
this.packages = Object.entries(packages).reduce((acc, [name, {manifest: {version}, absPath, relPath}]) => {
|
|
21
|
+
acc[name] = {
|
|
22
|
+
status: 'initial',
|
|
23
|
+
name,
|
|
24
|
+
version,
|
|
25
|
+
path: absPath,
|
|
26
|
+
relPath
|
|
27
|
+
}
|
|
28
|
+
return acc
|
|
29
|
+
}, {})
|
|
30
|
+
return this
|
|
31
|
+
},
|
|
32
|
+
get(key, pkgName) {
|
|
33
|
+
return get(
|
|
34
|
+
pkgName ? this.packages[pkgName] : this,
|
|
35
|
+
key
|
|
36
|
+
)
|
|
37
|
+
},
|
|
38
|
+
set(key, value, pkgName) {
|
|
39
|
+
set(
|
|
40
|
+
pkgName ? this.packages[pkgName] : this,
|
|
41
|
+
key,
|
|
42
|
+
value
|
|
43
|
+
)
|
|
44
|
+
return this
|
|
45
|
+
},
|
|
46
|
+
setStatus(status, name) {
|
|
47
|
+
this.set('status', status, name)
|
|
48
|
+
this.save()
|
|
49
|
+
return this
|
|
50
|
+
},
|
|
51
|
+
getStatus(status, name) {
|
|
52
|
+
return this.get('status', name)
|
|
53
|
+
},
|
|
54
|
+
log(ctx = {}) {
|
|
55
|
+
return function (...chunks) {
|
|
56
|
+
const {pkg, scope = pkg?.name || $.scope || '~', level = 'info'} = ctx
|
|
57
|
+
const msg = chunks.map(c => typeof c === 'string' ? tpl(c, ctx) : c)
|
|
58
|
+
const event = {msg, scope, date: Date.now(), level}
|
|
59
|
+
this.events.push(event)
|
|
60
|
+
logger[level](`[${scope}]`, ...msg)
|
|
61
|
+
|
|
62
|
+
return this
|
|
63
|
+
}.bind(this)
|
|
64
|
+
},
|
|
65
|
+
save() {
|
|
66
|
+
this.file && fs.outputJsonSync(this.file, this)
|
|
67
|
+
return this
|
|
68
|
+
}
|
|
69
|
+
})
|
package/src/main/js/meta.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import {ctx, semver, $, fs, path} from 'zx-extra'
|
|
4
4
|
import {Buffer} from 'buffer'
|
|
5
5
|
import {log} from './log.js'
|
|
6
|
-
import {fetchRepo, pushCommit} from './
|
|
6
|
+
import {fetchRepo, pushCommit, getTags as getGitTags} from './git.js'
|
|
7
7
|
import {fetchManifest} from './npm.js'
|
|
8
8
|
|
|
9
9
|
export const pushTag = (pkg) => ctx(async ($) => {
|
|
@@ -138,8 +138,7 @@ export const parseTag = (tag) => f0.parse(tag) || f1.parse(tag) || lerna.parse(t
|
|
|
138
138
|
export const formatTag = (tag) => f0.format(tag) || f1.format(tag) || null
|
|
139
139
|
|
|
140
140
|
export const getTags = async (cwd, ref = '') =>
|
|
141
|
-
(await
|
|
142
|
-
.split('\n')
|
|
141
|
+
(await getGitTags(cwd, ref))
|
|
143
142
|
.map(tag => parseTag(tag.trim()))
|
|
144
143
|
.filter(Boolean)
|
|
145
144
|
.sort((a, b) => semver.rcompare(a.version, b.version))
|
package/src/main/js/processor.js
CHANGED
|
@@ -2,35 +2,35 @@ import os from 'node:os'
|
|
|
2
2
|
import {$, fs, within} from 'zx-extra'
|
|
3
3
|
import {queuefy} from 'queuefy'
|
|
4
4
|
import {analyze} from './analyze.js'
|
|
5
|
-
import {
|
|
5
|
+
import {pushChangelog} from './changelog.js'
|
|
6
6
|
import {getPkgConfig} from './config.js'
|
|
7
|
-
import {topo, traverseQueue} from './deps.js'
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
7
|
+
import {topo, traverseDeps, traverseQueue} from './deps.js'
|
|
8
|
+
import {ghPages, ghRelease} from './gh.js'
|
|
9
|
+
import {getRoot, getSha} from './git.js'
|
|
10
|
+
import {log, createReport} from './log.js'
|
|
11
|
+
import {getLatest, pushMeta, pushTag} from './meta.js'
|
|
12
|
+
import {fetchPkg, npmPublish} from './npm.js'
|
|
13
|
+
import {memoizeBy, tpl} from './util.js'
|
|
13
14
|
|
|
14
15
|
export const run = async ({cwd = process.cwd(), env, flags = {}} = {}) => within(async () => {
|
|
15
|
-
const {
|
|
16
|
+
const {report, build, publish} = createContext(flags, env)
|
|
16
17
|
|
|
17
|
-
log()('zx-bulk-release')
|
|
18
|
+
report.log()('zx-bulk-release')
|
|
18
19
|
|
|
19
20
|
try {
|
|
20
|
-
const {packages, queue, root,
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
.setQueue(queue)
|
|
21
|
+
const {packages, queue, root, prev, graphs} = await topo({cwd, flags})
|
|
22
|
+
report
|
|
23
|
+
.log()('queue:', queue)
|
|
24
|
+
.log()('graphs', graphs)
|
|
25
|
+
.set('queue', queue)
|
|
26
26
|
.setPackages(packages)
|
|
27
27
|
|
|
28
28
|
await traverseQueue({queue, prev, async cb(name) {
|
|
29
|
-
|
|
29
|
+
report.setStatus('analyzing', name)
|
|
30
30
|
const pkg = packages[name]
|
|
31
31
|
await contextify(pkg, packages, root)
|
|
32
32
|
await analyze(pkg, packages)
|
|
33
|
-
|
|
33
|
+
report
|
|
34
34
|
.set('config', pkg.config, name)
|
|
35
35
|
.set('version', pkg.version, name)
|
|
36
36
|
.set('prevVersion', pkg.latest.tag?.version || pkg.manifest.version, name)
|
|
@@ -38,38 +38,39 @@ export const run = async ({cwd = process.cwd(), env, flags = {}} = {}) => within
|
|
|
38
38
|
.set('tag', pkg.tag, name)
|
|
39
39
|
}})
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
report.setStatus('pending')
|
|
42
42
|
|
|
43
43
|
await traverseQueue({queue, prev, async cb(name) {
|
|
44
44
|
const pkg = packages[name]
|
|
45
45
|
|
|
46
46
|
if (!pkg.releaseType) {
|
|
47
|
-
|
|
47
|
+
report.setStatus('skipped', name)
|
|
48
48
|
return
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
report.setStatus('building', name)
|
|
52
52
|
await build(pkg, packages)
|
|
53
53
|
|
|
54
54
|
if (flags.dryRun) {
|
|
55
|
-
|
|
55
|
+
report.setStatus('success', name)
|
|
56
56
|
return
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
|
|
59
|
+
report.setStatus('publishing', name)
|
|
60
60
|
await publish(pkg)
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
report.setStatus('success', name)
|
|
63
63
|
}})
|
|
64
64
|
} catch (e) {
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
report
|
|
66
|
+
.log({level: 'error'})(e)
|
|
67
67
|
.set('error', e)
|
|
68
68
|
.setStatus('failure')
|
|
69
69
|
throw e
|
|
70
70
|
}
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
report
|
|
72
|
+
.setStatus('success')
|
|
73
|
+
.log()('Great success!')
|
|
73
74
|
})
|
|
74
75
|
|
|
75
76
|
export const runCmd = async (pkg, name) => {
|
|
@@ -82,17 +83,17 @@ export const runCmd = async (pkg, name) => {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
const createContext = (flags, env) => {
|
|
85
|
-
const
|
|
86
|
+
const report = createReport({file: flags.report})
|
|
86
87
|
const _runCmd = queuefy(runCmd, flags.concurrency || os.cpus().length)
|
|
87
88
|
const _build = memoizeBy((pkg, packages) => build(pkg, packages, _runCmd, _build))
|
|
88
89
|
const _publish = memoizeBy((pkg) => publish(pkg, _runCmd))
|
|
89
90
|
|
|
90
|
-
$.
|
|
91
|
+
$.report = report
|
|
91
92
|
$.env = {...process.env, ...env}
|
|
92
93
|
$.verbose = !!(flags.debug || $.env.DEBUG ) || $.verbose
|
|
93
94
|
|
|
94
95
|
return {
|
|
95
|
-
|
|
96
|
+
report,
|
|
96
97
|
runCmd: _runCmd,
|
|
97
98
|
build: _build,
|
|
98
99
|
publish: _publish
|
|
@@ -100,7 +101,7 @@ const createContext = (flags, env) => {
|
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
// Inspired by https://docs.github.com/en/actions/learn-github-actions/contexts
|
|
103
|
-
|
|
104
|
+
const contextify = async (pkg, packages, root) => {
|
|
104
105
|
pkg.config = await getPkgConfig(pkg.absPath, root.absPath)
|
|
105
106
|
pkg.latest = await getLatest(pkg)
|
|
106
107
|
pkg.context = {
|
|
@@ -113,63 +114,36 @@ export const contextify = async (pkg, packages, root) => {
|
|
|
113
114
|
}
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
status: 'initial',
|
|
131
|
-
name,
|
|
132
|
-
version,
|
|
133
|
-
path: absPath,
|
|
134
|
-
relPath
|
|
135
|
-
}
|
|
136
|
-
return acc
|
|
137
|
-
}, {})
|
|
138
|
-
return this
|
|
139
|
-
},
|
|
140
|
-
get(key, pkgName) {
|
|
141
|
-
return get(
|
|
142
|
-
pkgName ? this.packages[pkgName] : this,
|
|
143
|
-
key
|
|
144
|
-
)
|
|
145
|
-
},
|
|
146
|
-
set(key, value, pkgName) {
|
|
147
|
-
set(
|
|
148
|
-
pkgName ? this.packages[pkgName] : this,
|
|
149
|
-
key,
|
|
150
|
-
value
|
|
151
|
-
)
|
|
152
|
-
return this
|
|
153
|
-
},
|
|
154
|
-
setStatus(status, name) {
|
|
155
|
-
this.set('status', status, name)
|
|
156
|
-
this.save()
|
|
157
|
-
return this
|
|
158
|
-
},
|
|
159
|
-
getStatus(status, name) {
|
|
160
|
-
return this.get('status', name)
|
|
161
|
-
},
|
|
162
|
-
log(ctx = {}) {
|
|
163
|
-
return function (...chunks) {
|
|
164
|
-
const {pkg, scope = pkg?.name || '~', level = 'info'} = ctx
|
|
165
|
-
const msg = chunks.map(c => typeof c === 'string' ? tpl(c, ctx) : c)
|
|
166
|
-
const event = {msg, scope, date: Date.now(), level}
|
|
167
|
-
this.events.push(event)
|
|
168
|
-
logger[level](`[${scope}]`, ...msg)
|
|
169
|
-
}.bind(this)
|
|
170
|
-
},
|
|
171
|
-
save() {
|
|
172
|
-
this.file && fs.outputJsonSync(this.file, this)
|
|
173
|
-
return this
|
|
117
|
+
const build = async (pkg, packages, run = runCmd, self = build) => within(async () => {
|
|
118
|
+
$.scope = pkg.name
|
|
119
|
+
if (pkg.built) return
|
|
120
|
+
|
|
121
|
+
await Promise.all([
|
|
122
|
+
traverseDeps(pkg, packages, async (_, {pkg}) => self(pkg, packages, run, self)),
|
|
123
|
+
pkg.changes.length === 0 && pkg.config.npmFetch
|
|
124
|
+
? fetchPkg(pkg)
|
|
125
|
+
: Promise.resolve()
|
|
126
|
+
])
|
|
127
|
+
|
|
128
|
+
if (!pkg.fetched) {
|
|
129
|
+
await run(pkg, 'buildCmd')
|
|
130
|
+
await run(pkg, 'testCmd')
|
|
174
131
|
}
|
|
132
|
+
|
|
133
|
+
pkg.built = true
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
const publish = async (pkg, run = runCmd) => within(async () => {
|
|
137
|
+
$.scope = pkg.name
|
|
138
|
+
await fs.writeJson(pkg.manifestPath, pkg.manifest, {spaces: 2})
|
|
139
|
+
await pushTag(pkg)
|
|
140
|
+
|
|
141
|
+
await Promise.all([
|
|
142
|
+
pushMeta(pkg),
|
|
143
|
+
pushChangelog(pkg),
|
|
144
|
+
npmPublish(pkg),
|
|
145
|
+
ghRelease(pkg),
|
|
146
|
+
ghPages(pkg),
|
|
147
|
+
run(pkg, 'publishCmd')
|
|
148
|
+
])
|
|
175
149
|
})
|
package/src/main/js/build.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import {traverseDeps} from './deps.js'
|
|
2
|
-
import {fetchPkg} from './npm.js'
|
|
3
|
-
import {runCmd} from './processor.js'
|
|
4
|
-
|
|
5
|
-
export const build = async (pkg, packages, run = runCmd, self = build) => {
|
|
6
|
-
if (pkg.built) return true
|
|
7
|
-
|
|
8
|
-
await traverseDeps(pkg, packages, async (_, {pkg}) => self(pkg, packages, run, self))
|
|
9
|
-
|
|
10
|
-
if (pkg.changes.length === 0 && pkg.config.npmFetch) {
|
|
11
|
-
await fetchPkg(pkg)
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
if (!pkg.fetched) {
|
|
15
|
-
await run(pkg, 'buildCmd')
|
|
16
|
-
await run(pkg, 'testCmd')
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
pkg.built = true
|
|
20
|
-
return true
|
|
21
|
-
}
|