@liuli-util/cli 3.20.2 → 3.21.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -57,6 +57,10 @@ export interface GhPagesDeployOptions extends Omit<BaseDeployOptions, 'type'> {
57
57
  * 远端分支名,默认为 gh-pages
58
58
  */
59
59
  branch?: string;
60
+ /**
61
+ * 是否增量推送,默认会清理 dest 目录
62
+ */
63
+ add?: boolean;
60
64
  }
61
65
  /**
62
66
  * 将本地静态资源推送到 gh-pages 远端
@@ -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;AASzD,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;CAChB;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;IA4E7C,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;CAkBlD"}
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.20.2",
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 packaged for libraries and CLI applications.\r\n\r\n## Getting started\r\n\r\n### Install\r\n\r\n```sh\r\nyarn add -D @liuli-util/cli # local installation\r\nnpm i -g @liuli-util/cli # install globally\r\n```\r\n\r\n### Bale\r\n\r\n```sh\r\nyarn liuli-cli build lib # package library\r\nyarn liuli-cli build cli # package cli reference program\r\n```\r\n\r\n> Add the `-w` option to start the watch mode of rollup, the packaged dist/ will not be compressed and the dependencies will not be included in the bundle.\r\n\r\n![Monitor 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\nyarn liuli-cli generate <name> --template lib # Generate ts-lib project\r\nyarn liuli-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\nyarn liuli-cli generate\r\n```\r\n\r\n![Liuli-cli interactively create screenshots](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### Sync configuration\r\n\r\n```shell\r\nyarn liuli-cli sync\r\n```\r\n\r\nWhich configuration needs to be synced 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 will include checking the synchronization of the cli itself (if it needs to be used outside of a monorepo), eslint/style-lint etc., and implementing an interactive cli when not configured\r\n\r\n> Note: Currently only the dependencies are synced and no installation is performed\r\n\r\nInteractive initialization synchronization configuration is also supported\r\n\r\n```shell\r\nyarn liuli-cli sync init\r\n```\r\n\r\n## design concept\r\n\r\n- Convention over configuration, configuration should not be provided if possible. VitePress does this too, reference: https://vitepress.vuejs.org/#lighter-page-weight This leads to some constraints, including the following\r\n - When packaging the library, the entry file must be `src/index.ts`, and the export file must be `dist/index.esm.js` and `dist/index.js`\r\n - When packaging the CLI, the entry file must be `src/bin.ts`, and the exit file must be `dist/bin.js`\r\n - All dependencies will be treated as external dependencies when packaging lib, and all dependencies will be bundled when packaging cli\r\n\r\n## FAQ\r\n\r\n### Why not bundle external dependencies\r\n\r\nThe main reason is that you want to leave the bundling work to the final application, avoid bundling the same dependencies repeatedly, and also avoid dealing with the problem of using `worker_threads` directly based on the file system in nodejs.\r\n"
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.skip('测试 GhPagesDeployService', () => {
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)