zx-bulk-release 1.26.2 → 2.0.0
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 +8 -0
- package/package.json +2 -1
- package/src/main/js/build.js +6 -4
- package/src/main/js/index.js +1 -1
- package/src/main/js/processor.js +20 -13
- package/src/main/js/publish.js +6 -6
- package/src/main/js/repo.js +33 -21
- package/src/main/js/topo.js +15 -1
- package/src/main/js/util.js +16 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
## [2.0.0](https://github.com/semrel-extra/zx-bulk-release/compare/v1.26.2...v2.0.0) (2023-03-21)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
* feat: replace sequent flow with concurrent ([ec35d7e](https://github.com/semrel-extra/zx-bulk-release/commit/ec35d7e337e64369f0423b71008345177f3ac949))
|
|
5
|
+
|
|
6
|
+
### BREAKING CHANGES
|
|
7
|
+
* concurrent flow might cause throttling issues ([ec35d7e](https://github.com/semrel-extra/zx-bulk-release/commit/ec35d7e337e64369f0423b71008345177f3ac949))
|
|
8
|
+
|
|
1
9
|
## [1.26.2](https://github.com/semrel-extra/zx-bulk-release/compare/v1.26.1...v1.26.2) (2023-03-21)
|
|
2
10
|
|
|
3
11
|
### Fixes & improvements
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zx-bulk-release",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "zx-based alternative for multi-semantic-release",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@semrel-extra/topo": "^1.6.0",
|
|
25
25
|
"cosmiconfig": "^8.1.3",
|
|
26
|
+
"queuefy": "^1.2.1",
|
|
26
27
|
"zx-extra": "^2.5.4"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
package/src/main/js/build.js
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import {traverseDeps} from './deps.js'
|
|
2
2
|
import {fetchPkg} from './npm.js'
|
|
3
|
-
import {
|
|
3
|
+
import {runCmd} from './processor.js'
|
|
4
4
|
|
|
5
|
-
export const build = async (pkg, packages) => {
|
|
5
|
+
export const build = async (pkg, packages, run = runCmd) => {
|
|
6
6
|
if (pkg.built) return true
|
|
7
7
|
|
|
8
8
|
await traverseDeps(pkg, packages, async (_, {pkg}) => build(pkg, packages))
|
|
9
9
|
|
|
10
10
|
const {config} = pkg
|
|
11
11
|
|
|
12
|
-
if (pkg.changes.length === 0 && config.npmFetch)
|
|
12
|
+
if (pkg.changes.length === 0 && config.npmFetch) {
|
|
13
|
+
await fetchPkg(pkg)
|
|
14
|
+
}
|
|
13
15
|
|
|
14
16
|
if (!pkg.fetched && config.buildCmd) {
|
|
15
|
-
await
|
|
17
|
+
await run(pkg, 'buildCmd')
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
pkg.built = true
|
package/src/main/js/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {run} from './processor.js'
|
|
1
|
+
export {run} from './processor.js'
|
package/src/main/js/processor.js
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import os from 'node:os'
|
|
2
2
|
import {$, fs, within} from 'zx-extra'
|
|
3
3
|
import {log} from './log.js'
|
|
4
|
-
import {topo} from './topo.js'
|
|
4
|
+
import {topo, traverse} from './topo.js'
|
|
5
5
|
import {contextify} from './contextify.js'
|
|
6
6
|
import {analyze} from './analyze.js'
|
|
7
7
|
import {build} from './build.js'
|
|
8
8
|
import {publish} from './publish.js'
|
|
9
9
|
import {createState} from './state.js'
|
|
10
|
-
import {tpl} from
|
|
10
|
+
import {tpl} from './util.js'
|
|
11
|
+
import {queuefy} from 'queuefy'
|
|
11
12
|
|
|
12
13
|
export const run = async ({cwd = process.cwd(), env, flags = {}, concurrency = os.cpus().length} = {}) => within(async () => {
|
|
13
14
|
const state = createState({file: flags.report})
|
|
15
|
+
const _runCmd = queuefy(runCmd, concurrency)
|
|
16
|
+
|
|
14
17
|
$.state = state
|
|
15
18
|
$.env = {...process.env, ...env}
|
|
16
19
|
$.verbose = !!(flags.debug || $.env.DEBUG ) || $.verbose
|
|
@@ -18,16 +21,14 @@ export const run = async ({cwd = process.cwd(), env, flags = {}, concurrency = o
|
|
|
18
21
|
log()('zx-bulk-release')
|
|
19
22
|
|
|
20
23
|
try {
|
|
21
|
-
const {packages, queue, root} = await topo({cwd, flags})
|
|
24
|
+
const {packages, queue, root, sources, next, prev, nodes} = await topo({cwd, flags})
|
|
22
25
|
log()('queue:', queue)
|
|
23
26
|
|
|
24
27
|
state.setQueue(queue, packages)
|
|
25
|
-
state.setStatus('pending')
|
|
26
|
-
|
|
27
|
-
for (let name of queue) {
|
|
28
|
-
const pkg = packages[name]
|
|
29
28
|
|
|
29
|
+
await traverse({nodes, prev, async cb(name) {
|
|
30
30
|
state.setStatus('analyzing', name)
|
|
31
|
+
const pkg = packages[name]
|
|
31
32
|
await contextify(pkg, packages, root)
|
|
32
33
|
await analyze(pkg, packages)
|
|
33
34
|
state.set('config', pkg.config, name)
|
|
@@ -35,25 +36,31 @@ export const run = async ({cwd = process.cwd(), env, flags = {}, concurrency = o
|
|
|
35
36
|
state.set('prevVersion', pkg.latest.tag?.version || pkg.manifest.version, name)
|
|
36
37
|
state.set('releaseType', pkg.releaseType, name)
|
|
37
38
|
state.set('tag', pkg.tag, name)
|
|
39
|
+
}})
|
|
40
|
+
|
|
41
|
+
state.setStatus('pending')
|
|
42
|
+
|
|
43
|
+
await traverse({nodes, prev, async cb(name) {
|
|
44
|
+
const pkg = packages[name]
|
|
38
45
|
|
|
39
46
|
if (!pkg.releaseType) {
|
|
40
47
|
state.setStatus('skipped', name)
|
|
41
|
-
|
|
48
|
+
return
|
|
42
49
|
}
|
|
43
50
|
|
|
44
51
|
state.setStatus('building', name)
|
|
45
|
-
await build(pkg, packages)
|
|
52
|
+
await build(pkg, packages, _runCmd)
|
|
46
53
|
|
|
47
54
|
if (flags.dryRun) {
|
|
48
55
|
state.setStatus('success', name)
|
|
49
|
-
|
|
56
|
+
return
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
state.setStatus('publishing', name)
|
|
53
|
-
await publish(pkg)
|
|
60
|
+
await publish(pkg, _runCmd)
|
|
54
61
|
|
|
55
62
|
state.setStatus('success', name)
|
|
56
|
-
}
|
|
63
|
+
}})
|
|
57
64
|
} catch (e) {
|
|
58
65
|
log({level: 'error'})(e)
|
|
59
66
|
state.set('error', e)
|
|
@@ -64,7 +71,7 @@ export const run = async ({cwd = process.cwd(), env, flags = {}, concurrency = o
|
|
|
64
71
|
log()('Great success!')
|
|
65
72
|
})
|
|
66
73
|
|
|
67
|
-
export const
|
|
74
|
+
export const runCmd = async (pkg, name) => {
|
|
68
75
|
const cmd = tpl(pkg.config[name], {...pkg, ...pkg.context})
|
|
69
76
|
|
|
70
77
|
if (cmd) {
|
package/src/main/js/publish.js
CHANGED
|
@@ -3,11 +3,11 @@ import {formatTag, getLatestTag, pushTag} from './tag.js'
|
|
|
3
3
|
import {push, fetch, parseRepo} from './repo.js'
|
|
4
4
|
import {parseEnv} from './config.js'
|
|
5
5
|
import {fetchManifest, npmPublish} from './npm.js'
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import {msgJoin} from './util.js'
|
|
7
|
+
import {runCmd} from './processor.js'
|
|
8
8
|
import {log} from './log.js'
|
|
9
9
|
|
|
10
|
-
export const publish = async (pkg) => {
|
|
10
|
+
export const publish = async (pkg, run = runCmd) => {
|
|
11
11
|
await fs.writeJson(pkg.manifestPath, pkg.manifest, {spaces: 2})
|
|
12
12
|
await pushTag(pkg)
|
|
13
13
|
await pushMeta(pkg)
|
|
@@ -15,7 +15,7 @@ export const publish = async (pkg) => {
|
|
|
15
15
|
await npmPublish(pkg)
|
|
16
16
|
await ghRelease(pkg)
|
|
17
17
|
await ghPages(pkg)
|
|
18
|
-
await
|
|
18
|
+
await run(pkg, 'publishCmd')
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export const pushMeta = async (pkg) => {
|
|
@@ -70,7 +70,7 @@ const pushChangelog = async (pkg) => {
|
|
|
70
70
|
? opts.split(' ')
|
|
71
71
|
: [opts.branch, opts.file, opts.msg]
|
|
72
72
|
const _cwd = await fetch({cwd: pkg.absPath, branch})
|
|
73
|
-
const msg =
|
|
73
|
+
const msg = msgJoin(_msg, pkg, 'chore: update changelog ${{name}}')
|
|
74
74
|
const releaseNotes = await formatReleaseNotes(pkg)
|
|
75
75
|
|
|
76
76
|
await $.o({cwd: _cwd})`echo ${releaseNotes}"\n$(cat ./${file})" > ./${file}`
|
|
@@ -105,7 +105,7 @@ const ghPages = async (pkg) => {
|
|
|
105
105
|
const [branch = 'gh-pages', from = 'docs', to = '.', ..._msg] = typeof opts === 'string'
|
|
106
106
|
? opts.split(' ')
|
|
107
107
|
: [opts.branch, opts.from, opts.to, opts.msg]
|
|
108
|
-
const msg =
|
|
108
|
+
const msg = msgJoin(_msg, pkg, 'docs: update docs ${{name}} ${{version}}')
|
|
109
109
|
|
|
110
110
|
log({pkg})(`publish docs to ${branch}`)
|
|
111
111
|
|
package/src/main/js/repo.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {$, ctx, fs, path, tempy, copy} from 'zx-extra'
|
|
2
2
|
import {parseEnv} from './config.js'
|
|
3
3
|
import {log} from './log.js'
|
|
4
|
+
import {keyByValue} from './util.js'
|
|
4
5
|
|
|
5
6
|
const branches = {}
|
|
6
7
|
export const fetch = async ({cwd: _cwd, branch, origin: _origin}) => ctx(async ($) => {
|
|
@@ -25,28 +26,39 @@ export const fetch = async ({cwd: _cwd, branch, origin: _origin}) => ctx(async (
|
|
|
25
26
|
})
|
|
26
27
|
|
|
27
28
|
export const push = async ({cwd, from, to, branch, origin, msg, ignoreFiles, files = []}) => ctx(async ($) => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
29
|
+
let retries = 3
|
|
30
|
+
let _cwd
|
|
31
|
+
|
|
32
|
+
while (retries > 0) {
|
|
33
|
+
try {
|
|
34
|
+
const {gitCommitterEmail, gitCommitterName} = parseEnv($.env)
|
|
35
|
+
_cwd = await fetch({cwd, branch, origin})
|
|
36
|
+
|
|
37
|
+
for (let {relpath, contents} of files) {
|
|
38
|
+
const _contents = typeof contents === 'string' ? contents : JSON.stringify(contents, null, 2)
|
|
39
|
+
await fs.outputFile(path.resolve(_cwd, to, relpath), _contents)
|
|
40
|
+
}
|
|
41
|
+
if (from) await copy({baseFrom: cwd, from, baseTo: _cwd, to, ignoreFiles, cwd})
|
|
42
|
+
|
|
43
|
+
$.cwd = _cwd
|
|
44
|
+
|
|
45
|
+
await $`git config user.name ${gitCommitterName}`
|
|
46
|
+
await $`git config user.email ${gitCommitterEmail}`
|
|
47
|
+
await $`git add .`
|
|
48
|
+
try {
|
|
49
|
+
await $`git commit -m ${msg}`
|
|
50
|
+
} catch {
|
|
51
|
+
log({level: 'warn'})(`no changes to commit to ${branch}`)
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return await $.raw`git push origin HEAD:refs/heads/${branch}`
|
|
56
|
+
} catch (e) {
|
|
57
|
+
retries -= 1
|
|
58
|
+
branches[keyByValue(branches, _cwd)] = null
|
|
59
|
+
console.warn('git push failed', 'retries left', retries, e)
|
|
60
|
+
}
|
|
47
61
|
}
|
|
48
|
-
|
|
49
|
-
await $.raw`git push origin HEAD:refs/heads/${branch}`
|
|
50
62
|
})
|
|
51
63
|
|
|
52
64
|
const repos = {}
|
package/src/main/js/topo.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {topo as _topo} from '@semrel-extra/topo'
|
|
2
|
+
import {getPromise} from './util.js'
|
|
2
3
|
|
|
3
4
|
export const topo = async ({flags = {}, cwd} = {}) => {
|
|
4
5
|
const ignore = typeof flags.ignore === 'string'
|
|
@@ -14,4 +15,17 @@ export const topo = async ({flags = {}, cwd} = {}) => {
|
|
|
14
15
|
!ignore.includes(name)
|
|
15
16
|
|
|
16
17
|
return _topo({cwd, filter})
|
|
17
|
-
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const traverse = async ({nodes, prev, cb}) => {
|
|
21
|
+
const waitings = nodes.reduce((acc, node) => {
|
|
22
|
+
acc[node] = getPromise()
|
|
23
|
+
return acc
|
|
24
|
+
}, {})
|
|
25
|
+
|
|
26
|
+
await Promise.all(nodes.map(async (name) => {
|
|
27
|
+
await Promise.all((prev.get(name) || []).map((p) => waitings[p].promise))
|
|
28
|
+
await cb(name)
|
|
29
|
+
waitings[name].resolve(true)
|
|
30
|
+
}))
|
|
31
|
+
}
|
package/src/main/js/util.js
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import {$, fs} from 'zx-extra'
|
|
2
|
-
|
|
3
1
|
export const tpl = (str, context) =>
|
|
4
2
|
str?.replace(/\$\{\{\s*([.a-z0-9]+)\s*}}/gi, (matched, key) => get(context, key) ?? '')
|
|
5
3
|
|
|
@@ -30,4 +28,19 @@ export const set = (obj, path, value) => {
|
|
|
30
28
|
return result
|
|
31
29
|
}
|
|
32
30
|
|
|
33
|
-
export const
|
|
31
|
+
export const msgJoin = (rest, context, def) => tpl(rest.filter(Boolean).join(' ') || def, context)
|
|
32
|
+
|
|
33
|
+
export const getPromise = () => {
|
|
34
|
+
let resolve, reject
|
|
35
|
+
const promise = new Promise((...args) => {
|
|
36
|
+
[resolve, reject] = args
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
resolve,
|
|
41
|
+
reject,
|
|
42
|
+
promise,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const keyByValue = (obj, value) => Object.keys(obj).find((key) => obj[key] === value)
|