@coze-arch/rush-publish-plugin 0.0.4 → 0.0.5-alpha.5049d2

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/command-line.json CHANGED
@@ -34,7 +34,7 @@
34
34
  "required": false
35
35
  },
36
36
  {
37
- "parameterKind": "string",
37
+ "parameterKind": "stringList",
38
38
  "shortName": "-t",
39
39
  "longName": "--to",
40
40
  "description": "Publish specified packages and their downstream dependencies",
@@ -43,7 +43,7 @@
43
43
  "required": false
44
44
  },
45
45
  {
46
- "parameterKind": "string",
46
+ "parameterKind": "stringList",
47
47
  "shortName": "-f",
48
48
  "longName": "--from",
49
49
  "description": "Publish specified packages and their upstream/downstream dependencies",
@@ -52,7 +52,7 @@
52
52
  "required": false
53
53
  },
54
54
  {
55
- "parameterKind": "string",
55
+ "parameterKind": "stringList",
56
56
  "shortName": "-o",
57
57
  "longName": "--only",
58
58
  "description": "Only publish specified packages",
@@ -106,6 +106,22 @@
106
106
  "associatedCommands": ["pub"],
107
107
  "required": false
108
108
  },
109
+ {
110
+ "parameterKind": "string",
111
+ "longName": "--branch-prefix",
112
+ "description": "Git branch name prefix (default: 'release')",
113
+ "argumentName": "BRANCH_PREFIX",
114
+ "associatedCommands": ["pub"],
115
+ "required": false
116
+ },
117
+ {
118
+ "parameterKind": "flag",
119
+ "longName": "--release",
120
+ "shortName": "-l",
121
+ "description": "Directly publish packages (only for alpha/beta versions)",
122
+ "associatedCommands": ["pub"],
123
+ "required": false
124
+ },
109
125
  {
110
126
  "parameterKind": "flag",
111
127
  "longName": "--amend-commit",
@@ -135,6 +151,14 @@
135
151
  "shortName": "-c",
136
152
  "description": "Git commit hash",
137
153
  "associatedCommands": ["release"]
154
+ },
155
+ {
156
+ "parameterKind": "string",
157
+ "argumentName": "REGISTRY",
158
+ "longName": "--registry",
159
+ "shortName": "-r",
160
+ "description": "NPM registry URL (default: https://registry.npmjs.org)",
161
+ "associatedCommands": ["release", "pub"]
138
162
  }
139
163
  ]
140
164
  }
@@ -1,2 +1,6 @@
1
1
  import { type PublishManifest } from './types';
2
- export declare const confirmForPublish: (publishManifest: PublishManifest[], dryRun: boolean) => Promise<boolean>;
2
+ export interface ConfirmForPublishOptions {
3
+ isReleaseMode?: boolean;
4
+ registry?: string;
5
+ }
6
+ export declare const confirmForPublish: (publishManifest: PublishManifest[], dryRun: boolean, options?: ConfirmForPublishOptions) => Promise<boolean>;
@@ -1,3 +1,3 @@
1
1
  import { type RushConfigurationProject } from '@rushstack/rush-sdk';
2
2
  import { type PublishOptions } from './types';
3
- export declare const validateAndGetPackages: (options: PublishOptions) => Set<RushConfigurationProject>;
3
+ export declare const validateAndGetPackages: (options: PublishOptions) => RushConfigurationProject[];
@@ -8,6 +8,7 @@ interface PushToRemoteOptions {
8
8
  skipCommit: boolean;
9
9
  skipPush: boolean;
10
10
  repoUrl: string;
11
+ branchPrefix?: string;
11
12
  }
12
13
  export declare const pushToRemote: (options: PushToRemoteOptions) => Promise<void>;
13
14
  export {};
@@ -16,6 +16,9 @@ export interface PublishOptions {
16
16
  skipCommit?: boolean;
17
17
  skipPush?: boolean;
18
18
  repoUrl: string;
19
+ branchPrefix?: string;
20
+ release?: boolean;
21
+ registry?: string;
19
22
  }
