@coze-arch/rush-publish-plugin 0.0.5-alpha.8b5f6f → 0.0.5-alpha.a5f14f
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/lib/index.js +251 -51
- package/lib/utils/git.d.ts +22 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -282,6 +282,84 @@ const getCurrentOrigin = async (
|
|
|
282
282
|
}
|
|
283
283
|
};
|
|
284
284
|
|
|
285
|
+
/**
|
|
286
|
+
* 解析 Git 远程仓库 URL,提取主机和仓库路径
|
|
287
|
+
* 支持 HTTP/HTTPS 和 SSH 格式
|
|
288
|
+
* @param gitUrl Git 仓库 URL
|
|
289
|
+
* @returns 包含主机和仓库路径的对象,解析失败返回 null
|
|
290
|
+
*/
|
|
291
|
+
const parseGitRemoteUrl = (
|
|
292
|
+
gitUrl,
|
|
293
|
+
) => {
|
|
294
|
+
if (!gitUrl) {
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const trimmedUrl = gitUrl.trim().replace(/\.git$/, '');
|
|
299
|
+
|
|
300
|
+
// 匹配 SSH 格式: git@github.com:owner/repo.git
|
|
301
|
+
const sshMatch = trimmedUrl.match(/^git@([^:]+):(.+)$/);
|
|
302
|
+
if (sshMatch) {
|
|
303
|
+
const host = sshMatch[1];
|
|
304
|
+
const path = sshMatch[2];
|
|
305
|
+
return {
|
|
306
|
+
host,
|
|
307
|
+
path,
|
|
308
|
+
fullUrl: `https://${host}/${path}`,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// 匹配 HTTP/HTTPS 格式: https://github.com/owner/repo.git
|
|
313
|
+
const httpMatch = trimmedUrl.match(/^https?:\/\/([^/]+)\/(.+)$/);
|
|
314
|
+
if (httpMatch) {
|
|
315
|
+
const host = httpMatch[1];
|
|
316
|
+
const path = httpMatch[2];
|
|
317
|
+
return {
|
|
318
|
+
host,
|
|
319
|
+
path,
|
|
320
|
+
fullUrl: `https://${host}/${path}`,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return null;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* 根据仓库信息构建 MR/PR 创建链接
|
|
329
|
+
* @param repoInfo 仓库信息
|
|
330
|
+
* @param branchName 分支名称
|
|
331
|
+
* @returns MR/PR 创建链接,如果无法构建则返回 null
|
|
332
|
+
*/
|
|
333
|
+
const buildMergeRequestUrl = (
|
|
334
|
+
repoInfo,
|
|
335
|
+
branchName,
|
|
336
|
+
) => {
|
|
337
|
+
const { host, fullUrl } = repoInfo;
|
|
338
|
+
|
|
339
|
+
// GitHub
|
|
340
|
+
if (host.includes('github.com')) {
|
|
341
|
+
return `${fullUrl}/compare/${branchName}?expand=1`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// GitLab
|
|
345
|
+
if (host.includes('gitlab')) {
|
|
346
|
+
return `${fullUrl}/-/merge_requests/new?merge_request[source_branch]=${branchName}`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Gitee
|
|
350
|
+
if (host.includes('gitee.com')) {
|
|
351
|
+
return `${fullUrl}/compare/${branchName}...master`;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Bitbucket
|
|
355
|
+
if (host.includes('bitbucket')) {
|
|
356
|
+
return `${fullUrl}/pull-requests/new?source=${branchName}`;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// 无法识别的平台
|
|
360
|
+
return null;
|
|
361
|
+
};
|
|
362
|
+
|
|
285
363
|
// Copyright (c) 2025 coze-dev
|
|
286
364
|
// SPDX-License-Identifier: MIT
|
|
287
365
|
|
|
@@ -323,8 +401,7 @@ const getRushConfiguration$1 = (() => {
|
|
|
323
401
|
};
|
|
324
402
|
})();
|
|
325
403
|
|
|
326
|
-
// Copyright (c) 2025 coze-dev
|
|
327
|
-
// SPDX-License-Identifier: MIT
|
|
404
|
+
function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// Copyright (c) 2025 coze-dev
|
|
328
405
|
|
|
329
406
|
|
|
330
407
|
|
|
@@ -355,14 +432,21 @@ const updateDependencyVersions = async (
|
|
|
355
432
|
return Promise.resolve(packageJson);
|
|
356
433
|
};
|
|
357
434
|
|
|
358
|
-
|
|
435
|
+
/**
|
|
436
|
+
* 应用发布配置
|
|
437
|
+
* 优先使用 botPublishConfig,如果不存在则使用 cozePublishConfig
|
|
438
|
+
*/
|
|
439
|
+
const applyPublishConfigSettings = async (
|
|
359
440
|
packageJson,
|
|
360
441
|
) => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
442
|
+
// 优先使用 botPublishConfig,如果不存在则回退到 cozePublishConfig
|
|
443
|
+
const publishConfig =
|
|
444
|
+
_nullishCoalesce(packageJson.botPublishConfig, () => ( packageJson.cozePublishConfig));
|
|
445
|
+
|
|
446
|
+
if (publishConfig) {
|
|
447
|
+
const keys = Object.keys(publishConfig);
|
|
364
448
|
for (const key of keys) {
|
|
365
|
-
packageJson[key] =
|
|
449
|
+
packageJson[key] = publishConfig[key];
|
|
366
450
|
}
|
|
367
451
|
}
|
|
368
452
|
return Promise.resolve(packageJson);
|
|
@@ -371,7 +455,7 @@ const applyCozePublishConfig = async (
|
|
|
371
455
|
const applyPublishConfig = async (project) => {
|
|
372
456
|
const jobs = [
|
|
373
457
|
updateDependencyVersions,
|
|
374
|
-
|
|
458
|
+
applyPublishConfigSettings,
|
|
375
459
|
];
|
|
376
460
|
const packageJsonPath = path.join(project.projectFolder, 'package.json');
|
|
377
461
|
let packageJson = await readJsonFile(packageJsonPath);
|
|
@@ -484,7 +568,7 @@ const checkReleasePlan = (
|
|
|
484
568
|
!allowBranches.includes(branchName)
|
|
485
569
|
) {
|
|
486
570
|
throw new Error(
|
|
487
|
-
`For LATEST release, should be on one of these branches: ${allowBranches.join(', ')}
|
|
571
|
+
`For LATEST release, should be on one of these branches: ${allowBranches.join(', ')}. Current Branch: ${branchName}`,
|
|
488
572
|
);
|
|
489
573
|
}
|
|
490
574
|
return true;
|
|
@@ -910,6 +994,144 @@ async function push({ refs, cwd, repoUrl }) {
|
|
|
910
994
|
|
|
911
995
|
|
|
912
996
|
|
|
997
|
+
/**
|
|
998
|
+
* 获取或创建发布分支
|
|
999
|
+
*/
|
|
1000
|
+
const getOrCreateBranch = async (params
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
) => {
|
|
1006
|
+
const { bumpPolicy, sessionId, branchPrefix, cwd } = params;
|
|
1007
|
+
|
|
1008
|
+
if (bumpPolicy === BumpType.BETA) {
|
|
1009
|
+
return await getCurrentBranchName();
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
const date = dayjs().format('YYYYMMDD');
|
|
1013
|
+
const branchName = `${branchPrefix}/${date}-${sessionId}`;
|
|
1014
|
+
await exec(`git checkout -b ${branchName}`, { cwd });
|
|
1015
|
+
return branchName;
|
|
1016
|
+
};
|
|
1017
|
+
|
|
1018
|
+
/**
|
|
1019
|
+
* 处理 Beta 发布流程:询问并执行 git push
|
|
1020
|
+
*/
|
|
1021
|
+
const handleBetaPublish = async (
|
|
1022
|
+
branchName,
|
|
1023
|
+
cwd,
|
|
1024
|
+
) => {
|
|
1025
|
+
logger.success(`Changes have been committed to branch "${branchName}".`);
|
|
1026
|
+
|
|
1027
|
+
const shouldPush = await prompts.confirm({
|
|
1028
|
+
message: 'Do you want to push the changes now?',
|
|
1029
|
+
default: true,
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
if (shouldPush) {
|
|
1033
|
+
logger.info('Pushing changes to remote...');
|
|
1034
|
+
await exec('git push', { cwd });
|
|
1035
|
+
logger.success('Changes pushed successfully!');
|
|
1036
|
+
} else {
|
|
1037
|
+
logger.info('Please run "git push" manually when you are ready.');
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* 显示手动创建 MR 的提示消息
|
|
1043
|
+
*/
|
|
1044
|
+
const showManualMrMessage = (
|
|
1045
|
+
branchName,
|
|
1046
|
+
repositoryUrl,
|
|
1047
|
+
) => {
|
|
1048
|
+
const baseMessage = `Please create a merge request from branch "${branchName}" to the main branch`;
|
|
1049
|
+
const suffix =
|
|
1050
|
+
'The release will be triggered after the merge request is merged.';
|
|
1051
|
+
|
|
1052
|
+
if (repositoryUrl) {
|
|
1053
|
+
logger.success(
|
|
1054
|
+
`Repository: ${repositoryUrl}\n${baseMessage}.\n${suffix}`,
|
|
1055
|
+
false,
|
|
1056
|
+
);
|
|
1057
|
+
} else {
|
|
1058
|
+
logger.success(`${baseMessage} in your repository.\n${suffix}`);
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
/**
|
|
1063
|
+
* 显示 MR/PR 创建链接并打开浏览器
|
|
1064
|
+
*/
|
|
1065
|
+
const showMrLinkAndOpenBrowser = async (mrUrl) => {
|
|
1066
|
+
const log = [
|
|
1067
|
+
'************************************************',
|
|
1068
|
+
'*',
|
|
1069
|
+
`* Please create MR/PR: ${mrUrl}`,
|
|
1070
|
+
'*',
|
|
1071
|
+
'* The release will be triggered after the MR is merged.',
|
|
1072
|
+
'*',
|
|
1073
|
+
'************************************************',
|
|
1074
|
+
];
|
|
1075
|
+
logger.success(log.join('\n'), false);
|
|
1076
|
+
|
|
1077
|
+
const open = await import('open');
|
|
1078
|
+
await open.default(mrUrl);
|
|
1079
|
+
};
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* 处理正式版本发布流程:提示创建 MR/PR
|
|
1083
|
+
*/
|
|
1084
|
+
const handleProductionPublish = async (
|
|
1085
|
+
branchName,
|
|
1086
|
+
cwd,
|
|
1087
|
+
) => {
|
|
1088
|
+
const originUrl = await getCurrentOrigin(cwd);
|
|
1089
|
+
if (!originUrl) {
|
|
1090
|
+
showManualMrMessage(branchName);
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
const repoInfo = parseGitRemoteUrl(originUrl);
|
|
1095
|
+
if (!repoInfo) {
|
|
1096
|
+
showManualMrMessage(branchName);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
const mrUrl = buildMergeRequestUrl(repoInfo, branchName);
|
|
1101
|
+
if (!mrUrl) {
|
|
1102
|
+
showManualMrMessage(branchName, repoInfo.fullUrl);
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
await showMrLinkAndOpenBrowser(mrUrl);
|
|
1107
|
+
};
|
|
1108
|
+
|
|
1109
|
+
/**
|
|
1110
|
+
* 根据发布类型处理后续提示
|
|
1111
|
+
*/
|
|
1112
|
+
const handlePostPushPrompts = async (
|
|
1113
|
+
bumpPolicy,
|
|
1114
|
+
branchName,
|
|
1115
|
+
cwd,
|
|
1116
|
+
) => {
|
|
1117
|
+
const isAlphaPublish = bumpPolicy === BumpType.ALPHA;
|
|
1118
|
+
const isBetaPublish = bumpPolicy === BumpType.BETA;
|
|
1119
|
+
|
|
1120
|
+
// Alpha 发布:不需要提示(会自动触发 CI 发布)
|
|
1121
|
+
if (isAlphaPublish) {
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// Beta 发布:询问用户是否立即执行 git push
|
|
1126
|
+
if (isBetaPublish) {
|
|
1127
|
+
await handleBetaPublish(branchName, cwd);
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
// 正式版本发布:提示创建 MR/PR
|
|
1132
|
+
await handleProductionPublish(branchName, cwd);
|
|
1133
|
+
};
|
|
1134
|
+
|
|
913
1135
|
const pushToRemote = async (options) => {
|
|
914
1136
|
const {
|
|
915
1137
|
sessionId,
|
|
@@ -921,65 +1143,39 @@ const pushToRemote = async (options) => {
|
|
|
921
1143
|
repoUrl,
|
|
922
1144
|
branchPrefix = 'release',
|
|
923
1145
|
} = options;
|
|
1146
|
+
|
|
924
1147
|
if (skipCommit) {
|
|
925
1148
|
return;
|
|
926
1149
|
}
|
|
927
1150
|
|
|
928
|
-
//
|
|
929
|
-
const
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
}
|
|
935
|
-
const date = dayjs().format('YYYYMMDD');
|
|
936
|
-
branchName = `${branchPrefix}/${date}-${sessionId}`;
|
|
937
|
-
await exec(`git checkout -b ${branchName}`, { cwd });
|
|
938
|
-
}
|
|
939
|
-
const isTestPublish = [BumpType.ALPHA, BumpType.BETA].includes(
|
|
940
|
-
bumpPolicy ,
|
|
941
|
-
);
|
|
1151
|
+
// 1. 获取或创建发布分支
|
|
1152
|
+
const branchName = await getOrCreateBranch({
|
|
1153
|
+
bumpPolicy,
|
|
1154
|
+
sessionId,
|
|
1155
|
+
branchPrefix,
|
|
1156
|
+
cwd,
|
|
1157
|
+
});
|
|
942
1158
|
|
|
943
|
-
//
|
|
1159
|
+
// 2. 提交变更
|
|
944
1160
|
const { effects } = await commitChanges({
|
|
945
1161
|
files: changedFiles,
|
|
946
1162
|
cwd,
|
|
947
1163
|
branchName,
|
|
948
1164
|
});
|
|
1165
|
+
|
|
949
1166
|
if (skipPush) {
|
|
950
1167
|
return;
|
|
951
1168
|
}
|
|
1169
|
+
|
|
1170
|
+
// 3. 推送变更
|
|
952
1171
|
await push({
|
|
953
1172
|
refs: effects,
|
|
954
1173
|
cwd,
|
|
955
|
-
repoUrl
|
|
1174
|
+
repoUrl,
|
|
956
1175
|
});
|
|
957
1176
|
|
|
958
|
-
//
|
|
959
|
-
|
|
960
|
-
if (!repoInfoMatch) {
|
|
961
|
-
throw new Error('Invalid git repository URL');
|
|
962
|
-
}
|
|
963
|
-
const repoOwner = repoInfoMatch[1];
|
|
964
|
-
const repoName = repoInfoMatch[2];
|
|
965
|
-
|
|
966
|
-
if (isTestPublish) {
|
|
967
|
-
logger.success(
|
|
968
|
-
`Please refer to https://github.com/${repoOwner}/${repoName}/actions/workflows/release.yml for the release progress.`,
|
|
969
|
-
);
|
|
970
|
-
} else {
|
|
971
|
-
const prUrl = `https://github.com/${repoOwner}/${repoName}/compare/${branchName}?expand=1`;
|
|
972
|
-
const log = [
|
|
973
|
-
'************************************************',
|
|
974
|
-
'*',
|
|
975
|
-
`* Please create PR: ${prUrl}`,
|
|
976
|
-
'*',
|
|
977
|
-
'************************************************',
|
|
978
|
-
];
|
|
979
|
-
logger.success(log.join('\n'), false);
|
|
980
|
-
const open = await import('open');
|
|
981
|
-
await open.default(prUrl);
|
|
982
|
-
}
|
|
1177
|
+
// 4. 根据发布类型显示不同提示
|
|
1178
|
+
await handlePostPushPrompts(bumpPolicy, branchName, cwd);
|
|
983
1179
|
};
|
|
984
1180
|
|
|
985
1181
|
// Copyright (c) 2025 coze-dev
|
|
@@ -1591,7 +1787,11 @@ const publish = async (options) => {
|
|
|
1591
1787
|
const isBetaPublish = [BumpType.BETA, BumpType.ALPHA].includes(
|
|
1592
1788
|
bumpPolicy ,
|
|
1593
1789
|
);
|
|
1594
|
-
if (
|
|
1790
|
+
if (
|
|
1791
|
+
process.env.SKIP_BRANCH_CHECK !== 'true' &&
|
|
1792
|
+
isBetaPublish === false &&
|
|
1793
|
+
(await isMainBranch()) === false
|
|
1794
|
+
) {
|
|
1595
1795
|
// 只允许在主分支发布
|
|
1596
1796
|
logger.error(
|
|
1597
1797
|
'You are not in main branch, please switch to main branch and try again.',
|
package/lib/utils/git.d.ts
CHANGED
|
@@ -22,3 +22,25 @@ export declare const ensureNotUncommittedChanges: () => Promise<boolean>;
|
|
|
22
22
|
*/
|
|
23
23
|
export declare const getCurrentOrigin: (cwd?: string) => Promise<string | undefined>;
|
|
24
24
|
export declare const convertGitSchemaToHttp: (gitUrl: string) => string;
|
|
25
|
+
/**
|
|
26
|
+
* 解析 Git 远程仓库 URL,提取主机和仓库路径
|
|
27
|
+
* 支持 HTTP/HTTPS 和 SSH 格式
|
|
28
|
+
* @param gitUrl Git 仓库 URL
|
|
29
|
+
* @returns 包含主机和仓库路径的对象,解析失败返回 null
|
|
30
|
+
*/
|
|
31
|
+
export declare const parseGitRemoteUrl: (gitUrl: string) => {
|
|
32
|
+
host: string;
|
|
33
|
+
path: string;
|
|
34
|
+
fullUrl: string;
|
|
35
|
+
} | null;
|
|
36
|
+
/**
|
|
37
|
+
* 根据仓库信息构建 MR/PR 创建链接
|
|
38
|
+
* @param repoInfo 仓库信息
|
|
39
|
+
* @param branchName 分支名称
|
|
40
|
+
* @returns MR/PR 创建链接,如果无法构建则返回 null
|
|
41
|
+
*/
|
|
42
|
+
export declare const buildMergeRequestUrl: (repoInfo: {
|
|
43
|
+
host: string;
|
|
44
|
+
path: string;
|
|
45
|
+
fullUrl: string;
|
|
46
|
+
}, branchName: string) => string | null;
|