create-halo-plugin-template 1.0.0 → 1.0.1

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.
Files changed (108) hide show
  1. package/.editorconfig +520 -0
  2. package/.github/workflows/cd.yaml +20 -0
  3. package/.github/workflows/ci.yaml +32 -0
  4. package/.github/workflows/publish-npm.yaml +46 -0
  5. package/.gitignore +84 -0
  6. package/LICENSE +674 -0
  7. package/README.md +191 -0
  8. package/build.gradle +103 -0
  9. package/docs/first-npm-release-checklist.md +58 -0
  10. package/docs/publish-template.md +148 -0
  11. package/docs/rsbuild-switch.md +90 -0
  12. package/docs/template-pruning.md +43 -0
  13. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  14. package/gradle/wrapper/gradle-wrapper.properties +7 -0
  15. package/gradle.properties +1 -0
  16. package/gradlew +248 -0
  17. package/gradlew.bat +93 -0
  18. package/package.json +67 -7
  19. package/scripts/create-project.mjs +399 -0
  20. package/scripts/init-template.mjs +281 -0
  21. package/scripts/publish-check.mjs +97 -0
  22. package/scripts/release.mjs +278 -0
  23. package/scripts/verify-template.mjs +407 -0
  24. package/settings.gradle +7 -0
  25. package/src/main/java/run/halo/plugintemplate/PluginTemplatePlugin.java +43 -0
  26. package/src/main/java/run/halo/plugintemplate/config/PluginTemplateConfig.java +14 -0
  27. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateChecklistItem.java +30 -0
  28. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateFeatureItem.java +30 -0
  29. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateOverview.java +73 -0
  30. package/src/main/java/run/halo/plugintemplate/dto/PluginTemplateStatItem.java +30 -0
  31. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplateConsoleEndpoint.java +33 -0
  32. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplatePublicEndpoint.java +26 -0
  33. package/src/main/java/run/halo/plugintemplate/endpoint/PluginTemplateUcEndpoint.java +33 -0
  34. package/src/main/java/run/halo/plugintemplate/endpoint/routes/PluginTemplateOverviewRoutes.java +60 -0
  35. package/src/main/java/run/halo/plugintemplate/model/PluginTemplateAudience.java +23 -0
  36. package/src/main/java/run/halo/plugintemplate/query/PluginTemplateOverviewQuery.java +26 -0
  37. package/src/main/java/run/halo/plugintemplate/reconcile/PluginTemplateSettingsReconciler.java +17 -0
  38. package/src/main/java/run/halo/plugintemplate/scheme/PluginTemplateRecord.java +43 -0
  39. package/src/main/java/run/halo/plugintemplate/service/PluginTemplateOverviewService.java +10 -0
  40. package/src/main/java/run/halo/plugintemplate/service/impl/PluginTemplateOverviewServiceImpl.java +74 -0
  41. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateGeneralSetting.java +25 -0
  42. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateSettingKeys.java +24 -0
  43. package/src/main/java/run/halo/plugintemplate/setting/PluginTemplateUiSetting.java +13 -0
  44. package/src/main/java/run/halo/plugintemplate/utils/PluginTemplateSeeds.java +197 -0
  45. package/src/main/resources/extensions/roleTemplate-console.yaml +39 -0
  46. package/src/main/resources/extensions/roleTemplate-uc.yaml +19 -0
  47. package/src/main/resources/extensions/settings.yaml +47 -0
  48. package/src/main/resources/logo.png +0 -0
  49. package/src/main/resources/plugin.yaml +24 -0
  50. package/src/test/java/run/halo/plugintemplate/PluginTemplatePluginTest.java +34 -0
  51. package/src/test/java/run/halo/plugintemplate/service/impl/PluginTemplateOverviewServiceImplTest.java +97 -0
  52. package/ui/build.gradle +41 -0
  53. package/ui/env.d.ts +2 -0
  54. package/ui/eslint.config.ts +30 -0
  55. package/ui/package.json +57 -0
  56. package/ui/pnpm-lock.yaml +5250 -0
  57. package/ui/src/api/__tests__/normalizers.spec.ts +65 -0
  58. package/ui/src/api/generated/.openapi-generator/FILES +23 -0
  59. package/ui/src/api/generated/.openapi-generator/VERSION +1 -0
  60. package/ui/src/api/generated/.openapi-generator-ignore +23 -0
  61. package/ui/src/api/generated/api/plugin-template-console-api.ts +128 -0
  62. package/ui/src/api/generated/api/plugin-template-uc-api.ts +128 -0
  63. package/ui/src/api/generated/api.ts +19 -0
  64. package/ui/src/api/generated/base.ts +86 -0
  65. package/ui/src/api/generated/common.ts +150 -0
  66. package/ui/src/api/generated/configuration.ts +110 -0
  67. package/ui/src/api/generated/git_push.sh +57 -0
  68. package/ui/src/api/generated/index.ts +18 -0
  69. package/ui/src/api/generated/models/add-operation.ts +49 -0
  70. package/ui/src/api/generated/models/copy-operation.ts +49 -0
  71. package/ui/src/api/generated/models/index.ts +11 -0
  72. package/ui/src/api/generated/models/json-patch-inner.ts +41 -0
  73. package/ui/src/api/generated/models/move-operation.ts +49 -0
  74. package/ui/src/api/generated/models/plugin-template-checklist-item.ts +54 -0
  75. package/ui/src/api/generated/models/plugin-template-feature-item.ts +54 -0
  76. package/ui/src/api/generated/models/plugin-template-overview.ts +147 -0
  77. package/ui/src/api/generated/models/plugin-template-stat-item.ts +54 -0
  78. package/ui/src/api/generated/models/remove-operation.ts +43 -0
  79. package/ui/src/api/generated/models/replace-operation.ts +49 -0
  80. package/ui/src/api/generated/models/test-operation.ts +49 -0
  81. package/ui/src/api/index.ts +42 -0
  82. package/ui/src/api/normalizers.ts +65 -0
  83. package/ui/src/assets/element.scss +24 -0
  84. package/ui/src/assets/index.css +361 -0
  85. package/ui/src/assets/logo.svg +1 -0
  86. package/ui/src/components/PluginTemplateAttachmentTab.vue +69 -0
  87. package/ui/src/components/PluginTemplateCommonTable.vue +69 -0
  88. package/ui/src/components/PluginTemplateDashboardWidget.vue +62 -0
  89. package/ui/src/components/PluginTemplateOverviewPage.vue +254 -0
  90. package/ui/src/components/ui/PluginUiProvider.vue +40 -0
  91. package/ui/src/components/ui/UiMetricCard.vue +21 -0
  92. package/ui/src/components/ui/UiSectionCard.vue +25 -0
  93. package/ui/src/components/ui/UiStatusPill.vue +18 -0
  94. package/ui/src/composables/useTemplateOverview.ts +38 -0
  95. package/ui/src/index.ts +88 -0
  96. package/ui/src/lib/__tests__/plugin-ui.spec.ts +19 -0
  97. package/ui/src/lib/plugin-ui.ts +19 -0
  98. package/ui/src/lib/template.spec.ts +24 -0
  99. package/ui/src/lib/template.ts +52 -0
  100. package/ui/src/lib/theme.ts +31 -0
  101. package/ui/src/types/index.ts +59 -0
  102. package/ui/src/views/console/ConsoleDashboardView.vue +7 -0
  103. package/ui/src/views/uc/UcDashboardView.vue +7 -0
  104. package/ui/tsconfig.app.json +12 -0
  105. package/ui/tsconfig.json +14 -0
  106. package/ui/tsconfig.node.json +15 -0
  107. package/ui/tsconfig.vitest.json +11 -0
  108. package/ui/vite.config.ts +25 -0
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from 'node:path'
4
+ import process from 'node:process'
5
+ import { spawn } from 'node:child_process'
6
+
7
+ const ROOT = process.cwd()
8
+
9
+ const usage = `
10
+ Usage:
11
+ node scripts/publish-check.mjs
12
+ node scripts/publish-check.mjs --pack-only
13
+ node scripts/publish-check.mjs --skip-build
14
+ `.trim()
15
+
16
+ const parseArgs = (argv) => {
17
+ const options = {
18
+ packOnly: false,
19
+ skipBuild: false,
20
+ help: false,
21
+ }
22
+
23
+ for (const token of argv) {
24
+ if (token === '--help' || token === '-h') {
25
+ options.help = true
26
+ continue
27
+ }
28
+ if (token === '--pack-only') {
29
+ options.packOnly = true
30
+ continue
31
+ }
32
+ if (token === '--skip-build') {
33
+ options.skipBuild = true
34
+ continue
35
+ }
36
+ throw new Error(`Unknown argument: ${token}`)
37
+ }
38
+
39
+ return options
40
+ }
41
+
42
+ const runCommand = async (command, args, cwd = ROOT, env = process.env) => {
43
+ await new Promise((resolve, reject) => {
44
+ const child = spawn(command, args, {
45
+ cwd,
46
+ env,
47
+ stdio: 'inherit',
48
+ shell: false,
49
+ })
50
+
51
+ child.on('error', reject)
52
+ child.on('close', (code) => {
53
+ if (code === 0) {
54
+ resolve(undefined)
55
+ return
56
+ }
57
+ reject(new Error(`Command failed (${code}): ${command} ${args.join(' ')}`))
58
+ })
59
+ })
60
+ }
61
+
62
+ const main = async () => {
63
+ try {
64
+ const options = parseArgs(process.argv.slice(2))
65
+
66
+ if (options.help) {
67
+ console.log(usage)
68
+ return
69
+ }
70
+
71
+ const npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'
72
+ const pnpmCommand = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm'
73
+ const gradleCommand = process.platform === 'win32' ? 'gradlew.bat' : './gradlew'
74
+ const npmEnv = {
75
+ ...process.env,
76
+ npm_config_cache: path.join(ROOT, '.npm-cache'),
77
+ }
78
+
79
+ if (!options.packOnly) {
80
+ await runCommand(process.execPath, [path.join('scripts', 'verify-template.mjs')])
81
+ await runCommand(pnpmCommand, ['install', '--dir', 'ui', '--frozen-lockfile'])
82
+ await runCommand(pnpmCommand, ['verify'], path.join(ROOT, 'ui'))
83
+
84
+ if (!options.skipBuild) {
85
+ await runCommand(gradleCommand, ['build'])
86
+ }
87
+ }
88
+
89
+ await runCommand(npmCommand, ['pack', '--dry-run'], ROOT, npmEnv)
90
+ } catch (error) {
91
+ console.error(`Publish check failed: ${error instanceof Error ? error.message : String(error)}`)
92
+ console.error(usage)
93
+ process.exitCode = 1
94
+ }
95
+ }
96
+
97
+ await main()
@@ -0,0 +1,278 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from 'node:fs/promises'
4
+ import path from 'node:path'
5
+ import process from 'node:process'
6
+ import { spawn } from 'node:child_process'
7
+
8
+ const ROOT = process.cwd()
9
+ const PACKAGE_JSON_PATH = path.join(ROOT, 'package.json')
10
+
11
+ const usage = `
12
+ Usage:
13
+ node scripts/release.mjs --bump patch|minor|major [--skip-checks] [--push]
14
+ node scripts/release.mjs --version x.y.z [--skip-checks] [--push]
15
+
16
+ Examples:
17
+ node scripts/release.mjs --bump patch
18
+ node scripts/release.mjs --bump minor --push
19
+ node scripts/release.mjs --version 1.0.0 --push
20
+ `.trim()
21
+
22
+ const parseArgs = (argv) => {
23
+ const options = {
24
+ bump: null,
25
+ version: null,
26
+ push: false,
27
+ skipChecks: false,
28
+ help: false,
29
+ }
30
+
31
+ for (let index = 0; index < argv.length; index += 1) {
32
+ const token = argv[index]
33
+
34
+ if (token === '--help' || token === '-h') {
35
+ options.help = true
36
+ continue
37
+ }
38
+
39
+ if (token === '--push') {
40
+ options.push = true
41
+ continue
42
+ }
43
+
44
+ if (token === '--skip-checks') {
45
+ options.skipChecks = true
46
+ continue
47
+ }
48
+
49
+ if (token === '--bump') {
50
+ const value = argv[index + 1]
51
+ if (!value) {
52
+ throw new Error('Missing value for --bump')
53
+ }
54
+ options.bump = value
55
+ index += 1
56
+ continue
57
+ }
58
+
59
+ if (token === '--version') {
60
+ const value = argv[index + 1]
61
+ if (!value) {
62
+ throw new Error('Missing value for --version')
63
+ }
64
+ options.version = value
65
+ index += 1
66
+ continue
67
+ }
68
+
69
+ throw new Error(`Unknown argument: ${token}`)
70
+ }
71
+
72
+ if (!options.help && !options.bump && !options.version) {
73
+ throw new Error('Either --bump or --version is required')
74
+ }
75
+
76
+ if (options.bump && options.version) {
77
+ throw new Error('Use either --bump or --version, not both')
78
+ }
79
+
80
+ return options
81
+ }
82
+
83
+ const runCommand = async (command, args, cwd = ROOT) => {
84
+ await new Promise((resolve, reject) => {
85
+ const child = spawn(command, args, {
86
+ cwd,
87
+ stdio: 'inherit',
88
+ shell: false,
89
+ })
90
+
91
+ child.on('error', reject)
92
+ child.on('close', (code) => {
93
+ if (code === 0) {
94
+ resolve(undefined)
95
+ return
96
+ }
97
+ reject(new Error(`Command failed (${code}): ${command} ${args.join(' ')}`))
98
+ })
99
+ })
100
+ }
101
+
102
+ const captureCommand = async (command, args, cwd = ROOT) =>
103
+ new Promise((resolve, reject) => {
104
+ const child = spawn(command, args, {
105
+ cwd,
106
+ stdio: ['ignore', 'pipe', 'pipe'],
107
+ shell: false,
108
+ })
109
+
110
+ let stdout = ''
111
+ let stderr = ''
112
+
113
+ child.stdout.on('data', (chunk) => {
114
+ stdout += chunk.toString()
115
+ })
116
+
117
+ child.stderr.on('data', (chunk) => {
118
+ stderr += chunk.toString()
119
+ })
120
+
121
+ child.on('error', reject)
122
+ child.on('close', (code) => {
123
+ if (code === 0) {
124
+ resolve(stdout.trim())
125
+ return
126
+ }
127
+ reject(
128
+ new Error(
129
+ `Command failed (${code}): ${command} ${args.join(' ')}\n${stderr.trim()}`.trim(),
130
+ ),
131
+ )
132
+ })
133
+ })
134
+
135
+ const parseVersion = (version) => {
136
+ const match = /^(\d+)\.(\d+)\.(\d+)$/.exec(version)
137
+ if (!match) {
138
+ throw new Error(`Invalid semver version: ${version}`)
139
+ }
140
+
141
+ return {
142
+ major: Number(match[1]),
143
+ minor: Number(match[2]),
144
+ patch: Number(match[3]),
145
+ }
146
+ }
147
+
148
+ const bumpVersion = (version, bumpType) => {
149
+ const parsed = parseVersion(version)
150
+
151
+ switch (bumpType) {
152
+ case 'patch':
153
+ return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`
154
+ case 'minor':
155
+ return `${parsed.major}.${parsed.minor + 1}.0`
156
+ case 'major':
157
+ return `${parsed.major + 1}.0.0`
158
+ default:
159
+ throw new Error(`Unsupported bump type: ${bumpType}`)
160
+ }
161
+ }
162
+
163
+ const compareVersions = (left, right) => {
164
+ const leftParsed = parseVersion(left)
165
+ const rightParsed = parseVersion(right)
166
+
167
+ if (leftParsed.major !== rightParsed.major) {
168
+ return leftParsed.major - rightParsed.major
169
+ }
170
+
171
+ if (leftParsed.minor !== rightParsed.minor) {
172
+ return leftParsed.minor - rightParsed.minor
173
+ }
174
+
175
+ return leftParsed.patch - rightParsed.patch
176
+ }
177
+
178
+ const fetchPublishedVersions = async (packageName) => {
179
+ try {
180
+ const output = await captureCommand('npm', ['view', packageName, 'versions', '--json'])
181
+ if (!output) {
182
+ return []
183
+ }
184
+
185
+ const parsed = JSON.parse(output)
186
+ if (Array.isArray(parsed)) {
187
+ return parsed
188
+ }
189
+
190
+ return [String(parsed)]
191
+ } catch (error) {
192
+ const message = error instanceof Error ? error.message : String(error)
193
+ if (message.includes('E404') || message.includes('404 Not Found')) {
194
+ return []
195
+ }
196
+ throw error
197
+ }
198
+ }
199
+
200
+ const main = async () => {
201
+ let originalPackageJson = null
202
+
203
+ try {
204
+ const options = parseArgs(process.argv.slice(2))
205
+
206
+ if (options.help) {
207
+ console.log(usage)
208
+ return
209
+ }
210
+
211
+ const gitStatus = await captureCommand('git', ['status', '--porcelain'])
212
+ if (gitStatus) {
213
+ throw new Error('Working tree is not clean. Commit or stash changes before releasing.')
214
+ }
215
+
216
+ const currentBranch = await captureCommand('git', ['branch', '--show-current'])
217
+ if (currentBranch !== 'main') {
218
+ throw new Error(`Release must be prepared from main. Current branch: ${currentBranch}`)
219
+ }
220
+
221
+ const packageJsonRaw = await fs.readFile(PACKAGE_JSON_PATH, 'utf8')
222
+ originalPackageJson = packageJsonRaw
223
+ const packageJson = JSON.parse(packageJsonRaw)
224
+
225
+ const nextVersion = options.version ?? bumpVersion(packageJson.version, options.bump)
226
+ parseVersion(nextVersion)
227
+
228
+ const publishedVersions = await fetchPublishedVersions(packageJson.name)
229
+ const latestPublishedVersion = publishedVersions
230
+ .filter(Boolean)
231
+ .sort(compareVersions)
232
+ .at(-1)
233
+
234
+ if (latestPublishedVersion && compareVersions(nextVersion, latestPublishedVersion) <= 0) {
235
+ throw new Error(
236
+ `Version ${nextVersion} must be greater than the latest published npm version ${latestPublishedVersion}`,
237
+ )
238
+ }
239
+
240
+ const existingLocalTag = await captureCommand('git', ['tag', '--list', `v${nextVersion}`])
241
+ if (existingLocalTag) {
242
+ throw new Error(`Tag v${nextVersion} already exists locally`)
243
+ }
244
+
245
+ packageJson.version = nextVersion
246
+ await fs.writeFile(PACKAGE_JSON_PATH, `${JSON.stringify(packageJson, null, 2)}\n`, 'utf8')
247
+
248
+ if (!options.skipChecks) {
249
+ await runCommand(process.execPath, [path.join('scripts', 'publish-check.mjs')])
250
+ }
251
+
252
+ await runCommand('git', ['add', 'package.json'])
253
+ await runCommand('git', ['commit', '-m', `chore: release v${nextVersion}`])
254
+ await runCommand('git', ['tag', '-a', `v${nextVersion}`, '-m', `v${nextVersion}`])
255
+
256
+ if (options.push) {
257
+ await runCommand('git', ['push', 'origin', 'main'])
258
+ await runCommand('git', ['push', 'origin', `v${nextVersion}`])
259
+ }
260
+
261
+ console.log(`Prepared release v${nextVersion}`)
262
+ console.log(
263
+ options.push
264
+ ? 'main and tags have been pushed. The npm publish workflow should run from the tag push once Trusted Publishing is configured.'
265
+ : 'Next step: git push origin main --follow-tags',
266
+ )
267
+ } catch (error) {
268
+ if (originalPackageJson !== null) {
269
+ await fs.writeFile(PACKAGE_JSON_PATH, originalPackageJson, 'utf8')
270
+ }
271
+
272
+ console.error(`Release preparation failed: ${error instanceof Error ? error.message : String(error)}`)
273
+ console.error(usage)
274
+ process.exitCode = 1
275
+ }
276
+ }
277
+
278
+ await main()