@liuli-util/cli 3.20.0 → 3.21.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +22 -0
- package/README.md +69 -25
- package/README.zh-CN.md +7 -7
- package/dist/bin.js +43 -43
- package/dist/bin.js.map +2 -2
- package/dist/commands/deploy/DeployService.d.ts +4 -0
- package/dist/commands/deploy/DeployService.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/commands/deploy/DeployService.ts +20 -2
- package/src/commands/deploy/__tests__/DeployService.test.ts +23 -4
- package/src/commands/generate/index.ts +3 -3
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"DeployService.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy/DeployService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAe,MAAM,oBAAoB,CAAA;AACjE,OAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;
|
1
|
+
{"version":3,"file":"DeployService.d.ts","sourceRoot":"","sources":["../../../src/commands/deploy/DeployService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAe,MAAM,oBAAoB,CAAA;AACjE,OAAe,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAUzD,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAAA;IACpD;;OAEG;IACH,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC,CAAA;CAC9C;AAED,oBAAY,cAAc;IACxB,OAAO,aAAa;IACpB,IAAI,SAAS;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,OAAO,CAAA;IACd,IAAI,EAAE,cAAc,CAAA;CACrB;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACxE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,cAAc,CAAA;CAC1B;AAED;;GAEG;AACH,qBAAa,iBAAkB,YAAW,cAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,iBAAiB;IAEvD,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC;IAc7C,QAAQ,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;CAsBrD;AAED,MAAM,WAAW,oBAAqB,SAAQ,IAAI,CAAC,iBAAiB,EAAE,MAAM,CAAC;IAC3E;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAED;;GAEG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,oBAAoB;IAE1D,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,YAAY,CAAC;IAwF7C,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;CAmBlD"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@liuli-util/cli",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.21.0",
|
4
4
|
"description": "一个针对于库和 CLI 应用程序打包的零配置 CLI",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "dist/index.esm.js",
|
@@ -70,5 +70,5 @@
|
|
70
70
|
"test": "jest --all",
|
71
71
|
"lint": "eslint --fix src/**"
|
72
72
|
},
|
73
|
-
"readme": "# @liuli-util/cli\r\n\r\n> [中文](https://github.com/rxliuli/liuli-tools/tree/master/apps/liuli-cli/README.zh-CN.md)\r\n\r\nA zero-configuration CLI
|
73
|
+
"readme": "# @liuli-util/cli\r\n\r\n> [中文](https://github.com/rxliuli/liuli-tools/tree/master/apps/liuli-cli/README.zh-CN.md)\r\n\r\nA zero-configuration CLI for packaging libraries and CLI applications.\r\n\r\n## Getting Started\r\n\r\n### Install\r\n\r\n```sh\r\npnpm i -D @liuli-util/cli # Local installation\r\npnpm i -g @liuli-util/cli # global install\r\n```\r\n\r\n### Packages\r\n\r\n```sh\r\nliuli-cli build lib # Package the library\r\nliuli-cli build cli # Package cli references\r\n```\r\n\r\n> Adding the `-w` option starts the rollup monitoring mode, the dist/ will not be compressed and the dependencies will not be added to the bundle.\r\n\r\n![watchdog mode](https://liuli.dev/images/liuli-cli%20%E7%9B%91%E8%A7%86%E6%A8%A1%E5%BC%8F.gif)\r\n\r\n### Generate\r\n\r\n```sh\r\nliuli-cli generate <name> --template lib # Generate ts-lib project\r\nliuli-cli generate <name> --template cli # generate cli project\r\n```\r\n\r\nutil also supports interactive project creation\r\n\r\n```shell\r\nliuli-cli generate\r\n```\r\n\r\n![liuli-cli interactive creation screenshot](https://liuli.dev/images/liuli-cli%20%E4%BA%A4%E4%BA%92%E5%BC%8F%E5%88%9B%E5%BB%BA%E6%88%AA%E5%9B%BE.gif)\r\n\r\n### Deployment\r\n\r\nSupport for deploying front-end resources to a remote location via sftp/gh-pages, with configuration information in the `deploy` field in package.json\r\n\r\n```sh\r\nliuli deploy\r\n```\r\n\r\npublic\r\n\r\n| configuration | description | defaults |\r\n| ------------- | --------------------------------- | -------- |\r\n| ``type` | deployment type, ``sftp/gh-pgaes` | none |\r\n| `dist` | Static resource directory | None |\r\n| `dest` | deployed remote directory | none |\r\n\r\nsftp\r\n\r\n| configuration | description | defaults |\r\n| -------------------- | ----------------- | -------- |\r\n| `sshConfig.host` | ip address of ssh | |\r\n| `sshConfig.port` | ssh's port number | 22 |\r\n| `sshConfig.username` | ssh's username | |\r\n\r\ngh-pages\r\n\r\n| configuration | description | default |\r\n| ----------------- | ----------------------------------------- | --------------------------------------- |\r\n| `repo?: string` | the git address of the project to push to | the default is the current project |\r\n| `remote?: string` | push remote | defaults to origin |\r\n| `branch?: string` | remote branch name | defaults to gh-pages |\r\n| `add?: boolean` | whether to push incrementally | cleans up the dest directory by default |\r\n\r\nExample configuration for deploying a vuepress documentation site\r\n\r\n```json\r\n{\r\n \"deploy\": {\r\n \"type\": \"gh-pages\",\r\n \"dist\": \"docs/.vuepress/dist\"\r\n }\r\n}\r\n```\r\n\r\n### Sync configuration\r\n\r\n```shell\r\nliuli-cli sync\r\n```\r\n\r\nYou need to specify which configuration to sync in package.json\r\n\r\n```json\r\n{\r\n \"sync\": [\"prettier\", \"workspaces\", \"commitlint\", \"simplehooks\"]\r\n}\r\n```\r\n\r\nCurrently supported configuration items\r\n\r\n- prettier\r\n- commitlint\r\n- simplehooks\r\n- workspaces\r\n- gitignore\r\n- eslint-ts\r\n- eslint-vue-ts\r\n- jest\r\n\r\nFuture goals: By default, this will include checking the cli's own sync (if it needs to be used outside of monorepo), eslint/style-lint, and interactive cli when not configured\r\n\r\n> Note: Currently, only dependencies are synchronized and no installation is performed\r\n\r\nInteractive initialization of synchronized configuration is also supported\r\n\r\n```shell\r\nliuli-cli sync init\r\n```\r\n\r\n## Design philosophy\r\n\r\n- Conventions outweigh configuration and should be left out if possible. VitePress does the same thing, see: https://vitepress.vuejs.org/#lighter-page-weight This leads to a number of constraints, including the following\r\n - The entry file must be `src/index.ts` when packaging the library, and the exit file must be `dist/index.esm.js` and `dist/index.js`\r\n - The entry file must be `src/bin.ts` and the exit file is `dist/bin.js` when packaging the CLI.\r\n - When packaging lib, all dependencies are treated as external dependencies, while when packaging cli, all dependencies are typed into the bundle\r\n\r\n## FAQ\r\n\r\n### Why not bundle external dependencies\r\n\r\nThe main reason is that we want to leave the bundling to the final application, to avoid bundling the same dependencies over and over again, and to avoid dealing with the problem of using `worker_threads` directly on the filesystem in nodejs.\r\n"
|
74
74
|
}
|
@@ -2,11 +2,12 @@ import { EventExtPromise, PromiseUtil } from './util/PromiseUtil'
|
|
2
2
|
import Client, { ConnectOptions } from 'ssh2-sftp-client'
|
3
3
|
import * as path from 'path'
|
4
4
|
import * as os from 'os'
|
5
|
-
import { copy, mkdirp, pathExists, readFile } from 'fs-extra'
|
5
|
+
import { copy, emptyDir, mkdirp, pathExists, readdir, readFile, remove } from 'fs-extra'
|
6
6
|
import simpleGit from 'simple-git'
|
7
7
|
import { nodeCacheDir } from '../../utils/nodeCacheDir'
|
8
8
|
import { performance, PerformanceObserver } from 'perf_hooks'
|
9
9
|
import { validate } from './util/validate'
|
10
|
+
import { AsyncArray } from '../../utils'
|
10
11
|
|
11
12
|
export interface DeployEvents {
|
12
13
|
process(title: string): void
|
@@ -105,6 +106,10 @@ export interface GhPagesDeployOptions extends Omit<BaseDeployOptions, 'type'> {
|
|
105
106
|
* 远端分支名,默认为 gh-pages
|
106
107
|
*/
|
107
108
|
branch?: string
|
109
|
+
/**
|
110
|
+
* 是否增量推送,默认会清理 dest 目录
|
111
|
+
*/
|
112
|
+
add?: boolean
|
108
113
|
}
|
109
114
|
|
110
115
|
/**
|
@@ -170,8 +175,20 @@ export class GhPagesDeployService implements IDeployService {
|
|
170
175
|
'--allow-unrelated-histories': null,
|
171
176
|
})
|
172
177
|
}
|
178
|
+
const remoteDestPath = path.resolve(path.join(localRepoPath, this.options.dest ?? './'))
|
179
|
+
if (!this.options.add) {
|
180
|
+
mark('清理文件')
|
181
|
+
if (remoteDestPath === localRepoPath) {
|
182
|
+
const whiteList = ['.git']
|
183
|
+
await AsyncArray.forEach(
|
184
|
+
(await readdir(remoteDestPath)).filter((name) => !whiteList.includes(name)),
|
185
|
+
(name) => remove(path.resolve(remoteDestPath, name)),
|
186
|
+
)
|
187
|
+
} else {
|
188
|
+
await emptyDir(remoteDestPath)
|
189
|
+
}
|
190
|
+
}
|
173
191
|
mark('复制文件')
|
174
|
-
const remoteDestPath = path.join(localRepoPath, this.options.dest ?? './')
|
175
192
|
await mkdirp(remoteDestPath)
|
176
193
|
await copy(path.resolve(this.options.cwd, this.options.dist), remoteDestPath)
|
177
194
|
mark('提交所有文件')
|
@@ -201,6 +218,7 @@ export class GhPagesDeployService implements IDeployService {
|
|
201
218
|
repo: { type: 'string', nullable: true },
|
202
219
|
remote: { type: 'string', nullable: true },
|
203
220
|
branch: { type: 'string', nullable: true },
|
221
|
+
add: { type: 'boolean', nullable: true },
|
204
222
|
},
|
205
223
|
required: ['debug', 'cwd', 'dist'],
|
206
224
|
},
|
@@ -55,7 +55,7 @@ describe.skip('测试 SftpDeployService', () => {
|
|
55
55
|
})
|
56
56
|
})
|
57
57
|
|
58
|
-
describe
|
58
|
+
describe('测试 GhPagesDeployService', () => {
|
59
59
|
const options: GhPagesDeployOptions = {
|
60
60
|
debug: false,
|
61
61
|
cwd: tempPath,
|
@@ -86,19 +86,38 @@ describe.skip('测试 GhPagesDeployService', () => {
|
|
86
86
|
)
|
87
87
|
mock.mockClear()
|
88
88
|
})
|
89
|
-
it('基本示例', async () => {
|
89
|
+
it.skip('基本示例', async () => {
|
90
|
+
await ghPagesDeployService.deploy().on('process', mock)
|
91
|
+
console.log(mock.mock.calls)
|
92
|
+
expect(mock.mock.calls.some((item: string[]) => item.includes('完成推送'))).toBeTruthy()
|
93
|
+
}, 10_000)
|
94
|
+
it.skip('测试推送到子目录', async () => {
|
95
|
+
const ghPagesDeployService = new GhPagesDeployService({
|
96
|
+
...options,
|
97
|
+
dest: '/test',
|
98
|
+
})
|
99
|
+
await ghPagesDeployService.deploy().on('process', mock)
|
100
|
+
console.log(mock.mock.calls)
|
101
|
+
expect(mock.mock.calls.some((item: string[]) => item.includes('完成推送'))).toBeTruthy()
|
102
|
+
}, 10_000)
|
103
|
+
it('测试增量推送', async () => {
|
104
|
+
const ghPagesDeployService = new GhPagesDeployService({
|
105
|
+
...options,
|
106
|
+
dist: './',
|
107
|
+
add: true,
|
108
|
+
})
|
90
109
|
await ghPagesDeployService.deploy().on('process', mock)
|
91
110
|
console.log(mock.mock.calls)
|
92
111
|
expect(mock.mock.calls.some((item: string[]) => item.includes('完成推送'))).toBeTruthy()
|
93
112
|
}, 10_000)
|
94
|
-
it('测试没有任何修改', async () => {
|
113
|
+
it.skip('测试没有任何修改', async () => {
|
95
114
|
await writeFile(path.resolve(distPath, 'index.html'), 'test')
|
96
115
|
await ghPagesDeployService.deploy().on('process', mock)
|
97
116
|
await ghPagesDeployService.deploy().on('process', mock)
|
98
117
|
expect(mock.mock.calls.some((item: string[]) => item.includes('没有任何提交,跳过提交'))).toBeTruthy()
|
99
118
|
expect(mock.mock.calls.some((item: string[]) => item.includes('没有更新,跳过推送'))).toBeTruthy()
|
100
119
|
}, 20_000)
|
101
|
-
it('测试首次拉取代码', async () => {
|
120
|
+
it.skip('测试首次拉取代码', async () => {
|
102
121
|
const dir = path.resolve(nodeCacheDir('liuli-cli'), 'gh-pages', options.repo!.replace(new RegExp('[/:]', 'g'), '_'))
|
103
122
|
await remove(dir)
|
104
123
|
await ghPagesDeployService.deploy().on('process', mock)
|
@@ -13,11 +13,11 @@ export const generateCommand = new Command()
|
|
13
13
|
.command('generate [dest]')
|
14
14
|
.description('生成一些初始项目')
|
15
15
|
.addOption(templateOption)
|
16
|
-
.option('--init-sync', '是否同步初始化', true)
|
17
|
-
.action(async (dest, options: Pick<GenerateConfig, 'template' | '
|
16
|
+
.option('--init-sync [initSync]', '是否同步初始化', 'true')
|
17
|
+
.action(async (dest, options: Pick<GenerateConfig, 'template'> & { initSync: 'true' | 'false' }) => {
|
18
18
|
await generateProgram.generate({
|
19
19
|
...options,
|
20
|
+
initSync: options.initSync === 'true',
|
20
21
|
dest: dest,
|
21
|
-
initSync: options.initSync,
|
22
22
|
})
|
23
23
|
})
|