@farris/cli 1.0.28 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
package/bin/index.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../lib/index.js';
package/package.json CHANGED
@@ -1,26 +1,40 @@
1
1
  {
2
2
  "name": "@farris/cli",
3
- "version": "1.0.28",
4
- "description": "Farris command line interface",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
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
- "repository": {
10
- "type": "git",
11
- "url": "https://git.iec.io/webadp/farris-cli.git"
10
+ "engines": {
11
+ "node": ">=16.0.0"
12
12
  },
13
- "keywords": [
14
- "Farris",
15
- "CLI"
16
- ],
17
- "bin": {
18
- "farris": "ci/cli.js"
13
+ "scripts": {
14
+ "build": "rimraf ./lib && tsc"
19
15
  },
20
- "author": "Sagi Chen",
21
- "license": "ISC",
16
+ "files": [
17
+ "lib",
18
+ "templates",
19
+ "bin.js"
20
+ ],
21
+ "license": "MIT",
22
22
  "dependencies": {
23
- "lerna": "^4.0.0",
24
- "moment": "^2.29.3"
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,8 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/prettierrc",
3
+ "semi": false,
4
+ "tabWidth": 2,
5
+ "singleQuote": true,
6
+ "printWidth": 100,
7
+ "trailingComma": "none"
8
+ }
@@ -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,3 @@
1
+ <template>
2
+ <fm-button>按钮</fm-button>
3
+ </template>
@@ -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,15 @@
1
+ <template>
2
+ <div class="about">
3
+ <h1>This is an about page</h1>
4
+ </div>
5
+ </template>
6
+
7
+ <style>
8
+ @media (min-width: 1024px) {
9
+ .about {
10
+ min-height: 100vh;
11
+ display: flex;
12
+ align-items: center;
13
+ }
14
+ }
15
+ </style>
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import TheButton from '../components/TheButton.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <main>
7
+ <TheButton />
8
+ </main>
9
+ </template>
@@ -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,8 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/prettierrc",
3
+ "semi": false,
4
+ "tabWidth": 2,
5
+ "singleQuote": true,
6
+ "printWidth": 100,
7
+ "trailingComma": "none"
8
+ }
@@ -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,3 @@
1
+ <template>
2
+ <f-button>按钮</f-button>
3
+ </template>
@@ -0,0 +1,10 @@
1
+ import { createApp } from 'vue'
2
+ import FarrisVue from '@farris/ui-vue'
3
+ import App from './App.vue'
4
+ import router from './router'
5
+
6
+ const app = createApp(App)
7
+
8
+ app.use(router).use(FarrisVue)
9
+
10
+ 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,15 @@
1
+ <template>
2
+ <div class="about">
3
+ <h1>This is an about page</h1>
4
+ </div>
5
+ </template>
6
+
7
+ <style>
8
+ @media (min-width: 1024px) {
9
+ .about {
10
+ min-height: 100vh;
11
+ display: flex;
12
+ align-items: center;
13
+ }
14
+ }
15
+ </style>
@@ -0,0 +1,9 @@
1
+ <script setup lang="ts">
2
+ import TheButton from '../components/TheButton.vue'
3
+ </script>
4
+
5
+ <template>
6
+ <main>
7
+ <TheButton />
8
+ </main>
9
+ </template>
@@ -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
@@ -1,2 +0,0 @@
1
- # farris-cli
2
-
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
- }