@spaceflow/publish 0.21.3 → 0.22.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/dist/index.js CHANGED
@@ -1,11 +1,8 @@
1
1
  import * as __rspack_external_fs from "fs";
2
2
  import * as __rspack_external_release_it_4c635798 from "release-it";
3
- import { ConfigReaderModule, ConfigReaderService, GitProviderModule, GitProviderService, addLocaleResources, ciConfig, t as core_t, z } from "@spaceflow/core";
4
- import { Injectable, Module } from "@nestjs/common";
5
- import { ConfigModule, ConfigService } from "@nestjs/config";
6
- import { Command, CommandRunner, Option } from "nest-commander";
7
- import { execSync } from "child_process";
3
+ import { addLocaleResources, ciConfig, defineExtension, t as core_t, z } from "@spaceflow/core";
8
4
  import { join } from "path";
5
+ import { execSync } from "child_process";
9
6
  var __webpack_modules__ = ({
10
7
  421(module) {
11
8
 
@@ -64,13 +61,8 @@ var __webpack_exports__ = {};
64
61
 
65
62
  // EXPORTS
66
63
  __webpack_require__.d(__webpack_exports__, {
67
- Vy: () => (/* reexport */ MonorepoService),
68
- Ay: () => (/* binding */ src),
69
- D5: () => (/* reexport */ PublishCommand),
70
- i8: () => (/* reexport */ PublishModule),
71
- jX: () => (/* binding */ PublishExtension),
72
- DU: () => (/* reexport */ PublishService),
73
- bH: () => (/* binding */ publishMetadata)
64
+ A: () => (/* binding */ src),
65
+ c: () => (/* binding */ extension)
74
66
  });
75
67
 
76
68
  ;// CONCATENATED MODULE: external "@spaceflow/core"
@@ -89,469 +81,201 @@ var en_publish_namespaceObject = JSON.parse('{"description":"CI publish command
89
81
  };
90
82
  addLocaleResources("publish", publishLocales);
91
83
 
92
- ;// CONCATENATED MODULE: external "@nestjs/common"
93
-
94
- ;// CONCATENATED MODULE: external "@nestjs/config"
95
-
96
- ;// CONCATENATED MODULE: external "nest-commander"
84
+ ;// CONCATENATED MODULE: ./src/publish.config.ts
97
85
 
98
- ;// CONCATENATED MODULE: external "child_process"
86
+ /** publish 命令配置 schema */ const publishSchema = z.object({
87
+ /** monorepo 发布模式配置 */ monorepo: z.object({
88
+ /** 是否启用 monorepo 发布模式 */ enabled: z.boolean().default(false),
89
+ /** 是否传递依赖变更(依赖的包变更时,依赖方也发布) */ propagateDeps: z.boolean().default(true)
90
+ }).optional(),
91
+ changelog: z.object({
92
+ /** changelog 文件输出目录 */ infileDir: z.string().default(".").optional(),
93
+ preset: z.object({
94
+ /** preset 名称,默认 conventionalcommits */ name: z.string().default("conventionalcommits").optional(),
95
+ /** commit type 到 section 的映射 */ type: z.array(z.object({
96
+ type: z.string(),
97
+ section: z.string()
98
+ })).default([])
99
+ }).optional()
100
+ }).optional(),
101
+ /** npm 发布配置 */ npm: z.object({
102
+ /** 是否发布到 npm registry */ publish: z.boolean().default(false),
103
+ /** 包管理器,npm 或 pnpm */ packageManager: z["enum"]([
104
+ "npm",
105
+ "pnpm"
106
+ ]).default("npm"),
107
+ /** npm registry 地址 */ registry: z.string().optional(),
108
+ /** npm tag,如 latest、beta、next */ tag: z.string().default("latest"),
109
+ /** 是否忽略 package.json 中的版本号 */ ignoreVersion: z.boolean().default(true),
110
+ /** npm version 命令额外参数 */ versionArgs: z.array(z.string()).default([
111
+ "--workspaces false"
112
+ ]),
113
+ /** npm/pnpm publish 命令额外参数 */ publishArgs: z.array(z.string()).default([])
114
+ }).optional(),
115
+ release: z.object({
116
+ host: z.string().default("localhost"),
117
+ assetSourcemap: z.object({
118
+ path: z.string(),
119
+ name: z.string()
120
+ }).optional(),
121
+ assets: z.array(z.object({
122
+ path: z.string(),
123
+ name: z.string(),
124
+ type: z.string()
125
+ })).default([])
126
+ }).optional(),
127
+ /** git 配置 */ git: z.object({
128
+ /** 允许发布的分支列表 */ requireBranch: z.array(z.string()).default([
129
+ "main",
130
+ "dev",
131
+ "develop"
132
+ ]),
133
+ /** 分支锁定时允许推送的用户名白名单(如 CI 机器人) */ pushWhitelistUsernames: z.array(z.string()).default([]),
134
+ /** 是否在发布时锁定分支 */ lockBranch: z.boolean().default(true)
135
+ }).optional(),
136
+ /** release-it hooks 配置,如 before:bump, after:bump 等 */ hooks: z.record(z.string(), z.union([
137
+ z.string(),
138
+ z.array(z.string())
139
+ ])).optional()
140
+ });
99
141
 
100
- // EXTERNAL MODULE: external "fs"
101
- var external_fs_ = __webpack_require__(421);
102
142
  ;// CONCATENATED MODULE: external "path"
103
143
 
104
- ;// CONCATENATED MODULE: ./src/monorepo.service.ts
105
- function _ts_decorate(decorators, target, key, desc) {
106
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
107
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
108
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
109
- return c > 3 && r && Object.defineProperty(target, key, r), r;
110
- }
111
- function _ts_metadata(k, v) {
112
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
113
- }
144
+ ;// CONCATENATED MODULE: external "child_process"
114
145
 
146
+ ;// CONCATENATED MODULE: ./src/publish.service.ts
115
147
 
116
148
 
117
149
 
118
- class MonorepoService {
119
- cwd;
120
- constructor(){
121
- this.cwd = process.cwd();
150
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
151
+ const releaseItModule = __webpack_require__(547);
152
+ const releaseIt = typeof releaseItModule === "function" ? releaseItModule : releaseItModule.default;
153
+ class PublishService {
154
+ gitProvider;
155
+ config;
156
+ configReader;
157
+ monorepoService;
158
+ cleanupOnExit = null;
159
+ uncaughtExceptionHandler = null;
160
+ branchUnlocked = false;
161
+ constructor(gitProvider, config, configReader, monorepoService){
162
+ this.gitProvider = gitProvider;
163
+ this.config = config;
164
+ this.configReader = configReader;
165
+ this.monorepoService = monorepoService;
122
166
  }
123
- /**
124
- * 分析 monorepo 变更,返回需要发布的包列表(拓扑排序后)
125
- * @param dryRun 是否为 dry-run 模式
126
- * @param propagateDeps 是否传递依赖变更(依赖的包变更时,依赖方也发布)
127
- */ async analyze(dryRun, propagateDeps = true) {
128
- const workspacePackages = this.getWorkspacePackages();
129
- const allPackages = this.getAllPackageInfos(workspacePackages);
130
- // 为每个包单独检测变更(基于各自的最新 tag)
131
- const changedPackages = this.getChangedPackages(allPackages, dryRun);
132
- if (dryRun) {
133
- console.log(`📦 直接变更的包: ${changedPackages.map((p)=>p.name).join(", ") || "无"}`);
167
+ getContextFromEnv(options) {
168
+ this.gitProvider.validateConfig();
169
+ const ciConf = ciConfig();
170
+ const repository = ciConf.repository;
171
+ const branch = ciConf.refName;
172
+ if (!repository) {
173
+ throw new Error("缺少配置 ci.repository (环境变量 GITHUB_REPOSITORY)");
134
174
  }
135
- // 计算依赖传递,找出所有需要发布的包
136
- const packagesToPublish = propagateDeps ? this.calculateAffectedPackages(changedPackages, allPackages) : changedPackages;
137
- if (dryRun) {
138
- console.log(`🔄 需要发布的包(含依赖传递): ${packagesToPublish.map((p)=>p.name).join(", ") || "无"}`);
175
+ if (!branch) {
176
+ throw new Error("缺少配置 ci.refName (环境变量 GITHUB_REF_NAME)");
139
177
  }
140
- // 拓扑排序
141
- const sortedPackages = this.topologicalSort(packagesToPublish, allPackages);
142
- if (dryRun) {
143
- console.log(`📋 发布顺序: ${sortedPackages.map((p)=>p.name).join(" -> ") || "无"}`);
178
+ const [owner, repo] = repository.split("/");
179
+ if (!owner || !repo) {
180
+ throw new Error(`ci.repository 格式不正确,期望 "owner/repo",实际: "${repository}"`);
144
181
  }
145
182
  return {
146
- changedPackages,
147
- packagesToPublish: sortedPackages
183
+ owner,
184
+ repo,
185
+ branch,
186
+ dryRun: options.dryRun ?? false,
187
+ prerelease: options.prerelease,
188
+ ci: options.ci,
189
+ rehearsal: options.rehearsal ?? false
148
190
  };
149
191
  }
192
+ async execute(context) {
193
+ const publishConf = this.configReader.getPluginConfig("publish");
194
+ const monorepoConf = publishConf.monorepo;
195
+ // CI 环境下自动 fetch tags,确保 release-it 能正确计算版本
196
+ if (context.ci) {
197
+ await this.ensureTagsFetched();
198
+ }
199
+ // 检查是否启用 monorepo 模式
200
+ if (monorepoConf?.enabled) {
201
+ return this.executeMonorepo(context, publishConf);
202
+ }
203
+ // 单包发布模式
204
+ return this.executeSinglePackage(context, publishConf);
205
+ }
150
206
  /**
151
- * 简单解析 pnpm-workspace.yaml(只提取 packages 数组)
152
- */ parseSimpleYaml(content) {
153
- const packages = [];
154
- const lines = content.split("\n");
155
- let inPackages = false;
156
- for (const line of lines){
157
- const trimmed = line.trim();
158
- if (trimmed === "packages:") {
159
- inPackages = true;
160
- continue;
207
+ * Monorepo 发布模式:扫描变更包,按依赖顺序发布
208
+ */ async executeMonorepo(context, publishConf) {
209
+ const { dryRun } = context;
210
+ console.log("\n📦 Monorepo 发布模式");
211
+ console.log("=".repeat(50));
212
+ const propagateDeps = publishConf.monorepo?.propagateDeps ?? true;
213
+ // 分析变更包
214
+ const analysis = await this.monorepoService.analyze(dryRun, propagateDeps);
215
+ if (analysis.packagesToPublish.length === 0) {
216
+ console.log("\n✅ 没有需要发布的包");
217
+ return {
218
+ success: true,
219
+ message: "没有需要发布的包"
220
+ };
221
+ }
222
+ console.log(`\n🚀 将发布 ${analysis.packagesToPublish.length} 个包`);
223
+ await this.handleBegin(context, publishConf);
224
+ try {
225
+ // 按顺序发布每个包
226
+ for(let i = 0; i < analysis.packagesToPublish.length; i++){
227
+ const pkg = analysis.packagesToPublish[i];
228
+ console.log(`\n[${i + 1}/${analysis.packagesToPublish.length}] 发布 ${pkg.name}`);
229
+ console.log("-".repeat(40));
230
+ await this.executePackageRelease(context, publishConf, pkg);
161
231
  }
162
- if (inPackages) {
163
- if (trimmed.startsWith("- ")) {
164
- // 提取包路径,去除引号
165
- let pkg = trimmed.slice(2).trim();
166
- pkg = pkg.replace(/^["']|["']$/g, "");
167
- packages.push(pkg);
168
- } else if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("-")) {
169
- break;
170
- }
232
+ await this.handleEnd(context, publishConf);
233
+ return {
234
+ success: true,
235
+ message: `成功发布 ${analysis.packagesToPublish.length} 个包`
236
+ };
237
+ } catch (error) {
238
+ console.error("\n❌ Monorepo 发布失败:", error instanceof Error ? error.message : error);
239
+ try {
240
+ await this.handleEnd(context, publishConf);
241
+ } catch (unlockError) {
242
+ console.error("⚠️ 解锁分支失败:", unlockError instanceof Error ? unlockError.message : unlockError);
171
243
  }
244
+ return {
245
+ success: false,
246
+ message: "Monorepo 发布失败"
247
+ };
172
248
  }
173
- return {
174
- packages: packages.length > 0 ? packages : undefined
175
- };
176
249
  }
177
250
  /**
178
- * pnpm-workspace.yaml 读取 workspace 包配置
179
- */ getWorkspacePackages() {
180
- const workspaceFile = join(this.cwd, "pnpm-workspace.yaml");
181
- if (!(0,external_fs_.existsSync)(workspaceFile)) {
182
- throw new Error("未找到 pnpm-workspace.yaml 文件");
251
+ * 发布单个包(monorepo 模式)
252
+ */ async executePackageRelease(context, publishConf, pkg) {
253
+ const { dryRun, prerelease, ci, rehearsal } = context;
254
+ if (rehearsal) {
255
+ console.log(`🎭 [REHEARSAL] 将发布包: ${pkg.name} (${pkg.dir})`);
256
+ } else if (dryRun) {
257
+ console.log(`🔍 [DRY-RUN] 将发布包: ${pkg.name} (${pkg.dir})`);
183
258
  }
184
- const content = (0,external_fs_.readFileSync)(workspaceFile, "utf-8");
185
- const config = this.parseSimpleYaml(content);
186
- if (!config.packages || !Array.isArray(config.packages)) {
187
- throw new Error("pnpm-workspace.yaml 中未配置 packages");
188
- }
189
- return config.packages;
190
- }
191
- /**
192
- * 展开 workspace 包配置,获取所有实际的包目录
193
- */ expandWorkspacePatterns(patterns) {
194
- const dirs = [];
195
- for (const pattern of patterns){
196
- if (pattern.includes("*")) {
197
- // 使用 glob 展开,这里简化处理,只支持 extensions/* 这种模式
198
- const baseDir = pattern.replace("/*", "");
199
- const basePath = join(this.cwd, baseDir);
200
- if ((0,external_fs_.existsSync)(basePath)) {
201
- const { readdirSync, statSync } = __webpack_require__(421);
202
- const entries = readdirSync(basePath);
203
- for (const entry of entries){
204
- const entryPath = join(basePath, entry);
205
- if (statSync(entryPath).isDirectory()) {
206
- const pkgJson = join(entryPath, "package.json");
207
- if ((0,external_fs_.existsSync)(pkgJson)) {
208
- dirs.push(join(baseDir, entry));
209
- }
210
- }
211
- }
212
- }
213
- } else {
214
- // 直接目录
215
- const pkgJson = join(this.cwd, pattern, "package.json");
216
- if ((0,external_fs_.existsSync)(pkgJson)) {
217
- dirs.push(pattern);
218
- }
219
- }
220
- }
221
- return dirs;
222
- }
223
- /**
224
- * 获取所有包的详细信息(排除私有包)
225
- */ getAllPackageInfos(patterns) {
226
- const dirs = this.expandWorkspacePatterns(patterns);
227
- const packages = [];
228
- for (const dir of dirs){
229
- const pkgJsonPath = join(this.cwd, dir, "package.json");
230
- if (!(0,external_fs_.existsSync)(pkgJsonPath)) continue;
231
- const pkgJson = JSON.parse((0,external_fs_.readFileSync)(pkgJsonPath, "utf-8"));
232
- // 跳过私有包
233
- if (pkgJson.private === true) continue;
234
- const workspaceDeps = this.extractWorkspaceDeps(pkgJson);
235
- packages.push({
236
- dir,
237
- name: pkgJson.name,
238
- version: pkgJson.version,
239
- workspaceDeps
240
- });
241
- }
242
- return packages;
243
- }
244
- /**
245
- * 提取包的 workspace 依赖
246
- */ extractWorkspaceDeps(pkgJson) {
247
- const deps = [];
248
- const allDeps = {
249
- ...pkgJson.dependencies,
250
- ...pkgJson.devDependencies,
251
- ...pkgJson.peerDependencies
252
- };
253
- for (const [name, version] of Object.entries(allDeps)){
254
- if (version && (version.startsWith("workspace:") || version === "*")) {
255
- deps.push(name);
256
- }
257
- }
258
- return deps;
259
- }
260
- /**
261
- * 检测每个包的变更(基于各自的最新 tag)
262
- */ getChangedPackages(allPackages, dryRun) {
263
- const changedPackages = [];
264
- for (const pkg of allPackages){
265
- const hasChanges = this.hasPackageChanges(pkg);
266
- if (hasChanges) {
267
- changedPackages.push(pkg);
268
- }
269
- if (dryRun) {
270
- console.log(` ${hasChanges ? "✅" : "⭕"} ${pkg.name}`);
271
- }
272
- }
273
- return changedPackages;
274
- }
275
- /**
276
- * 检测单个包是否有变更(基于该包的最新 tag)
277
- */ hasPackageChanges(pkg) {
278
- try {
279
- // 获取该包的最新 tag(格式: @scope/pkg@version 或 pkg@version)
280
- const tagPattern = `${pkg.name}@*`;
281
- const latestTag = execSync(`git describe --tags --abbrev=0 --match "${tagPattern}" 2>/dev/null || echo ''`, {
282
- cwd: this.cwd,
283
- encoding: "utf-8"
284
- }).trim();
285
- if (!latestTag) {
286
- // 没有 tag,说明是新包,需要发布
287
- console.log(`📌 ${pkg.name}: 无 tag,需要发布`);
288
- return true;
289
- }
290
- // 检测从该 tag 到 HEAD,该包目录下是否有变更
291
- const diffOutput = execSync(`git diff --name-only "${latestTag}"..HEAD -- "${pkg.dir}"`, {
292
- cwd: this.cwd,
293
- encoding: "utf-8"
294
- }).trim();
295
- const hasChanges = diffOutput.length > 0;
296
- if (hasChanges) {
297
- console.log(`📌 ${pkg.name}: ${latestTag} -> HEAD 有变更`);
298
- console.log(` 变更文件: ${diffOutput.split("\n").slice(0, 3).join(", ")}${diffOutput.split("\n").length > 3 ? "..." : ""}`);
299
- }
300
- return hasChanges;
301
- } catch (error) {
302
- // 出错时保守处理,认为有变更
303
- console.log(`📌 ${pkg.name}: 检测出错,保守处理为有变更`);
304
- console.log(` 错误: ${error instanceof Error ? error.message : error}`);
305
- return true;
306
- }
307
- }
308
- /**
309
- * 将变更文件映射到包目录
310
- */ mapFilesToPackages(files, patterns) {
311
- const packageDirs = this.expandWorkspacePatterns(patterns);
312
- const changedPackages = new Set();
313
- for (const file of files){
314
- for (const dir of packageDirs){
315
- if (file.startsWith(dir + "/") || file === dir) {
316
- changedPackages.add(dir);
317
- break;
318
- }
319
- }
320
- }
321
- return changedPackages;
322
- }
323
- /**
324
- * 计算受影响的包(包含依赖传递)
325
- */ calculateAffectedPackages(changedPackages, allPackages) {
326
- const changedNames = new Set(changedPackages.map((p)=>p.name));
327
- const affectedNames = new Set(changedNames);
328
- // 构建反向依赖图:谁依赖了我
329
- const reverseDeps = new Map();
330
- for (const pkg of allPackages){
331
- for (const dep of pkg.workspaceDeps){
332
- if (!reverseDeps.has(dep)) {
333
- reverseDeps.set(dep, new Set());
334
- }
335
- reverseDeps.get(dep).add(pkg.name);
336
- }
337
- }
338
- // BFS 传递依赖
339
- const queue = [
340
- ...changedNames
341
- ];
342
- while(queue.length > 0){
343
- const current = queue.shift();
344
- const dependents = reverseDeps.get(current);
345
- if (dependents) {
346
- for (const dependent of dependents){
347
- if (!affectedNames.has(dependent)) {
348
- affectedNames.add(dependent);
349
- queue.push(dependent);
350
- }
351
- }
352
- }
353
- }
354
- return allPackages.filter((p)=>affectedNames.has(p.name));
355
- }
356
- /**
357
- * 拓扑排序:被依赖的包先发布
358
- */ topologicalSort(packages, _allPackages) {
359
- const packageNames = new Set(packages.map((p)=>p.name));
360
- const nameToPackage = new Map(packages.map((p)=>[
361
- p.name,
362
- p
363
- ]));
364
- // 构建依赖图(只考虑待发布包之间的依赖)
365
- const inDegree = new Map();
366
- const graph = new Map();
367
- for (const pkg of packages){
368
- inDegree.set(pkg.name, 0);
369
- graph.set(pkg.name, []);
370
- }
371
- for (const pkg of packages){
372
- for (const dep of pkg.workspaceDeps){
373
- if (packageNames.has(dep)) {
374
- graph.get(dep).push(pkg.name);
375
- inDegree.set(pkg.name, (inDegree.get(pkg.name) || 0) + 1);
376
- }
377
- }
378
- }
379
- // Kahn's algorithm
380
- const queue = [];
381
- for (const [name, degree] of inDegree){
382
- if (degree === 0) {
383
- queue.push(name);
384
- }
385
- }
386
- const sorted = [];
387
- while(queue.length > 0){
388
- const current = queue.shift();
389
- sorted.push(nameToPackage.get(current));
390
- for (const neighbor of graph.get(current) || []){
391
- const newDegree = (inDegree.get(neighbor) || 0) - 1;
392
- inDegree.set(neighbor, newDegree);
393
- if (newDegree === 0) {
394
- queue.push(neighbor);
395
- }
396
- }
397
- }
398
- if (sorted.length !== packages.length) {
399
- throw new Error("检测到循环依赖,无法确定发布顺序");
400
- }
401
- return sorted;
402
- }
403
- }
404
- MonorepoService = _ts_decorate([
405
- Injectable(),
406
- _ts_metadata("design:type", Function),
407
- _ts_metadata("design:paramtypes", [])
408
- ], MonorepoService);
409
-
410
- ;// CONCATENATED MODULE: ./src/publish.service.ts
411
- function publish_service_ts_decorate(decorators, target, key, desc) {
412
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
413
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
414
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
415
- return c > 3 && r && Object.defineProperty(target, key, r), r;
416
- }
417
- function publish_service_ts_metadata(k, v) {
418
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
419
- }
420
-
421
-
422
-
423
-
424
-
425
-
426
- // eslint-disable-next-line @typescript-eslint/no-require-imports
427
- const releaseItModule = __webpack_require__(547);
428
- const releaseIt = typeof releaseItModule === "function" ? releaseItModule : releaseItModule.default;
429
- class PublishService {
430
- gitProvider;
431
- configService;
432
- configReader;
433
- monorepoService;
434
- cleanupOnExit = null;
435
- uncaughtExceptionHandler = null;
436
- branchUnlocked = false;
437
- constructor(gitProvider, configService, configReader, monorepoService){
438
- this.gitProvider = gitProvider;
439
- this.configService = configService;
440
- this.configReader = configReader;
441
- this.monorepoService = monorepoService;
442
- }
443
- getContextFromEnv(options) {
444
- this.gitProvider.validateConfig();
445
- const ciConf = this.configService.get("ci");
446
- const repository = ciConf?.repository;
447
- const branch = ciConf?.refName;
448
- if (!repository) {
449
- throw new Error("缺少配置 ci.repository (环境变量 GITHUB_REPOSITORY)");
450
- }
451
- if (!branch) {
452
- throw new Error("缺少配置 ci.refName (环境变量 GITHUB_REF_NAME)");
453
- }
454
- const [owner, repo] = repository.split("/");
455
- if (!owner || !repo) {
456
- throw new Error(`ci.repository 格式不正确,期望 "owner/repo",实际: "${repository}"`);
457
- }
458
- return {
459
- owner,
460
- repo,
461
- branch,
462
- dryRun: options.dryRun ?? false,
463
- prerelease: options.prerelease,
464
- ci: options.ci,
465
- rehearsal: options.rehearsal ?? false
466
- };
467
- }
468
- async execute(context) {
469
- const publishConf = this.configReader.getPluginConfig("publish");
470
- const monorepoConf = publishConf.monorepo;
471
- // CI 环境下自动 fetch tags,确保 release-it 能正确计算版本
472
- if (context.ci) {
473
- await this.ensureTagsFetched();
474
- }
475
- // 检查是否启用 monorepo 模式
476
- if (monorepoConf?.enabled) {
477
- return this.executeMonorepo(context, publishConf);
478
- }
479
- // 单包发布模式
480
- return this.executeSinglePackage(context, publishConf);
481
- }
482
- /**
483
- * Monorepo 发布模式:扫描变更包,按依赖顺序发布
484
- */ async executeMonorepo(context, publishConf) {
485
- const { dryRun } = context;
486
- console.log("\n📦 Monorepo 发布模式");
487
- console.log("=".repeat(50));
488
- const propagateDeps = publishConf.monorepo?.propagateDeps ?? true;
489
- // 分析变更包
490
- const analysis = await this.monorepoService.analyze(dryRun, propagateDeps);
491
- if (analysis.packagesToPublish.length === 0) {
492
- console.log("\n✅ 没有需要发布的包");
493
- return {
494
- success: true,
495
- message: "没有需要发布的包"
496
- };
497
- }
498
- console.log(`\n🚀 将发布 ${analysis.packagesToPublish.length} 个包`);
499
- await this.handleBegin(context, publishConf);
500
- try {
501
- // 按顺序发布每个包
502
- for(let i = 0; i < analysis.packagesToPublish.length; i++){
503
- const pkg = analysis.packagesToPublish[i];
504
- console.log(`\n[${i + 1}/${analysis.packagesToPublish.length}] 发布 ${pkg.name}`);
505
- console.log("-".repeat(40));
506
- await this.executePackageRelease(context, publishConf, pkg);
507
- }
508
- await this.handleEnd(context, publishConf);
509
- return {
510
- success: true,
511
- message: `成功发布 ${analysis.packagesToPublish.length} 个包`
512
- };
513
- } catch (error) {
514
- console.error("\n❌ Monorepo 发布失败:", error instanceof Error ? error.message : error);
515
- try {
516
- await this.handleEnd(context, publishConf);
517
- } catch (unlockError) {
518
- console.error("⚠️ 解锁分支失败:", unlockError instanceof Error ? unlockError.message : unlockError);
519
- }
520
- return {
521
- success: false,
522
- message: "Monorepo 发布失败"
523
- };
524
- }
525
- }
526
- /**
527
- * 发布单个包(monorepo 模式)
528
- */ async executePackageRelease(context, publishConf, pkg) {
529
- const { dryRun, prerelease, ci, rehearsal } = context;
530
- if (rehearsal) {
531
- console.log(`🎭 [REHEARSAL] 将发布包: ${pkg.name} (${pkg.dir})`);
532
- } else if (dryRun) {
533
- console.log(`🔍 [DRY-RUN] 将发布包: ${pkg.name} (${pkg.dir})`);
534
- }
535
- const pkgDir = join(process.cwd(), pkg.dir);
536
- const originalCwd = process.cwd();
537
- const config = this.buildReleaseItConfig({
538
- dryRun,
539
- prerelease,
540
- ci,
541
- rehearsal,
542
- pkgDir,
543
- pkgName: pkg.name,
544
- pkgBase: pkg.dir.split("/").pop() || pkg.dir,
545
- publishConf
546
- });
547
- // 切换到包目录运行 release-it,确保读取正确的 package.json
548
- process.chdir(pkgDir);
549
- try {
550
- await releaseIt(config);
551
- console.log(`✅ ${pkg.name} 发布完成`);
552
- } finally{
553
- // 恢复原工作目录
554
- process.chdir(originalCwd);
259
+ const pkgDir = join(process.cwd(), pkg.dir);
260
+ const originalCwd = process.cwd();
261
+ const config = this.buildReleaseItConfig({
262
+ dryRun,
263
+ prerelease,
264
+ ci,
265
+ rehearsal,
266
+ pkgDir,
267
+ pkgName: pkg.name,
268
+ pkgBase: pkg.dir.split("/").pop() || pkg.dir,
269
+ publishConf
270
+ });
271
+ // 切换到包目录运行 release-it,确保读取正确的 package.json
272
+ process.chdir(pkgDir);
273
+ try {
274
+ await releaseIt(config);
275
+ console.log(`✅ ${pkg.name} 发布完成`);
276
+ } finally{
277
+ // 恢复原工作目录
278
+ process.chdir(originalCwd);
555
279
  }
556
280
  }
557
281
  /**
@@ -887,274 +611,402 @@ class PublishService {
887
611
  }
888
612
  }
889
613
  /**
890
- * 同步解锁分支(用于进程退出时的清理)
891
- */ unlockBranchSync(context, publishConf) {
892
- const { owner, repo, branch, dryRun } = context;
893
- const shouldLockBranch = publishConf.git?.lockBranch ?? true;
894
- if (!shouldLockBranch || dryRun) {
895
- return;
614
+ * 同步解锁分支(用于进程退出时的清理)
615
+ */ unlockBranchSync(context, publishConf) {
616
+ const { owner, repo, branch, dryRun } = context;
617
+ const shouldLockBranch = publishConf.git?.lockBranch ?? true;
618
+ if (!shouldLockBranch || dryRun) {
619
+ return;
620
+ }
621
+ this.gitProvider.unlockBranchSync(owner, repo, branch);
622
+ }
623
+ /**
624
+ * 确保 git tags 已获取(CI 环境中 shallow clone 可能缺失 tags)
625
+ * 这对于 release-it 正确计算版本号至关重要
626
+ */ async ensureTagsFetched() {
627
+ try {
628
+ // 检查是否有 tags
629
+ const existingTags = execSync("git tag --list 2>/dev/null || echo ''", {
630
+ encoding: "utf-8"
631
+ }).trim();
632
+ if (!existingTags) {
633
+ console.log("🏷️ 正在获取 git tags...");
634
+ execSync("git fetch --tags --force", {
635
+ stdio: "inherit"
636
+ });
637
+ console.log("✅ Git tags 已获取");
638
+ }
639
+ } catch (error) {
640
+ console.warn("⚠️ 获取 git tags 失败:", error instanceof Error ? error.message : error);
641
+ console.warn(" 版本计算可能不准确,建议在 CI checkout 时添加 fetch-depth: 0 和 fetch-tags: true");
642
+ }
643
+ }
644
+ }
645
+
646
+ // EXTERNAL MODULE: external "fs"
647
+ var external_fs_ = __webpack_require__(421);
648
+ ;// CONCATENATED MODULE: ./src/monorepo.service.ts
649
+
650
+
651
+
652
+ class MonorepoService {
653
+ cwd;
654
+ constructor(){
655
+ this.cwd = process.cwd();
656
+ }
657
+ /**
658
+ * 分析 monorepo 变更,返回需要发布的包列表(拓扑排序后)
659
+ * @param dryRun 是否为 dry-run 模式
660
+ * @param propagateDeps 是否传递依赖变更(依赖的包变更时,依赖方也发布)
661
+ */ async analyze(dryRun, propagateDeps = true) {
662
+ const workspacePackages = this.getWorkspacePackages();
663
+ const allPackages = this.getAllPackageInfos(workspacePackages);
664
+ // 为每个包单独检测变更(基于各自的最新 tag)
665
+ const changedPackages = this.getChangedPackages(allPackages, dryRun);
666
+ if (dryRun) {
667
+ console.log(`📦 直接变更的包: ${changedPackages.map((p)=>p.name).join(", ") || "无"}`);
668
+ }
669
+ // 计算依赖传递,找出所有需要发布的包
670
+ const packagesToPublish = propagateDeps ? this.calculateAffectedPackages(changedPackages, allPackages) : changedPackages;
671
+ if (dryRun) {
672
+ console.log(`🔄 需要发布的包(含依赖传递): ${packagesToPublish.map((p)=>p.name).join(", ") || "无"}`);
673
+ }
674
+ // 拓扑排序
675
+ const sortedPackages = this.topologicalSort(packagesToPublish, allPackages);
676
+ if (dryRun) {
677
+ console.log(`📋 发布顺序: ${sortedPackages.map((p)=>p.name).join(" -> ") || "无"}`);
678
+ }
679
+ return {
680
+ changedPackages,
681
+ packagesToPublish: sortedPackages
682
+ };
683
+ }
684
+ /**
685
+ * 简单解析 pnpm-workspace.yaml(只提取 packages 数组)
686
+ */ parseSimpleYaml(content) {
687
+ const packages = [];
688
+ const lines = content.split("\n");
689
+ let inPackages = false;
690
+ for (const line of lines){
691
+ const trimmed = line.trim();
692
+ if (trimmed === "packages:") {
693
+ inPackages = true;
694
+ continue;
695
+ }
696
+ if (inPackages) {
697
+ if (trimmed.startsWith("- ")) {
698
+ // 提取包路径,去除引号
699
+ let pkg = trimmed.slice(2).trim();
700
+ pkg = pkg.replace(/^["']|["']$/g, "");
701
+ packages.push(pkg);
702
+ } else if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("-")) {
703
+ break;
704
+ }
705
+ }
706
+ }
707
+ return {
708
+ packages: packages.length > 0 ? packages : undefined
709
+ };
710
+ }
711
+ /**
712
+ * 从 pnpm-workspace.yaml 读取 workspace 包配置
713
+ */ getWorkspacePackages() {
714
+ const workspaceFile = join(this.cwd, "pnpm-workspace.yaml");
715
+ if (!(0,external_fs_.existsSync)(workspaceFile)) {
716
+ throw new Error("未找到 pnpm-workspace.yaml 文件");
717
+ }
718
+ const content = (0,external_fs_.readFileSync)(workspaceFile, "utf-8");
719
+ const config = this.parseSimpleYaml(content);
720
+ if (!config.packages || !Array.isArray(config.packages)) {
721
+ throw new Error("pnpm-workspace.yaml 中未配置 packages");
722
+ }
723
+ return config.packages;
724
+ }
725
+ /**
726
+ * 展开 workspace 包配置,获取所有实际的包目录
727
+ */ expandWorkspacePatterns(patterns) {
728
+ const dirs = [];
729
+ for (const pattern of patterns){
730
+ if (pattern.includes("*")) {
731
+ // 使用 glob 展开,这里简化处理,只支持 extensions/* 这种模式
732
+ const baseDir = pattern.replace("/*", "");
733
+ const basePath = join(this.cwd, baseDir);
734
+ if ((0,external_fs_.existsSync)(basePath)) {
735
+ const { readdirSync, statSync } = __webpack_require__(421);
736
+ const entries = readdirSync(basePath);
737
+ for (const entry of entries){
738
+ const entryPath = join(basePath, entry);
739
+ if (statSync(entryPath).isDirectory()) {
740
+ const pkgJson = join(entryPath, "package.json");
741
+ if ((0,external_fs_.existsSync)(pkgJson)) {
742
+ dirs.push(join(baseDir, entry));
743
+ }
744
+ }
745
+ }
746
+ }
747
+ } else {
748
+ // 直接目录
749
+ const pkgJson = join(this.cwd, pattern, "package.json");
750
+ if ((0,external_fs_.existsSync)(pkgJson)) {
751
+ dirs.push(pattern);
752
+ }
753
+ }
754
+ }
755
+ return dirs;
756
+ }
757
+ /**
758
+ * 获取所有包的详细信息(排除私有包)
759
+ */ getAllPackageInfos(patterns) {
760
+ const dirs = this.expandWorkspacePatterns(patterns);
761
+ const packages = [];
762
+ for (const dir of dirs){
763
+ const pkgJsonPath = join(this.cwd, dir, "package.json");
764
+ if (!(0,external_fs_.existsSync)(pkgJsonPath)) continue;
765
+ const pkgJson = JSON.parse((0,external_fs_.readFileSync)(pkgJsonPath, "utf-8"));
766
+ // 跳过私有包
767
+ if (pkgJson.private === true) continue;
768
+ const workspaceDeps = this.extractWorkspaceDeps(pkgJson);
769
+ packages.push({
770
+ dir,
771
+ name: pkgJson.name,
772
+ version: pkgJson.version,
773
+ workspaceDeps
774
+ });
775
+ }
776
+ return packages;
777
+ }
778
+ /**
779
+ * 提取包的 workspace 依赖
780
+ */ extractWorkspaceDeps(pkgJson) {
781
+ const deps = [];
782
+ const allDeps = {
783
+ ...pkgJson.dependencies,
784
+ ...pkgJson.devDependencies,
785
+ ...pkgJson.peerDependencies
786
+ };
787
+ for (const [name, version] of Object.entries(allDeps)){
788
+ if (version && (version.startsWith("workspace:") || version === "*")) {
789
+ deps.push(name);
790
+ }
791
+ }
792
+ return deps;
793
+ }
794
+ /**
795
+ * 检测每个包的变更(基于各自的最新 tag)
796
+ */ getChangedPackages(allPackages, dryRun) {
797
+ const changedPackages = [];
798
+ for (const pkg of allPackages){
799
+ const hasChanges = this.hasPackageChanges(pkg);
800
+ if (hasChanges) {
801
+ changedPackages.push(pkg);
802
+ }
803
+ if (dryRun) {
804
+ console.log(` ${hasChanges ? "✅" : "⭕"} ${pkg.name}`);
805
+ }
896
806
  }
897
- this.gitProvider.unlockBranchSync(owner, repo, branch);
807
+ return changedPackages;
898
808
  }
899
809
  /**
900
- * 确保 git tags 已获取(CI 环境中 shallow clone 可能缺失 tags
901
- * 这对于 release-it 正确计算版本号至关重要
902
- */ async ensureTagsFetched() {
810
+ * 检测单个包是否有变更(基于该包的最新 tag
811
+ */ hasPackageChanges(pkg) {
903
812
  try {
904
- // 检查是否有 tags
905
- const existingTags = execSync("git tag --list 2>/dev/null || echo ''", {
813
+ // 获取该包的最新 tag(格式: @scope/pkg@version 或 pkg@version)
814
+ const tagPattern = `${pkg.name}@*`;
815
+ const latestTag = execSync(`git describe --tags --abbrev=0 --match "${tagPattern}" 2>/dev/null || echo ''`, {
816
+ cwd: this.cwd,
906
817
  encoding: "utf-8"
907
818
  }).trim();
908
- if (!existingTags) {
909
- console.log("🏷️ 正在获取 git tags...");
910
- execSync("git fetch --tags --force", {
911
- stdio: "inherit"
912
- });
913
- console.log("✅ Git tags 已获取");
819
+ if (!latestTag) {
820
+ // 没有 tag,说明是新包,需要发布
821
+ console.log(`📌 ${pkg.name}: tag,需要发布`);
822
+ return true;
823
+ }
824
+ // 检测从该 tag 到 HEAD,该包目录下是否有变更
825
+ const diffOutput = execSync(`git diff --name-only "${latestTag}"..HEAD -- "${pkg.dir}"`, {
826
+ cwd: this.cwd,
827
+ encoding: "utf-8"
828
+ }).trim();
829
+ const hasChanges = diffOutput.length > 0;
830
+ if (hasChanges) {
831
+ console.log(`📌 ${pkg.name}: ${latestTag} -> HEAD 有变更`);
832
+ console.log(` 变更文件: ${diffOutput.split("\n").slice(0, 3).join(", ")}${diffOutput.split("\n").length > 3 ? "..." : ""}`);
914
833
  }
834
+ return hasChanges;
915
835
  } catch (error) {
916
- console.warn("⚠️ 获取 git tags 失败:", error instanceof Error ? error.message : error);
917
- console.warn(" 版本计算可能不准确,建议在 CI checkout 时添加 fetch-depth: 0 和 fetch-tags: true");
836
+ // 出错时保守处理,认为有变更
837
+ console.log(`📌 ${pkg.name}: 检测出错,保守处理为有变更`);
838
+ console.log(` 错误: ${error instanceof Error ? error.message : error}`);
839
+ return true;
918
840
  }
919
841
  }
920
- }
921
- PublishService = publish_service_ts_decorate([
922
- Injectable(),
923
- publish_service_ts_metadata("design:type", Function),
924
- publish_service_ts_metadata("design:paramtypes", [
925
- typeof GitProviderService === "undefined" ? Object : GitProviderService,
926
- typeof ConfigService === "undefined" ? Object : ConfigService,
927
- typeof ConfigReaderService === "undefined" ? Object : ConfigReaderService,
928
- typeof MonorepoService === "undefined" ? Object : MonorepoService
929
- ])
930
- ], PublishService);
931
-
932
- ;// CONCATENATED MODULE: ./src/publish.command.ts
933
- function publish_command_ts_decorate(decorators, target, key, desc) {
934
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
935
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
936
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
937
- return c > 3 && r && Object.defineProperty(target, key, r), r;
938
- }
939
- function publish_command_ts_metadata(k, v) {
940
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
941
- }
942
-
943
-
944
-
945
- class PublishCommand extends CommandRunner {
946
- publishService;
947
- constructor(publishService){
948
- super(), this.publishService = publishService;
842
+ /**
843
+ * 将变更文件映射到包目录
844
+ */ mapFilesToPackages(files, patterns) {
845
+ const packageDirs = this.expandWorkspacePatterns(patterns);
846
+ const changedPackages = new Set();
847
+ for (const file of files){
848
+ for (const dir of packageDirs){
849
+ if (file.startsWith(dir + "/") || file === dir) {
850
+ changedPackages.add(dir);
851
+ break;
852
+ }
853
+ }
854
+ }
855
+ return changedPackages;
949
856
  }
950
- async run(_passedParams, options) {
951
- if (options.rehearsal) {
952
- console.log(core_t("publish:rehearsalMode"));
953
- } else if (options.dryRun) {
954
- console.log(core_t("publish:dryRunMode"));
857
+ /**
858
+ * 计算受影响的包(包含依赖传递)
859
+ */ calculateAffectedPackages(changedPackages, allPackages) {
860
+ const changedNames = new Set(changedPackages.map((p)=>p.name));
861
+ const affectedNames = new Set(changedNames);
862
+ // 构建反向依赖图:谁依赖了我
863
+ const reverseDeps = new Map();
864
+ for (const pkg of allPackages){
865
+ for (const dep of pkg.workspaceDeps){
866
+ if (!reverseDeps.has(dep)) {
867
+ reverseDeps.set(dep, new Set());
868
+ }
869
+ reverseDeps.get(dep).add(pkg.name);
870
+ }
955
871
  }
956
- try {
957
- const context = this.publishService.getContextFromEnv(options);
958
- await this.publishService.execute(context);
959
- } catch (error) {
960
- console.error(core_t("common.executionFailed", {
961
- error: error instanceof Error ? error.message : error
962
- }));
963
- process.exit(1);
872
+ // BFS 传递依赖
873
+ const queue = [
874
+ ...changedNames
875
+ ];
876
+ while(queue.length > 0){
877
+ const current = queue.shift();
878
+ const dependents = reverseDeps.get(current);
879
+ if (dependents) {
880
+ for (const dependent of dependents){
881
+ if (!affectedNames.has(dependent)) {
882
+ affectedNames.add(dependent);
883
+ queue.push(dependent);
884
+ }
885
+ }
886
+ }
964
887
  }
888
+ return allPackages.filter((p)=>affectedNames.has(p.name));
965
889
  }
966
- parseDryRun(val) {
967
- return val;
968
- }
969
- parseCi(val) {
970
- return val;
971
- }
972
- parsePrerelease(val) {
973
- return val;
974
- }
975
- parseRehearsal(val) {
976
- return val;
890
+ /**
891
+ * 拓扑排序:被依赖的包先发布
892
+ */ topologicalSort(packages, _allPackages) {
893
+ const packageNames = new Set(packages.map((p)=>p.name));
894
+ const nameToPackage = new Map(packages.map((p)=>[
895
+ p.name,
896
+ p
897
+ ]));
898
+ // 构建依赖图(只考虑待发布包之间的依赖)
899
+ const inDegree = new Map();
900
+ const graph = new Map();
901
+ for (const pkg of packages){
902
+ inDegree.set(pkg.name, 0);
903
+ graph.set(pkg.name, []);
904
+ }
905
+ for (const pkg of packages){
906
+ for (const dep of pkg.workspaceDeps){
907
+ if (packageNames.has(dep)) {
908
+ graph.get(dep).push(pkg.name);
909
+ inDegree.set(pkg.name, (inDegree.get(pkg.name) || 0) + 1);
910
+ }
911
+ }
912
+ }
913
+ // Kahn's algorithm
914
+ const queue = [];
915
+ for (const [name, degree] of inDegree){
916
+ if (degree === 0) {
917
+ queue.push(name);
918
+ }
919
+ }
920
+ const sorted = [];
921
+ while(queue.length > 0){
922
+ const current = queue.shift();
923
+ sorted.push(nameToPackage.get(current));
924
+ for (const neighbor of graph.get(current) || []){
925
+ const newDegree = (inDegree.get(neighbor) || 0) - 1;
926
+ inDegree.set(neighbor, newDegree);
927
+ if (newDegree === 0) {
928
+ queue.push(neighbor);
929
+ }
930
+ }
931
+ }
932
+ if (sorted.length !== packages.length) {
933
+ throw new Error("检测到循环依赖,无法确定发布顺序");
934
+ }
935
+ return sorted;
977
936
  }
978
937
  }
979
- publish_command_ts_decorate([
980
- Option({
981
- flags: "-d, --dry-run",
982
- description: core_t("common.options.dryRun")
983
- }),
984
- publish_command_ts_metadata("design:type", Function),
985
- publish_command_ts_metadata("design:paramtypes", [
986
- Boolean
987
- ]),
988
- publish_command_ts_metadata("design:returntype", Boolean)
989
- ], PublishCommand.prototype, "parseDryRun", null);
990
- publish_command_ts_decorate([
991
- Option({
992
- flags: "-c, --ci",
993
- description: core_t("common.options.ci")
994
- }),
995
- publish_command_ts_metadata("design:type", Function),
996
- publish_command_ts_metadata("design:paramtypes", [
997
- Boolean
998
- ]),
999
- publish_command_ts_metadata("design:returntype", Boolean)
1000
- ], PublishCommand.prototype, "parseCi", null);
1001
- publish_command_ts_decorate([
1002
- Option({
1003
- flags: "-p, --prerelease <tag>",
1004
- description: core_t("publish:options.prerelease")
1005
- }),
1006
- publish_command_ts_metadata("design:type", Function),
1007
- publish_command_ts_metadata("design:paramtypes", [
1008
- String
1009
- ]),
1010
- publish_command_ts_metadata("design:returntype", String)
1011
- ], PublishCommand.prototype, "parsePrerelease", null);
1012
- publish_command_ts_decorate([
1013
- Option({
1014
- flags: "-r, --rehearsal",
1015
- description: core_t("publish:options.rehearsal")
1016
- }),
1017
- publish_command_ts_metadata("design:type", Function),
1018
- publish_command_ts_metadata("design:paramtypes", [
1019
- Boolean
1020
- ]),
1021
- publish_command_ts_metadata("design:returntype", Boolean)
1022
- ], PublishCommand.prototype, "parseRehearsal", null);
1023
- PublishCommand = publish_command_ts_decorate([
1024
- Command({
1025
- name: "publish",
1026
- description: core_t("publish:description")
1027
- }),
1028
- publish_command_ts_metadata("design:type", Function),
1029
- publish_command_ts_metadata("design:paramtypes", [
1030
- typeof PublishService === "undefined" ? Object : PublishService
1031
- ])
1032
- ], PublishCommand);
1033
-
1034
- ;// CONCATENATED MODULE: ./src/publish.module.ts
1035
- function publish_module_ts_decorate(decorators, target, key, desc) {
1036
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1037
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1038
- else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1039
- return c > 3 && r && Object.defineProperty(target, key, r), r;
1040
- }
1041
-
1042
-
1043
-
1044
-
1045
-
1046
-
1047
- class PublishModule {
1048
- }
1049
- PublishModule = publish_module_ts_decorate([
1050
- Module({
1051
- imports: [
1052
- ConfigModule.forFeature(ciConfig),
1053
- GitProviderModule.forFeature(),
1054
- ConfigReaderModule
1055
- ],
1056
- providers: [
1057
- PublishCommand,
1058
- PublishService,
1059
- MonorepoService
1060
- ]
1061
- })
1062
- ], PublishModule);
1063
-
1064
- ;// CONCATENATED MODULE: ./src/publish.config.ts
1065
-
1066
- /** publish 命令配置 schema */ const publishSchema = z.object({
1067
- /** monorepo 发布模式配置 */ monorepo: z.object({
1068
- /** 是否启用 monorepo 发布模式 */ enabled: z.boolean().default(false),
1069
- /** 是否传递依赖变更(依赖的包变更时,依赖方也发布) */ propagateDeps: z.boolean().default(true)
1070
- }).optional(),
1071
- changelog: z.object({
1072
- /** changelog 文件输出目录 */ infileDir: z.string().default(".").optional(),
1073
- preset: z.object({
1074
- /** preset 名称,默认 conventionalcommits */ name: z.string().default("conventionalcommits").optional(),
1075
- /** commit type 到 section 的映射 */ type: z.array(z.object({
1076
- type: z.string(),
1077
- section: z.string()
1078
- })).default([])
1079
- }).optional()
1080
- }).optional(),
1081
- /** npm 发布配置 */ npm: z.object({
1082
- /** 是否发布到 npm registry */ publish: z.boolean().default(false),
1083
- /** 包管理器,npm 或 pnpm */ packageManager: z["enum"]([
1084
- "npm",
1085
- "pnpm"
1086
- ]).default("npm"),
1087
- /** npm registry 地址 */ registry: z.string().optional(),
1088
- /** npm tag,如 latest、beta、next */ tag: z.string().default("latest"),
1089
- /** 是否忽略 package.json 中的版本号 */ ignoreVersion: z.boolean().default(true),
1090
- /** npm version 命令额外参数 */ versionArgs: z.array(z.string()).default([
1091
- "--workspaces false"
1092
- ]),
1093
- /** npm/pnpm publish 命令额外参数 */ publishArgs: z.array(z.string()).default([])
1094
- }).optional(),
1095
- release: z.object({
1096
- host: z.string().default("localhost"),
1097
- assetSourcemap: z.object({
1098
- path: z.string(),
1099
- name: z.string()
1100
- }).optional(),
1101
- assets: z.array(z.object({
1102
- path: z.string(),
1103
- name: z.string(),
1104
- type: z.string()
1105
- })).default([])
1106
- }).optional(),
1107
- /** git 配置 */ git: z.object({
1108
- /** 允许发布的分支列表 */ requireBranch: z.array(z.string()).default([
1109
- "main",
1110
- "dev",
1111
- "develop"
1112
- ]),
1113
- /** 分支锁定时允许推送的用户名白名单(如 CI 机器人) */ pushWhitelistUsernames: z.array(z.string()).default([]),
1114
- /** 是否在发布时锁定分支 */ lockBranch: z.boolean().default(true)
1115
- }).optional(),
1116
- /** release-it hooks 配置,如 before:bump, after:bump 等 */ hooks: z.record(z.string(), z.union([
1117
- z.string(),
1118
- z.array(z.string())
1119
- ])).optional()
1120
- });
1121
938
 
1122
939
  ;// CONCATENATED MODULE: ./src/index.ts
1123
940
 
1124
941
 
1125
942
 
1126
943
 
1127
- /** publish Extension 元数据 */ const publishMetadata = {
944
+
945
+ const extension = defineExtension({
1128
946
  name: "publish",
1129
- commands: [
1130
- "publish"
1131
- ],
947
+ version: "1.0.0",
948
+ description: core_t("publish:extensionDescription"),
1132
949
  configKey: "publish",
1133
950
  configSchema: ()=>publishSchema,
1134
- version: "1.0.0",
1135
- description: core_t("publish:extensionDescription")
1136
- };
1137
- class PublishExtension {
1138
- getMetadata() {
1139
- return publishMetadata;
1140
- }
1141
- getModule() {
1142
- return PublishModule;
1143
- }
1144
- }
1145
- /* export default */ const src = (PublishExtension);
1146
-
1147
-
1148
-
1149
-
951
+ commands: [
952
+ {
953
+ name: "publish",
954
+ description: core_t("publish:description"),
955
+ options: [
956
+ {
957
+ flags: "-d, --dry-run",
958
+ description: core_t("common.options.dryRun")
959
+ },
960
+ {
961
+ flags: "-c, --ci",
962
+ description: core_t("common.options.ci")
963
+ },
964
+ {
965
+ flags: "-p, --prerelease <tag>",
966
+ description: core_t("publish:options.prerelease")
967
+ },
968
+ {
969
+ flags: "-r, --rehearsal",
970
+ description: core_t("publish:options.rehearsal")
971
+ }
972
+ ],
973
+ run: async (_args, options, ctx)=>{
974
+ const gitProvider = ctx.getService("gitProvider");
975
+ const configReader = ctx.getService("config");
976
+ if (!gitProvider) {
977
+ ctx.output.error("publish 命令需要配置 Git Provider");
978
+ process.exit(1);
979
+ }
980
+ const monorepoService = new MonorepoService();
981
+ const publishService = new PublishService(gitProvider, ctx.config, configReader, monorepoService);
982
+ const publishOptions = {
983
+ dryRun: !!options?.dryRun,
984
+ ci: !!options?.ci,
985
+ prerelease: options?.prerelease,
986
+ rehearsal: !!options?.rehearsal
987
+ };
988
+ if (publishOptions.rehearsal) {
989
+ console.log(core_t("publish:rehearsalMode"));
990
+ } else if (publishOptions.dryRun) {
991
+ console.log(core_t("publish:dryRunMode"));
992
+ }
993
+ try {
994
+ const context = publishService.getContextFromEnv(publishOptions);
995
+ await publishService.execute(context);
996
+ } catch (error) {
997
+ ctx.output.error(core_t("common.executionFailed", {
998
+ error: error instanceof Error ? error.message : error
999
+ }));
1000
+ process.exit(1);
1001
+ }
1002
+ }
1003
+ }
1004
+ ]
1005
+ });
1006
+ /* export default */ const src = (extension);
1150
1007
 
1151
1008
  })();
1152
1009
 
1153
- var __webpack_exports__MonorepoService = __webpack_exports__.Vy;
1154
- var __webpack_exports__PublishCommand = __webpack_exports__.D5;
1155
- var __webpack_exports__PublishExtension = __webpack_exports__.jX;
1156
- var __webpack_exports__PublishModule = __webpack_exports__.i8;
1157
- var __webpack_exports__PublishService = __webpack_exports__.DU;
1158
- var __webpack_exports__default = __webpack_exports__.Ay;
1159
- var __webpack_exports__publishMetadata = __webpack_exports__.bH;
1160
- export { __webpack_exports__MonorepoService as MonorepoService, __webpack_exports__PublishCommand as PublishCommand, __webpack_exports__PublishExtension as PublishExtension, __webpack_exports__PublishModule as PublishModule, __webpack_exports__PublishService as PublishService, __webpack_exports__default as default, __webpack_exports__publishMetadata as publishMetadata };
1010
+ var __webpack_exports__default = __webpack_exports__.A;
1011
+ var __webpack_exports__extension = __webpack_exports__.c;
1012
+ export { __webpack_exports__default as default, __webpack_exports__extension as extension };