20
23
  export interface PublishManifest {
21
24
  project: RushConfigurationProject;
@@ -9,7 +9,7 @@ interface VersionOptions {
9
9
  /**
10
10
  * 生成发布清单
11
11
  */
12
- export declare const generatePublishManifest: (packages: Set<RushConfigurationProject>, options: VersionOptions) => Promise<{
12
+ export declare const generatePublishManifest: (packages: RushConfigurationProject[], options: VersionOptions) => Promise<{
13
13
  manifests: PublishManifest[];
14
14
  bumpPolicy: BumpType | string | undefined;
15
15
  }>;
@@ -1,8 +1,9 @@
1
1
  import { type RushConfigurationProject } from '@rushstack/rush-sdk';
2
2
  export interface ReleaseOptions {
3
- commit: string;
3
+ commit?: string;
4
4
  dryRun?: boolean;
5
5
  registry: string;
6
+ packages?: PackageToPublish[];
6
7
  }
7
8
  export interface PackageToPublish {
8
9
  packageName: string;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 默认的 NPM registry 地址
3
+ */
4
+ export declare const DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
5
+ /**
6
+ * 默认的 Git 分支名前缀
7
+ */
8
+ export declare const DEFAULT_BRANCH_PREFIX = "bump";
package/lib/index.js CHANGED
@@ -13,6 +13,9 @@ var prompts = require('@inquirer/prompts');
13
13
  var dayjs = require('dayjs');
14
14
  var ChangeFile = require('@rushstack/rush-sdk/lib/api/ChangeFile');
15
15
 
16
+ // Copyright (c) 2025 coze-dev
17
+ // SPDX-License-Identifier: MIT
18
+
16
19
  /**
17
20
  * 日志工具
18
21
  *
@@ -142,6 +145,29 @@ const logger = {
142
145
  },
143
146
  };
144
147
 
148
+ // Copyright (c) 2025 coze-dev
149
+ // SPDX-License-Identifier: MIT
150
+
151
+ /**
152
+ * 默认的 NPM registry 地址
153
+ */
154
+ const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org';
155
+
156
+ /**
157
+ * 默认的 Git 分支名前缀
158
+ */
159
+ const DEFAULT_BRANCH_PREFIX = 'bump';
160
+
161
+ // Copyright (c) 2025 coze-dev
162
+ // SPDX-License-Identifier: MIT
163
+
164
+
165
+
166
+
167
+
168
+
169
+
170
+
145
171
  class ExecError extends Error {
146
172
 
147
173
 
@@ -168,6 +194,10 @@ const exec = (
168
194
  });
169
195
  });
170
196
 
197
+ // Copyright (c) 2025 coze-dev
198
+ // SPDX-License-Identifier: MIT
199
+
200
+
171
201
  const serializeFilesName = (output) =>
172
202
  output
173
203
  .split('\n')
@@ -197,6 +227,15 @@ const getCurrentBranchName = async () => {
197
227
  return stdout.trim();
198
228
  };
199
229
 
230
+ /**
231
+ * 获取当前 commit hash
232
+ * @returns commit hash
233
+ */
234
+ const getCurrentCommitHash = async () => {
235
+ const { stdout } = await exec('git rev-parse HEAD');
236
+ return stdout.trim();
237
+ };
238
+
200
239
  const isMainBranch = async () => {
201
240
  const currentBranchName = await getCurrentBranchName();
202
241
  return currentBranchName === 'main';
@@ -238,6 +277,10 @@ const getCurrentOrigin = async (
238
277
  }
239
278
  };
240
279
 
280
+ // Copyright (c) 2025 coze-dev
281
+ // SPDX-License-Identifier: MIT
282
+
283
+
241
284
  const readJsonFile = async ( path) => {
242
285
  const content = await fs.readFile(path, 'utf8');
243
286
  return JSON.parse(content) ;
@@ -259,7 +302,11 @@ const isDirExists = async (path) =>
259
302
  .then(() => true)
260
303
  .catch(() => false);
261
304
 
262
- const getRushConfiguration = (() => {
305
+ // Copyright (c) 2025 coze-dev
306
+ // SPDX-License-Identifier: MIT
307
+
308
+
309
+ const getRushConfiguration$1 = (() => {
263
310
  let rushConfiguration = null;
264
311
  return (useCache = true) => {
265
312
  if (!useCache) {
@@ -271,19 +318,32 @@ const getRushConfiguration = (() => {
271
318
  };
272
319
  })();
273
320
 
321
+ // Copyright (c) 2025 coze-dev
322
+ // SPDX-License-Identifier: MIT
323
+
324
+
325
+
326
+
327
+
328
+
329
+
330
+
331
+
274
332
  /**
275
333
  * 更新依赖版本
276
334
  */
277
335
  const updateDependencyVersions = async (
278
336
  packageJson,
279
337
  ) => {
280
- const rushConfiguration = getRushConfiguration();
281
- const { dependencies } = packageJson;
282
- if (dependencies) {
283
- for (const [dep, ver] of Object.entries(dependencies)) {
284
- const project = rushConfiguration.getProjectByName(dep);
285
- if (/^workspace:/.test(ver) && project) {
286
- dependencies[dep] = project.packageJson.version;
338
+ const rushConfiguration = getRushConfiguration$1();
339
+ const depTypes = ['dependencies', 'peerDependencies'];
340
+ for (const depType of depTypes) {
341
+ if (packageJson[depType]) {
342
+ for (const [dep, ver] of Object.entries(packageJson[depType])) {
343
+ const project = rushConfiguration.getProjectByName(dep);
344
+ if (/^workspace:/.test(ver) && project) {
345
+ packageJson[depType][dep] = project.packageJson.version;
346
+ }
287
347
  }
288
348
  }
289
349
  }
@@ -331,7 +391,12 @@ const publishPackage = async (
331
391
  : version.includes('beta')
332
392
  ? 'beta'
333
393
  : 'latest';
334
- const args = [`NPM_AUTH_TOKEN=${token}`, 'npm', 'publish', `--tag ${tag}`];
394
+ const setToken = `npm config set //bnpm.byted.org/:_authToken ${token}`;
395
+ await exec(setToken, {
396
+ cwd: project.projectFolder,
397
+ });
398
+
399
+ const args = [`NODE_AUTH_TOKEN=${token}`, 'npm', 'publish', `--tag ${tag}`];
335
400
  if (dryRun) {
336
401
  args.push('--dry-run');
337
402
  }
@@ -417,22 +482,37 @@ const checkReleasePlan = (
417
482
  return true;
418
483
  };
419
484
 
485
+ // Copyright (c) 2025 coze-dev
486
+ // SPDX-License-Identifier: MIT
487
+
488
+
489
+
420
490
  /**
421
491
  * 构建发布依赖树
422
492
  */
423
493
  function buildReleaseManifest(
424
494
  packages,
425
495
  ) {
426
- const rushConfiguration = getRushConfiguration();
427
- return packages.map(pkg => {
428
- const project = rushConfiguration.getProjectByName(pkg.packageName);
429
- if (!project) {
430
- throw new Error(`Cannot find project: ${pkg.packageName}`);
431
- }
432
- return { project, version: project.packageJson.version };
433
- });
496
+ const rushConfiguration = getRushConfiguration$1();
497
+ return packages
498
+ .map(pkg => {
499
+ const project = rushConfiguration.getProjectByName(pkg.packageName);
500
+ if (!project) {
501
+ throw new Error(`Cannot find project: ${pkg.packageName}`);
502
+ }
503
+ if (project.shouldPublish) {
504
+ return { project, version: project.packageJson.version };
505
+ }
506
+ return undefined;
507
+ })
508
+ .filter(Boolean) ;
434
509
  }
435
510
 
511
+ // Copyright (c) 2025 coze-dev
512
+ // SPDX-License-Identifier: MIT
513
+
514
+
515
+
436
516
  /**
437
517
  * 从 git tag 中解析需要发布的包信息
438
518
  */
@@ -461,11 +541,32 @@ const getPackagesToPublish = async (
461
541
  return packages;
462
542
  };
463
543
 
544
+ // Copyright (c) 2025 coze-dev
545
+ // SPDX-License-Identifier: MIT
546
+
547
+
464
548
  async function release(options) {
465
- const { commit, dryRun = false, registry } = options;
549
+ const { dryRun = false, registry, packages } = options;
550
+ let { commit } = options;
551
+ const hasPassedCommit = !!options.commit;
466
552
 
467
553
  // 1. 获取需要发布的包列表
468
- const packagesToPublish = await getPackagesToPublish(commit);
554
+ let packagesToPublish;
555
+ if (packages) {
556
+ // 直接使用传入的包列表
557
+ packagesToPublish = packages;
558
+ logger.info('Using provided package list');
559
+ } else {
560
+ // 从 git tags 获取包列表
561
+ if (!hasPassedCommit) {
562
+ commit = await getCurrentCommitHash();
563
+ logger.info('Using current commit');
564
+ }
565
+ // 此时 commit 必定有值(要么传入了,要么刚获取了)
566
+ const commitHash = commit ;
567
+ packagesToPublish = await getPackagesToPublish(commitHash);
568
+ }
569
+
469
570
  if (packagesToPublish.length === 0) {
470
571
  logger.warn('No packages to publish');
471
572
  return;
@@ -482,7 +583,15 @@ async function release(options) {
482
583
  );
483
584
  const branchName = await getCurrentBranchName();
484
585
  checkReleasePlan(releaseManifests, branchName);
485
- await exec(`git checkout ${commit}`);
586
+
587
+ // 只有在指定了 commit 且与当前 HEAD 不同时才切换
588
+ if (hasPassedCommit) {
589
+ const currentHead = await getCurrentCommitHash();
590
+ if (currentHead !== commit) {
591
+ logger.info(`Checking out commit: ${commit}`);
592
+ await exec(`git checkout ${commit}`);
593
+ }
594
+ }
486
595
 
487
596
  await releasePackages(releaseManifests, { dryRun, registry });
488
597
  logger.success('All packages published successfully!');
@@ -498,18 +607,15 @@ const installAction$2 = (program) => {
498
607
  program
499
608
  .command('release')
500
609
  .description('Release packages based on git tags.')
501
- .requiredOption('--commit <string>', '需要执行发布的 commit id')
610
+ .option('--commit <string>', '需要执行发布的 commit id (默认使用当前 HEAD)')
502
611
  .option('--dry-run', '是否只执行不真实发布', false)
503
612
  .option(
504
613
  '-r, --registry <string>',
505
- '发布到的 registry',
506
- 'https://registry.npmjs.org',
614
+ `发布到的 registry (默认: ${DEFAULT_NPM_REGISTRY})`,
615
+ DEFAULT_NPM_REGISTRY,
507
616
  )
508
617
  .action(async (options) => {
509
618
  try {
510
- if (!options.commit) {
511
- throw new Error('请提供需要发布的 commit id');
512
- }
513
619
  if (!process.env.NPM_AUTH_TOKEN) {
514
620
  throw new Error('请设置 NPM_AUTH_TOKEN 环境变量');
515
621
  }
@@ -522,7 +628,14 @@ const installAction$2 = (program) => {
522
628
  });
523
629
  };
524
630
 
525
- const GIT_REPO_URL_REGEX = /git@github\.com:([^\/]+)\/([^\.]+)\.git/;
631
+ // Copyright (c) 2025 coze-dev
632
+ // SPDX-License-Identifier: MIT
633
+
634
+ const GIT_REPO_URL_REGEX = /git@.+:([^\/]+)\/([^\.]+)\.git/;
635
+
636
+ // Copyright (c) 2025 coze-dev
637
+ // SPDX-License-Identifier: MIT
638
+
526
639
 
527
640
  /**
528
641
  * 生成指定长度的随机字符串(使用 crypto 模块)
@@ -544,6 +657,10 @@ var BumpType; (function (BumpType) {
544
657
  const MAJOR = 'major'; BumpType["MAJOR"] = MAJOR;
545
658
  })(BumpType || (BumpType = {}));
546
659
 
660
+ // Copyright (c) 2025 coze-dev
661
+ // SPDX-License-Identifier: MIT
662
+
663
+
547
664
  /**
548
665
  * 获取更新类型的描述
549
666
  */
@@ -592,6 +709,16 @@ const requestBumpType = async () => {
592
709
  }
593
710
  };
594
711
 
712
+ // Copyright (c) 2025 coze-dev
713
+ // SPDX-License-Identifier: MIT
714
+
715
+
716
+
717
+
718
+
719
+
720
+
721
+
595
722
  /**
596
723
  * 根据当前版本和发布类型计算新版本号
597
724
  */
@@ -718,6 +845,18 @@ const generatePublishManifest = async (
718
845
  };
719
846
  };
720
847
 
848
+ // Copyright (c) 2025 coze-dev
849
+ // SPDX-License-Identifier: MIT
850
+
851
+
852
+
853
+
854
+
855
+
856
+
857
+
858
+
859
+
721
860
  async function commitChanges({
722
861
  sessionId,
723
862
  files,
@@ -754,6 +893,22 @@ async function push({ refs, cwd, repoUrl }) {
754
893
  });
755
894
  }
756
895
 
896
+ // Copyright (c) 2025 coze-dev
897
+ // SPDX-License-Identifier: MIT
898
+
899
+
900
+
901
+
902
+
903
+
904
+
905
+
906
+
907
+
908
+
909
+
910
+
911
+
757
912
  const pushToRemote = async (options) => {
758
913
  const {
759
914
  sessionId,
@@ -764,6 +919,7 @@ const pushToRemote = async (options) => {
764
919
  skipCommit,
765
920
  skipPush,
766
921
  repoUrl,
922
+ branchPrefix = 'release',
767
923
  } = options;
768
924
  if (skipCommit) {
769
925
  return;
@@ -777,7 +933,7 @@ const pushToRemote = async (options) => {
777
933
  branchName = await getCurrentBranchName();
778
934
  } else {
779
935
  const date = dayjs().format('YYYYMMDD');
780
- branchName = `release/${date}-${sessionId}`;
936
+ branchName = `${branchPrefix}/${date}-${sessionId}`;
781
937
  await exec(`git checkout -b ${branchName}`, { cwd });
782
938
  }
783
939
  const isTestPublish = [BumpType.ALPHA, BumpType.BETA].includes(
@@ -830,7 +986,107 @@ const pushToRemote = async (options) => {
830
986
  }
831
987
  };
832
988
 
833
- function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
989
+ // Copyright (c) 2025 coze-dev
990
+ // SPDX-License-Identifier: MIT
991
+
992
+
993
+ const getRushConfiguration = (() => {
994
+ const cachedRushConfigs = new Map();
995
+ return (startingFolder) => {
996
+ startingFolder = startingFolder || process.cwd();
997
+ const possibleRushFile = rushSdk.RushConfiguration.tryFindRushJsonLocation({
998
+ startingFolder,
999
+ });
1000
+ if (!possibleRushFile) {
1001
+ throw new Error(
1002
+ `rush.json not found from starting folder: ${startingFolder}`,
1003
+ );
1004
+ }
1005
+ if (cachedRushConfigs.has(possibleRushFile)) {
1006
+ return cachedRushConfigs.get(possibleRushFile) ;
1007
+ }
1008
+
1009
+ const rushConfig =
1010
+ rushSdk.RushConfiguration.loadFromConfigurationFile(possibleRushFile);
1011
+ cachedRushConfigs.set(startingFolder, rushConfig);
1012
+ return rushConfig;
1013
+ };
1014
+ })();
1015
+
1016
+ const lookupTo = (to) => {
1017
+ const cached = new Map();
1018
+ const config = getRushConfiguration();
1019
+ const core = (pkgName) => {
1020
+ if (cached.has(pkgName)) {
1021
+ return cached.get(pkgName);
1022
+ }
1023
+ const result = [pkgName];
1024
+ cached.set(pkgName, result);
1025
+ const projects = config.projects.filter(p => p.packageName === pkgName);
1026
+ if (projects.length === 0) {
1027
+ throw new Error(`Project ${pkgName} not found`);
1028
+ }
1029
+ const project = projects[0];
1030
+ const deps = Array.from(project.dependencyProjects.values()).map(
1031
+ p => p.packageName,
1032
+ );
1033
+ result.push(...deps);
1034
+ deps.forEach(dep => {
1035
+ const subPkgs = core(dep);
1036
+ if (subPkgs) {
1037
+ result.push(...subPkgs);
1038
+ }
1039
+ });
1040
+ return result;
1041
+ };
1042
+ const result = core(to);
1043
+ return [...new Set(result)];
1044
+ };
1045
+
1046
+ const lookupFrom = (from) => {
1047
+ const cached = new Map();
1048
+ const config = getRushConfiguration();
1049
+ const core = (pkgName) => {
1050
+ if (cached.has(pkgName)) {
1051
+ return cached.get(pkgName);
1052
+ }
1053
+ const result = new Set();
1054
+ cached.set(pkgName, result);
1055
+ const projects = config.projects.filter(p => p.packageName === pkgName);
1056
+ if (projects.length === 0) {
1057
+ throw new Error(`Project ${pkgName} not found`);
1058
+ }
1059
+ const project = projects[0];
1060
+ const deps = Array.from([
1061
+ ...project.dependencyProjects.values(),
1062
+ ...project.consumingProjects.values(),
1063
+ ]).map(p => p.packageName);
1064
+ deps.forEach(dep => {
1065
+ result.add(dep);
1066
+ const subPkgs = cached.has(dep) ? cached.get(dep) : core(dep);
1067
+ if (subPkgs) {
1068
+ subPkgs.forEach(p => {
1069
+ result.add(p);
1070
+ });
1071
+ }
1072
+ });
1073
+ return result;
1074
+ };
1075
+ const result = core(from);
1076
+ return [...new Set(result)];
1077
+ };
1078
+
1079
+ const lookupOnly = (packageName) => {
1080
+ const config = getRushConfiguration();
1081
+ const projects = config.projects.filter(p => p.packageName === packageName);
1082
+ if (projects.length === 0) {
1083
+ throw new Error(`Project ${packageName} not found`);
1084
+ }
1085
+ return projects[0];
1086
+ };
1087
+
1088
+ function _optionalChain$2(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
1089
+
834
1090
 
835
1091
 
836
1092
  var RetrievePattern; (function (RetrievePattern) {
@@ -843,10 +1099,9 @@ const retrievePackages = (
843
1099
  pattern,
844
1100
  packages,
845
1101
  ) => {
846
- const rushConfiguration = getRushConfiguration();
847
1102
  const matchedPackages = new Set();
848
1103
  packages.forEach(pkg => {
849
- const project = rushConfiguration.getProjectByName(pkg);
1104
+ const project = lookupOnly(pkg);
850
1105
  if (!project) {
851
1106
  throw new Error(`Package "${pkg}" not found in rush configuration`);
852
1107
  }
@@ -858,16 +1113,15 @@ const retrievePackages = (
858
1113
  const matched = [];
859
1114
  switch (pattern) {
860
1115
  case 'to': {
861
- matched.push(project.dependencyProjects);
1116
+ matched.push(...lookupTo(pkg));
862
1117
  break;
863
1118
  }
864
1119
  case 'from': {
865
- matched.push(project.consumingProjects);
866
- matched.push(project.dependencyProjects);
1120
+ matched.push(...lookupFrom(pkg));
867
1121
  break;
868
1122
  }
869
1123
  case 'only': {
870
- // do nothing
1124
+ matched.push(pkg);
871
1125
  break;
872
1126
  }
873
1127
  default: {
@@ -875,50 +1129,81 @@ const retrievePackages = (
875
1129
  }
876
1130
  }
877
1131
 
878
- for (const matchedSet of matched) {
879
- for (const p of matchedSet) {
880
- if (p.shouldPublish) {
881
- matchedPackages.add(p);
882
- }
883
- }
884
- }
885
- matchedPackages.add(project);
1132
+ matched.forEach(pkgName => {
1133
+ matchedPackages.add(pkgName);
1134
+ });
886
1135
  });
887
- return matchedPackages;
1136
+
1137
+ return [...matchedPackages];
888
1138
  };
889
1139
 
890
1140
  const validateAndGetPackages = (options) => {
891
1141
  const retrievePatterns = Object.values(RetrievePattern);
892
- if (retrievePatterns.every(pattern => (_optionalChain$1([options, 'access', _ => _[pattern], 'optionalAccess', _2 => _2.length]) || 0) <= 0)) {
1142
+ if (retrievePatterns.every(pattern => (_optionalChain$2([options, 'access', _ => _[pattern], 'optionalAccess', _2 => _2.length]) || 0) <= 0)) {
893
1143
  throw new Error('No packages to publish');
894
1144
  }
895
- return retrievePatterns.reduce((acc, pattern) => {
1145
+ const res = retrievePatterns.reduce((acc, pattern) => {
896
1146
  const packages = options[pattern];
897
1147
  if (!packages || packages.length <= 0) {
898
1148
  return acc;
899
1149
  }
900
1150
  const placeholders = retrievePackages(pattern , packages);
901
- return new Set([...acc, ...placeholders]);
1151
+ placeholders.forEach(pkgName => {
1152
+ acc.add(pkgName);
1153
+ });
1154
+ return acc;
902
1155
  }, new Set());
1156
+ const result = [...res]
1157
+ .map(pkgName => {
1158
+ const p = lookupOnly(pkgName);
1159
+ if (p && p.shouldPublish) {
1160
+ return p;
1161
+ }
1162
+ return undefined;
1163
+ })
1164
+ .filter(Boolean) ;
1165
+ return result;
903
1166
  };
904
1167
 
1168
+ function _optionalChain$1(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// Copyright (c) 2025 coze-dev
1169
+
1170
+
1171
+
1172
+
1173
+
1174
+
1175
+
1176
+
905
1177
  const confirmForPublish = async (
906
1178
  publishManifest,
907
1179
  dryRun,
1180
+ options,
908
1181
  ) => {
909
- console.log(chalk.gray('Will publish the following packages:'));
1182
+ logger.info(chalk.gray('Will publish the following packages:'), false);
910
1183
  publishManifest.forEach(manifest => {
911
- const msg = `${manifest.project.packageName}: ${chalk.bgGreen(`${manifest.currentVersion} -> ${chalk.bold(manifest.newVersion)}`)}`;
912
- console.log(`- ${msg}`);
1184
+ const versionChange = `${manifest.currentVersion} -> ${chalk.bold(manifest.newVersion)}`;
1185
+ const msg = `${manifest.project.packageName}: ${chalk.bgGreen(versionChange)}`;
1186
+ logger.info(`- ${msg}`, false);
913
1187
  });
1188
+
1189
+ // Release 模式的额外提示
1190
+ if (_optionalChain$1([options, 'optionalAccess', _ => _.isReleaseMode])) {
1191
+ logger.info('', false);
1192
+ logger.warn(chalk.yellow.bold('⚠️ Release Mode Enabled:'), false);
1193
+ const registryMsg = ` Packages will be published directly to: ${chalk.bold(options.registry || 'default registry')}`;
1194
+ logger.warn(chalk.yellow(registryMsg), false);
1195
+ }
1196
+
914
1197
  if (dryRun) {
915
1198
  return false;
916
1199
  }
917
1200
 
918
- console.log('\n');
1201
+ logger.info('', false);
919
1202
  try {
920
1203
  const result = await prompts.confirm({
921
- message: 'Are you sure to publish?',
1204
+ message: _optionalChain$1([options, 'optionalAccess', _2 => _2.isReleaseMode])
1205
+ ? 'Are you sure to publish directly?'
1206
+ : 'Are you sure to publish?',
922
1207
  default: true,
923
1208
  });
924
1209
  return result;
@@ -927,7 +1212,8 @@ const confirmForPublish = async (
927
1212
  }
928
1213
  };
929
1214
 
930
- function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }
1215
+ function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// Copyright (c) 2025 coze-dev
1216
+
931
1217
 
932
1218
 
933
1219
 
@@ -1132,6 +1418,11 @@ const generateChangelog$1 = ({
1132
1418
  };
1133
1419
  };
1134
1420
 
1421
+ // Copyright (c) 2025 coze-dev
1422
+ // SPDX-License-Identifier: MIT
1423
+
1424
+
1425
+
1135
1426
  const deleteFiles = async (files) => {
1136
1427
  await Promise.all(
1137
1428
  files.map(async file => {
@@ -1187,7 +1478,7 @@ const readPreviousChangelog = async (
1187
1478
 
1188
1479
  const generateChangelogForProject = async (manifest) => {
1189
1480
  const { project, newVersion } = manifest;
1190
- const rushConfiguration = getRushConfiguration();
1481
+ const rushConfiguration = getRushConfiguration$1();
1191
1482
  const { changesFolder } = rushConfiguration;
1192
1483
  const changedFolderOfPkg = path.resolve(changesFolder, project.packageName);
1193
1484
  const changelogJsonPath = path.resolve(
@@ -1229,6 +1520,12 @@ const generateChangelog = async (
1229
1520
  return modifiedFiles.flat();
1230
1521
  };
1231
1522
 
1523
+ // Copyright (c) 2025 coze-dev
1524
+ // SPDX-License-Identifier: MIT
1525
+
1526
+
1527
+
1528
+
1232
1529
  const updatePackageVersion = async (
1233
1530
  project,
1234
1531
  newVersion,
@@ -1257,6 +1554,10 @@ const applyPublishManifest = async (
1257
1554
  return modifiedFiles;
1258
1555
  };
1259
1556
 
1557
+ // Copyright (c) 2025 coze-dev
1558
+ // SPDX-License-Identifier: MIT
1559
+
1560
+
1260
1561
  // 针对不同类型的发布,对应不同 sideEffects:
1261
1562
  // 1. alpha: 直接创建并push 分支,触发 CI,执行发布;
1262
1563
  // 2. beta: 本分支直接切换版本号,并发布
@@ -1264,15 +1565,18 @@ const applyPublishManifest = async (
1264
1565
 
1265
1566
  const publish = async (options) => {
1266
1567
  const sessionId = randomHash(6);
1267
- const rushConfiguration = getRushConfiguration();
1568
+ const rushConfiguration = getRushConfiguration$1();
1268
1569
  const rushFolder = rushConfiguration.rushJsonFolder;
1269
- if (process.env.SKIP_UNCOMMITTED_CHECK !== 'true') {
1570
+ if (
1571
+ process.env.SKIP_UNCOMMITTED_CHECK !== 'true' &&
1572
+ options.release !== true
1573
+ ) {
1270
1574
  await ensureNotUncommittedChanges();
1271
1575
  }
1272
1576
 
1273
1577
  // 1. 验证并获取需要发布的包列表
1274
1578
  const packagesToPublish = validateAndGetPackages(options);
1275
- if (packagesToPublish.size === 0) {
1579
+ if (packagesToPublish.length === 0) {
1276
1580
  logger.error(
1277
1581
  'No packages to publish, should specify some package by `--to` or `--from` or `--only`',
1278
1582
  );
@@ -1302,6 +1606,10 @@ const publish = async (options) => {
1302
1606
  const continuePublish = await confirmForPublish(
1303
1607
  publishManifests,
1304
1608
  !!options.dryRun,
1609
+ {
1610
+ isReleaseMode: !!options.release,
1611
+ registry: options.registry || DEFAULT_NPM_REGISTRY,
1612
+ },
1305
1613
  );
1306
1614
 
1307
1615
  if (!continuePublish) {
@@ -1317,17 +1625,47 @@ const publish = async (options) => {
1317
1625
  await Promise.all(postHandles.map(handle => handle(publishManifests)))
1318
1626
  ).flat();
1319
1627
 
1320
- // 4. 创建并推送发布分支
1321
- await pushToRemote({
1322
- publishManifests,
1323
- bumpPolicy: bumpPolicy ,
1324
- sessionId,
1325
- changedFiles,
1326
- cwd: rushFolder,
1327
- skipCommit: !!options.skipCommit,
1328
- skipPush: !!options.skipPush,
1329
- repoUrl: options.repoUrl,
1330
- });
1628
+ // 4. 创建并推送发布分支 或 直接发布
1629
+ let shouldRelease = false;
1630
+ if (options.release) {
1631
+ // 验证 release 模式的前置条件
1632
+ if (isBetaPublish === false) {
1633
+ logger.error(
1634
+ 'Direct release (--release) is only allowed for alpha or beta versions.',
1635
+ );
1636
+ logger.error(`Current bump type is: ${bumpPolicy}`);
1637
+ logger.warn('Falling back to normal publish mode...');
1638
+ } else {
1639
+ shouldRelease = true;
1640
+ }
1641
+ }
1642
+
1643
+ if (shouldRelease) {
1644
+ // Release 模式:直接发布
1645
+ logger.info('Running in direct release mode...');
1646
+ logger.info('Starting package release...');
1647
+ const registry = options.registry || DEFAULT_NPM_REGISTRY;
1648
+ // 将 PublishManifest[] 转换为 PackageToPublish[]
1649
+ const packages = publishManifests.map(manifest => ({
1650
+ packageName: manifest.project.packageName,
1651
+ version: manifest.newVersion,
1652
+ }));
1653
+ await release({ dryRun: !!options.dryRun, registry, packages });
1654
+ } else {
1655
+ // 普通模式:创建并推送发布分支
1656
+ await pushToRemote({
1657
+ publishManifests,
1658
+ bumpPolicy: bumpPolicy ,
1659
+ sessionId,
1660
+ changedFiles,
1661
+ cwd: rushFolder,
1662
+ skipCommit: !!options.skipCommit,
1663
+ skipPush: !!options.skipPush,
1664
+ repoUrl: options.repoUrl,
1665
+ branchPrefix: options.branchPrefix,
1666
+ });
1667
+ }
1668
+
1331
1669
  logger.success('Publish success.');
1332
1670
  };
1333
1671
 
@@ -1358,6 +1696,21 @@ const installAction$1 = (program) => {
1358
1696
  'Git repository URL (e.g. git@github.com:coze-dev/coze-js.git)',
1359
1697
  undefined,
1360
1698
  )
1699
+ .option(
1700
+ '--branch-prefix <prefix>',
1701
+ `Git branch name prefix (default: ${DEFAULT_BRANCH_PREFIX})`,
1702
+ DEFAULT_BRANCH_PREFIX,
1703
+ )
1704
+ .option(
1705
+ '-l, --release',
1706
+ 'Directly publish packages (only for alpha/beta versions)',
1707
+ false,
1708
+ )
1709
+ .option(
1710
+ '--registry <url>',
1711
+ `NPM registry URL (default: ${DEFAULT_NPM_REGISTRY})`,
1712
+ DEFAULT_NPM_REGISTRY,
1713
+ )
1361
1714
  .action(async (options) => {
1362
1715
  try {
1363
1716
  const repoUrl = options.repoUrl || (await getCurrentOrigin());
@@ -1365,8 +1718,9 @@ const installAction$1 = (program) => {
1365
1718
  throw new Error('Git repository URL is required');
1366
1719
  }
1367
1720
  if (!GIT_REPO_URL_REGEX.test(repoUrl)) {
1721
+ const expectedFormat = 'git@github.com:${org}/${repo}.git';
1368
1722
  throw new Error(
1369
- `Invalid git repository URL: ${repoUrl}, it should be follow the format: git@github.com:\${org}/\${repo}.git`,
1723
+ `Invalid git repository URL: ${repoUrl}, it should follow the format: ${expectedFormat}`,
1370
1724
  );
1371
1725
  }
1372
1726
  const normalizeOptions = {
@@ -1381,6 +1735,10 @@ const installAction$1 = (program) => {
1381
1735
  });
1382
1736
  };
1383
1737
 
1738
+ // Copyright (c) 2025 coze-dev
1739
+ // SPDX-License-Identifier: MIT
1740
+
1741
+
1384
1742
  const whoAmI = async () => {
1385
1743
  const [name, email] = await Promise.all([
1386
1744
  exec('git config user.name', { cwd: __dirname, silent: true }),
@@ -1392,6 +1750,10 @@ const whoAmI = async () => {
1392
1750
  };
1393
1751
  };
1394
1752
 
1753
+ // Copyright (c) 2025 coze-dev
1754
+ // SPDX-License-Identifier: MIT
1755
+
1756
+
1395
1757
  // 这两个包没有 module 导出
1396
1758
  // eslint-disable-next-line @typescript-eslint/no-require-imports
1397
1759
  const { sync } = require('conventional-commits-parser');
@@ -1408,7 +1770,7 @@ const collectShouldUpdateChangesProjects = async (
1408
1770
 
1409
1771
  ) => {
1410
1772
  const changedFiles = await getChangedFilesFromCached();
1411
- const rushConfiguration = getRushConfiguration();
1773
+ const rushConfiguration = getRushConfiguration$1();
1412
1774
  const lookup = rushConfiguration.getProjectLookupForRoot(
1413
1775
  rushConfiguration.rushJsonFolder,
1414
1776
  );
@@ -1520,7 +1882,7 @@ async function generateAllChangesFile(
1520
1882
  comment,
1521
1883
  patchType,
1522
1884
  ) {
1523
- const rushConfiguration = getRushConfiguration();
1885
+ const rushConfiguration = getRushConfiguration$1();
1524
1886
  const needUpdateProjects = await collectShouldUpdateChangesProjects();
1525
1887
  const { email } = await whoAmI();
1526
1888
 
@@ -1544,9 +1906,13 @@ async function generateAllChangesFile(
1544
1906
  }
1545
1907
  }
1546
1908
 
1909
+ // Copyright (c) 2025 coze-dev
1910
+ // SPDX-License-Identifier: MIT
1911
+
1912
+
1547
1913
  const amendCommit = async () => {
1548
1914
  const changedFiles = await getChangedFilesFromCached();
1549
- const rushConfiguration = getRushConfiguration();
1915
+ const rushConfiguration = getRushConfiguration$1();
1550
1916
 
1551
1917
  const relativeChangesFolder = path.relative(
1552
1918
  rushConfiguration.rushJsonFolder,
@@ -1561,6 +1927,10 @@ const amendCommit = async () => {
1561
1927
  }
1562
1928
  };
1563
1929
 
1930
+ // Copyright (c) 2025 coze-dev
1931
+ // SPDX-License-Identifier: MIT
1932
+
1933
+
1564
1934
  const generateChangeFiles = async (options) => {
1565
1935
  // CI 环境的提交不做处理
1566
1936
  if (options.ci || process.env.CI === 'true') {
@@ -1573,7 +1943,7 @@ const generateChangeFiles = async (options) => {
1573
1943
  try {
1574
1944
  let { commitMsg } = options;
1575
1945
  if (!commitMsg) {
1576
- const rushConfiguration = getRushConfiguration();
1946
+ const rushConfiguration = getRushConfiguration$1();
1577
1947
  commitMsg = await fs.readFile(
1578
1948
  path.resolve(rushConfiguration.rushJsonFolder, '.git/COMMIT_EDITMSG'),
1579
1949
  'utf-8',
@@ -1606,6 +1976,10 @@ const installAction = (program) => {
1606
1976
  });
1607
1977
  };
1608
1978
 
1979
+ // Copyright (c) 2025 coze-dev
1980
+ // SPDX-License-Identifier: MIT
1981
+
1982
+
1609
1983
  const main = () => {
1610
1984
  const packageJson = JSON.parse(
1611
1985
  fs$1.readFileSync(path.resolve(__dirname, '../package.json'), 'utf8'),
@@ -0,0 +1,86 @@
1
+ /**
2
+ * CI 环境检测工具
3
+ */
4
+ export declare const ciEnvironment: {
5
+ /**
6
+ * 检查是否在 GitHub Actions 环境中
7
+ */
8
+ isGitHubActions(): boolean;
9
+ /**
10
+ * 检查是否在任何 CI 环境中
11
+ */
12
+ isCI(): boolean;
13
+ /**
14
+ * 获取 GitHub 仓库信息
15
+ */
16
+ getRepository(): string | undefined;
17
+ /**
18
+ * 获取当前工作流名称
19
+ */
20
+ getWorkflow(): string | undefined;
21
+ /**
22
+ * 获取运行 ID
23
+ */
24
+ getRunId(): string | undefined;
25
+ /**
26
+ * 获取当前分支名
27
+ */
28
+ getBranch(): string | undefined;
29
+ /**
30
+ * 检查是否是 Pull Request 事件
31
+ */
32
+ isPullRequest(): boolean;
33
+ /**
34
+ * 检查是否是 Push 事件
35
+ */
36
+ isPush(): boolean;
37
+ /**
38
+ * 获取触发用户
39
+ */
40
+ getActor(): string | undefined;
41
+ /**
42
+ * 获取提交 SHA
43
+ */
44
+ getCommitSha(): string | undefined;
45
+ /**
46
+ * 获取运行器操作系统
47
+ */
48
+ getRunnerOS(): string | undefined;
49
+ /**
50
+ * 获取完整的环境信息
51
+ */
52
+ getEnvironmentInfo(): {
53
+ name: string;
54
+ isCI: boolean;
55
+ isGitHubActions: boolean;
56
+ repository?: undefined;
57
+ workflow?: undefined;
58
+ runId?: undefined;
59
+ branch?: undefined;
60
+ actor?: undefined;
61
+ commitSha?: undefined;
62
+ runnerOS?: undefined;
63
+ eventName?: undefined;
64
+ isPullRequest?: undefined;
65
+ isPush?: undefined;
66
+ } | {
67
+ name: string;
68
+ isCI: boolean;
69
+ isGitHubActions: boolean;
70
+ repository: string | undefined;
71
+ workflow: string | undefined;
72
+ runId: string | undefined;
73
+ branch: string | undefined;
74
+ actor: string | undefined;
75
+ commitSha: string | undefined;
76
+ runnerOS: string | undefined;
77
+ eventName: string | undefined;
78
+ isPullRequest: boolean;
79
+ isPush: boolean;
80
+ };
81
+ };
82
+ /**
83
+ * 简单的检查函数
84
+ */
85
+ export declare const isGitHubActions: () => boolean;
86
+ export declare const isCI: () => boolean;
@@ -0,0 +1,8 @@
1
+ export interface IPublishPluginConfig {
2
+ branchPrefix?: string;
3
+ }
4
+ /**
5
+ * Read plugin configuration from common/config/rush-plugins/@coze-arch/rush-publish-plugin.json
6
+ * @returns Plugin configuration object
7
+ */
8
+ export declare function getPluginConfig(): IPublishPluginConfig;
@@ -4,6 +4,11 @@ export declare const getChangedFilesFromCached: () => Promise<string[]>;
4
4
  * @returns string
5
5
  */
6
6
  export declare const getCurrentBranchName: () => Promise<string>;
7
+ /**
8
+ * 获取当前 commit hash
9
+ * @returns commit hash
10
+ */
11
+ export declare const getCurrentCommitHash: () => Promise<string>;
7
12
  export declare const isMainBranch: () => Promise<boolean>;
8
13
  export declare const getChangedFiles: () => Promise<string[]>;
9
14
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coze-arch/rush-publish-plugin",
3
- "version": "0.0.4",
3
+ "version": "0.0.5-alpha.5049d2",
4
4
  "description": "rush plugin to generate change log and publish packages",
5
5
  "keywords": [
6
6
  "rush",
@@ -9,7 +9,7 @@
9
9
  "release",
10
10
  "publish"
11
11
  ],
12
- "license": "ISC",
12
+ "license": "MIT",
13
13
  "author": "tecvan.fe@gmail.com",
14
14
  "maintainers": [],
15
15
  "main": "./lib/index.js",
@@ -42,24 +42,20 @@
42
42
  },
43
43
  "devDependencies": {
44
44
  "@commitlint/types": "^17.4.0",
45
+ "@coze-arch/build-lib-preset": "workspace:*",
45
46
  "@coze-arch/eslint-config": "workspace:*",
46
47
  "@coze-arch/fs-enhance": "workspace:*",
47
48
  "@coze-arch/logger": "workspace:*",
49
+ "@coze-arch/monorepo-kits": "workspace:*",
48
50
  "@coze-arch/ts-config": "workspace:*",
49
51
  "@coze-arch/vitest-config": "workspace:*",
50
- "@rollup/plugin-commonjs": "^24.0.0",
51
- "@rollup/plugin-json": "~6.0.0",
52
- "@rollup/plugin-node-resolve": "~15.0.1",
53
- "@rollup/plugin-sucrase": "^5.0.2",
54
- "@types/node": "^22.13.13",
52
+ "@types/node": "^22",
55
53
  "@types/semver": "^7.5.8",
56
54
  "@types/shelljs": "^0.8.15",
57
55
  "@vitest/coverage-v8": "^3.0.9",
58
56
  "commander": "^13.1.0",
59
- "rollup": "^4.9.0",
60
- "rollup-plugin-terser": "^7.0.2",
57
+ "rollup": "^4.41.1",
61
58
  "sucrase": "^3.32.0",
62
- "tsx": "^4.19.3",
63
59
  "vitest": "^3.0.9"
64
60
  },
65
61
  "peerDependencies": {