@farris/cli 1.0.28 → 2.0.0
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/bin/index.js +2 -0
- package/package.json +32 -18
- package/templates/mobile/.eslintrc.cjs +15 -0
- package/templates/mobile/.prettierrc.json +8 -0
- package/templates/mobile/farris.config.mjs +24 -0
- package/templates/mobile/index.html +12 -0
- package/templates/mobile/package.json +29 -0
- package/templates/mobile/src/App.vue +80 -0
- package/templates/mobile/src/components/TheButton.vue +3 -0
- package/templates/mobile/src/main.ts +12 -0
- package/templates/mobile/src/router/index.ts +23 -0
- package/templates/mobile/src/views/AboutView.vue +15 -0
- package/templates/mobile/src/views/HomeView.vue +9 -0
- package/templates/mobile/tsconfig.json +18 -0
- package/templates/web/.eslintrc.cjs +15 -0
- package/templates/web/.prettierrc.json +8 -0
- package/templates/web/farris.config.mjs +24 -0
- package/templates/web/index.html +12 -0
- package/templates/web/package.json +29 -0
- package/templates/web/src/App.vue +80 -0
- package/templates/web/src/components/TheButton.vue +3 -0
- package/templates/web/src/main.ts +10 -0
- package/templates/web/src/router/index.ts +23 -0
- package/templates/web/src/views/AboutView.vue +15 -0
- package/templates/web/src/views/HomeView.vue +9 -0
- package/templates/web/tsconfig.json +18 -0
- package/README.md +0 -2
- package/ci/cli.js +0 -467
package/bin/index.js
ADDED
package/package.json
CHANGED
@@ -1,26 +1,40 @@
|
|
1
1
|
{
|
2
2
|
"name": "@farris/cli",
|
3
|
-
"
|
4
|
-
"
|
5
|
-
"
|
6
|
-
"
|
7
|
-
|
3
|
+
"private": false,
|
4
|
+
"version": "2.0.0",
|
5
|
+
"type": "module",
|
6
|
+
"typings": "lib/index.d.ts",
|
7
|
+
"bin": {
|
8
|
+
"farris-cli": "./bin/index.js"
|
8
9
|
},
|
9
|
-
"
|
10
|
-
"
|
11
|
-
"url": "https://git.iec.io/webadp/farris-cli.git"
|
10
|
+
"engines": {
|
11
|
+
"node": ">=16.0.0"
|
12
12
|
},
|
13
|
-
"
|
14
|
-
"
|
15
|
-
"CLI"
|
16
|
-
],
|
17
|
-
"bin": {
|
18
|
-
"farris": "ci/cli.js"
|
13
|
+
"scripts": {
|
14
|
+
"build": "rimraf ./lib && tsc"
|
19
15
|
},
|
20
|
-
"
|
21
|
-
|
16
|
+
"files": [
|
17
|
+
"lib",
|
18
|
+
"templates",
|
19
|
+
"bin.js"
|
20
|
+
],
|
21
|
+
"license": "MIT",
|
22
22
|
"dependencies": {
|
23
|
-
"
|
24
|
-
"
|
23
|
+
"@types/inquirer": "^9.0.7",
|
24
|
+
"@vitejs/plugin-vue": "^4.0.0",
|
25
|
+
"@vitejs/plugin-vue-jsx": "^3.0.0",
|
26
|
+
"commander": "^9.4.0",
|
27
|
+
"esbuild": "^0.23.0",
|
28
|
+
"esbuild-sass-plugin": "^3.3.1",
|
29
|
+
"inquirer": "^9.3.0",
|
30
|
+
"ora": "^8.0.1",
|
31
|
+
"typescript": "^4.6.4",
|
32
|
+
"vite": "^4.4.1",
|
33
|
+
"vite-plugin-dts": "^3.9.1"
|
34
|
+
},
|
35
|
+
"devDependencies": {
|
36
|
+
"@types/inquirer": "^9.0.7",
|
37
|
+
"rimraf": "^5.0.7",
|
38
|
+
"vue": "^3.2.37"
|
25
39
|
}
|
26
40
|
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/* eslint-env node */
|
2
|
+
require('@rushstack/eslint-patch/modern-module-resolution')
|
3
|
+
|
4
|
+
module.exports = {
|
5
|
+
root: true,
|
6
|
+
'extends': [
|
7
|
+
'plugin:vue/vue3-essential',
|
8
|
+
'eslint:recommended',
|
9
|
+
'@vue/eslint-config-typescript',
|
10
|
+
'@vue/eslint-config-prettier/skip-formatting'
|
11
|
+
],
|
12
|
+
parserOptions: {
|
13
|
+
ecmaVersion: 'latest'
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { fileURLToPath, URL } from 'node:url';
|
2
|
+
|
3
|
+
export default {
|
4
|
+
format: "<%= format %>",
|
5
|
+
// 输出目录 App模式默认值 './dist' Lib模式 './lib'
|
6
|
+
// outDir: fileURLToPath(new URL('./dist', import.meta.url)),
|
7
|
+
// 最小化 默认值 true
|
8
|
+
minify: true,
|
9
|
+
// 外部依赖排除项 默认值 { include: [], exclude: [] }
|
10
|
+
// externals: {
|
11
|
+
// include: [],
|
12
|
+
// exclude: []
|
13
|
+
// },
|
14
|
+
// 是否排除 package.json 中 dependencies和 peerDependencies 依赖的包; App模式默认值 false Lib模式默认值 true
|
15
|
+
externalDependencies: false,
|
16
|
+
// 路径别名 默认值 null
|
17
|
+
alias: [
|
18
|
+
{ find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) }
|
19
|
+
],
|
20
|
+
// 插件 默认值 [vue(), vueJsx()] 不要重复添加
|
21
|
+
// plugins: [],
|
22
|
+
// viteConfig 配置项
|
23
|
+
viteConfig: {}
|
24
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>Vite App</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div id="app"></div>
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
11
|
+
</body>
|
12
|
+
</html>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"name": "<%= name %>",
|
3
|
+
"version": "0.0.0",
|
4
|
+
"private": true,
|
5
|
+
"type": "module",
|
6
|
+
"scripts": {
|
7
|
+
"dev": "farris-cli dev",
|
8
|
+
"build": "farris-cli build",
|
9
|
+
"preview": "farris-cli preview",
|
10
|
+
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
11
|
+
"format": "prettier --write src/"
|
12
|
+
},
|
13
|
+
"dependencies": {
|
14
|
+
"@farris/mobile-ui-vue": "latest",
|
15
|
+
"vue": "^3.4.29",
|
16
|
+
"vue-router": "^4.3.0"
|
17
|
+
},
|
18
|
+
"devDependencies": {
|
19
|
+
"@farris/cli": "<%= cliVersion %>",
|
20
|
+
"@rushstack/eslint-patch": "^1.8.0",
|
21
|
+
"@vue/eslint-config-prettier": "^9.0.0",
|
22
|
+
"@vue/eslint-config-typescript": "^13.0.0",
|
23
|
+
"@vue/tsconfig": "^0.5.1",
|
24
|
+
"eslint": "^8.57.0",
|
25
|
+
"eslint-plugin-vue": "^9.23.0",
|
26
|
+
"prettier": "^3.2.5",
|
27
|
+
"typescript": "~5.4.0"
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
import { RouterLink, RouterView } from 'vue-router'
|
3
|
+
</script>
|
4
|
+
|
5
|
+
<template>
|
6
|
+
<header>
|
7
|
+
<div class="wrapper">
|
8
|
+
<nav>
|
9
|
+
<RouterLink to="/">Home</RouterLink>
|
10
|
+
<RouterLink to="/about">About</RouterLink>
|
11
|
+
</nav>
|
12
|
+
</div>
|
13
|
+
</header>
|
14
|
+
|
15
|
+
<RouterView />
|
16
|
+
</template>
|
17
|
+
|
18
|
+
<style scoped>
|
19
|
+
header {
|
20
|
+
line-height: 1.5;
|
21
|
+
max-height: 100vh;
|
22
|
+
}
|
23
|
+
|
24
|
+
.logo {
|
25
|
+
display: block;
|
26
|
+
margin: 0 auto 2rem;
|
27
|
+
}
|
28
|
+
|
29
|
+
nav {
|
30
|
+
width: 100%;
|
31
|
+
font-size: 12px;
|
32
|
+
text-align: center;
|
33
|
+
margin-top: 2rem;
|
34
|
+
}
|
35
|
+
|
36
|
+
nav a.router-link-exact-active {
|
37
|
+
color: var(--color-text);
|
38
|
+
}
|
39
|
+
|
40
|
+
nav a.router-link-exact-active:hover {
|
41
|
+
background-color: transparent;
|
42
|
+
}
|
43
|
+
|
44
|
+
nav a {
|
45
|
+
display: inline-block;
|
46
|
+
padding: 0 1rem;
|
47
|
+
border-left: 1px solid var(--color-border);
|
48
|
+
}
|
49
|
+
|
50
|
+
nav a:first-of-type {
|
51
|
+
border: 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
@media (min-width: 1024px) {
|
55
|
+
header {
|
56
|
+
display: flex;
|
57
|
+
place-items: center;
|
58
|
+
padding-right: calc(var(--section-gap) / 2);
|
59
|
+
}
|
60
|
+
|
61
|
+
.logo {
|
62
|
+
margin: 0 2rem 0 0;
|
63
|
+
}
|
64
|
+
|
65
|
+
header .wrapper {
|
66
|
+
display: flex;
|
67
|
+
place-items: flex-start;
|
68
|
+
flex-wrap: wrap;
|
69
|
+
}
|
70
|
+
|
71
|
+
nav {
|
72
|
+
text-align: left;
|
73
|
+
margin-left: -1rem;
|
74
|
+
font-size: 1rem;
|
75
|
+
|
76
|
+
padding: 1rem 0;
|
77
|
+
margin-top: 1rem;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
</style>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { createApp } from 'vue'
|
2
|
+
import FarrisVue from '@farris/mobile-ui-vue'
|
3
|
+
import App from './App.vue'
|
4
|
+
import router from './router'
|
5
|
+
|
6
|
+
import '@farris/mobile-ui-vue/style.css'
|
7
|
+
|
8
|
+
const app = createApp(App)
|
9
|
+
|
10
|
+
app.use(router).use(FarrisVue)
|
11
|
+
|
12
|
+
app.mount('#app')
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
2
|
+
import HomeView from '../views/HomeView.vue'
|
3
|
+
|
4
|
+
const router = createRouter({
|
5
|
+
history: createWebHistory(import.meta.env.BASE_URL),
|
6
|
+
routes: [
|
7
|
+
{
|
8
|
+
path: '/',
|
9
|
+
name: 'home',
|
10
|
+
component: HomeView
|
11
|
+
},
|
12
|
+
{
|
13
|
+
path: '/about',
|
14
|
+
name: 'about',
|
15
|
+
// route level code-splitting
|
16
|
+
// this generates a separate chunk (About.[hash].js) for this route
|
17
|
+
// which is lazy-loaded when the route is visited.
|
18
|
+
component: () => import('../views/AboutView.vue')
|
19
|
+
}
|
20
|
+
]
|
21
|
+
})
|
22
|
+
|
23
|
+
export default router
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
3
|
+
"include": [
|
4
|
+
"env.d.ts",
|
5
|
+
"src/**/*",
|
6
|
+
"src/**/*.vue"
|
7
|
+
],
|
8
|
+
"compilerOptions": {
|
9
|
+
"composite": true,
|
10
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
11
|
+
"baseUrl": ".",
|
12
|
+
"paths": {
|
13
|
+
"@/*": [
|
14
|
+
"./src/*"
|
15
|
+
]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/* eslint-env node */
|
2
|
+
require('@rushstack/eslint-patch/modern-module-resolution')
|
3
|
+
|
4
|
+
module.exports = {
|
5
|
+
root: true,
|
6
|
+
'extends': [
|
7
|
+
'plugin:vue/vue3-essential',
|
8
|
+
'eslint:recommended',
|
9
|
+
'@vue/eslint-config-typescript',
|
10
|
+
'@vue/eslint-config-prettier/skip-formatting'
|
11
|
+
],
|
12
|
+
parserOptions: {
|
13
|
+
ecmaVersion: 'latest'
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
import { fileURLToPath, URL } from 'node:url';
|
2
|
+
|
3
|
+
export default {
|
4
|
+
format: "<%= format %>",
|
5
|
+
// 输出目录 App模式默认值 './dist' Lib模式 './lib'
|
6
|
+
// outDir: fileURLToPath(new URL('./dist', import.meta.url)),
|
7
|
+
// 最小化 默认值 true
|
8
|
+
minify: true,
|
9
|
+
// 外部依赖排除项 默认值 { include: [], exclude: [] }
|
10
|
+
// externals: {
|
11
|
+
// include: [],
|
12
|
+
// exclude: []
|
13
|
+
// },
|
14
|
+
// 是否排除 package.json 中 dependencies和 peerDependencies 依赖的包; App模式默认值 false Lib模式默认值 true
|
15
|
+
externalDependencies: false,
|
16
|
+
// 路径别名 默认值 null
|
17
|
+
alias: [
|
18
|
+
{ find: '@', replacement: fileURLToPath(new URL('./src', import.meta.url)) }
|
19
|
+
],
|
20
|
+
// 插件 默认值 [vue(), vueJsx()] 不要重复添加
|
21
|
+
// plugins: [],
|
22
|
+
// viteConfig 配置项
|
23
|
+
viteConfig: {}
|
24
|
+
}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="UTF-8">
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6
|
+
<title>Vite App</title>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div id="app"></div>
|
10
|
+
<script type="module" src="/src/main.ts"></script>
|
11
|
+
</body>
|
12
|
+
</html>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"name": "<%= name %>",
|
3
|
+
"version": "0.0.0",
|
4
|
+
"private": true,
|
5
|
+
"type": "module",
|
6
|
+
"scripts": {
|
7
|
+
"dev": "farris-cli dev",
|
8
|
+
"build": "farris-cli build",
|
9
|
+
"preview": "farris-cli preview",
|
10
|
+
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore",
|
11
|
+
"format": "prettier --write src/"
|
12
|
+
},
|
13
|
+
"dependencies": {
|
14
|
+
"@farris/ui-vue": "latest",
|
15
|
+
"vue": "^3.4.29",
|
16
|
+
"vue-router": "^4.3.0"
|
17
|
+
},
|
18
|
+
"devDependencies": {
|
19
|
+
"@farris/cli": "<%= cliVersion %>",
|
20
|
+
"@rushstack/eslint-patch": "^1.8.0",
|
21
|
+
"@vue/eslint-config-prettier": "^9.0.0",
|
22
|
+
"@vue/eslint-config-typescript": "^13.0.0",
|
23
|
+
"@vue/tsconfig": "^0.5.1",
|
24
|
+
"eslint": "^8.57.0",
|
25
|
+
"eslint-plugin-vue": "^9.23.0",
|
26
|
+
"prettier": "^3.2.5",
|
27
|
+
"typescript": "~5.4.0"
|
28
|
+
}
|
29
|
+
}
|
@@ -0,0 +1,80 @@
|
|
1
|
+
<script setup lang="ts">
|
2
|
+
import { RouterLink, RouterView } from 'vue-router'
|
3
|
+
</script>
|
4
|
+
|
5
|
+
<template>
|
6
|
+
<header>
|
7
|
+
<div class="wrapper">
|
8
|
+
<nav>
|
9
|
+
<RouterLink to="/">Home</RouterLink>
|
10
|
+
<RouterLink to="/about">About</RouterLink>
|
11
|
+
</nav>
|
12
|
+
</div>
|
13
|
+
</header>
|
14
|
+
|
15
|
+
<RouterView />
|
16
|
+
</template>
|
17
|
+
|
18
|
+
<style scoped>
|
19
|
+
header {
|
20
|
+
line-height: 1.5;
|
21
|
+
max-height: 100vh;
|
22
|
+
}
|
23
|
+
|
24
|
+
.logo {
|
25
|
+
display: block;
|
26
|
+
margin: 0 auto 2rem;
|
27
|
+
}
|
28
|
+
|
29
|
+
nav {
|
30
|
+
width: 100%;
|
31
|
+
font-size: 12px;
|
32
|
+
text-align: center;
|
33
|
+
margin-top: 2rem;
|
34
|
+
}
|
35
|
+
|
36
|
+
nav a.router-link-exact-active {
|
37
|
+
color: var(--color-text);
|
38
|
+
}
|
39
|
+
|
40
|
+
nav a.router-link-exact-active:hover {
|
41
|
+
background-color: transparent;
|
42
|
+
}
|
43
|
+
|
44
|
+
nav a {
|
45
|
+
display: inline-block;
|
46
|
+
padding: 0 1rem;
|
47
|
+
border-left: 1px solid var(--color-border);
|
48
|
+
}
|
49
|
+
|
50
|
+
nav a:first-of-type {
|
51
|
+
border: 0;
|
52
|
+
}
|
53
|
+
|
54
|
+
@media (min-width: 1024px) {
|
55
|
+
header {
|
56
|
+
display: flex;
|
57
|
+
place-items: center;
|
58
|
+
padding-right: calc(var(--section-gap) / 2);
|
59
|
+
}
|
60
|
+
|
61
|
+
.logo {
|
62
|
+
margin: 0 2rem 0 0;
|
63
|
+
}
|
64
|
+
|
65
|
+
header .wrapper {
|
66
|
+
display: flex;
|
67
|
+
place-items: flex-start;
|
68
|
+
flex-wrap: wrap;
|
69
|
+
}
|
70
|
+
|
71
|
+
nav {
|
72
|
+
text-align: left;
|
73
|
+
margin-left: -1rem;
|
74
|
+
font-size: 1rem;
|
75
|
+
|
76
|
+
padding: 1rem 0;
|
77
|
+
margin-top: 1rem;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
</style>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
2
|
+
import HomeView from '../views/HomeView.vue'
|
3
|
+
|
4
|
+
const router = createRouter({
|
5
|
+
history: createWebHistory(import.meta.env.BASE_URL),
|
6
|
+
routes: [
|
7
|
+
{
|
8
|
+
path: '/',
|
9
|
+
name: 'home',
|
10
|
+
component: HomeView
|
11
|
+
},
|
12
|
+
{
|
13
|
+
path: '/about',
|
14
|
+
name: 'about',
|
15
|
+
// route level code-splitting
|
16
|
+
// this generates a separate chunk (About.[hash].js) for this route
|
17
|
+
// which is lazy-loaded when the route is visited.
|
18
|
+
component: () => import('../views/AboutView.vue')
|
19
|
+
}
|
20
|
+
]
|
21
|
+
})
|
22
|
+
|
23
|
+
export default router
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
3
|
+
"include": [
|
4
|
+
"env.d.ts",
|
5
|
+
"src/**/*",
|
6
|
+
"src/**/*.vue"
|
7
|
+
],
|
8
|
+
"compilerOptions": {
|
9
|
+
"composite": true,
|
10
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
11
|
+
"baseUrl": ".",
|
12
|
+
"paths": {
|
13
|
+
"@/*": [
|
14
|
+
"./src/*"
|
15
|
+
]
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
package/README.md
DELETED
package/ci/cli.js
DELETED
@@ -1,467 +0,0 @@
|
|
1
|
-
#!/usr/bin/env node
|
2
|
-
|
3
|
-
'use strict';
|
4
|
-
|
5
|
-
const fs = require('fs');
|
6
|
-
const path = require('path');
|
7
|
-
const log = require("npmlog");
|
8
|
-
const moment = require("moment");
|
9
|
-
const childProcess = require("@lerna/child-process");
|
10
|
-
const { Project } = require("@lerna/project");
|
11
|
-
|
12
|
-
|
13
|
-
const yargs = require('yargs/yargs');
|
14
|
-
const cli = yargs(process.argv.slice(2), process.cwd())
|
15
|
-
|
16
|
-
cli
|
17
|
-
.command(
|
18
|
-
'check',
|
19
|
-
'check file changes from last commit.',
|
20
|
-
(yargs) => {
|
21
|
-
return yargs;
|
22
|
-
},
|
23
|
-
(argv) => {
|
24
|
-
const projectPath = argv.project;
|
25
|
-
const lastCommit = getLastCommit();
|
26
|
-
console.log(`last commit ${lastCommit}`);
|
27
|
-
checkProjectChanges(projectPath, latestMessage);
|
28
|
-
}
|
29
|
-
)
|
30
|
-
.command(
|
31
|
-
'prerelease',
|
32
|
-
'Update package prerelease version when package has changed.',
|
33
|
-
(yargs) => {
|
34
|
-
return yargs;
|
35
|
-
},
|
36
|
-
(argv) => {
|
37
|
-
// 读取预发布工程路径
|
38
|
-
const project = argv.project;
|
39
|
-
// 读取commit url地址
|
40
|
-
const url = argv.url;
|
41
|
-
// 读取是否预发布全部工程
|
42
|
-
const prereleaseAll = argv.all;
|
43
|
-
if (prereleaseAll) {
|
44
|
-
console.log('Prerelease all.');
|
45
|
-
// 发布所有变更的项目
|
46
|
-
return publish(url, 'prerelease');
|
47
|
-
} else if (project) {
|
48
|
-
let chain = Promise.resolve();
|
49
|
-
const lastCommit = getLastCommit();
|
50
|
-
console.log(`last commit ${lastCommit}`);
|
51
|
-
chain = chain.then(() => checkProjectChanges(project, lastCommit));
|
52
|
-
chain = chain.then((hasChanged) => {
|
53
|
-
const projectInfo = { 'project': { 'path': project } };
|
54
|
-
if (hasChanged) {
|
55
|
-
return updateProjectVersion(projectInfo, 'prerelease')
|
56
|
-
}
|
57
|
-
});
|
58
|
-
} else {
|
59
|
-
console.log('You must provide param of either --all or --project.')
|
60
|
-
}
|
61
|
-
}
|
62
|
-
)
|
63
|
-
.command(
|
64
|
-
'patch',
|
65
|
-
'Update package patch version when package has changed.',
|
66
|
-
(yargs) => {
|
67
|
-
return yargs;
|
68
|
-
},
|
69
|
-
(argv) => {
|
70
|
-
const project = argv.project;
|
71
|
-
const url = argv.url;
|
72
|
-
const patchAll = argv.all;
|
73
|
-
if (patchAll) {
|
74
|
-
return publish(url, 'patch');
|
75
|
-
} else if (project) {
|
76
|
-
let chain = Promise.resolve();
|
77
|
-
const lastCommit = getLastCommit();
|
78
|
-
console.log(`last commit ${lastCommit}`);
|
79
|
-
chain = chain.then(() => checkProjectChanges(project, lastCommit));
|
80
|
-
chain = chain.then((hasChanged) => {
|
81
|
-
if (hasChanged) {
|
82
|
-
const projectInfo = { 'project': { 'path': project } };
|
83
|
-
return updateProjectVersion(projectInfo, 'patch')
|
84
|
-
}
|
85
|
-
});
|
86
|
-
} else {
|
87
|
-
console.log('You must provide param of either --all or --project.')
|
88
|
-
}
|
89
|
-
}
|
90
|
-
)
|
91
|
-
.command(
|
92
|
-
'publish',
|
93
|
-
'Publish package which has changed sence last commit.',
|
94
|
-
(yargs) => {
|
95
|
-
return yargs;
|
96
|
-
},
|
97
|
-
(argv) => {
|
98
|
-
const project = argv.project;
|
99
|
-
let chain = Promise.resolve();
|
100
|
-
const lastCommit = getLastCommit();
|
101
|
-
console.log(`last commit ${lastCommit}`);
|
102
|
-
chain = chain.then(() => checkProjectChanges(project, lastCommit));
|
103
|
-
chain = chain.then((hasChanged) => {
|
104
|
-
if (hasChanged) {
|
105
|
-
return publish(project)
|
106
|
-
}
|
107
|
-
});
|
108
|
-
}
|
109
|
-
)
|
110
|
-
.command(
|
111
|
-
'publishAll',
|
112
|
-
'Publish all packages that have changed sence latst publish.',
|
113
|
-
(yargs) => {
|
114
|
-
return yargs;
|
115
|
-
},
|
116
|
-
(argv) => {
|
117
|
-
const projectPath = argv.project;
|
118
|
-
const url = argv.url;
|
119
|
-
publishAll(url);
|
120
|
-
}
|
121
|
-
)
|
122
|
-
.argv;
|
123
|
-
|
124
|
-
/**
|
125
|
-
* @param {import("@lerna/child-process").ExecOpts} execOpts
|
126
|
-
*/
|
127
|
-
function getLastCommit() {
|
128
|
-
if (hasTags()) {
|
129
|
-
console.log("getLastTagInBranch");
|
130
|
-
return childProcess.execSync("git", ["describe", "--tags", "--abbrev=0"]);
|
131
|
-
}
|
132
|
-
console.log("getFirstCommit");
|
133
|
-
return childProcess.execSync("git", ["rev-list", "--max-parents=0", "HEAD"]);
|
134
|
-
}
|
135
|
-
|
136
|
-
/**
|
137
|
-
* @param {import("@lerna/child-process").ExecOpts} opts
|
138
|
-
*/
|
139
|
-
function hasTags() {
|
140
|
-
let result = false;
|
141
|
-
try {
|
142
|
-
result = !!childProcess.execSync("git", ["tag"]);
|
143
|
-
} catch (err) {
|
144
|
-
log.warn("ENOTAGS", "No git tags were reachable from this branch!");
|
145
|
-
log.verbose("hasTags error", err);
|
146
|
-
}
|
147
|
-
log.verbose("hasTags", result);
|
148
|
-
return result;
|
149
|
-
}
|
150
|
-
|
151
|
-
|
152
|
-
/**
|
153
|
-
* 检查指定工程目录下是否存在变更文件
|
154
|
-
* @param {string} projectInfo 目标工程信息
|
155
|
-
* @param {string} lastCommit 最后提交标识
|
156
|
-
* @returns 检查结果
|
157
|
-
*/
|
158
|
-
function checkProjectChanges(projectInfo, lastCommit) {
|
159
|
-
const projectPath = projectInfo.project.path;
|
160
|
-
const packageName = projectInfo.package.name || projectPath;
|
161
|
-
return childProcess
|
162
|
-
// 使用 git diff 命令查询自上传提交以来,目标工程路径下是否有变更的文件
|
163
|
-
.exec("git", ["diff", "--name-only", lastCommit, projectPath])
|
164
|
-
.then((returnValue) => {
|
165
|
-
// 提取命令输出结果中的文件集合ß
|
166
|
-
const changedFiles = returnValue.stdout.split("\n").filter(Boolean);
|
167
|
-
// 根据文件个数确定是否存在变更
|
168
|
-
const hasChanges = changedFiles.length > 0;
|
169
|
-
if (hasChanges) {
|
170
|
-
projectInfo.workspace.hasChanged = hasChanges;
|
171
|
-
console.log(`${packageName} has changed since latest tag ${lastCommit}.`)
|
172
|
-
} else {
|
173
|
-
console.log(`${packageName} has not changed.`)
|
174
|
-
}
|
175
|
-
// 返回检测结果
|
176
|
-
return hasChanges;
|
177
|
-
});
|
178
|
-
}
|
179
|
-
|
180
|
-
/**
|
181
|
-
* 更新指定工程的预发布版本
|
182
|
-
* @param {string} projectInfo 目标工程信息
|
183
|
-
* @returns 更新后的版本
|
184
|
-
*/
|
185
|
-
function updateProjectVersion(projectInfo, updateVersionType) {
|
186
|
-
const projectPath = projectInfo.project.path;
|
187
|
-
if (!projectPath) {
|
188
|
-
throw new Error(`update project version error: you must provide project path by project info object.`)
|
189
|
-
}
|
190
|
-
const updateProjectVersion = ['version', updateVersionType, '--force', '--no-git-tag-version', '--prefix', projectPath];
|
191
|
-
if (updateVersionType === 'prerelease') {
|
192
|
-
updateProjectVersion.push('--preid=beta');
|
193
|
-
}
|
194
|
-
return childProcess
|
195
|
-
// 使用 npm version prerelease 更新指定工程的预发布版本
|
196
|
-
.exec('npm', updateProjectVersion)
|
197
|
-
.then((returnValue) => {
|
198
|
-
// 读取目标工程的package.json文件
|
199
|
-
const packageJsonFilePath = `${projectPath}/package.json`;
|
200
|
-
const packageConfig = JSON.parse(fs.readFileSync(packageJsonFilePath, 'utf-8'));
|
201
|
-
// 提取更新后的版本
|
202
|
-
const updatedVersion = returnValue.stdout;
|
203
|
-
console.log(`Update ${packageConfig.name} prerelease version to ${updatedVersion}.`);
|
204
|
-
const updateResult = {};
|
205
|
-
updateResult[packageConfig.name] = updatedVersion;
|
206
|
-
return updateResult;
|
207
|
-
})
|
208
|
-
}
|
209
|
-
|
210
|
-
function builderVersionChangeMessage(prefix, updatedVersions, suffix = '') {
|
211
|
-
const versionMessage = Object.keys(updatedVersions).reduce((latestMessage, packageName, index, originalArray) => {
|
212
|
-
const version = updatedVersions[packageName];
|
213
|
-
let message = `${packageName} to ${version}`;
|
214
|
-
if (index <= originalArray.length - 2) {
|
215
|
-
message = message + ', ';
|
216
|
-
}
|
217
|
-
return latestMessage = latestMessage + message;
|
218
|
-
}, `${prefix} `)
|
219
|
-
return `${versionMessage} ${suffix}`;
|
220
|
-
}
|
221
|
-
|
222
|
-
function commitVersionChanges(updatedVersions, commitUrl, monoWorkspace, updateVersionType) {
|
223
|
-
const commitMessage = builderVersionChangeMessage('update', updatedVersions, '');
|
224
|
-
if (commitMessage) {
|
225
|
-
const updateWorkspaceVersion = ['version', '--force', '--no-git-tag-version', updateVersionType];
|
226
|
-
if (updateVersionType === 'prerelease') {
|
227
|
-
updateWorkspaceVersion.push('--preid=beta');
|
228
|
-
}
|
229
|
-
console.log(`executing npm ${updateWorkspaceVersion.join(' ')} in root directory.`)
|
230
|
-
childProcess.execSync('npm', updateWorkspaceVersion);
|
231
|
-
|
232
|
-
const packageJsonFilePath = `./package.json`;
|
233
|
-
const packageConfig = JSON.parse(fs.readFileSync(packageJsonFilePath, 'utf-8'));
|
234
|
-
monoWorkspace.version = packageConfig.version;
|
235
|
-
|
236
|
-
// 向git缓冲区中添加变更
|
237
|
-
childProcess.execSync('git', ['add', '.']);
|
238
|
-
// 提交变更记录
|
239
|
-
childProcess.execSync('git', ['commit', '-m', `Update workspace version to v${packageConfig.version} for ${commitMessage}. [skip ci]`]);
|
240
|
-
|
241
|
-
const branch = childProcess.execSync("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
|
242
|
-
// 提交变更集
|
243
|
-
if (commitUrl) {
|
244
|
-
console.log(`executing git push ${branch} to ${commitUrl}`);
|
245
|
-
return childProcess.exec("git", ["push", commitUrl]);
|
246
|
-
} else {
|
247
|
-
console.log(`executing git push ${branch}`);
|
248
|
-
return childProcess.exec('git', ['push']);
|
249
|
-
}
|
250
|
-
}
|
251
|
-
}
|
252
|
-
|
253
|
-
function buildWorkspace(workspace) {
|
254
|
-
console.log(`executing lerna run build --scope=${workspace.packageName}`)
|
255
|
-
return childProcess.exec('lerna', ['run', 'build', `--scope=${workspace.packageName}`]);
|
256
|
-
}
|
257
|
-
|
258
|
-
function addTagToMonoWorkspace(monoWorkspace, commitUrl) {
|
259
|
-
const monoWorkspaceVersion = `v${monoWorkspace.version}`;
|
260
|
-
childProcess.execSync('git', ['tag', monoWorkspaceVersion, '-m', 'Publish npm packages. [skip ci]']);
|
261
|
-
// 提交变更集
|
262
|
-
if (commitUrl) {
|
263
|
-
console.log(`git push --tags ${commitUrl}`);
|
264
|
-
return childProcess.exec("git", ["push", '--tags', commitUrl]);
|
265
|
-
} else {
|
266
|
-
console.log(`git push --tags`);
|
267
|
-
return childProcess.exec('git', ['push', '--tags',]);
|
268
|
-
}
|
269
|
-
}
|
270
|
-
|
271
|
-
/**
|
272
|
-
* 发布指定路径下的npm包
|
273
|
-
* @param {string} projectPath 目标工程路径
|
274
|
-
* @returns 发布结果
|
275
|
-
*/
|
276
|
-
function publishToNpmRepository(projectPath) {
|
277
|
-
// 读取目标工程的package.json文件
|
278
|
-
const ngPackageJsonFilePath = `${projectPath}/ng-package.json`;
|
279
|
-
const ngPackageConfig = JSON.parse(fs.readFileSync(ngPackageJsonFilePath, 'utf-8'));
|
280
|
-
const dest = ngPackageConfig.dest;
|
281
|
-
const packagePath = path.normalize(`${projectPath}/${dest}`);
|
282
|
-
// 调用 npm publish 发布指定路径下的npm包
|
283
|
-
return childProcess.exec('npm', ['publish', packagePath])
|
284
|
-
}
|
285
|
-
|
286
|
-
/**
|
287
|
-
* 将所有变更发布为新的npm包
|
288
|
-
* @param {string} commitUrl commit api 地址
|
289
|
-
*/
|
290
|
-
function publish(commitUrl, updateVersionType) {
|
291
|
-
// 初始化当前工作目录下的多代码仓库项目
|
292
|
-
const monoRepoProject = new Project(process.cwd());
|
293
|
-
let chain = Promise.resolve();
|
294
|
-
// 1. 提取当前多代码仓库中的所有子项目,创建多项目工作区
|
295
|
-
chain = chain.then(() => {
|
296
|
-
// 提取所有子项目
|
297
|
-
return monoRepoProject.getPackages()
|
298
|
-
.then(packages => {
|
299
|
-
// 创建并返回多项目工作区
|
300
|
-
const monoWorkspace = { packages };
|
301
|
-
return monoWorkspace;
|
302
|
-
})
|
303
|
-
});
|
304
|
-
// 2. 读取多项目工作区下的Angular工作区和所有Angular项目
|
305
|
-
chain = chain.then((monoWorkspace) => {
|
306
|
-
// 提取所有子仓库项目
|
307
|
-
const packages = monoWorkspace.packages;
|
308
|
-
// 初始化Angular工作区集合
|
309
|
-
monoWorkspace.workspaces = [];
|
310
|
-
// 初始化Angular工程集合
|
311
|
-
monoWorkspace.projects = [];
|
312
|
-
// 遍历所有子仓库
|
313
|
-
packages.forEach(packageJson => {
|
314
|
-
// 读取Angular工作区路径
|
315
|
-
const workspacePath = packageJson.location;
|
316
|
-
// 读取Angular工作区下的angular.json文件内容
|
317
|
-
const angularJson = readAngularJson(workspacePath)
|
318
|
-
// 构造Angular工作区
|
319
|
-
const workspace = readWorkspace(angularJson, packageJson);
|
320
|
-
// 记录Angular工作区对象
|
321
|
-
monoWorkspace.workspaces.push(workspace);
|
322
|
-
// 遍历Angular工作区下的Angular项目,归集到根工作区中
|
323
|
-
workspace.projects.reduce((monoWorkspace, projectInfo) => {
|
324
|
-
monoWorkspace.projects.push(projectInfo);
|
325
|
-
return monoWorkspace;
|
326
|
-
}, monoWorkspace);
|
327
|
-
});
|
328
|
-
return monoWorkspace;
|
329
|
-
});
|
330
|
-
// 3. 检查代码提交记录,获取自上次发布以来所有发生变化的Angular工程
|
331
|
-
chain = chain.then(monoWorkspace => {
|
332
|
-
const projects = monoWorkspace.projects;
|
333
|
-
const lastCommit = getLastCommit();
|
334
|
-
console.log(`last commit ${lastCommit}`);
|
335
|
-
const checkProjects = projects.map((projectInfo) => {
|
336
|
-
let checkPromise = checkProjectChanges(projectInfo, lastCommit);
|
337
|
-
let changedPromise = checkPromise.then(hasChanged => {
|
338
|
-
projectInfo.hasChanged = hasChanged;
|
339
|
-
return Promise.resolve(projectInfo);
|
340
|
-
});
|
341
|
-
return changedPromise;
|
342
|
-
});
|
343
|
-
return Promise.all(checkProjects)
|
344
|
-
.then((checkResults) => {
|
345
|
-
monoWorkspace.changedProjects = checkResults.filter((projectInfo) => projectInfo.hasChanged);
|
346
|
-
return Promise.resolve(monoWorkspace);
|
347
|
-
});
|
348
|
-
});
|
349
|
-
// 4. 更新所有变更项目预发布版本,提交代码仓库,供发布时使用
|
350
|
-
chain = chain.then(monoWorkspace => {
|
351
|
-
const changedProjects = monoWorkspace.changedProjects;
|
352
|
-
const prereleasePromise = changedProjects.map(projectInfo => updateProjectVersion(projectInfo, updateVersionType));
|
353
|
-
return Promise.all(prereleasePromise)
|
354
|
-
.then((results) => {
|
355
|
-
results.reduce((workspace, updateResult) => {
|
356
|
-
workspace.updateResult = workspace.updateResult || {};
|
357
|
-
Object.assign(workspace.updateResult, updateResult);
|
358
|
-
return workspace;
|
359
|
-
}, monoWorkspace);
|
360
|
-
const updatedVersions = monoWorkspace.updateResult;
|
361
|
-
if (updatedVersions) {
|
362
|
-
return commitVersionChanges(updatedVersions, commitUrl, monoWorkspace, updateVersionType)
|
363
|
-
.then((result) => {
|
364
|
-
if (result.stderr) {
|
365
|
-
console.log(result.stderr);
|
366
|
-
}
|
367
|
-
if (result.stdout) {
|
368
|
-
console.log(result.stdout);
|
369
|
-
}
|
370
|
-
return Promise.resolve(monoWorkspace);
|
371
|
-
});
|
372
|
-
} else {
|
373
|
-
return Promise.resolve(monoWorkspace);
|
374
|
-
}
|
375
|
-
|
376
|
-
});
|
377
|
-
});
|
378
|
-
// 5. 编译所有Angular工作区
|
379
|
-
chain = chain.then(monoWorkspace => {
|
380
|
-
const buildPromises = monoWorkspace.workspaces
|
381
|
-
.filter(workspace => workspace.hasChanged)
|
382
|
-
.map((workspace) => buildWorkspace(workspace));
|
383
|
-
if (buildPromises.length) {
|
384
|
-
return Promise.all(buildPromises)
|
385
|
-
.then((results) => {
|
386
|
-
if (results) {
|
387
|
-
results.map((result) => {
|
388
|
-
if (result.stderr) {
|
389
|
-
console.log(result.stderr);
|
390
|
-
}
|
391
|
-
if (result.stdout) {
|
392
|
-
console.log(result.stdout);
|
393
|
-
}
|
394
|
-
});
|
395
|
-
}
|
396
|
-
return Promise.resolve(monoWorkspace);
|
397
|
-
});
|
398
|
-
} else {
|
399
|
-
return Promise.resolve(monoWorkspace);
|
400
|
-
}
|
401
|
-
});
|
402
|
-
// 6. 将变更项目的内容发布为npm包,并增加发布Tag标签
|
403
|
-
chain = chain.then(monoWorkspace => {
|
404
|
-
const changedProjects = monoWorkspace.changedProjects;
|
405
|
-
if (changedProjects.length) {
|
406
|
-
const publishPromises = changedProjects.map(projectInfo => publishToNpmRepository(projectInfo.project.path));
|
407
|
-
Promise.all(publishPromises)
|
408
|
-
.then(() => {
|
409
|
-
return addTagToMonoWorkspace(monoWorkspace, commitUrl);
|
410
|
-
});
|
411
|
-
} else {
|
412
|
-
return Promise.resolve(monoWorkspace);
|
413
|
-
}
|
414
|
-
|
415
|
-
});
|
416
|
-
}
|
417
|
-
|
418
|
-
function readAngularJson(workspacePath) {
|
419
|
-
const angularJsonPath = path.normalize(`${workspacePath}/angular.json`);
|
420
|
-
return JSON.parse(fs.readFileSync(angularJsonPath, 'utf-8'));
|
421
|
-
}
|
422
|
-
|
423
|
-
function readWorkspace(angularJson, packageJson) {
|
424
|
-
const projects = angularJson.projects;
|
425
|
-
const workspacePath = packageJson.location;
|
426
|
-
const packageName = packageJson.name;
|
427
|
-
const workspace = {
|
428
|
-
packageName,
|
429
|
-
path: workspacePath,
|
430
|
-
projects: [],
|
431
|
-
hasChanged: false
|
432
|
-
};
|
433
|
-
Object.keys(projects)
|
434
|
-
.reduce((workspace, projectName) => {
|
435
|
-
const projectInfo = readProjectInfo(projectName, projects[projectName], workspace);
|
436
|
-
if (projectInfo) {
|
437
|
-
workspace.projects.push(projectInfo);
|
438
|
-
}
|
439
|
-
return workspace;
|
440
|
-
}, workspace);
|
441
|
-
return workspace;
|
442
|
-
}
|
443
|
-
|
444
|
-
function readProjectInfo(projectName, project, workspace) {
|
445
|
-
const projectPath = path.normalize(`${workspace.path}/${project.root}`);
|
446
|
-
const projectType = project.projectType;
|
447
|
-
if (projectType === 'library') {
|
448
|
-
const packageJsonPath = path.normalize(`${projectPath}/package.json`);
|
449
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
450
|
-
const packageName = packageJson.name;
|
451
|
-
const ngPackagePath = path.normalize(`${projectPath}/ng-package.json`);
|
452
|
-
const ngPackage = JSON.parse(fs.readFileSync(ngPackagePath, 'utf-8'));
|
453
|
-
const packagePath = path.normalize(`${projectPath}/${ngPackage.dest}`);
|
454
|
-
return {
|
455
|
-
workspace,
|
456
|
-
project: {
|
457
|
-
name: projectName,
|
458
|
-
path: projectPath,
|
459
|
-
type: projectType
|
460
|
-
},
|
461
|
-
package: {
|
462
|
-
name: packageName,
|
463
|
-
path: packagePath
|
464
|
-
}
|
465
|
-
}
|
466
|
-
}
|
467
|
-
}
|