@icebreakers/monorepo-templates 1.0.15 → 1.1.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/assets/.changeset/ledger.yaml +26 -0
- package/assets/.github/workflows/release.yml +22 -97
- package/assets/AGENTS.md +1 -1
- package/assets/package.json +5 -6
- package/assets/pnpm-workspace.yaml +8 -0
- package/package.json +1 -1
- package/templates/client/package.json +5 -5
- package/templates/server/package.json +3 -3
- package/templates/server/vitest.config.ts +1 -4
- package/templates/tsdown/vitest.config.ts +1 -4
- package/templates/vitepress/ai/llms-txt.md +6 -6
- package/templates/vitepress/en/repoctl/index.md +1 -1
- package/templates/vitepress/knowledge/index.md +1 -1
- package/templates/vitepress/monorepo/index.md +1 -1
- package/templates/vitepress/monorepo/publish.md +45 -218
- package/templates/vitepress/package.json +1 -1
- package/templates/vitepress/repoctl/index.md +1 -1
- package/templates/vitepress/thinking.md +1 -1
- package/templates/vitepress/tools/changeset.md +40 -63
- package/templates/vitepress/tools/index.md +10 -10
- package/templates/vue-lib/vitest.config.ts +1 -1
- package/assets/.changeset/config.json +0 -21
- package/assets/.changeset/publish-versioned-packages.md +0 -5
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"@icebreakers/monorepo-templates@1.1.0":
|
|
2
|
+
dir: packages/monorepo-templates
|
|
3
|
+
intents:
|
|
4
|
+
- pnpm-native-versioning
|
|
5
|
+
- release-ci-token
|
|
6
|
+
- repoctl-release-orchestration
|
|
7
|
+
- vitest-native-config
|
|
8
|
+
"@icebreakers/monorepo@5.1.0":
|
|
9
|
+
dir: packages/monorepo
|
|
10
|
+
intents:
|
|
11
|
+
- close-legacy-release-pr
|
|
12
|
+
- human-readable-release-notes
|
|
13
|
+
- pnpm-native-versioning
|
|
14
|
+
- publish-versioned-packages
|
|
15
|
+
- release-ci-token
|
|
16
|
+
- release-links
|
|
17
|
+
- release-npm-links
|
|
18
|
+
- release-npm-links-prepublish
|
|
19
|
+
- release-pr-body
|
|
20
|
+
- release-pr-layout
|
|
21
|
+
- release-test-isolation
|
|
22
|
+
- repoctl-release-orchestration
|
|
23
|
+
create-icebreaker@1.1.0:
|
|
24
|
+
dir: packages/create-icebreaker
|
|
25
|
+
intents:
|
|
26
|
+
- pnpm-native-versioning
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# repoctl-managed: release/v2
|
|
1
2
|
name: Release
|
|
2
3
|
|
|
3
4
|
on:
|
|
@@ -13,33 +14,37 @@ on:
|
|
|
13
14
|
mode:
|
|
14
15
|
description: Release operation
|
|
15
16
|
required: true
|
|
16
|
-
default:
|
|
17
|
+
default: auto
|
|
17
18
|
type: choice
|
|
18
19
|
options:
|
|
19
|
-
-
|
|
20
|
+
- auto
|
|
21
|
+
- prepare
|
|
22
|
+
- publish
|
|
20
23
|
- publish-unpublished
|
|
21
24
|
package:
|
|
22
|
-
description: Package used
|
|
25
|
+
description: Package used for unpublished-version recovery
|
|
23
26
|
required: false
|
|
24
27
|
type: string
|
|
25
28
|
version:
|
|
26
|
-
description: Version used
|
|
29
|
+
description: Version used for unpublished-version recovery
|
|
27
30
|
required: false
|
|
28
31
|
type: string
|
|
29
32
|
|
|
30
33
|
concurrency: ${{ github.workflow }}-${{ github.ref }}
|
|
34
|
+
|
|
31
35
|
env:
|
|
32
36
|
HUSKY: 0
|
|
37
|
+
NPM_CONFIG_PROVENANCE: true
|
|
38
|
+
npm_config_registry: https://registry.npmjs.org
|
|
33
39
|
|
|
34
40
|
permissions:
|
|
35
|
-
contents: write
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
id-token: write # to use OpenID Connect token for provenance (changesets/action)
|
|
41
|
+
contents: write
|
|
42
|
+
pull-requests: write
|
|
43
|
+
id-token: write
|
|
39
44
|
|
|
40
45
|
jobs:
|
|
41
46
|
release:
|
|
42
|
-
if: github.
|
|
47
|
+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
|
43
48
|
name: Release
|
|
44
49
|
runs-on: ubuntu-latest
|
|
45
50
|
steps:
|
|
@@ -53,95 +58,15 @@ jobs:
|
|
|
53
58
|
with:
|
|
54
59
|
node-version: 24
|
|
55
60
|
cache: pnpm
|
|
61
|
+
registry-url: https://registry.npmjs.org
|
|
56
62
|
|
|
57
63
|
- name: Install Dependencies
|
|
58
|
-
run: pnpm
|
|
59
|
-
|
|
60
|
-
- name: Create Release Pull Request or Publish to npm
|
|
61
|
-
if: github.event_name != 'workflow_dispatch' || inputs.mode == 'changesets'
|
|
62
|
-
id: changesets
|
|
63
|
-
uses: changesets/action@v2.0.0
|
|
64
|
-
with:
|
|
65
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
66
|
-
publish-script: pnpm exec repo release stable
|
|
67
|
-
env:
|
|
68
|
-
# this doesn't work but semantic-release works
|
|
69
|
-
# see https://github.com/sonofmagic/npm-lib-rollup-template/blob/main/.github/workflows/release.yml#L46
|
|
70
|
-
# NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
|
71
|
-
# NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
72
|
-
npm_config_registry: https://registry.npmjs.org
|
|
73
|
-
# https://github.com/changesets/changesets/pull/1659
|
|
74
|
-
NPM_CONFIG_PROVENANCE: true
|
|
75
|
-
|
|
76
|
-
- name: Validate unpublished-version recovery
|
|
77
|
-
if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-unpublished'
|
|
78
|
-
shell: bash
|
|
79
|
-
env:
|
|
80
|
-
RECOVERY_PACKAGE: ${{ inputs.package }}
|
|
81
|
-
RECOVERY_VERSION: ${{ inputs.version }}
|
|
82
|
-
run: |
|
|
83
|
-
if [[ -z "$RECOVERY_PACKAGE" || -z "$RECOVERY_VERSION" ]]; then
|
|
84
|
-
echo "package and version are required for publish-unpublished" >&2
|
|
85
|
-
exit 1
|
|
86
|
-
fi
|
|
87
|
-
actual_version="$(pnpm --filter "$RECOVERY_PACKAGE" exec node -p "require('./package.json').version")"
|
|
88
|
-
if [[ "$actual_version" != "$RECOVERY_VERSION" ]]; then
|
|
89
|
-
echo "Expected $RECOVERY_PACKAGE@$RECOVERY_VERSION on main, found $actual_version" >&2
|
|
90
|
-
exit 1
|
|
91
|
-
fi
|
|
92
|
-
|
|
93
|
-
- name: Publish unpublished versions to npm
|
|
94
|
-
if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-unpublished'
|
|
95
|
-
run: pnpm exec repo release stable
|
|
96
|
-
env:
|
|
97
|
-
npm_config_registry: https://registry.npmjs.org
|
|
98
|
-
NPM_CONFIG_PROVENANCE: true
|
|
99
|
-
|
|
100
|
-
- name: Verify recovered npm version
|
|
101
|
-
if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-unpublished'
|
|
102
|
-
shell: bash
|
|
103
|
-
env:
|
|
104
|
-
RECOVERY_PACKAGE: ${{ inputs.package }}
|
|
105
|
-
RECOVERY_VERSION: ${{ inputs.version }}
|
|
106
|
-
run: |
|
|
107
|
-
published_version="$(npm view "$RECOVERY_PACKAGE@$RECOVERY_VERSION" version)"
|
|
108
|
-
test "$published_version" = "$RECOVERY_VERSION"
|
|
109
|
-
|
|
110
|
-
- name: Push recovered release tags
|
|
111
|
-
if: github.event_name == 'workflow_dispatch' && inputs.mode == 'publish-unpublished'
|
|
112
|
-
run: git push origin --follow-tags
|
|
113
|
-
|
|
114
|
-
- name: Upload coverage reports to Codecov
|
|
115
|
-
uses: codecov/codecov-action@v7
|
|
116
|
-
env:
|
|
117
|
-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
118
|
-
|
|
119
|
-
prerelease:
|
|
120
|
-
if: github.event_name == 'push' && github.ref_name != 'main'
|
|
121
|
-
name: Prerelease
|
|
122
|
-
runs-on: ubuntu-latest
|
|
123
|
-
steps:
|
|
124
|
-
- name: Checkout Repo
|
|
125
|
-
uses: actions/checkout@v7
|
|
126
|
-
|
|
127
|
-
- uses: pnpm/action-setup@v6
|
|
128
|
-
|
|
129
|
-
- name: Setup Node.js environment
|
|
130
|
-
uses: actions/setup-node@v7
|
|
131
|
-
with:
|
|
132
|
-
node-version: 24
|
|
133
|
-
cache: pnpm
|
|
134
|
-
|
|
135
|
-
- name: Install Dependencies
|
|
136
|
-
run: pnpm i
|
|
137
|
-
|
|
138
|
-
- name: Configure Git
|
|
139
|
-
run: |
|
|
140
|
-
git config user.name "github-actions[bot]"
|
|
141
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
64
|
+
run: pnpm install --frozen-lockfile
|
|
142
65
|
|
|
143
|
-
- name:
|
|
144
|
-
run: pnpm exec repo release pre publish
|
|
66
|
+
- name: Run repo release CI
|
|
145
67
|
env:
|
|
146
|
-
|
|
147
|
-
|
|
68
|
+
GITHUB_TOKEN: ${{ github.token }}
|
|
69
|
+
REPO_RELEASE_MODE: ${{ inputs.mode || 'auto' }}
|
|
70
|
+
REPO_RELEASE_PACKAGE: ${{ inputs.package }}
|
|
71
|
+
REPO_RELEASE_VERSION: ${{ inputs.version }}
|
|
72
|
+
run: pnpm exec repo release ci
|
package/assets/AGENTS.md
CHANGED
|
@@ -40,7 +40,7 @@ When building TypeScript libraries (type-focused APIs or public type definitions
|
|
|
40
40
|
|
|
41
41
|
## Commit & Pull Request Guidelines
|
|
42
42
|
|
|
43
|
-
Commits must conform to Conventional Commit syntax; recent history uses prefixes like `feat`, `fix`, and `chore`. Example: `feat(server): add auth router`. Use `pnpm commit` (commitlint prompt) or ensure your manual message passes `pnpm commitlint --edit`. Before opening a PR, make sure `pnpm lint` and `pnpm test` succeed, link related issues, and provide screenshots or logs for user-facing changes. Touching publishable packages requires a
|
|
43
|
+
Commits must conform to Conventional Commit syntax; recent history uses prefixes like `feat`, `fix`, and `chore`. Example: `feat(server): add auth router`. Use `pnpm commit` (commitlint prompt) or ensure your manual message passes `pnpm commitlint --edit`. Before opening a PR, make sure `pnpm lint` and `pnpm test` succeed, link related issues, and provide screenshots or logs for user-facing changes. Touching publishable packages requires a pnpm change intent (`pnpm change`) so releases stay traceable.
|
|
44
44
|
|
|
45
45
|
For AI-generated or AI-assisted changes, use this verification order before commit or PR:
|
|
46
46
|
|
package/assets/package.json
CHANGED
|
@@ -30,8 +30,9 @@
|
|
|
30
30
|
"typecheck": "turbo run typecheck",
|
|
31
31
|
"format": "eslint . --fix",
|
|
32
32
|
"validate": "pnpm run build && pnpm run lint && pnpm run typecheck && pnpm run tsd && pnpm run test",
|
|
33
|
-
"release": "
|
|
34
|
-
"
|
|
33
|
+
"release": "pnpm change",
|
|
34
|
+
"version-packages": "pnpm version -r",
|
|
35
|
+
"publish-packages": "repo release stable publish",
|
|
35
36
|
"release:pre": "repo release pre publish",
|
|
36
37
|
"------": "--------------",
|
|
37
38
|
"preinstall": "npx only-allow pnpm",
|
|
@@ -52,9 +53,7 @@
|
|
|
52
53
|
"--------": "----------------"
|
|
53
54
|
},
|
|
54
55
|
"devDependencies": {
|
|
55
|
-
"@
|
|
56
|
-
"@commitlint/cli": "^21.2.1",
|
|
57
|
-
"@icebreakers/changelog-github": "^2.0.0",
|
|
56
|
+
"@commitlint/cli": "^21.2.2",
|
|
58
57
|
"@icebreakers/monorepo": "workspace:*",
|
|
59
58
|
"@types/node": "^26.2.0",
|
|
60
59
|
"@types/semver": "^7.8.0",
|
|
@@ -76,7 +75,7 @@
|
|
|
76
75
|
"tsdown": "0.22.14",
|
|
77
76
|
"tslib": "^2.8.1",
|
|
78
77
|
"tsx": "^4.23.12",
|
|
79
|
-
"turbo": "^2.10.
|
|
78
|
+
"turbo": "^2.10.10",
|
|
80
79
|
"type-fest": "^5.8.0",
|
|
81
80
|
"typescript": "^6.0.3",
|
|
82
81
|
"vitest": "~4.1.10",
|
package/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"typecheck": "pnpm cf-typegen:check && vue-tsc -b"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@faker-js/faker": "^10.
|
|
18
|
+
"@faker-js/faker": "^10.6.0",
|
|
19
19
|
"@tanstack/vue-query": "^5.101.4",
|
|
20
20
|
"@tanstack/vue-query-devtools": "^6.1.38",
|
|
21
21
|
"@tanstack/vue-table": "^9.1.2",
|
|
@@ -30,8 +30,8 @@
|
|
|
30
30
|
"vue-router": "^5.2.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
|
-
"@cloudflare/vite-plugin": "^1.52.
|
|
34
|
-
"@hono/node-server": "^2.1.
|
|
33
|
+
"@cloudflare/vite-plugin": "^1.52.1",
|
|
34
|
+
"@hono/node-server": "^2.1.1",
|
|
35
35
|
"@hono/trpc-server": "^0.4.2",
|
|
36
36
|
"@tailwindcss/vite": "^4.3.3",
|
|
37
37
|
"@trpc/server": "^11.18.0",
|
|
@@ -39,14 +39,14 @@
|
|
|
39
39
|
"@vitejs/plugin-vue-jsx": "^5.1.6",
|
|
40
40
|
"@vue/tsconfig": "^0.9.1",
|
|
41
41
|
"consola": "^3.4.2",
|
|
42
|
-
"hono": "^4.13.
|
|
42
|
+
"hono": "^4.13.2",
|
|
43
43
|
"tailwindcss": "^4.3.3",
|
|
44
44
|
"typescript": "~6.0.3",
|
|
45
45
|
"vite": "^8.2.1",
|
|
46
46
|
"vite-plugin-vue-devtools": "^8.2.1",
|
|
47
47
|
"vite-tsconfig-paths": "^6.1.1",
|
|
48
48
|
"vue-tsc": "3.3.9",
|
|
49
|
-
"wrangler": "^4.
|
|
49
|
+
"wrangler": "^4.123.0",
|
|
50
50
|
"zod": "^4.4.3"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"types": "./dist/index.d.ts"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@hono/node-server": "^2.1.
|
|
57
|
+
"@hono/node-server": "^2.1.1",
|
|
58
58
|
"consola": "^3.4.2",
|
|
59
|
-
"hono": "^4.13.
|
|
59
|
+
"hono": "^4.13.2",
|
|
60
60
|
"tsdown": "0.22.14",
|
|
61
|
-
"wrangler": "^4.
|
|
61
|
+
"wrangler": "^4.123.0",
|
|
62
62
|
"zod": "^4.4.3"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
2
|
import { defineVitestProjectConfig } from 'repoctl/tooling'
|
|
4
3
|
import { defineProject } from 'vitest/config'
|
|
5
4
|
|
|
6
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
-
|
|
8
5
|
export default defineProject(await defineVitestProjectConfig({
|
|
9
6
|
options: {
|
|
10
7
|
alias: [
|
|
11
8
|
{
|
|
12
9
|
find: '@',
|
|
13
|
-
replacement: path.resolve(
|
|
10
|
+
replacement: path.resolve(import.meta.dirname, './src'),
|
|
14
11
|
},
|
|
15
12
|
],
|
|
16
13
|
},
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
|
-
import { fileURLToPath } from 'node:url'
|
|
3
2
|
import { defineVitestProjectConfig } from 'repoctl/tooling'
|
|
4
3
|
import { defineProject } from 'vitest/config'
|
|
5
4
|
|
|
6
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
7
|
-
|
|
8
5
|
export default defineProject(await defineVitestProjectConfig({
|
|
9
6
|
options: {
|
|
10
7
|
alias: [
|
|
11
8
|
{
|
|
12
9
|
find: '@',
|
|
13
|
-
replacement: path.resolve(
|
|
10
|
+
replacement: path.resolve(import.meta.dirname, './src'),
|
|
14
11
|
},
|
|
15
12
|
],
|
|
16
13
|
},
|
|
@@ -34,9 +34,9 @@ description: 说明这个页面解决的问题和适用场景。
|
|
|
34
34
|
|
|
35
35
|
AI 入口应该保持显眼,但不要替代正常文档结构:
|
|
36
36
|
|
|
37
|
-
| 页面类型
|
|
38
|
-
|
|
|
39
|
-
| repoctl 命令、校验、诊断、报告
|
|
40
|
-
| monorepo 和 npm 包基础知识
|
|
41
|
-
| pnpm、Turborepo、
|
|
42
|
-
| llms.txt 和 AI 工具读取约定
|
|
37
|
+
| 页面类型 | 推荐位置 |
|
|
38
|
+
| -------------------------------------- | ------------------------------------ |
|
|
39
|
+
| repoctl 命令、校验、诊断、报告 | `/repoctl/` |
|
|
40
|
+
| monorepo 和 npm 包基础知识 | `/knowledge/`、`/monorepo/`、`/why/` |
|
|
41
|
+
| pnpm、Turborepo、versioning 等工具专题 | `/tools/` |
|
|
42
|
+
| llms.txt 和 AI 工具读取约定 | `/ai/` |
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
`repoctl` is the user-facing package name for this monorepo toolkit. Its recommended command is `repo`.
|
|
4
4
|
|
|
5
|
-
The CLI does not replace pnpm, Turborepo, or
|
|
5
|
+
The CLI does not replace pnpm, Turborepo, or pnpm versioning. It gives teams a stable layer for common monorepo actions: setup, diagnostics, scaffolding, local verification, and template asset upgrades.
|
|
6
6
|
|
|
7
7
|
## When To Use It
|
|
8
8
|
|
|
@@ -12,7 +12,7 @@ description: repoctl 文档站的知识库入口,汇总 monorepo 管理、现
|
|
|
12
12
|
| -------------------------------------------------- | ---------------------------------- |
|
|
13
13
|
| [为什么往 monorepo 方向演进](../monorepo/index.md) | 判断多包仓库是否值得合并管理 |
|
|
14
14
|
| [如何管理 monorepo](../monorepo/manage.md) | 理解 workspace、任务编排和依赖边界 |
|
|
15
|
-
| [发包与变更日志](../monorepo/publish.md) | 设计
|
|
15
|
+
| [发包与变更日志](../monorepo/publish.md) | 设计 pnpm intent、版本和发布链路 |
|
|
16
16
|
| [monorepo 命令参考](../monorepo/commands.md) | 查看通用 monorepo 操作命令 |
|
|
17
17
|
| [monorepo 模板体系](../monorepo/templates.md) | 理解模板如何减少重复初始化 |
|
|
18
18
|
| [monorepo 排障](../monorepo/troubleshooting.md) | 排查依赖、构建、类型和发布问题 |
|
|
@@ -1,47 +1,10 @@
|
|
|
1
1
|
# monorepo 发包与变更日志
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
这套模板默认使用 pnpm 原生 versioning。它保留 Changesets 格式的变更意图,同时把版本计算、依赖传播、changelog 和发布收进 pnpm 本身。
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
- 版本升级能自动联动内部依赖
|
|
7
|
-
- changelog 可以稳定产出
|
|
8
|
-
- 很容易接到 CI 里
|
|
5
|
+
## 日常流程
|
|
9
6
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
## repoctl 在发布前做什么
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
pnpm exec repo doctor --strict
|
|
16
|
-
pnpm exec repo check --full
|
|
17
|
-
pnpm exec repo env support --markdown --redact --out reports/support.md
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
| 命令 | 发布前价值 |
|
|
21
|
-
| ---------------------- | -------------------------------------------------------- |
|
|
22
|
-
| `repo doctor --strict` | 确认仓库结构、Node、脚本、配置和提交链路没有漂移 |
|
|
23
|
-
| `repo check --full` | 跑根脚本里的 lint/typecheck/test/build 计划 |
|
|
24
|
-
| `repo env support` | 保存环境、配置、doctor 和 check plan,方便发布失败后回溯 |
|
|
25
|
-
|
|
26
|
-
发布本身仍交给 `changesets`:
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
pnpm changeset
|
|
30
|
-
pnpm exec repo release stable
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
正式发布只走 `main`;`alpha`、`beta`、`rc`、`next` 只做 Changesets 的 prerelease,并发布对应 tag 包。
|
|
34
|
-
|
|
35
|
-
## 一条务实的发布流程
|
|
36
|
-
|
|
37
|
-
先把顺序记住:
|
|
38
|
-
|
|
39
|
-
1. 写代码
|
|
40
|
-
2. 跑校验
|
|
41
|
-
3. 生成 changeset
|
|
42
|
-
4. 合并后 version / publish
|
|
43
|
-
|
|
44
|
-
对应到命令,一般是:
|
|
7
|
+
先完成质量校验,再记录变更:
|
|
45
8
|
|
|
46
9
|
```bash
|
|
47
10
|
pnpm build
|
|
@@ -49,212 +12,76 @@ pnpm lint
|
|
|
49
12
|
pnpm typecheck
|
|
50
13
|
pnpm tsd
|
|
51
14
|
pnpm test
|
|
52
|
-
pnpm
|
|
15
|
+
pnpm change
|
|
16
|
+
pnpm change status
|
|
53
17
|
```
|
|
54
18
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
## 为什么推荐 `changesets`
|
|
58
|
-
|
|
59
|
-
| 需求 | `changesets` 的做法 |
|
|
60
|
-
| -------------- | ----------------------------------------- |
|
|
61
|
-
| 记录哪些包变了 | 每次变更生成单独的 `.changeset/*.md` 文件 |
|
|
62
|
-
| 控制版本类型 | 明确选择 `patch` / `minor` / `major` |
|
|
63
|
-
| 自动生成日志 | `changeset version` 统一产出 changelog |
|
|
64
|
-
| 联动内部包版本 | 自动改内部依赖引用 |
|
|
65
|
-
| CI 自动发布 | 可接 `changesets/action` |
|
|
19
|
+
变更意图文件放在 `.changeset/*.md`,描述受影响包和 patch/minor/major。不要手动修改包版本。
|
|
66
20
|
|
|
67
|
-
##
|
|
21
|
+
## Release PR
|
|
68
22
|
|
|
69
|
-
|
|
23
|
+
main push 会运行:
|
|
70
24
|
|
|
71
25
|
```bash
|
|
72
|
-
pnpm
|
|
73
|
-
pnpm
|
|
74
|
-
pnpm typecheck
|
|
75
|
-
pnpm tsd
|
|
76
|
-
pnpm test
|
|
26
|
+
pnpm version -r --dry-run
|
|
27
|
+
pnpm version -r
|
|
77
28
|
```
|
|
78
29
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
### 2. 记录 changeset
|
|
30
|
+
CI 将版本号、各包 `CHANGELOG.md` 和 `.changeset/ledger.yaml` 提交到 Release PR。合并 Release PR 后,下一次 main push 执行:
|
|
82
31
|
|
|
83
32
|
```bash
|
|
84
|
-
pnpm
|
|
33
|
+
pnpm publish -r --report-summary --provenance --no-git-checks
|
|
85
34
|
```
|
|
86
35
|
|
|
87
|
-
|
|
36
|
+
pnpm 根据 registry 中已有的版本自动跳过已发布包。CI 读取 `pnpm-publish-summary.json` 创建 `package@version` tag 和 GitHub Release,发布操作可以安全重试。
|
|
88
37
|
|
|
89
|
-
|
|
90
|
-
2. 这些包分别是 `patch` / `minor` / `major`
|
|
91
|
-
3. 这次改动怎么写进 changelog
|
|
38
|
+
## Workspace versioning 配置
|
|
92
39
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
```md
|
|
96
|
-
---
|
|
97
|
-
"@my/utils": minor
|
|
98
|
-
"@my/ui": patch
|
|
99
|
-
---
|
|
100
|
-
|
|
101
|
-
- feat(utils): 新增时间格式化工具
|
|
102
|
-
- fix(ui): 修复按钮禁用态样式
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### 3. 合并前看一眼影响面
|
|
106
|
-
|
|
107
|
-
changeset 文件本身就是最便宜的“发布预告”。代码评审时顺手看一下,通常就能避免:
|
|
108
|
-
|
|
109
|
-
- 漏记某个包
|
|
110
|
-
- 版本类型选错
|
|
111
|
-
- changelog 写得太含糊
|
|
112
|
-
|
|
113
|
-
## 发布阶段怎么做
|
|
114
|
-
|
|
115
|
-
### 手动流程
|
|
116
|
-
|
|
117
|
-
```bash
|
|
118
|
-
pnpm exec repo release stable
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
`repo release stable` 会先执行构建、lint 和测试,再调用 `changeset version` 与 `changeset publish`。其中 `changeset version` 会做这些事:
|
|
122
|
-
|
|
123
|
-
- 更新受影响包的版本号
|
|
124
|
-
- 调整内部依赖版本
|
|
125
|
-
- 生成或更新每个包的 `CHANGELOG.md`
|
|
126
|
-
|
|
127
|
-
### CI 自动流程
|
|
128
|
-
|
|
129
|
-
模板推荐结合 `changesets/action`。
|
|
130
|
-
|
|
131
|
-
一个常见的工作流结构如下:
|
|
40
|
+
根 `pnpm-workspace.yaml` 中的关键配置:
|
|
132
41
|
|
|
133
42
|
```yaml
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
- beta
|
|
142
|
-
- rc
|
|
143
|
-
- next
|
|
144
|
-
workflow_dispatch:
|
|
145
|
-
|
|
146
|
-
permissions:
|
|
147
|
-
contents: write
|
|
148
|
-
pull-requests: write
|
|
149
|
-
issues: write
|
|
150
|
-
id-token: write
|
|
151
|
-
|
|
152
|
-
env:
|
|
153
|
-
HUSKY: 0
|
|
154
|
-
|
|
155
|
-
jobs:
|
|
156
|
-
release:
|
|
157
|
-
if: github.ref_name == 'main'
|
|
158
|
-
runs-on: ubuntu-latest
|
|
159
|
-
steps:
|
|
160
|
-
- uses: actions/checkout@v7
|
|
161
|
-
- uses: pnpm/action-setup@v6
|
|
162
|
-
- uses: actions/setup-node@v7
|
|
163
|
-
with:
|
|
164
|
-
node-version: 24
|
|
165
|
-
cache: pnpm
|
|
166
|
-
registry-url: https://registry.npmjs.org
|
|
167
|
-
- run: pnpm install
|
|
168
|
-
- name: Create Release Pull Request or Publish to npm
|
|
169
|
-
uses: changesets/action@v2.0.0
|
|
170
|
-
with:
|
|
171
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
172
|
-
publish-script: pnpm exec repo release stable
|
|
173
|
-
env:
|
|
174
|
-
NPM_CONFIG_PROVENANCE: true
|
|
175
|
-
|
|
176
|
-
prerelease:
|
|
177
|
-
if: github.ref_name != 'main'
|
|
178
|
-
runs-on: ubuntu-latest
|
|
179
|
-
steps:
|
|
180
|
-
- uses: actions/checkout@v7
|
|
181
|
-
- uses: pnpm/action-setup@v6
|
|
182
|
-
- uses: actions/setup-node@v7
|
|
183
|
-
with:
|
|
184
|
-
node-version: 24
|
|
185
|
-
cache: pnpm
|
|
186
|
-
- run: pnpm install
|
|
187
|
-
- run: git config user.name "github-actions[bot]"
|
|
188
|
-
- run: git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
189
|
-
- name: Publish Prerelease
|
|
190
|
-
run: pnpm exec repo release pre publish
|
|
43
|
+
versioning:
|
|
44
|
+
fixed:
|
|
45
|
+
- ['@icebreakers/monorepo', repoctl]
|
|
46
|
+
ignore:
|
|
47
|
+
- '@icebreakers/client'
|
|
48
|
+
changelog:
|
|
49
|
+
storage: repository
|
|
191
50
|
```
|
|
192
51
|
|
|
193
|
-
|
|
52
|
+
`fixed` 保证组内包同版本;`ignore` 排除 private 包;`repository` 让 changelog 作为源代码提交。
|
|
194
53
|
|
|
195
|
-
|
|
54
|
+
## Prerelease lanes
|
|
196
55
|
|
|
197
|
-
|
|
56
|
+
预发布使用 pnpm lanes:
|
|
198
57
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
```yaml
|
|
206
|
-
permissions:
|
|
207
|
-
id-token: write
|
|
58
|
+
```bash
|
|
59
|
+
pnpm exec repo release pre enter beta
|
|
60
|
+
git add pnpm-workspace.yaml && git commit -m "chore(release): enter beta lane"
|
|
61
|
+
git push
|
|
62
|
+
pnpm exec repo release pre publish
|
|
208
63
|
```
|
|
209
64
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
### 私有包不会被发布
|
|
65
|
+
预发布版本为 `X.Y.Z-beta.N`,并使用 npm `beta` dist-tag。退出时运行:
|
|
213
66
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
{
|
|
218
|
-
"private": true
|
|
219
|
-
}
|
|
67
|
+
```bash
|
|
68
|
+
pnpm exec repo release pre exit
|
|
69
|
+
git add pnpm-workspace.yaml && git commit -m "chore(release): exit prerelease lane"
|
|
220
70
|
```
|
|
221
71
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
### 没有 changeset 就不会有版本 PR
|
|
225
|
-
|
|
226
|
-
如果你改了公开包,却没有提交 `.changeset/*.md`,那么后续版本流转通常会断掉。
|
|
227
|
-
|
|
228
|
-
### 先 build 再发
|
|
229
|
-
|
|
230
|
-
这个仓库的约定很明确:先 build,再 lint / typecheck / tsd / test,再谈发布。不要跳步。
|
|
231
|
-
|
|
232
|
-
## 常见问题
|
|
233
|
-
|
|
234
|
-
### 为什么没有生成 changelog?
|
|
235
|
-
|
|
236
|
-
通常是下面几种原因:
|
|
237
|
-
|
|
238
|
-
- 没有执行 `pnpm changeset version`
|
|
239
|
-
- `.changeset/*.md` 没有提交
|
|
240
|
-
- 受影响包实际没有进入版本计算
|
|
241
|
-
|
|
242
|
-
### 如何跳过某个包的发布?
|
|
243
|
-
|
|
244
|
-
- 在 changeset 里不要勾选它
|
|
245
|
-
- 或者把它标记为 `private: true`
|
|
246
|
-
|
|
247
|
-
### 为什么要在 PR 阶段就看 changeset?
|
|
72
|
+
fixed group 必须整体切换 lane,不能只移动其中一个包。
|
|
248
73
|
|
|
249
|
-
|
|
74
|
+
## 恢复未发布版本
|
|
250
75
|
|
|
251
|
-
|
|
76
|
+
如果版本提交已合并但 npm 发布失败,在 Release workflow 手动选择 `publish-unpublished`,填入 package 和 version。CI 会校验 main 上的 manifest 版本,使用 pnpm 发布并重新生成 tag 和 GitHub Release 元数据。
|
|
252
77
|
|
|
253
|
-
|
|
78
|
+
## repoctl 的边界
|
|
254
79
|
|
|
255
|
-
|
|
80
|
+
生成的 GitHub Actions 只保留环境准备和一个 `pnpm exec repo release ci` 调用。
|
|
81
|
+
repoctl 负责发布前 build/lint/test、lane 一致性检查、Release PR、npm
|
|
82
|
+
发布、package tag 与 GitHub Release;pnpm 负责变更意图、版本计算、changelog、
|
|
83
|
+
ledger 和 registry 发布细节。
|
|
256
84
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
- [命令别名](../repoctl/aliases.md)
|
|
85
|
+
存量项目首次迁移运行 `pnpm dlx repoctl@latest upgrade --yes`,后续使用
|
|
86
|
+
`pnpm exec repo upgrade --yes` 即可跟随 repoctl 升级。未标记的自定义 release
|
|
87
|
+
workflow 默认不会被覆盖,确认后可使用 `repo upgrade --overwrite-release`。
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
|
|
62
62
|
### 发包流程
|
|
63
63
|
|
|
64
|
-
|
|
64
|
+
现在使用 pnpm 原生 versioning:用 `pnpm change` 记录意图,用 `pnpm version -r` 生成版本和 changelog,再用 `pnpm publish -r` 发布。版本计划保留在 `.changeset/ledger.yaml`,预发布则由 pnpm lanes 管理。
|
|
65
65
|
|
|
66
66
|
### Github 相关配置
|
|
67
67
|
|
|
@@ -1,98 +1,75 @@
|
|
|
1
|
-
#
|
|
1
|
+
# pnpm Versioning
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本模板使用 pnpm 11 原生 versioning 管理 monorepo 的变更意图、版本号、changelog 和发布。变更意图仍然使用 `.changeset/*.md` 格式,因此每次改动可以独立提交,不会直接修改包版本。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 日常开发
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
pnpm
|
|
9
|
-
pnpm
|
|
10
|
-
pnpm changeset
|
|
11
|
-
pnpm exec repo release stable
|
|
8
|
+
pnpm change
|
|
9
|
+
pnpm change status
|
|
12
10
|
```
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## 1. 什么是 Changeset?
|
|
17
|
-
|
|
18
|
-
- **核心思想**:每一次改动,不直接修改 `package.json` 里的版本号,而是通过写一个 `changeset` 文件(通常放在 `.changeset` 文件夹下)。
|
|
19
|
-
- **作用**:
|
|
20
|
-
- 记录每次改动影响了哪些包(哪些需要 bump 版本)。
|
|
21
|
-
- 指定改动类型(`patch`、`minor`、`major`)。
|
|
22
|
-
- 自动生成 **Changelog**。
|
|
23
|
-
- 自动修改 `package.json` 的版本号。
|
|
24
|
-
- 与 CI/CD 集成后,可以实现一键自动发版。
|
|
25
|
-
|
|
26
|
-
## 2. 如何使用 Changesets?
|
|
27
|
-
|
|
28
|
-
### 安装
|
|
12
|
+
`pnpm change` 会询问受影响的包、patch/minor/major 类型和 changelog 摘要。脚本或自动化场景可以直接指定:
|
|
29
13
|
|
|
30
14
|
```bash
|
|
31
|
-
|
|
15
|
+
pnpm change --bump patch --summary "修复空输入崩溃" repoctl
|
|
32
16
|
```
|
|
33
17
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```bash
|
|
37
|
-
npx changeset init
|
|
38
|
-
```
|
|
18
|
+
变更意图会写入 `.changeset/`,与代码一起提交。`pnpm change status` 只预览计划,不会修改文件。
|
|
39
19
|
|
|
40
|
-
|
|
20
|
+
## 版本与 changelog
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
当你完成某个功能或修复后,运行:
|
|
22
|
+
在 Release PR 中由 CI 消费变更意图:
|
|
45
23
|
|
|
46
24
|
```bash
|
|
47
|
-
|
|
25
|
+
pnpm version -r --dry-run
|
|
26
|
+
pnpm version -r
|
|
48
27
|
```
|
|
49
28
|
|
|
50
|
-
|
|
29
|
+
`pnpm version -r` 会更新受影响包、传播 workspace 依赖、生成 `CHANGELOG.md`,并把消费记录追加到 `.changeset/ledger.yaml`。仓库配置使用 `versioning.changelog.storage: repository`,所以 changelog 会和版本提交一起审查。
|
|
51
30
|
|
|
52
|
-
|
|
53
|
-
2. 这是 **patch**(补丁)、**minor**(新功能)、还是 **major**(重大变更)?
|
|
54
|
-
3. 变更的描述是什么?
|
|
31
|
+
`@icebreakers/monorepo` 与 `repoctl` 属于 pnpm fixed group,任一包需要发布时两者始终使用同一个版本。
|
|
55
32
|
|
|
56
|
-
|
|
33
|
+
## 发布
|
|
57
34
|
|
|
58
|
-
|
|
59
|
-
# .changeset/sweet-pandas-sing.md
|
|
60
|
-
---
|
|
61
|
-
my-package: patch
|
|
62
|
-
---
|
|
35
|
+
正式发布由 Release PR 合并后的 main workflow 完成:
|
|
63
36
|
|
|
64
|
-
|
|
37
|
+
```bash
|
|
38
|
+
pnpm publish -r --report-summary --provenance --no-git-checks
|
|
65
39
|
```
|
|
66
40
|
|
|
67
|
-
|
|
41
|
+
pnpm 会跳过 registry 中已经存在的版本,并把新发布包写入 `pnpm-publish-summary.json`。CI 根据 summary 创建 `package@version` Git tag 和 GitHub Release,因此重复执行不会重新发布已存在版本。
|
|
68
42
|
|
|
69
|
-
|
|
43
|
+
本地推荐使用 repoctl 包装命令:
|
|
70
44
|
|
|
71
45
|
```bash
|
|
72
|
-
|
|
46
|
+
pnpm exec repo release stable prepare
|
|
47
|
+
pnpm exec repo release stable publish
|
|
73
48
|
```
|
|
74
49
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
- 更新对应包的版本号。
|
|
78
|
-
- 生成/更新 `CHANGELOG.md`。
|
|
50
|
+
## Prerelease lanes
|
|
79
51
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
最后可以发布:
|
|
52
|
+
alpha、beta、rc、next 是 pnpm lanes,而不是 Changesets pre 状态:
|
|
83
53
|
|
|
84
54
|
```bash
|
|
85
|
-
|
|
86
|
-
|
|
55
|
+
pnpm exec repo release pre enter alpha
|
|
56
|
+
git add pnpm-workspace.yaml && git commit -m "chore(release): enter alpha lane"
|
|
57
|
+
git push
|
|
87
58
|
|
|
88
|
-
|
|
59
|
+
pnpm exec repo release pre publish
|
|
60
|
+
```
|
|
89
61
|
|
|
90
|
-
|
|
62
|
+
退出预发布轨道时执行 `pnpm exec repo release pre exit`,提交 `pnpm-workspace.yaml` 后合并回 main。lane 切换必须覆盖 fixed group 的全部包。
|
|
91
63
|
|
|
92
|
-
|
|
93
|
-
- 统一生成 changelog:自动保证每个版本的改动都被记录。
|
|
94
|
-
- 自动化发布:和 GitHub Actions 等 CI 工具结合,可在合并到主分支后自动发版。
|
|
64
|
+
## CI 约定
|
|
95
65
|
|
|
96
|
-
|
|
66
|
+
- 生成的 release workflow 只负责 checkout、安装依赖和权限声明,全部业务统一由 `pnpm exec repo release ci` 执行。
|
|
67
|
+
- main push 先生成或更新 Release PR;Release PR 合并后才发布 npm。
|
|
68
|
+
- alpha、beta、rc、next 分支要求所有可发布包位于对应 lane。
|
|
69
|
+
- npm 发布使用 GitHub OIDC provenance,不需要长期保存 `NPM_TOKEN`。
|
|
70
|
+
- 未发布版本恢复使用 workflow dispatch 的 `publish-unpublished` 模式,并按 package/version 校验后发布。
|
|
71
|
+
- repoctl 通过 GitHub REST API 幂等创建或更新 Release PR、package tag 和 GitHub Release,重复执行不会重复创建元数据。
|
|
97
72
|
|
|
98
|
-
|
|
73
|
+
存量项目首次迁移运行 `pnpm dlx repoctl@latest upgrade --yes`。带有
|
|
74
|
+
`repoctl-managed: release/v2` 的 workflow 会自动升级;未标记的自定义
|
|
75
|
+
workflow 默认保留,可在确认后使用 `repo upgrade --overwrite-release`。
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: repoctl 文档站的工具专题入口,汇总 pnpm、Turborepo
|
|
2
|
+
description: repoctl 文档站的工具专题入口,汇总 pnpm、Turborepo、版本管理、Husky、lint-staged 和 Renovate。
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# 工具专题
|
|
@@ -8,14 +8,14 @@ description: repoctl 文档站的工具专题入口,汇总 pnpm、Turborepo、
|
|
|
8
8
|
|
|
9
9
|
## 1. 工具地图
|
|
10
10
|
|
|
11
|
-
| 工具
|
|
12
|
-
|
|
|
13
|
-
| pnpm
|
|
14
|
-
| Turborepo
|
|
15
|
-
|
|
|
16
|
-
| Husky
|
|
17
|
-
| lint-staged
|
|
18
|
-
| Renovate
|
|
11
|
+
| 工具 | 在 repoctl 工作流里的位置 | 详细页面 |
|
|
12
|
+
| --------------- | ----------------------------------------------- | ------------------------------- |
|
|
13
|
+
| pnpm | workspace、依赖安装、根脚本和包内脚本执行 | [pnpm](./pnpm.md) |
|
|
14
|
+
| Turborepo | build、lint、typecheck、test 等任务编排 | [turborepo](./turborepo.md) |
|
|
15
|
+
| pnpm versioning | 多包版本、变更记录和发布准备 | [versioning](./changeset.md) |
|
|
16
|
+
| Husky | Git hook 入口 | [husky](./husky.md) |
|
|
17
|
+
| lint-staged | staged 文件级 lint、stylelint 和 typecheck 路由 | [lint-staged](./lint-staged.md) |
|
|
18
|
+
| Renovate | 依赖更新和升级 PR 治理 | [renovate](./renovate.md) |
|
|
19
19
|
|
|
20
20
|
## 2. 和 repoctl 的关系
|
|
21
21
|
|
|
@@ -33,6 +33,6 @@ repoctl 不隐藏这些工具。它主要做三件事:
|
|
|
33
33
|
| ------------------------- | ------------------------------------------------------ |
|
|
34
34
|
| 让 workspace 包能互相引用 | [pnpm](./pnpm.md) |
|
|
35
35
|
| 提升整仓任务速度 | [turborepo](./turborepo.md) |
|
|
36
|
-
| 建立规范发版链路 | [
|
|
36
|
+
| 建立规范发版链路 | [pnpm versioning](./changeset.md) |
|
|
37
37
|
| 提交前自动修复格式和 lint | [Husky](./husky.md) 与 [lint-staged](./lint-staged.md) |
|
|
38
38
|
| 降低依赖升级成本 | [Renovate](./renovate.md) |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import Vue from '@vitejs/plugin-vue'
|
|
2
2
|
import { defineVitestProjectConfig } from 'repoctl/tooling'
|
|
3
3
|
import { mergeConfig } from 'vitest/config'
|
|
4
|
-
import { sharedConfig } from './vite.shared.config'
|
|
4
|
+
import { sharedConfig } from './vite.shared.config.ts'
|
|
5
5
|
|
|
6
6
|
export default mergeConfig(sharedConfig, {
|
|
7
7
|
...await defineVitestProjectConfig({
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://unpkg.com/@changesets/config@3.0.2/schema.json",
|
|
3
|
-
"changelog": [
|
|
4
|
-
"@icebreakers/changelog-github",
|
|
5
|
-
{
|
|
6
|
-
"repo": "sonofmagic/monorepo-template"
|
|
7
|
-
}
|
|
8
|
-
],
|
|
9
|
-
"commit": false,
|
|
10
|
-
"fixed": [],
|
|
11
|
-
"linked": [
|
|
12
|
-
[
|
|
13
|
-
"@icebreakers/monorepo",
|
|
14
|
-
"repoctl"
|
|
15
|
-
]
|
|
16
|
-
],
|
|
17
|
-
"access": "public",
|
|
18
|
-
"baseBranch": "main",
|
|
19
|
-
"updateInternalDependencies": "patch",
|
|
20
|
-
"ignore": []
|
|
21
|
-
}
|