@liuli-util/cli 3.17.2 → 3.18.0
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +4 -0
- package/README.md +30 -42
- package/README.zh-CN.md +86 -0
- package/dist/bin.js +65 -65
- package/dist/bin.js.map +3 -3
- package/dist/commands/deploy/DeployService.d.ts +25 -7
- package/dist/commands/deploy/DeployService.d.ts.map +1 -1
- package/dist/commands/deploy/util/validate.d.ts +8 -0
- package/dist/commands/deploy/util/validate.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/commands/deploy/DeployService.ts +76 -43
- package/src/commands/deploy/__tests__/DeployService.test.ts +52 -19
- package/src/commands/deploy/util/validate.ts +18 -0
- package/templates/cli/package.json +1 -5
- package/templates/cli/src/bin.ts +1 -1
- package/templates/lib/package.json +3 -10
@@ -22,11 +22,11 @@ export interface BaseDeployOptions {
|
|
22
22
|
debug: boolean;
|
23
23
|
type: DeployTypeEnum;
|
24
24
|
}
|
25
|
-
export
|
25
|
+
export interface SftpDeployOptions extends Omit<BaseDeployOptions, 'type'> {
|
26
|
+
dist: string;
|
26
27
|
dest: string;
|
27
|
-
remote: string;
|
28
28
|
sshConfig: ConnectOptions;
|
29
|
-
}
|
29
|
+
}
|
30
30
|
/**
|
31
31
|
* sftp 集成到远端
|
32
32
|
*/
|
@@ -36,10 +36,28 @@ export declare class SftpDeployService implements IDeployService {
|
|
36
36
|
deploy(): EventExtPromise<void, DeployEvents>;
|
37
37
|
validate(): [isValidate: boolean, errorText: string];
|
38
38
|
}
|
39
|
-
export
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
export interface GhPagesDeployOptions extends Omit<BaseDeployOptions, 'type'> {
|
40
|
+
/**
|
41
|
+
* 推送的本地目录
|
42
|
+
*/
|
43
|
+
dist: string;
|
44
|
+
/**
|
45
|
+
* 推送的远端目录,默认为分支根目录
|
46
|
+
*/
|
47
|
+
dest?: string;
|
48
|
+
/**
|
49
|
+
* 推送的项目 git 地址,默认为当前项目
|
50
|
+
*/
|
51
|
+
repo?: string;
|
52
|
+
/**
|
53
|
+
* 推送的远端,默认为 origin
|
54
|
+
*/
|
55
|
+
remote?: string;
|
56
|
+
/**
|
57
|
+
* 远端分支名,默认为 gh-pages
|
58
|
+
*/
|
59
|
+
branch?: string;
|
60
|
+
}
|
43
61
|
/**
|
44
62
|
* 将本地静态资源推送到 gh-pages 远端
|
45
63
|
*/
|
@@ -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;AAWzD,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;IA8E7C,QAAQ,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC;CAkBlD"}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import { JSONSchemaType } from 'ajv';
|
2
|
+
/**
|
3
|
+
* 使用 ajv 校验数据
|
4
|
+
* @param schema json 模式配置
|
5
|
+
* @param data 校验的数据
|
6
|
+
*/
|
7
|
+
export declare function validate<T>(schema: JSONSchemaType<T>, data: T): [isValid: boolean, errorText: string];
|
8
|
+
//# sourceMappingURL=validate.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../../../src/commands/deploy/util/validate.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,cAAc,EAAE,MAAM,KAAK,CAAA;AAIzC;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,CAQrG"}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@liuli-util/cli",
|
3
|
-
"version": "3.
|
3
|
+
"version": "3.18.0",
|
4
4
|
"description": "一个针对于库和 CLI 应用程序打包的零配置 CLI",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "dist/index.esm.js",
|
@@ -25,6 +25,7 @@
|
|
25
25
|
"@liuli-util/eslint-config-ts": "^0.2.0",
|
26
26
|
"@liuli-util/prettier-standard-config": "^0.1.0",
|
27
27
|
"ajv": "^8.8.2",
|
28
|
+
"ajv-formats": "^2.1.1",
|
28
29
|
"ajv-i18n": "^4.2.0",
|
29
30
|
"chokidar": "^3.5.2",
|
30
31
|
"commander": "^8.2.0",
|
@@ -69,5 +70,5 @@
|
|
69
70
|
"dev": "esno src/bin.ts build cli -w",
|
70
71
|
"start": "esno src/bin.ts"
|
71
72
|
},
|
72
|
-
"readme": "# @liuli-util/cli\r\n\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 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
74
|
}
|
@@ -8,25 +8,12 @@ import localize from 'ajv-i18n/localize'
|
|
8
8
|
import simpleGit from 'simple-git'
|
9
9
|
import { nodeCacheDir } from '../../utils/nodeCacheDir'
|
10
10
|
import { performance, PerformanceObserver } from 'perf_hooks'
|
11
|
+
import { validate } from './util/validate'
|
11
12
|
|
12
13
|
export interface DeployEvents {
|
13
14
|
process(title: string): void
|
14
15
|
}
|
15
16
|
|
16
|
-
/**
|
17
|
-
* 使用 ajv 校验数据
|
18
|
-
* @param schema
|
19
|
-
* @param data
|
20
|
-
*/
|
21
|
-
function ajvValidate(schema: object, data: object): [isValid: boolean, errorText: string] {
|
22
|
-
const ajv = new Ajv({ allErrors: true, messages: false })
|
23
|
-
const res = ajv.validate(schema, data)
|
24
|
-
if (!res) {
|
25
|
-
localize.zh(ajv.errors)
|
26
|
-
}
|
27
|
-
return [res, ajv.errorsText()]
|
28
|
-
}
|
29
|
-
|
30
17
|
/**
|
31
18
|
* 部署服务接口
|
32
19
|
*/
|
@@ -49,9 +36,9 @@ export interface BaseDeployOptions {
|
|
49
36
|
type: DeployTypeEnum
|
50
37
|
}
|
51
38
|
|
52
|
-
export
|
39
|
+
export interface SftpDeployOptions extends Omit<BaseDeployOptions, 'type'> {
|
40
|
+
dist: string
|
53
41
|
dest: string
|
54
|
-
remote: string
|
55
42
|
sshConfig: ConnectOptions
|
56
43
|
}
|
57
44
|
|
@@ -69,38 +56,57 @@ export class SftpDeployService implements IDeployService {
|
|
69
56
|
...this.options.sshConfig,
|
70
57
|
privateKey,
|
71
58
|
})
|
72
|
-
await client.mkdir(this.options.
|
73
|
-
await client.uploadDir(path.resolve(this.options.cwd, this.options.
|
59
|
+
await client.mkdir(this.options.dest, true)
|
60
|
+
await client.uploadDir(path.resolve(this.options.cwd, this.options.dist), this.options.dest)
|
74
61
|
await client.end()
|
75
62
|
})
|
76
63
|
}
|
77
64
|
|
78
65
|
validate(): [isValidate: boolean, errorText: string] {
|
79
|
-
return
|
66
|
+
return validate<SftpDeployOptions>(
|
80
67
|
{
|
81
68
|
type: 'object',
|
82
69
|
properties: {
|
70
|
+
debug: { type: 'boolean' },
|
83
71
|
cwd: { type: 'string' },
|
72
|
+
dist: { type: 'string' },
|
84
73
|
dest: { type: 'string' },
|
85
|
-
remote: { type: 'string' },
|
86
74
|
sshConfig: {
|
87
75
|
type: 'object',
|
88
76
|
properties: {
|
89
77
|
host: { type: 'string' },
|
90
78
|
username: { type: 'string' },
|
91
79
|
},
|
92
|
-
},
|
80
|
+
} as any,
|
93
81
|
},
|
94
|
-
required: ['cwd', '
|
82
|
+
required: ['cwd', 'dist', 'dest', 'sshConfig', 'debug'],
|
95
83
|
},
|
96
84
|
this.options,
|
97
85
|
)
|
98
86
|
}
|
99
87
|
}
|
100
88
|
|
101
|
-
export
|
102
|
-
|
103
|
-
|
89
|
+
export interface GhPagesDeployOptions extends Omit<BaseDeployOptions, 'type'> {
|
90
|
+
/**
|
91
|
+
* 推送的本地目录
|
92
|
+
*/
|
93
|
+
dist: string
|
94
|
+
/**
|
95
|
+
* 推送的远端目录,默认为分支根目录
|
96
|
+
*/
|
97
|
+
dest?: string
|
98
|
+
/**
|
99
|
+
* 推送的项目 git 地址,默认为当前项目
|
100
|
+
*/
|
101
|
+
repo?: string
|
102
|
+
/**
|
103
|
+
* 推送的远端,默认为 origin
|
104
|
+
*/
|
105
|
+
remote?: string
|
106
|
+
/**
|
107
|
+
* 远端分支名,默认为 gh-pages
|
108
|
+
*/
|
109
|
+
branch?: string
|
104
110
|
}
|
105
111
|
|
106
112
|
/**
|
@@ -110,10 +116,10 @@ export class GhPagesDeployService implements IDeployService {
|
|
110
116
|
constructor(private readonly options: GhPagesDeployOptions) {}
|
111
117
|
|
112
118
|
deploy(): EventExtPromise<void, DeployEvents> {
|
113
|
-
const defaultRemote = 'origin'
|
114
|
-
const defaultBranch = 'gh-pages'
|
119
|
+
const defaultRemote = this.options.remote ?? 'origin'
|
120
|
+
const defaultBranch = this.options.branch ?? 'gh-pages'
|
115
121
|
return PromiseUtil.wrapOnEvent(async (events: DeployEvents) => {
|
116
|
-
const obs = new PerformanceObserver((perfObserverList
|
122
|
+
const obs = new PerformanceObserver((perfObserverList) => {
|
117
123
|
if (this.options.debug) {
|
118
124
|
console.log(perfObserverList.getEntries())
|
119
125
|
}
|
@@ -126,25 +132,48 @@ export class GhPagesDeployService implements IDeployService {
|
|
126
132
|
}
|
127
133
|
mark('开始推送')
|
128
134
|
const git = simpleGit(this.options.cwd)
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
135
|
+
if (!this.options.repo) {
|
136
|
+
mark('获取当前项目的远端配置')
|
137
|
+
const originRemote = (await git.getRemotes(true)).find((item) => item.name === defaultRemote)
|
138
|
+
if (!originRemote) {
|
139
|
+
throw new Error('当前目录不是一个 git 项目或没有配置 git remote')
|
140
|
+
}
|
141
|
+
this.options.repo = originRemote.refs.fetch
|
133
142
|
}
|
134
143
|
const ghPagesRoot = path.resolve(nodeCacheDir('liuli-cli'), 'gh-pages')
|
135
|
-
const originRepoName =
|
144
|
+
const originRepoName = this.options.repo.replace(new RegExp('[/:]', 'g'), '_')
|
136
145
|
const localRepoPath = path.resolve(ghPagesRoot, originRepoName)
|
146
|
+
let forcePush = false
|
137
147
|
if (!(await pathExists(localRepoPath))) {
|
138
148
|
mark('克隆项目')
|
139
|
-
|
149
|
+
//如果失败,应该尝试克隆主分支,然后 checkout
|
150
|
+
try {
|
151
|
+
await git.clone(this.options.repo, localRepoPath, {
|
152
|
+
'--branch': defaultBranch,
|
153
|
+
'--single-branch': null,
|
154
|
+
'--depth': 1,
|
155
|
+
})
|
156
|
+
} catch (e) {
|
157
|
+
mark(`未找到 ${defaultBranch} 分支,尝试自动创建`)
|
158
|
+
await git.clone(this.options.repo, localRepoPath, {
|
159
|
+
'--single-branch': null,
|
160
|
+
'--depth': 1,
|
161
|
+
})
|
162
|
+
await git.cwd(localRepoPath)
|
163
|
+
await git.checkout({
|
164
|
+
'--orphan': defaultBranch,
|
165
|
+
})
|
166
|
+
forcePush = true
|
167
|
+
}
|
140
168
|
} else {
|
169
|
+
await git.cwd(localRepoPath)
|
141
170
|
mark('更新项目')
|
142
171
|
await git.pull()
|
143
172
|
}
|
144
173
|
mark('复制文件')
|
145
|
-
const remoteDestPath = path.join(localRepoPath, this.options.
|
174
|
+
const remoteDestPath = path.join(localRepoPath, this.options.dest ?? './')
|
146
175
|
await mkdirp(remoteDestPath)
|
147
|
-
await copy(path.resolve(this.options.cwd, this.options.
|
176
|
+
await copy(path.resolve(this.options.cwd, this.options.dist), remoteDestPath)
|
148
177
|
mark('提交所有文件')
|
149
178
|
await git.cwd(localRepoPath)
|
150
179
|
await git.add('-A')
|
@@ -154,26 +183,30 @@ export class GhPagesDeployService implements IDeployService {
|
|
154
183
|
await git.commit('Updates gh-pages by liuli-cli')
|
155
184
|
}
|
156
185
|
mark('推送到远端')
|
157
|
-
if ((await git.status()).ahead
|
158
|
-
mark('没有更新,跳过推送')
|
159
|
-
} else {
|
186
|
+
if ((await git.status()).ahead > 0 || forcePush) {
|
160
187
|
await git.push(defaultRemote, defaultBranch)
|
161
188
|
mark('完成推送')
|
189
|
+
} else {
|
190
|
+
mark('没有更新,跳过推送')
|
162
191
|
}
|
163
192
|
obs.disconnect()
|
164
193
|
})
|
165
194
|
}
|
166
195
|
|
167
196
|
validate(): [isValid: boolean, errorText: string] {
|
168
|
-
return
|
197
|
+
return validate<GhPagesDeployOptions>(
|
169
198
|
{
|
170
199
|
type: 'object',
|
171
200
|
properties: {
|
201
|
+
debug: { type: 'boolean' },
|
172
202
|
cwd: { type: 'string' },
|
173
|
-
|
174
|
-
|
203
|
+
dist: { type: 'string' },
|
204
|
+
dest: { type: 'string', nullable: true },
|
205
|
+
repo: { type: 'string', nullable: true },
|
206
|
+
remote: { type: 'string', nullable: true },
|
207
|
+
branch: { type: 'string', nullable: true },
|
175
208
|
},
|
176
|
-
required: ['
|
209
|
+
required: ['debug', 'cwd', 'dist'],
|
177
210
|
},
|
178
211
|
this.options,
|
179
212
|
)
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import * as path from 'path'
|
2
|
-
import { mkdirp, remove, writeFile } from 'fs-extra'
|
3
|
-
import { GhPagesDeployService, SftpDeployOptions, SftpDeployService } from '../DeployService'
|
2
|
+
import { mkdirp, remove, unlink, writeFile } from 'fs-extra'
|
3
|
+
import { GhPagesDeployOptions, GhPagesDeployService, SftpDeployOptions, SftpDeployService } from '../DeployService'
|
4
4
|
import { execPromise } from '../util/execPromise'
|
5
|
+
import { nodeCacheDir } from '../../../utils/nodeCacheDir'
|
5
6
|
|
6
7
|
const tempPath = path.resolve(__dirname, '.temp')
|
7
8
|
beforeAll(async () => {
|
@@ -25,14 +26,15 @@ beforeAll(async () => {
|
|
25
26
|
)
|
26
27
|
})
|
27
28
|
|
28
|
-
describe('测试 SftpDeployService', () => {
|
29
|
+
describe.skip('测试 SftpDeployService', () => {
|
29
30
|
const options: SftpDeployOptions = {
|
31
|
+
debug: false,
|
30
32
|
cwd: tempPath,
|
31
|
-
|
32
|
-
|
33
|
+
dist: 'dist',
|
34
|
+
dest: process.env.dest!,
|
33
35
|
sshConfig: {
|
34
|
-
host:
|
35
|
-
username:
|
36
|
+
host: process.env.host,
|
37
|
+
username: process.env.username,
|
36
38
|
},
|
37
39
|
}
|
38
40
|
it('基本示例', async () => {
|
@@ -55,21 +57,52 @@ describe('测试 SftpDeployService', () => {
|
|
55
57
|
})
|
56
58
|
|
57
59
|
describe('测试 GhPagesDeployService', () => {
|
58
|
-
const
|
60
|
+
const options: GhPagesDeployOptions = {
|
61
|
+
debug: false,
|
59
62
|
cwd: tempPath,
|
60
|
-
|
61
|
-
|
63
|
+
dist: 'dist',
|
64
|
+
dest: '/',
|
65
|
+
repo: 'https://github.com/rxliuli/test-git.git',
|
66
|
+
remote: 'origin',
|
67
|
+
branch: 'gh-pages',
|
68
|
+
}
|
69
|
+
const ghPagesDeployService = new GhPagesDeployService(options)
|
70
|
+
const distPath = path.resolve(tempPath, 'dist')
|
71
|
+
const mock = jest.fn().mockImplementation((title) => console.log(title))
|
72
|
+
beforeEach(async () => {
|
73
|
+
await writeFile(
|
74
|
+
path.resolve(distPath, 'index.html'),
|
75
|
+
`<!DOCTYPE html>
|
76
|
+
<html lang="en">
|
77
|
+
<head>
|
78
|
+
<meta charset="UTF-8" />
|
79
|
+
<title>测试部署</title>
|
80
|
+
</head>
|
81
|
+
<body>
|
82
|
+
<h1>测试部署</h1>
|
83
|
+
<p>${Date.now()}</p>
|
84
|
+
</body>
|
85
|
+
</html>
|
86
|
+
`,
|
87
|
+
)
|
88
|
+
mock.mockClear()
|
62
89
|
})
|
63
90
|
it('基本示例', async () => {
|
64
|
-
await ghPagesDeployService.deploy().on('process',
|
91
|
+
await ghPagesDeployService.deploy().on('process', mock)
|
92
|
+
console.log(mock.mock.calls)
|
93
|
+
expect(mock.mock.calls.some((item: string[]) => item.includes('完成推送'))).toBeTruthy()
|
65
94
|
}, 10_000)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
await
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
95
|
+
it('测试没有任何修改', async () => {
|
96
|
+
await writeFile(path.resolve(distPath, 'index.html'), 'test')
|
97
|
+
await ghPagesDeployService.deploy().on('process', mock)
|
98
|
+
await ghPagesDeployService.deploy().on('process', mock)
|
99
|
+
expect(mock.mock.calls.some((item: string[]) => item.includes('没有任何提交,跳过提交'))).toBeTruthy()
|
100
|
+
expect(mock.mock.calls.some((item: string[]) => item.includes('没有更新,跳过推送'))).toBeTruthy()
|
101
|
+
}, 20_000)
|
102
|
+
it('测试首次拉取代码', async () => {
|
103
|
+
const dir = path.resolve(nodeCacheDir('liuli-cli'), 'gh-pages', options.repo!.replace(new RegExp('[/:]', 'g'), '_'))
|
104
|
+
await remove(dir)
|
105
|
+
await ghPagesDeployService.deploy().on('process', mock)
|
106
|
+
expect(mock.mock.calls.some((item: string[]) => item.includes('克隆项目'))).toBeTruthy()
|
74
107
|
}, 10_000)
|
75
108
|
})
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import Ajv, { JSONSchemaType } from 'ajv'
|
2
|
+
import localize from 'ajv-i18n/localize'
|
3
|
+
import formatsPlugin from 'ajv-formats'
|
4
|
+
|
5
|
+
/**
|
6
|
+
* 使用 ajv 校验数据
|
7
|
+
* @param schema json 模式配置
|
8
|
+
* @param data 校验的数据
|
9
|
+
*/
|
10
|
+
export function validate<T>(schema: JSONSchemaType<T>, data: T): [isValid: boolean, errorText: string] {
|
11
|
+
const ajv = new Ajv({ allErrors: true, messages: false })
|
12
|
+
formatsPlugin(ajv)
|
13
|
+
const res = ajv.validate(schema, data)
|
14
|
+
if (!res) {
|
15
|
+
localize.zh(ajv.errors)
|
16
|
+
}
|
17
|
+
return [res, ajv.errorsText()]
|
18
|
+
}
|
@@ -13,18 +13,14 @@
|
|
13
13
|
"bin": {
|
14
14
|
"cli-name": "./bin.js"
|
15
15
|
},
|
16
|
-
"jest": {
|
17
|
-
"preset": "ts-jest"
|
18
|
-
},
|
19
16
|
"dependencies": {
|
20
17
|
"commander": "^8.2.0",
|
21
18
|
"enquirer": "^2.3.6",
|
22
19
|
"fs-extra": "^10.0.0"
|
23
20
|
},
|
24
21
|
"devDependencies": {
|
25
|
-
"@liuli-util/cli": "
|
22
|
+
"@liuli-util/cli": "^3.18.0",
|
26
23
|
"@types/fs-extra": "^9.0.13",
|
27
|
-
"@types/inquirer": "^8.1.2",
|
28
24
|
"@types/jest": "^27.0.2",
|
29
25
|
"@types/lodash": "^4.14.173",
|
30
26
|
"@types/node": "^16.9.6",
|
package/templates/cli/src/bin.ts
CHANGED
@@ -7,19 +7,12 @@
|
|
7
7
|
"types": "dist/index.d.ts",
|
8
8
|
"license": "MIT",
|
9
9
|
"scripts": {
|
10
|
-
"build": "rimraf dist && liuli-cli build
|
11
|
-
"dev": "liuli-cli build
|
12
|
-
},
|
13
|
-
"jest": {
|
14
|
-
"preset": "ts-jest"
|
10
|
+
"build": "rimraf dist && liuli-cli build lib",
|
11
|
+
"dev": "liuli-cli build lib -w"
|
15
12
|
},
|
16
13
|
"devDependencies": {
|
17
|
-
"@liuli-util/cli": "
|
18
|
-
"@types/jest": "^27.0.2",
|
19
|
-
"esno": "^0.9.1",
|
20
|
-
"jest": "^27.2.1",
|
14
|
+
"@liuli-util/cli": "^3.18.0",
|
21
15
|
"rimraf": "^3.0.2",
|
22
|
-
"ts-jest": "^27.0.5",
|
23
16
|
"type-fest": "^2.3.4",
|
24
17
|
"typescript": "^4.4.3"
|
25
18
|
}
|