zx-bulk-release 2.2.6 → 2.2.7

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 CHANGED
@@ -1,3 +1,9 @@
1
+ ## [2.2.7](https://github.com/semrel-extra/zx-bulk-release/compare/v2.2.6...v2.2.7) (2023-03-24)
2
+
3
+ ### Fixes & improvements
4
+ * docs: describe more CLI flags ([6f7a053](https://github.com/semrel-extra/zx-bulk-release/commit/6f7a053ae2fe2da8fd71858b132ef4ac4d1456ad))
5
+ * refactor: move `topo` to ctx builder ([6fec83c](https://github.com/semrel-extra/zx-bulk-release/commit/6fec83c10dd76feb93a3148eb2c032c6eaa902f1))
6
+
1
7
  ## [2.2.6](https://github.com/semrel-extra/zx-bulk-release/compare/v2.2.5...v2.2.6) (2023-03-24)
2
8
 
3
9
  ### Fixes & improvements
package/README.md CHANGED
@@ -18,10 +18,10 @@
18
18
  * No extra builds. The required deps are fetched from the pkg registry (`npmFetch` config opt).
19
19
 
20
20
  ## Roadmap
21
+ * [x] Store release metrics to `meta`.
22
+ * [ ] ~~Self-repair. Restore broken/missing metadata from external registries (npm, pypi, m2)~~. Tags should be the only source of truth
21
23
  * [ ] Multistack. Add support for java/kt/py.
22
- * [ ] Self-repair. Restore broken/missing metadata from external registries (npm, pypi, m2).
23
24
  * [ ] Semaphore. Let several release agents to serve the monorepo at the same time.
24
- * [ ] Stats. Store release metrics to `meta`.
25
25
 
26
26
  ## Requirements
27
27
  * macOS / linux
@@ -37,11 +37,16 @@ yarn add zx-bulk-release
37
37
  ```shell
38
38
  GH_TOKEN=ghtoken GH_USER=username NPM_TOKEN=npmtoken npx zx-bulk-release [opts]
39
39
  ```
40
- | Flag | Description | Default |
41
- |---------------------|----------------------------|----------|
42
- | `--dry-run` | Dry run mode | `false` |
43
- | `--ignore` | Packages to ignore: `a, b` | |
44
- | `--include-private` | Include private pkgs | `false` |
40
+ | Flag | Description | Default |
41
+ |------------------------------|----------------------------------------------------------------|------------------|
42
+ | `--ignore` | Packages to ignore: `a, b` | |
43
+ | `--include-private` | Include `private` packages | `false` |
44
+ | `--concurrency` | `build/publish` threads limit | `os.cpus.length` |
45
+ | `--no-build` | Skip `buildCmd` invoke | |
46
+ | `--no-npm-fetch` | Disable npm artifacts fetching | |
47
+ | `--dry-run` / `--no-publish` | Disable any publish logic | |
48
+ | `--report` | Persist release state to file | |
49
+ | `--debug` | Enable [zx](https://github.com/google/zx#verbose) verbose mode | |
45
50
 
46
51
  ### JS API
47
52
  ```js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zx-bulk-release",
3
- "version": "2.2.6",
3
+ "version": "2.2.7",
4
4
  "description": "zx-based alternative for multi-semantic-release",
5
5
  "type": "module",
6
6
  "exports": {
@@ -6,7 +6,7 @@ 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)
9
- const depsChanges = await updateDeps(pkg, packages)
9
+ const depsChanges = await updateDeps(pkg, pkg.context.packages)
10
10
  const changes = [...semanticChanges, ...depsChanges]
11
11
  const releaseType = getNextReleaseType(changes)
12
12
 
@@ -15,10 +15,10 @@ const CONFIG_FILES = [
15
15
  ]
16
16
 
17
17
  export const defaultConfig = {
18
- cmd: 'yarn && yarn build && yarn test',
19
- changelog: 'changelog',
20
- npmFetch: true,
21
- ghRelease: true,
18
+ cmd: 'yarn && yarn build && yarn test',
19
+ changelog: 'changelog',
20
+ npmFetch: true,
21
+ ghRelease: true,
22
22
  // npmPublish: true,
23
23
  // ghPages: 'gh-pages'
24
24
  }
@@ -38,10 +38,8 @@ export const normalizePkgConfig = (config, env) => ({
38
38
  }
39
39
  })
40
40
 
41
- export const parseEnv = (env = process.env) => {
42
- const {GH_USER, GH_USERNAME, GITHUB_USER, GITHUB_USERNAME, GH_TOKEN, GITHUB_TOKEN, NPM_TOKEN, NPM_REGISTRY, NPMRC, NPM_USERCONFIG, NPM_CONFIG_USERCONFIG, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL} = env
43
-
44
- return {
41
+ export const parseEnv = ({GH_USER, GH_USERNAME, GITHUB_USER, GITHUB_USERNAME, GH_TOKEN, GITHUB_TOKEN, NPM_TOKEN, NPM_REGISTRY, NPMRC, NPM_USERCONFIG, NPM_CONFIG_USERCONFIG, GIT_COMMITTER_NAME, GIT_COMMITTER_EMAIL} = process.env) =>
42
+ ({
45
43
  ghUser: GH_USER || GH_USERNAME || GITHUB_USER || GITHUB_USERNAME,
46
44
  ghToken: GH_TOKEN || GITHUB_TOKEN,
47
45
  npmConfig: NPMRC || NPM_USERCONFIG || NPM_CONFIG_USERCONFIG,
@@ -49,7 +47,6 @@ export const parseEnv = (env = process.env) => {
49
47
  npmRegistry: NPM_REGISTRY || 'https://registry.npmjs.org',
50
48
  gitCommitterName: GIT_COMMITTER_NAME || 'Semrel Extra Bot',
51
49
  gitCommitterEmail: GIT_COMMITTER_EMAIL || 'semrel-extra-bot@hotmail.com',
52
- }
53
- }
50
+ })
54
51
 
55
52
  export const normalizeFlags = (flags = {}) => Object.entries(flags).reduce((acc, [k, v]) => ({...acc, [camelize(k)]: v}), {})
@@ -1,34 +1,28 @@
1
1
  import {$, fs} from 'zx-extra'
2
2
  import {get, set, tpl} from './util.js'
3
3
 
4
- export const log = (ctx) => {
5
- if ($.report) {
6
- return $.report.log(ctx)
7
- }
8
-
9
- return console.log
10
- }
4
+ export const log = (ctx) =>
5
+ $.report
6
+ ? $.report.log(ctx)
7
+ : console.log
11
8
 
12
- export const createReport = ({logger = console, file = null} = {}) => ({
9
+ export const createReport = ({logger = console, packages = {}, queue = [], flags} = {}) => ({
13
10
  logger,
14
- file,
11
+ flags,
12
+ file: flags.report || flags.file,
15
13
  status: 'initial',
16
- queue: [],
17
- packages: {},
18
14
  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
- },
15
+ queue,
16
+ packages: Object.entries(packages).reduce((acc, [name, {manifest: {version}, absPath, relPath}]) => {
17
+ acc[name] = {
18
+ status: 'initial',
19
+ name,
20
+ version,
21
+ path: absPath,
22
+ relPath
23
+ }
24
+ return acc
25
+ }, {}),
32
26
  get(key, pkgName) {
33
27
  return get(
34
28
  pkgName ? this.packages[pkgName] : this,
@@ -13,23 +13,20 @@ import {fetchPkg, npmPublish} from './npm.js'
13
13
  import {memoizeBy, tpl} from './util.js'
14
14
 
15
15
  export const run = async ({cwd = process.cwd(), env, flags = {}} = {}) => within(async () => {
16
- const {report, build, publish} = createContext(flags, env)
16
+ const context = await createContext({flags, env, cwd})
17
+ const {report, build, publish, packages, queue, prev, graphs} = context
17
18
 
18
- report.log()('zx-bulk-release')
19
+ report
20
+ .log()('zx-bulk-release')
21
+ .log()('queue:', queue)
22
+ .log()('graphs', graphs)
19
23
 
20
24
  try {
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
- .setPackages(packages)
27
-
28
25
  await traverseQueue({queue, prev, async cb(name) {
29
26
  report.setStatus('analyzing', name)
30
27
  const pkg = packages[name]
31
- await contextify(pkg, packages, root)
32
- await analyze(pkg, packages)
28
+ await contextify(pkg, context)
29
+ await analyze(pkg)
33
30
  report
34
31
  .set('config', pkg.config, name)
35
32
  .set('version', pkg.version, name)
@@ -47,17 +44,14 @@ export const run = async ({cwd = process.cwd(), env, flags = {}} = {}) => within
47
44
  report.setStatus('skipped', name)
48
45
  return
49
46
  }
50
-
51
- report.setStatus('building', name)
52
- await build(pkg, packages)
53
-
54
- if (flags.dryRun) {
55
- report.setStatus('success', name)
56
- return
47
+ if (!flags.noBuild) {
48
+ report.setStatus('building', name)
49
+ await build(pkg)
50
+ }
51
+ if (!flags.dryRun && !flags.noPublish) {
52
+ report.setStatus('publishing', name)
53
+ await publish(pkg)
57
54
  }
58
-
59
- report.setStatus('publishing', name)
60
- await publish(pkg)
61
55
 
62
56
  report.setStatus('success', name)
63
57
  }})
@@ -78,30 +72,35 @@ export const runCmd = async (pkg, name) => {
78
72
 
79
73
  if (cmd) {
80
74
  log({pkg})(`run ${name} '${cmd}'`)
81
- await $.o({cwd: pkg.absPath, quote: v => v, preferLocal: true})`${cmd}`
75
+ return $.o({cwd: pkg.absPath, quote: v => v, preferLocal: true})`${cmd}`
82
76
  }
83
77
  }
84
78
 
85
- const createContext = (flags, env) => {
86
- const report = createReport({file: flags.report})
87
- const _runCmd = queuefy(runCmd, flags.concurrency || os.cpus().length)
88
- const _build = memoizeBy((pkg, packages) => build(pkg, packages, _runCmd, _build))
89
- const _publish = memoizeBy((pkg) => publish(pkg, _runCmd))
79
+ const createContext = async ({flags, env, cwd}) => {
80
+ const { packages, queue, root, prev, graphs } = await topo({cwd, flags})
81
+ const report = createReport({packages, queue, flags})
82
+ const run = queuefy(runCmd, flags.concurrency || os.cpus().length)
83
+ const _build = memoizeBy((pkg) => build(pkg, run, _build, flags))
84
+ const _publish = memoizeBy((pkg) => publish(pkg, run))
90
85
 
91
- $.report = report
92
- $.env = {...process.env, ...env}
93
- $.verbose = !!(flags.debug || $.env.DEBUG ) || $.verbose
86
+ $.report = report
87
+ $.env = {...process.env, ...env}
88
+ $.verbose = !!(flags.debug || $.env.DEBUG ) || $.verbose
94
89
 
95
90
  return {
96
91
  report,
97
- runCmd: _runCmd,
98
92
  build: _build,
99
- publish: _publish
93
+ publish: _publish,
94
+ packages,
95
+ root,
96
+ queue,
97
+ prev,
98
+ graphs
100
99
  }
101
100
  }
102
101
 
103
102
  // Inspired by https://docs.github.com/en/actions/learn-github-actions/contexts
104
- const contextify = async (pkg, packages, root) => {
103
+ const contextify = async (pkg, {packages, root}) => {
105
104
  pkg.config = await getPkgConfig(pkg.absPath, root.absPath)
106
105
  pkg.latest = await getLatest(pkg)
107
106
  pkg.context = {
@@ -114,13 +113,12 @@ const contextify = async (pkg, packages, root) => {
114
113
  }
115
114
  }
116
115
 
117
- const build = async (pkg, packages, run = runCmd, self = build) => within(async () => {
116
+ const build = async (pkg, run = runCmd, self = build, flags = {}) => within(async () => {
118
117
  $.scope = pkg.name
119
- if (pkg.built) return
120
118
 
121
119
  await Promise.all([
122
- traverseDeps(pkg, packages, async (_, {pkg}) => self(pkg, packages, run, self)),
123
- pkg.changes.length === 0 && pkg.config.npmFetch
120
+ traverseDeps(pkg, pkg.context.packages, async (_, {pkg}) => self(pkg, run, self, flags)),
121
+ pkg.changes.length === 0 && pkg.config.npmFetch && !flags.noNpmFetch
124
122
  ? fetchPkg(pkg)
125
123
  : Promise.resolve()
126
124
  ])
@@ -146,4 +144,6 @@ const publish = async (pkg, run = runCmd) => within(async () => {
146
144
  ghPages(pkg),
147
145
  run(pkg, 'publishCmd')
148
146
  ])
147
+
148
+ pkg.published = true
149
149
  })
@@ -30,19 +30,6 @@ export const set = (obj, path, value) => {
30
30
 
31
31
  export const msgJoin = (rest, context, def) => tpl(rest.filter(Boolean).join(' ') || def, context)
32
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
33
  export const keyByValue = (obj, value) => Object.keys(obj).find((key) => obj[key] === value)
47
34
 
48
35
  export const memoizeBy = (fn, getKey = v => v, memo = new Map()) => async (...args) => {