zx-bulk-release 1.7.8 → 1.9.1
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 +18 -0
- package/README.md +53 -21
- package/package.json +3 -2
- package/src/main/js/build.js +12 -10
- package/src/main/js/config.js +27 -0
- package/src/main/js/index.js +4 -1
- package/src/main/js/publish.js +25 -2
- package/src/test/js/integration.test.js +13 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
## [1.9.1](https://github.com/semrel-extra/zx-bulk-release/compare/v1.9.0...v1.9.1) (2022-06-26)
|
|
2
|
+
|
|
3
|
+
### Fixes & improvements
|
|
4
|
+
* refactor: replace postbuild hook with postupdate ([b7d68a5](https://github.com/semrel-extra/zx-bulk-release/commit/b7d68a5a2b9dec6516204f3fcbbc3c08db9c6d90))
|
|
5
|
+
|
|
6
|
+
## [1.9.0](https://github.com/semrel-extra/zx-bulk-release/compare/v1.8.0...v1.9.0) (2022-06-26)
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
* feat: add gh-pages push ([32130b6](https://github.com/semrel-extra/zx-bulk-release/commit/32130b64a2088cc98b1cae678691cd55c18fe0a3))
|
|
10
|
+
|
|
11
|
+
## [1.8.0](https://github.com/semrel-extra/zx-bulk-release/compare/v1.7.8...v1.8.0) (2022-06-26)
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
* feat: add cosmiconfig ([1fe694d](https://github.com/semrel-extra/zx-bulk-release/commit/1fe694d2c919a029eb4aa5d5f500b287a2035608))
|
|
15
|
+
|
|
16
|
+
### Fixes & improvements
|
|
17
|
+
* docs: formatting ([d2bac88](https://github.com/semrel-extra/zx-bulk-release/commit/d2bac8893d33f4c9ce6c003c4f7188ea56452023))
|
|
18
|
+
|
|
1
19
|
## [1.7.8](https://github.com/semrel-extra/zx-bulk-release/compare/v1.7.7...v1.7.8) (2022-06-26)
|
|
2
20
|
|
|
3
21
|
### Fixes & improvements
|
package/README.md
CHANGED
|
@@ -3,25 +3,51 @@
|
|
|
3
3
|
|
|
4
4
|
🚧 Work in progress. Early access preview
|
|
5
5
|
|
|
6
|
+
## Roadmap
|
|
7
|
+
* [x] [Conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#specification) trigger semantic releases.
|
|
8
|
+
* [x] Predictable [toposort](https://githib.com/semrel-extra/topo)-driven flow.
|
|
9
|
+
* [x] No blocking (no release commits).
|
|
10
|
+
* [ ] Changelogs, docs, bundles go to: release assets and/or meta branch.
|
|
11
|
+
* [x] No extra builds. The required deps are fetched from the pkg registry.
|
|
12
|
+
|
|
6
13
|
## Requirements
|
|
7
14
|
* macOS / linux
|
|
8
15
|
* Node.js >= 16.0.0
|
|
9
|
-
* yarn >=
|
|
16
|
+
* npm >=7 / yarn >= 3
|
|
10
17
|
|
|
11
18
|
## Usage
|
|
19
|
+
### CLI
|
|
12
20
|
```shell
|
|
13
21
|
GH_TOKEN=ghtoken GH_USER=username NPM_TOKEN=npmtoken npx zx-bulk-release [opts]
|
|
14
22
|
```
|
|
15
23
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
24
|
+
### JS API
|
|
25
|
+
```js
|
|
26
|
+
import { run } from 'zx-bulk-release'
|
|
27
|
+
|
|
28
|
+
const cwd = '/foo/bar'
|
|
29
|
+
const env = {GH_TOKEN: 'foo', NPM_TOKEN: 'bar'}
|
|
30
|
+
const flags = {dryRun: true}
|
|
22
31
|
|
|
23
|
-
|
|
24
|
-
|
|
32
|
+
await run({
|
|
33
|
+
cwd, // Defaults to process.cwd()
|
|
34
|
+
flags, // Defaults to process.env
|
|
35
|
+
env // Defaults to minimist-parsed `process.argv.slice(2)`
|
|
36
|
+
})
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Config
|
|
40
|
+
Any [cosmiconfig](https://github.com/davidtheclark/cosmiconfig) compliant format: `.releaserc`, `.release.json`, `.release.yaml`, etc.
|
|
41
|
+
```yaml
|
|
42
|
+
buildCmd: 'yarn build'
|
|
43
|
+
postbuildCmd: 'yarn install'
|
|
44
|
+
testCmd: 'yarn test'
|
|
45
|
+
fetch: true
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Implementation notes
|
|
49
|
+
### Tags
|
|
50
|
+
[Lerna](https://github.com/lerna/lerna) tags (like `@pkg/name@v1.0.0-beta.0`) are suitable for monorepos, but they don’t follow [semver spec](https://semver.org/). Therefore, we propose another contract:
|
|
25
51
|
```js
|
|
26
52
|
'2022.6.13-optional-org.pkg-name.v1.0.0-beta.1+sha.1-f0'
|
|
27
53
|
// date name version format
|
|
@@ -32,18 +58,7 @@ Note, [npm-package-name charset](https://www.npmjs.com/package/validate-npm-pack
|
|
|
32
58
|
// date name ver b64 format
|
|
33
59
|
```
|
|
34
60
|
|
|
35
|
-
|
|
36
|
-
```js
|
|
37
|
-
import { run } from 'zx-bulk-release'
|
|
38
|
-
|
|
39
|
-
const cwd = '/foo/bar' // Defaults to process.cwd()
|
|
40
|
-
const env = { GH_TOKEN: 'foo', NPM_TOKEN: 'bar' } // Defaults to process.env
|
|
41
|
-
const flags = {dryRun: true}
|
|
42
|
-
|
|
43
|
-
await run({cwd, flags, env})
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## env vars
|
|
61
|
+
### env vars
|
|
47
62
|
```js
|
|
48
63
|
export const parseEnv = (env = process.env) => {
|
|
49
64
|
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
|
|
@@ -61,6 +76,23 @@ export const parseEnv = (env = process.env) => {
|
|
|
61
76
|
}
|
|
62
77
|
```
|
|
63
78
|
|
|
79
|
+
### Meta
|
|
80
|
+
|
|
81
|
+
Each release projects its result into the `meta` branch.
|
|
82
|
+
`2022-6-26-semrel-extra-zxbr-test-c-1-3-1-f0.json`
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"META_VERSION": "1",
|
|
86
|
+
"name": "@semrel-extra/zxbr-test-c",
|
|
87
|
+
"hash": "07b7df33f0159f674c940bd7bbb2652cdaef5207",
|
|
88
|
+
"version": "1.3.1",
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"@semrel-extra/zxbr-test-a": "^1.4.0",
|
|
91
|
+
"@semrel-extra/zxbr-test-d": "~1.2.0"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
64
96
|
## References
|
|
65
97
|
* [semrel-extra/zx-semrel](https://github.com/semrel-extra/zx-semrel)
|
|
66
98
|
* [dhoulb/multi-semantic-release](https://github.com/dhoulb/multi-semantic-release)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zx-bulk-release",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "zx-based alternative for multi-semantic-release",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./src/main/js/index.js",
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@semrel-extra/topo": "^1.4.1",
|
|
15
|
+
"cosmiconfig": "^7.0.1",
|
|
15
16
|
"git-glob-cp": "^1.7.1",
|
|
16
17
|
"ini": "^3.0.0",
|
|
17
|
-
"zx-extra": "^1.7.
|
|
18
|
+
"zx-extra": "^1.7.1"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
20
21
|
"c8": "^7.11.3",
|
package/src/main/js/build.js
CHANGED
|
@@ -9,21 +9,23 @@ export const build = (pkg, packages) => ctx(async ($) => {
|
|
|
9
9
|
|
|
10
10
|
await traverseDeps(pkg, packages, async (_, {pkg}) => build(pkg, packages))
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
const {config} = pkg
|
|
13
|
+
$.cwd = pkg.absPath
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
if (config.buildCmd) {
|
|
16
|
+
if (pkg.changes?.length === 0 && config.fetch) await fetchPkg(pkg)
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
if (!pkg.fetched) {
|
|
19
|
+
await $.raw`${config.buildCmd}`
|
|
19
20
|
console.log(`built '${pkg.name}'`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// if (config.postbuildCmd) await $.raw`${config.postbuildCmd}`
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
+
if (!pkg.fetched && config.testCmd) {
|
|
26
|
+
await $.raw`${config.testCmd}`
|
|
27
|
+
console.log(`tested '${pkg.name}'`)
|
|
25
28
|
}
|
|
26
|
-
await $`yarn install`
|
|
27
29
|
}
|
|
28
30
|
|
|
29
31
|
pkg.built = true
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { cosmiconfig } from 'cosmiconfig'
|
|
2
|
+
|
|
3
|
+
const CONFIG_NAME = 'release'
|
|
4
|
+
const CONFIG_FILES = [
|
|
5
|
+
'package.json',
|
|
6
|
+
`.${CONFIG_NAME}rc`,
|
|
7
|
+
`.${CONFIG_NAME}rc.json`,
|
|
8
|
+
`.${CONFIG_NAME}rc.yaml`,
|
|
9
|
+
`.${CONFIG_NAME}rc.yml`,
|
|
10
|
+
`.${CONFIG_NAME}rc.js`,
|
|
11
|
+
`.${CONFIG_NAME}rc.cjs`,
|
|
12
|
+
`${CONFIG_NAME}.config.js`,
|
|
13
|
+
`${CONFIG_NAME}.config.cjs`
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
export const defaultConfig = {
|
|
17
|
+
buildCmd: 'yarn build',
|
|
18
|
+
postbuildCmd: 'yarn install',
|
|
19
|
+
testCmd: 'yarn test',
|
|
20
|
+
fetch: true
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const getConfig = async (...cwds) =>
|
|
24
|
+
(await Promise.all(cwds.map(
|
|
25
|
+
cwd => cosmiconfig(CONFIG_NAME, { searchPlaces: CONFIG_FILES }).search(cwd).then(r => r?.config)
|
|
26
|
+
))).find(Boolean) || defaultConfig
|
|
27
|
+
|
package/src/main/js/index.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import {fs,
|
|
1
|
+
import {fs, $} from 'zx-extra'
|
|
2
2
|
import {topo} from '@semrel-extra/topo'
|
|
3
3
|
import {updateDeps} from './deps.js'
|
|
4
4
|
import {getSemanticChanges, resolvePkgVersion} from './analyze.js'
|
|
5
5
|
import {publish, getLatest} from './publish.js'
|
|
6
6
|
import {build} from './build.js'
|
|
7
|
+
import {getConfig} from './config.js'
|
|
7
8
|
|
|
8
9
|
export const run = async ({cwd = process.cwd(), env = process.env, flags = {}} = {}) => {
|
|
9
10
|
const {packages, queue, root} = await topo({cwd})
|
|
@@ -11,6 +12,7 @@ export const run = async ({cwd = process.cwd(), env = process.env, flags = {}} =
|
|
|
11
12
|
|
|
12
13
|
for (let name of queue) {
|
|
13
14
|
const pkg = packages[name]
|
|
15
|
+
pkg.config = await getConfig(pkg.absPath, root.absPath)
|
|
14
16
|
pkg.latest = await getLatest(cwd, name)
|
|
15
17
|
|
|
16
18
|
const semanticChanges = await getSemanticChanges(pkg.absPath, pkg.latest.tag?.ref)
|
|
@@ -24,6 +26,7 @@ export const run = async ({cwd = process.cwd(), env = process.env, flags = {}} =
|
|
|
24
26
|
if (changes.length === 0) continue
|
|
25
27
|
console.log(`semantic changes of '${name}'`, changes)
|
|
26
28
|
|
|
29
|
+
$.o({cwd: pkg.absPath})`yarn install`
|
|
27
30
|
pkg.build = await build(pkg, packages, cwd)
|
|
28
31
|
|
|
29
32
|
if (dryRun) continue
|
package/src/main/js/publish.js
CHANGED
|
@@ -7,6 +7,7 @@ export const publish = async (pkg) => {
|
|
|
7
7
|
await pushMeta(pkg)
|
|
8
8
|
await npmPublish(pkg)
|
|
9
9
|
await createGhRelease(pkg)
|
|
10
|
+
await ghPages(pkg)
|
|
10
11
|
}
|
|
11
12
|
|
|
12
13
|
export const pushTag = (pkg) => ctx(async ($) => {
|
|
@@ -98,6 +99,22 @@ ${commits.join('\n')}`).join('\n')
|
|
|
98
99
|
await $`curl -u ${ghUser}:${ghToken} -H "Accept: application/vnd.github.v3+json" https://api.github.com/repos/${repoName}/releases -d ${releaseData}`
|
|
99
100
|
})
|
|
100
101
|
|
|
102
|
+
const ghPages = async (pkg) => {
|
|
103
|
+
const {config} = pkg
|
|
104
|
+
if (!config.ghPages) return
|
|
105
|
+
|
|
106
|
+
console.log('publish to gh-pages')
|
|
107
|
+
const [from, branch = 'gh-pages', to = '.'] = config.ghPages.split(' ')
|
|
108
|
+
|
|
109
|
+
await push({
|
|
110
|
+
cwd: path.resolve(pkg.absPath, from),
|
|
111
|
+
from: '.',
|
|
112
|
+
to,
|
|
113
|
+
branch,
|
|
114
|
+
msg: 'docs update'
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
|
|
101
118
|
const branches = {}
|
|
102
119
|
export const fetch = async ({cwd: _cwd, branch, origin: _origin}) => ctx(async ($) => {
|
|
103
120
|
let cwd = branches[branch]
|
|
@@ -127,14 +144,20 @@ export const push = async ({cwd, from, to, branch, origin, msg, ignoreFiles, fil
|
|
|
127
144
|
const _contents = typeof contents === 'string' ? contents : JSON.stringify(contents, null, 2)
|
|
128
145
|
await fs.outputFile(path.resolve(_cwd, to, relpath), _contents)
|
|
129
146
|
}
|
|
130
|
-
if (from) await copydir({baseFrom: cwd, from, baseTo: _cwd, to, ignoreFiles})
|
|
147
|
+
if (from) await copydir({baseFrom: cwd, from, baseTo: _cwd, to, ignoreFiles, cwd})
|
|
131
148
|
|
|
132
149
|
$.cwd = _cwd
|
|
133
150
|
|
|
134
151
|
await $`git config user.name ${gitCommitterEmail}`
|
|
135
152
|
await $`git config user.email ${gitCommitterName}`
|
|
136
153
|
await $`git add .`
|
|
137
|
-
|
|
154
|
+
try {
|
|
155
|
+
await $`git commit -m ${msg}`
|
|
156
|
+
} catch {
|
|
157
|
+
console.warn('no changes')
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
|
|
138
161
|
await $.raw`git push origin HEAD:refs/heads/${branch}`
|
|
139
162
|
})
|
|
140
163
|
|
|
@@ -49,9 +49,10 @@ const cwd = await createFakeRepo({
|
|
|
49
49
|
test: "node ./index.js"
|
|
50
50
|
},
|
|
51
51
|
release: {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
buildCmd: 'yarn build',
|
|
53
|
+
postbuildCmd: 'yarn install',
|
|
54
|
+
testCmd: 'yarn test',
|
|
55
|
+
fetch: true
|
|
55
56
|
},
|
|
56
57
|
exports: {
|
|
57
58
|
'.': {
|
|
@@ -107,13 +108,15 @@ const cwd = await createFakeRepo({
|
|
|
107
108
|
a: 'workspace:^'
|
|
108
109
|
},
|
|
109
110
|
scripts: {
|
|
110
|
-
build: 'cp index.js bundle.js',
|
|
111
|
+
build: 'cp index.js bundle.js && mkdir -p docs && echo "# docs" > docs/readme.md',
|
|
111
112
|
test: "node ./index.js"
|
|
112
113
|
},
|
|
113
114
|
release: {
|
|
114
|
-
|
|
115
|
+
buildCmd: 'yarn build',
|
|
116
|
+
postbuildCmd: 'yarn install',
|
|
117
|
+
testCmd: 'yarn test',
|
|
115
118
|
fetch: true,
|
|
116
|
-
|
|
119
|
+
ghPages: 'docs gh-pages b'
|
|
117
120
|
},
|
|
118
121
|
exports: {
|
|
119
122
|
'.': {
|
|
@@ -207,9 +210,13 @@ test('run()', async () => {
|
|
|
207
210
|
|
|
208
211
|
const origin = (await $`git remote get-url origin`).toString().trim()
|
|
209
212
|
const meta = tempy.temporaryDirectory()
|
|
213
|
+
const ghp = tempy.temporaryDirectory()
|
|
210
214
|
|
|
211
215
|
await $`git clone --single-branch --branch meta --depth 1 ${origin} ${meta}`
|
|
212
216
|
assert.is((await fs.readJson(`${meta}/${tag.toLowerCase().replace(/[^a-z0-9-]/g, '-')}.json`)).version, '1.1.0')
|
|
217
|
+
|
|
218
|
+
await $`git clone --single-branch --branch gh-pages --depth 1 ${origin} ${ghp}`
|
|
219
|
+
assert.is((await fs.readFile(`${ghp}/b/readme.md`, 'utf-8')).trim(), '# docs')
|
|
213
220
|
})
|
|
214
221
|
|
|
215
222
|
await registry.stop()
|