1 | 'use strict'
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | const shell = require('shelljs')
|
11 | const {join} = require('path')
|
12 | const spawn = require('cross-spawn')
|
13 | const signale = require('signale')
|
14 | const inquirer = require('inquirer')
|
15 | const constants = require('../config/constants')
|
16 | const {runForPkgs} = require('../config/build')
|
17 | const {findPkgs} = require('../config/utils')
|
18 | const getUserConfig = require('../config/get-user-config')
|
19 |
|
20 | function getUpdatedRepos(lernaPath, args = '') {
|
21 | const ret = shell.exec(`${lernaPath} changed --include-merged-tags ${args}`, {silent: false})
|
22 | .stdout
|
23 |
|
24 | return ret
|
25 | .split('\n')
|
26 | .map((line) => line.replace('- ', ''))
|
27 | .filter((line) => line !== '')
|
28 | }
|
29 |
|
30 | async function publish({cwd = process.cwd()}) {
|
31 |
|
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | const user = shell.exec('npm whoami --registry https://registry.npmjs.org/', {silent: true})
|
41 | .stdout
|
42 |
|
43 | if (user.trim() !== constants.username) {
|
44 | signale.error(`
|
45 | npm账号不对,请用公司账号登录
|
46 | `)
|
47 | process.exit(1)
|
48 | }
|
49 |
|
50 | const lernaPath = join(__dirname, '../node_modules/.bin/lerna')
|
51 | const updatedRepos = getUpdatedRepos(lernaPath)
|
52 | const rootUserConfig = getUserConfig({cwd})
|
53 |
|
54 | const forceUpdatePkgs = []
|
55 | const publishPkgNames = []
|
56 |
|
57 | const pkgs = findPkgs({
|
58 | cwd,
|
59 | packagesPatterns: rootUserConfig.packagesPatterns,
|
60 | ignoreNoBuild: false,
|
61 | cb: (pkg) => {
|
62 | const {pkgPath} = pkg
|
63 | const {pkgJson} = pkg
|
64 | const userConfig = getUserConfig({cwd: pkgPath})
|
65 |
|
66 | if (pkgJson && !userConfig.noPublish) {
|
67 | const update = updatedRepos.findIndex((repo) => repo === pkgJson.name) > -1
|
68 |
|
69 | if (update) {
|
70 | publishPkgNames.push(pkgJson.name)
|
71 | } else {
|
72 | forceUpdatePkgs.push({
|
73 | name: pkgJson.name,
|
74 | value: pkgJson.name,
|
75 | version: pkgJson.version,
|
76 | pkgPath,
|
77 | pkgJson,
|
78 | update,
|
79 | })
|
80 | }
|
81 | }
|
82 | pkg.name = pkg.pkgJson.name
|
83 |
|
84 | return pkg
|
85 | },
|
86 | })
|
87 |
|
88 | if (publishPkgNames.length) {
|
89 | signale.info(`有改动的包: ${publishPkgNames.join(', ')}`)
|
90 | } else {
|
91 | signale.info(`没有改动的包`)
|
92 | }
|
93 |
|
94 | let forceUpdateNames = []
|
95 |
|
96 | if (forceUpdatePkgs.length) {
|
97 | const res = await inquirer.prompt([
|
98 | {
|
99 | name: 'isForceUpdate',
|
100 | message: `是否需要强制更新包`,
|
101 | default: false,
|
102 | type: 'confirm',
|
103 | },
|
104 | {
|
105 | name: 'forceUpdateNames',
|
106 | message: `选择强制更新的包`,
|
107 | type: 'checkbox',
|
108 | choices: forceUpdatePkgs,
|
109 | when: (answers) => answers.isForceUpdate,
|
110 | },
|
111 | ])
|
112 |
|
113 | forceUpdateNames = res.forceUpdateNames || []
|
114 | }
|
115 |
|
116 | let publishRepos = []
|
117 |
|
118 | if (forceUpdateNames.length) {
|
119 | publishRepos = getUpdatedRepos(lernaPath, `--force-publish=${forceUpdateNames.join(',')}`)
|
120 | } else {
|
121 | publishRepos = getUpdatedRepos(lernaPath)
|
122 | }
|
123 |
|
124 | if (!publishRepos.length) {
|
125 | signale.warn('没有要更新的包')
|
126 | process.exit(1)
|
127 | }
|
128 | const publishPackages = []
|
129 |
|
130 | pkgs.forEach((pkg) => {
|
131 | const index = publishRepos.indexOf(pkg.name)
|
132 | if (index > -1) {
|
133 | publishPackages.push(pkg)
|
134 | }
|
135 | })
|
136 |
|
137 | try {
|
138 | await runForPkgs({
|
139 | cwd,
|
140 | watch: false,
|
141 | pkgs: publishPackages,
|
142 | rootUserConfig,
|
143 | })
|
144 | } catch (e) {
|
145 | signale.error(e)
|
146 | process.exit(1)
|
147 | }
|
148 |
|
149 | const {useConventionalCommits} = await inquirer.prompt({
|
150 | message: '是否使用常规提交',
|
151 | default: true,
|
152 | type: 'confirm',
|
153 | name: 'useConventionalCommits',
|
154 | })
|
155 |
|
156 | const versionArgs = ['publish', '--include-merged-tags']
|
157 |
|
158 | if (useConventionalCommits) {
|
159 | versionArgs.push('--conventional-commits')
|
160 | }
|
161 |
|
162 | if (publishRepos.length) {
|
163 | versionArgs.push(`--force-publish=${publishRepos.join(',')}`)
|
164 | }
|
165 |
|
166 | signale.info(`要发布的包: ${publishRepos.join(', ')}`)
|
167 | const cp = spawn(lernaPath, versionArgs, {
|
168 | stdio: 'inherit',
|
169 | cwd,
|
170 | })
|
171 | cp.on('error', (err) => {
|
172 | signale.error(err)
|
173 | })
|
174 | cp.on('close', async (code) => {
|
175 | signale.info('code', code)
|
176 | if (code === 1) {
|
177 | signale.error('Failed: lerna publish')
|
178 | process.exit(1)
|
179 | }
|
180 |
|
181 | const {isSyncTaobao} = await inquirer.prompt({
|
182 | message: '是否同步淘宝源',
|
183 | default: true,
|
184 | type: 'confirm',
|
185 | name: 'isSyncTaobao',
|
186 | })
|
187 |
|
188 | if (isSyncTaobao) {
|
189 | syncTaobao(publishRepos, cwd)
|
190 | }
|
191 | })
|
192 | }
|
193 |
|
194 | function syncTaobao(publishRepos = [], cwd = process.cwd()) {
|
195 | if (!publishRepos.length) {
|
196 | signale.error('not find publishRepos')
|
197 | process.exit(1)
|
198 | }
|
199 |
|
200 | signale.info(`同步淘宝源: ${publishRepos.join(', ')}`)
|
201 |
|
202 | const cnpmPath = join(__dirname, '../node_modules/.bin/cnpm')
|
203 |
|
204 | const {status, error} = spawn.sync(cnpmPath, ['sync', ...publishRepos], {
|
205 | stdio: 'inherit',
|
206 | cwd,
|
207 | })
|
208 |
|
209 | if (status === 1) {
|
210 | signale.error(error || 'sync error')
|
211 | process.exit(1)
|
212 | }
|
213 |
|
214 | signale.success('同步成功')
|
215 | }
|
216 |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 |
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | module.exports = publish
|