@qlover/fe-release 5.0.6 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +94 -3
- package/dist/cli.js +94 -3
- package/dist/index.cjs +77 -2
- package/dist/index.d.ts +42 -7
- package/dist/index.js +77 -2
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -28,7 +28,7 @@ var import_commander = require("commander");
|
|
|
28
28
|
|
|
29
29
|
// package.json
|
|
30
30
|
var description = "A tool for releasing front-end projects, supporting multiple release modes and configurations, simplifying the release process and improving efficiency.";
|
|
31
|
-
var version = "5.0
|
|
31
|
+
var version = "5.1.0";
|
|
32
32
|
|
|
33
33
|
// src/cli.ts
|
|
34
34
|
var import_semver = __toESM(require("semver"), 1);
|
|
@@ -82,6 +82,10 @@ var releaseJson = {
|
|
|
82
82
|
branchName: "release/${repoName}-${releaseId}",
|
|
83
83
|
releaseTagName: "release-tag-${count}-patch-${releaseId}",
|
|
84
84
|
commitMessage: "chore(release): ${spaces}",
|
|
85
|
+
/** GitHub release title template (createRelease mode) */
|
|
86
|
+
releaseName: "${name}@${version}",
|
|
87
|
+
/** Path prefixes skipped when creating GitHub releases */
|
|
88
|
+
ignoreReleasePaths: [],
|
|
85
89
|
label: {
|
|
86
90
|
name: "CI-Release",
|
|
87
91
|
color: "1A7F37",
|
|
@@ -2745,7 +2749,7 @@ var GithubManager = class {
|
|
|
2745
2749
|
*/
|
|
2746
2750
|
getOctokitReleaseOptions(options) {
|
|
2747
2751
|
const {
|
|
2748
|
-
releaseName,
|
|
2752
|
+
releaseName = releaseJson.github.releaseName,
|
|
2749
2753
|
draft = false,
|
|
2750
2754
|
preRelease = false,
|
|
2751
2755
|
autoGenerate = false,
|
|
@@ -2754,7 +2758,7 @@ var GithubManager = class {
|
|
|
2754
2758
|
discussionCategoryName = void 0
|
|
2755
2759
|
} = this.context.getParameters("github");
|
|
2756
2760
|
const name = releaseName;
|
|
2757
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2761
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2758
2762
|
return {
|
|
2759
2763
|
name,
|
|
2760
2764
|
make_latest: makeLatest.toString(),
|
|
@@ -3518,6 +3522,7 @@ var ReleaseFormatter = class {
|
|
|
3518
3522
|
var Github = class extends GitBase {
|
|
3519
3523
|
releaseFormatter;
|
|
3520
3524
|
githubManager;
|
|
3525
|
+
pather = new Pather();
|
|
3521
3526
|
constructor(context, props = {}) {
|
|
3522
3527
|
super(context, "github", props);
|
|
3523
3528
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3529,6 +3534,9 @@ var Github = class extends GitBase {
|
|
|
3529
3534
|
get mode() {
|
|
3530
3535
|
return this.config.mode || releaseJson.github.mode;
|
|
3531
3536
|
}
|
|
3537
|
+
get ignoreReleasePaths() {
|
|
3538
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3539
|
+
}
|
|
3532
3540
|
async onBefore() {
|
|
3533
3541
|
await super.onBefore();
|
|
3534
3542
|
await this.githubManager.validateToken();
|
|
@@ -3554,6 +3562,9 @@ var Github = class extends GitBase {
|
|
|
3554
3562
|
if (workspace.dependencyRelease) {
|
|
3555
3563
|
return workspace;
|
|
3556
3564
|
}
|
|
3565
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3566
|
+
return workspace;
|
|
3567
|
+
}
|
|
3557
3568
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3558
3569
|
})
|
|
3559
3570
|
)
|
|
@@ -3562,6 +3573,13 @@ var Github = class extends GitBase {
|
|
|
3562
3573
|
}
|
|
3563
3574
|
async onSuccess() {
|
|
3564
3575
|
const workspaces = this.context.requireWorkspaces();
|
|
3576
|
+
if (this.mode === "createRelease") {
|
|
3577
|
+
await this.step({
|
|
3578
|
+
label: "Create GitHub Releases",
|
|
3579
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3580
|
+
});
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3565
3583
|
const releaseBranchResult = await this.step({
|
|
3566
3584
|
label: "Create Release Branch",
|
|
3567
3585
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3578,6 +3596,63 @@ var Github = class extends GitBase {
|
|
|
3578
3596
|
}
|
|
3579
3597
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3580
3598
|
}
|
|
3599
|
+
/**
|
|
3600
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3601
|
+
*/
|
|
3602
|
+
isIgnoredReleasePath(workspace) {
|
|
3603
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3604
|
+
if (ignorePaths.length === 0) {
|
|
3605
|
+
return false;
|
|
3606
|
+
}
|
|
3607
|
+
return ignorePaths.some(
|
|
3608
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3609
|
+
);
|
|
3610
|
+
}
|
|
3611
|
+
/**
|
|
3612
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3613
|
+
*
|
|
3614
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3615
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3616
|
+
* when they have a tag.
|
|
3617
|
+
*/
|
|
3618
|
+
getReleaseWorkspaces(workspaces) {
|
|
3619
|
+
return workspaces.filter((workspace) => {
|
|
3620
|
+
if (!workspace.tagName) {
|
|
3621
|
+
return false;
|
|
3622
|
+
}
|
|
3623
|
+
if (workspace.dependencyRelease) {
|
|
3624
|
+
return false;
|
|
3625
|
+
}
|
|
3626
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3627
|
+
this.logger.info(
|
|
3628
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3629
|
+
);
|
|
3630
|
+
return false;
|
|
3631
|
+
}
|
|
3632
|
+
return true;
|
|
3633
|
+
});
|
|
3634
|
+
}
|
|
3635
|
+
/**
|
|
3636
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3637
|
+
*
|
|
3638
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3639
|
+
*/
|
|
3640
|
+
async createGithubReleases(workspaces) {
|
|
3641
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3642
|
+
if (releaseWorkspaces.length === 0) {
|
|
3643
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3644
|
+
return;
|
|
3645
|
+
}
|
|
3646
|
+
this.logger.info(
|
|
3647
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3648
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3649
|
+
);
|
|
3650
|
+
await Promise.all(
|
|
3651
|
+
releaseWorkspaces.map(
|
|
3652
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3653
|
+
)
|
|
3654
|
+
);
|
|
3655
|
+
}
|
|
3581
3656
|
/**
|
|
3582
3657
|
* Create the release PR and optionally auto-merge it.
|
|
3583
3658
|
*
|
|
@@ -3933,6 +4008,22 @@ function programArgs() {
|
|
|
3933
4008
|
).option(
|
|
3934
4009
|
"--workspaces.skip",
|
|
3935
4010
|
"Skip the Workspaces plugin"
|
|
4011
|
+
).option(
|
|
4012
|
+
"--github.mode <mode>",
|
|
4013
|
+
"Github mode: createPR (default) or createRelease (fe-config: release.github.mode)",
|
|
4014
|
+
(value) => {
|
|
4015
|
+
if (value !== "createPR" && value !== "createRelease") {
|
|
4016
|
+
throw new Error(
|
|
4017
|
+
'Invalid github.mode. Must be "createPR" or "createRelease"'
|
|
4018
|
+
);
|
|
4019
|
+
}
|
|
4020
|
+
return value;
|
|
4021
|
+
},
|
|
4022
|
+
"createPR"
|
|
4023
|
+
).option(
|
|
4024
|
+
"--github.ignore-release-paths <paths>",
|
|
4025
|
+
"Path prefixes to skip when creating GitHub Releases, comma-separated (fe-config: release.github.ignoreReleasePaths)",
|
|
4026
|
+
splitWithComma
|
|
3936
4027
|
).option(
|
|
3937
4028
|
"--github.skip [lifecycle]",
|
|
3938
4029
|
"Skip the Github plugin (no value) or a lifecycle such as onSuccess"
|
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// package.json
|
|
7
7
|
var description = "A tool for releasing front-end projects, supporting multiple release modes and configurations, simplifying the release process and improving efficiency.";
|
|
8
|
-
var version = "5.0
|
|
8
|
+
var version = "5.1.0";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
|
11
11
|
import semver from "semver";
|
|
@@ -59,6 +59,10 @@ var releaseJson = {
|
|
|
59
59
|
branchName: "release/${repoName}-${releaseId}",
|
|
60
60
|
releaseTagName: "release-tag-${count}-patch-${releaseId}",
|
|
61
61
|
commitMessage: "chore(release): ${spaces}",
|
|
62
|
+
/** GitHub release title template (createRelease mode) */
|
|
63
|
+
releaseName: "${name}@${version}",
|
|
64
|
+
/** Path prefixes skipped when creating GitHub releases */
|
|
65
|
+
ignoreReleasePaths: [],
|
|
62
66
|
label: {
|
|
63
67
|
name: "CI-Release",
|
|
64
68
|
color: "1A7F37",
|
|
@@ -2725,7 +2729,7 @@ var GithubManager = class {
|
|
|
2725
2729
|
*/
|
|
2726
2730
|
getOctokitReleaseOptions(options) {
|
|
2727
2731
|
const {
|
|
2728
|
-
releaseName,
|
|
2732
|
+
releaseName = releaseJson.github.releaseName,
|
|
2729
2733
|
draft = false,
|
|
2730
2734
|
preRelease = false,
|
|
2731
2735
|
autoGenerate = false,
|
|
@@ -2734,7 +2738,7 @@ var GithubManager = class {
|
|
|
2734
2738
|
discussionCategoryName = void 0
|
|
2735
2739
|
} = this.context.getParameters("github");
|
|
2736
2740
|
const name = releaseName;
|
|
2737
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2741
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2738
2742
|
return {
|
|
2739
2743
|
name,
|
|
2740
2744
|
make_latest: makeLatest.toString(),
|
|
@@ -3498,6 +3502,7 @@ var ReleaseFormatter = class {
|
|
|
3498
3502
|
var Github = class extends GitBase {
|
|
3499
3503
|
releaseFormatter;
|
|
3500
3504
|
githubManager;
|
|
3505
|
+
pather = new Pather();
|
|
3501
3506
|
constructor(context, props = {}) {
|
|
3502
3507
|
super(context, "github", props);
|
|
3503
3508
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3509,6 +3514,9 @@ var Github = class extends GitBase {
|
|
|
3509
3514
|
get mode() {
|
|
3510
3515
|
return this.config.mode || releaseJson.github.mode;
|
|
3511
3516
|
}
|
|
3517
|
+
get ignoreReleasePaths() {
|
|
3518
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3519
|
+
}
|
|
3512
3520
|
async onBefore() {
|
|
3513
3521
|
await super.onBefore();
|
|
3514
3522
|
await this.githubManager.validateToken();
|
|
@@ -3534,6 +3542,9 @@ var Github = class extends GitBase {
|
|
|
3534
3542
|
if (workspace.dependencyRelease) {
|
|
3535
3543
|
return workspace;
|
|
3536
3544
|
}
|
|
3545
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3546
|
+
return workspace;
|
|
3547
|
+
}
|
|
3537
3548
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3538
3549
|
})
|
|
3539
3550
|
)
|
|
@@ -3542,6 +3553,13 @@ var Github = class extends GitBase {
|
|
|
3542
3553
|
}
|
|
3543
3554
|
async onSuccess() {
|
|
3544
3555
|
const workspaces = this.context.requireWorkspaces();
|
|
3556
|
+
if (this.mode === "createRelease") {
|
|
3557
|
+
await this.step({
|
|
3558
|
+
label: "Create GitHub Releases",
|
|
3559
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3560
|
+
});
|
|
3561
|
+
return;
|
|
3562
|
+
}
|
|
3545
3563
|
const releaseBranchResult = await this.step({
|
|
3546
3564
|
label: "Create Release Branch",
|
|
3547
3565
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3558,6 +3576,63 @@ var Github = class extends GitBase {
|
|
|
3558
3576
|
}
|
|
3559
3577
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3560
3578
|
}
|
|
3579
|
+
/**
|
|
3580
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3581
|
+
*/
|
|
3582
|
+
isIgnoredReleasePath(workspace) {
|
|
3583
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3584
|
+
if (ignorePaths.length === 0) {
|
|
3585
|
+
return false;
|
|
3586
|
+
}
|
|
3587
|
+
return ignorePaths.some(
|
|
3588
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3589
|
+
);
|
|
3590
|
+
}
|
|
3591
|
+
/**
|
|
3592
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3593
|
+
*
|
|
3594
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3595
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3596
|
+
* when they have a tag.
|
|
3597
|
+
*/
|
|
3598
|
+
getReleaseWorkspaces(workspaces) {
|
|
3599
|
+
return workspaces.filter((workspace) => {
|
|
3600
|
+
if (!workspace.tagName) {
|
|
3601
|
+
return false;
|
|
3602
|
+
}
|
|
3603
|
+
if (workspace.dependencyRelease) {
|
|
3604
|
+
return false;
|
|
3605
|
+
}
|
|
3606
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3607
|
+
this.logger.info(
|
|
3608
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3609
|
+
);
|
|
3610
|
+
return false;
|
|
3611
|
+
}
|
|
3612
|
+
return true;
|
|
3613
|
+
});
|
|
3614
|
+
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3617
|
+
*
|
|
3618
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3619
|
+
*/
|
|
3620
|
+
async createGithubReleases(workspaces) {
|
|
3621
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3622
|
+
if (releaseWorkspaces.length === 0) {
|
|
3623
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3624
|
+
return;
|
|
3625
|
+
}
|
|
3626
|
+
this.logger.info(
|
|
3627
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3628
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3629
|
+
);
|
|
3630
|
+
await Promise.all(
|
|
3631
|
+
releaseWorkspaces.map(
|
|
3632
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3633
|
+
)
|
|
3634
|
+
);
|
|
3635
|
+
}
|
|
3561
3636
|
/**
|
|
3562
3637
|
* Create the release PR and optionally auto-merge it.
|
|
3563
3638
|
*
|
|
@@ -3913,6 +3988,22 @@ function programArgs() {
|
|
|
3913
3988
|
).option(
|
|
3914
3989
|
"--workspaces.skip",
|
|
3915
3990
|
"Skip the Workspaces plugin"
|
|
3991
|
+
).option(
|
|
3992
|
+
"--github.mode <mode>",
|
|
3993
|
+
"Github mode: createPR (default) or createRelease (fe-config: release.github.mode)",
|
|
3994
|
+
(value) => {
|
|
3995
|
+
if (value !== "createPR" && value !== "createRelease") {
|
|
3996
|
+
throw new Error(
|
|
3997
|
+
'Invalid github.mode. Must be "createPR" or "createRelease"'
|
|
3998
|
+
);
|
|
3999
|
+
}
|
|
4000
|
+
return value;
|
|
4001
|
+
},
|
|
4002
|
+
"createPR"
|
|
4003
|
+
).option(
|
|
4004
|
+
"--github.ignore-release-paths <paths>",
|
|
4005
|
+
"Path prefixes to skip when creating GitHub Releases, comma-separated (fe-config: release.github.ignoreReleasePaths)",
|
|
4006
|
+
splitWithComma
|
|
3916
4007
|
).option(
|
|
3917
4008
|
"--github.skip [lifecycle]",
|
|
3918
4009
|
"Skip the Github plugin (no value) or a lifecycle such as onSuccess"
|
package/dist/index.cjs
CHANGED
|
@@ -79,6 +79,10 @@ var releaseJson = {
|
|
|
79
79
|
branchName: "release/${repoName}-${releaseId}",
|
|
80
80
|
releaseTagName: "release-tag-${count}-patch-${releaseId}",
|
|
81
81
|
commitMessage: "chore(release): ${spaces}",
|
|
82
|
+
/** GitHub release title template (createRelease mode) */
|
|
83
|
+
releaseName: "${name}@${version}",
|
|
84
|
+
/** Path prefixes skipped when creating GitHub releases */
|
|
85
|
+
ignoreReleasePaths: [],
|
|
82
86
|
label: {
|
|
83
87
|
name: "CI-Release",
|
|
84
88
|
color: "1A7F37",
|
|
@@ -2750,7 +2754,7 @@ var GithubManager = class {
|
|
|
2750
2754
|
*/
|
|
2751
2755
|
getOctokitReleaseOptions(options) {
|
|
2752
2756
|
const {
|
|
2753
|
-
releaseName,
|
|
2757
|
+
releaseName = releaseJson.github.releaseName,
|
|
2754
2758
|
draft = false,
|
|
2755
2759
|
preRelease = false,
|
|
2756
2760
|
autoGenerate = false,
|
|
@@ -2759,7 +2763,7 @@ var GithubManager = class {
|
|
|
2759
2763
|
discussionCategoryName = void 0
|
|
2760
2764
|
} = this.context.getParameters("github");
|
|
2761
2765
|
const name = releaseName;
|
|
2762
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2766
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2763
2767
|
return {
|
|
2764
2768
|
name,
|
|
2765
2769
|
make_latest: makeLatest.toString(),
|
|
@@ -3523,6 +3527,7 @@ var ReleaseFormatter = class {
|
|
|
3523
3527
|
var Github = class extends GitBase {
|
|
3524
3528
|
releaseFormatter;
|
|
3525
3529
|
githubManager;
|
|
3530
|
+
pather = new Pather();
|
|
3526
3531
|
constructor(context, props = {}) {
|
|
3527
3532
|
super(context, "github", props);
|
|
3528
3533
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3534,6 +3539,9 @@ var Github = class extends GitBase {
|
|
|
3534
3539
|
get mode() {
|
|
3535
3540
|
return this.config.mode || releaseJson.github.mode;
|
|
3536
3541
|
}
|
|
3542
|
+
get ignoreReleasePaths() {
|
|
3543
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3544
|
+
}
|
|
3537
3545
|
async onBefore() {
|
|
3538
3546
|
await super.onBefore();
|
|
3539
3547
|
await this.githubManager.validateToken();
|
|
@@ -3559,6 +3567,9 @@ var Github = class extends GitBase {
|
|
|
3559
3567
|
if (workspace.dependencyRelease) {
|
|
3560
3568
|
return workspace;
|
|
3561
3569
|
}
|
|
3570
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3571
|
+
return workspace;
|
|
3572
|
+
}
|
|
3562
3573
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3563
3574
|
})
|
|
3564
3575
|
)
|
|
@@ -3567,6 +3578,13 @@ var Github = class extends GitBase {
|
|
|
3567
3578
|
}
|
|
3568
3579
|
async onSuccess() {
|
|
3569
3580
|
const workspaces = this.context.requireWorkspaces();
|
|
3581
|
+
if (this.mode === "createRelease") {
|
|
3582
|
+
await this.step({
|
|
3583
|
+
label: "Create GitHub Releases",
|
|
3584
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3585
|
+
});
|
|
3586
|
+
return;
|
|
3587
|
+
}
|
|
3570
3588
|
const releaseBranchResult = await this.step({
|
|
3571
3589
|
label: "Create Release Branch",
|
|
3572
3590
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3583,6 +3601,63 @@ var Github = class extends GitBase {
|
|
|
3583
3601
|
}
|
|
3584
3602
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3585
3603
|
}
|
|
3604
|
+
/**
|
|
3605
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3606
|
+
*/
|
|
3607
|
+
isIgnoredReleasePath(workspace) {
|
|
3608
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3609
|
+
if (ignorePaths.length === 0) {
|
|
3610
|
+
return false;
|
|
3611
|
+
}
|
|
3612
|
+
return ignorePaths.some(
|
|
3613
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3614
|
+
);
|
|
3615
|
+
}
|
|
3616
|
+
/**
|
|
3617
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3618
|
+
*
|
|
3619
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3620
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3621
|
+
* when they have a tag.
|
|
3622
|
+
*/
|
|
3623
|
+
getReleaseWorkspaces(workspaces) {
|
|
3624
|
+
return workspaces.filter((workspace) => {
|
|
3625
|
+
if (!workspace.tagName) {
|
|
3626
|
+
return false;
|
|
3627
|
+
}
|
|
3628
|
+
if (workspace.dependencyRelease) {
|
|
3629
|
+
return false;
|
|
3630
|
+
}
|
|
3631
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3632
|
+
this.logger.info(
|
|
3633
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3634
|
+
);
|
|
3635
|
+
return false;
|
|
3636
|
+
}
|
|
3637
|
+
return true;
|
|
3638
|
+
});
|
|
3639
|
+
}
|
|
3640
|
+
/**
|
|
3641
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3642
|
+
*
|
|
3643
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3644
|
+
*/
|
|
3645
|
+
async createGithubReleases(workspaces) {
|
|
3646
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3647
|
+
if (releaseWorkspaces.length === 0) {
|
|
3648
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3649
|
+
return;
|
|
3650
|
+
}
|
|
3651
|
+
this.logger.info(
|
|
3652
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3653
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3654
|
+
);
|
|
3655
|
+
await Promise.all(
|
|
3656
|
+
releaseWorkspaces.map(
|
|
3657
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3658
|
+
)
|
|
3659
|
+
);
|
|
3660
|
+
}
|
|
3586
3661
|
/**
|
|
3587
3662
|
* Create the release PR and optionally auto-merge it.
|
|
3588
3663
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -253,7 +253,7 @@ interface ReleaseFormatterConfig {
|
|
|
253
253
|
|
|
254
254
|
/**
|
|
255
255
|
* @module Github
|
|
256
|
-
* @description GitHub changelog enrichment
|
|
256
|
+
* @description GitHub changelog enrichment, release PR, and GitHub Release plugin
|
|
257
257
|
*
|
|
258
258
|
* Third plugin in the default release pipeline (after {@link Workspaces} and
|
|
259
259
|
* {@link ChangesetVersion}). Extends {@link GitBase} for git operations and
|
|
@@ -262,33 +262,48 @@ interface ReleaseFormatterConfig {
|
|
|
262
262
|
* Pipeline phases:
|
|
263
263
|
* - **onBefore**: validate GitHub token; seed {@link ReleaseFormatter} context
|
|
264
264
|
* - **onExec**: enrich workspace changelogs with PR/commit links via {@link GithubChangelog}
|
|
265
|
-
* - **onSuccess**:
|
|
265
|
+
* - **onSuccess**:
|
|
266
|
+
* - `createPR` — create release branch, commit, push, and open PR (unless skipped)
|
|
267
|
+
* - `createRelease` — create a GitHub Release per workspace (tag + changelog body)
|
|
266
268
|
*
|
|
267
|
-
* Release branch flow:
|
|
269
|
+
* Release branch flow (`createPR`):
|
|
268
270
|
* 1. `ReleaseFormatter.getReleaseBranch()` — derive branch and tag names from templates
|
|
269
271
|
* 2. Create branch from `sourceBranch`, commit version/changelog changes, push
|
|
270
272
|
* 3. Open PR with formatted title/body and optional labels
|
|
271
273
|
* 4. Auto-merge when `autoMergeReleasePr` is enabled
|
|
272
274
|
*
|
|
275
|
+
* GitHub Release flow (`createRelease`):
|
|
276
|
+
* 1. Filter workspaces with `tagName`, skipping `dependencyRelease` and
|
|
277
|
+
* paths matched by {@link GithubProps.ignoreReleasePaths}
|
|
278
|
+
* 2. Call {@link GithubManager.createRelease} with workspace changelog as notes
|
|
279
|
+
*
|
|
273
280
|
* @example Skip PR creation (local dry-run)
|
|
274
281
|
* ```bash
|
|
275
282
|
* fe-release --github.skip-create-release-pr --dry-run
|
|
276
283
|
* ```
|
|
277
284
|
*
|
|
285
|
+
* @example Publish + GitHub Releases (ignore examples)
|
|
286
|
+
* ```bash
|
|
287
|
+
* fe-release --changesetVersion.mode publish \
|
|
288
|
+
* --github.mode createRelease \
|
|
289
|
+
* --github.ignore-release-paths examples
|
|
290
|
+
* ```
|
|
291
|
+
*
|
|
278
292
|
* @example fe-config label and merge settings
|
|
279
293
|
* ```json
|
|
280
294
|
* {
|
|
281
295
|
* "release": {
|
|
282
296
|
* "github": {
|
|
283
297
|
* "autoMergeReleasePr": false,
|
|
284
|
-
* "label": { "name": "CI-Release" }
|
|
298
|
+
* "label": { "name": "CI-Release" },
|
|
299
|
+
* "ignoreReleasePaths": ["examples"]
|
|
285
300
|
* }
|
|
286
301
|
* }
|
|
287
302
|
* }
|
|
288
303
|
* ```
|
|
289
304
|
*/
|
|
290
305
|
|
|
291
|
-
type GithubMode = 'createPR';
|
|
306
|
+
type GithubMode = 'createPR' | 'createRelease';
|
|
292
307
|
type GithubLabel = {
|
|
293
308
|
/**
|
|
294
309
|
* Hexadecimal color code for label appearance
|
|
@@ -345,8 +360,8 @@ interface GithubProps extends ReleaseFormatterConfig, GitBaseProps {
|
|
|
345
360
|
/**
|
|
346
361
|
* Plugin work mode
|
|
347
362
|
*
|
|
348
|
-
*
|
|
349
|
-
* then create
|
|
363
|
+
* - `createPR`: enrich changelogs in `onExec`, then create release branch and PR in `onSuccess`
|
|
364
|
+
* - `createRelease`: enrich changelogs in `onExec`, then create GitHub Releases in `onSuccess`
|
|
350
365
|
*
|
|
351
366
|
* @default `'createPR'`
|
|
352
367
|
*/
|
|
@@ -423,6 +438,22 @@ interface GithubProps extends ReleaseFormatterConfig, GitBaseProps {
|
|
|
423
438
|
* @default false
|
|
424
439
|
*/
|
|
425
440
|
skipCreateReleasePr?: boolean;
|
|
441
|
+
/**
|
|
442
|
+
* Workspace path prefixes to skip when creating GitHub Releases.
|
|
443
|
+
*
|
|
444
|
+
* Matched with segment-aware path containment (e.g. `examples` skips
|
|
445
|
+
* `examples/react-seed`). Applies only in `createRelease` mode.
|
|
446
|
+
*
|
|
447
|
+
* CLI: `--github.ignore-release-paths`
|
|
448
|
+
* fe-config: `release.github.ignoreReleasePaths`
|
|
449
|
+
*
|
|
450
|
+
* @default `[]`
|
|
451
|
+
* @example
|
|
452
|
+
* ```json
|
|
453
|
+
* { "ignoreReleasePaths": ["examples", "apps/docs"] }
|
|
454
|
+
* ```
|
|
455
|
+
*/
|
|
456
|
+
ignoreReleasePaths?: string[];
|
|
426
457
|
/**
|
|
427
458
|
* Configuration for release pull request labels
|
|
428
459
|
*
|
|
@@ -1465,6 +1496,10 @@ declare const releaseJson: {
|
|
|
1465
1496
|
readonly branchName: "release/${repoName}-${releaseId}";
|
|
1466
1497
|
readonly releaseTagName: "release-tag-${count}-patch-${releaseId}";
|
|
1467
1498
|
readonly commitMessage: "chore(release): ${spaces}";
|
|
1499
|
+
/** GitHub release title template (createRelease mode) */
|
|
1500
|
+
readonly releaseName: "${name}@${version}";
|
|
1501
|
+
/** Path prefixes skipped when creating GitHub releases */
|
|
1502
|
+
readonly ignoreReleasePaths: readonly string[];
|
|
1468
1503
|
readonly label: {
|
|
1469
1504
|
readonly name: "CI-Release";
|
|
1470
1505
|
readonly color: "1A7F37";
|
package/dist/index.js
CHANGED
|
@@ -27,6 +27,10 @@ var releaseJson = {
|
|
|
27
27
|
branchName: "release/${repoName}-${releaseId}",
|
|
28
28
|
releaseTagName: "release-tag-${count}-patch-${releaseId}",
|
|
29
29
|
commitMessage: "chore(release): ${spaces}",
|
|
30
|
+
/** GitHub release title template (createRelease mode) */
|
|
31
|
+
releaseName: "${name}@${version}",
|
|
32
|
+
/** Path prefixes skipped when creating GitHub releases */
|
|
33
|
+
ignoreReleasePaths: [],
|
|
30
34
|
label: {
|
|
31
35
|
name: "CI-Release",
|
|
32
36
|
color: "1A7F37",
|
|
@@ -2701,7 +2705,7 @@ var GithubManager = class {
|
|
|
2701
2705
|
*/
|
|
2702
2706
|
getOctokitReleaseOptions(options) {
|
|
2703
2707
|
const {
|
|
2704
|
-
releaseName,
|
|
2708
|
+
releaseName = releaseJson.github.releaseName,
|
|
2705
2709
|
draft = false,
|
|
2706
2710
|
preRelease = false,
|
|
2707
2711
|
autoGenerate = false,
|
|
@@ -2710,7 +2714,7 @@ var GithubManager = class {
|
|
|
2710
2714
|
discussionCategoryName = void 0
|
|
2711
2715
|
} = this.context.getParameters("github");
|
|
2712
2716
|
const name = releaseName;
|
|
2713
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2717
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2714
2718
|
return {
|
|
2715
2719
|
name,
|
|
2716
2720
|
make_latest: makeLatest.toString(),
|
|
@@ -3474,6 +3478,7 @@ var ReleaseFormatter = class {
|
|
|
3474
3478
|
var Github = class extends GitBase {
|
|
3475
3479
|
releaseFormatter;
|
|
3476
3480
|
githubManager;
|
|
3481
|
+
pather = new Pather();
|
|
3477
3482
|
constructor(context, props = {}) {
|
|
3478
3483
|
super(context, "github", props);
|
|
3479
3484
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3485,6 +3490,9 @@ var Github = class extends GitBase {
|
|
|
3485
3490
|
get mode() {
|
|
3486
3491
|
return this.config.mode || releaseJson.github.mode;
|
|
3487
3492
|
}
|
|
3493
|
+
get ignoreReleasePaths() {
|
|
3494
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3495
|
+
}
|
|
3488
3496
|
async onBefore() {
|
|
3489
3497
|
await super.onBefore();
|
|
3490
3498
|
await this.githubManager.validateToken();
|
|
@@ -3510,6 +3518,9 @@ var Github = class extends GitBase {
|
|
|
3510
3518
|
if (workspace.dependencyRelease) {
|
|
3511
3519
|
return workspace;
|
|
3512
3520
|
}
|
|
3521
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3522
|
+
return workspace;
|
|
3523
|
+
}
|
|
3513
3524
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3514
3525
|
})
|
|
3515
3526
|
)
|
|
@@ -3518,6 +3529,13 @@ var Github = class extends GitBase {
|
|
|
3518
3529
|
}
|
|
3519
3530
|
async onSuccess() {
|
|
3520
3531
|
const workspaces = this.context.requireWorkspaces();
|
|
3532
|
+
if (this.mode === "createRelease") {
|
|
3533
|
+
await this.step({
|
|
3534
|
+
label: "Create GitHub Releases",
|
|
3535
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3536
|
+
});
|
|
3537
|
+
return;
|
|
3538
|
+
}
|
|
3521
3539
|
const releaseBranchResult = await this.step({
|
|
3522
3540
|
label: "Create Release Branch",
|
|
3523
3541
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3534,6 +3552,63 @@ var Github = class extends GitBase {
|
|
|
3534
3552
|
}
|
|
3535
3553
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3536
3554
|
}
|
|
3555
|
+
/**
|
|
3556
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3557
|
+
*/
|
|
3558
|
+
isIgnoredReleasePath(workspace) {
|
|
3559
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3560
|
+
if (ignorePaths.length === 0) {
|
|
3561
|
+
return false;
|
|
3562
|
+
}
|
|
3563
|
+
return ignorePaths.some(
|
|
3564
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3565
|
+
);
|
|
3566
|
+
}
|
|
3567
|
+
/**
|
|
3568
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3569
|
+
*
|
|
3570
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3571
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3572
|
+
* when they have a tag.
|
|
3573
|
+
*/
|
|
3574
|
+
getReleaseWorkspaces(workspaces) {
|
|
3575
|
+
return workspaces.filter((workspace) => {
|
|
3576
|
+
if (!workspace.tagName) {
|
|
3577
|
+
return false;
|
|
3578
|
+
}
|
|
3579
|
+
if (workspace.dependencyRelease) {
|
|
3580
|
+
return false;
|
|
3581
|
+
}
|
|
3582
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3583
|
+
this.logger.info(
|
|
3584
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3585
|
+
);
|
|
3586
|
+
return false;
|
|
3587
|
+
}
|
|
3588
|
+
return true;
|
|
3589
|
+
});
|
|
3590
|
+
}
|
|
3591
|
+
/**
|
|
3592
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3593
|
+
*
|
|
3594
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3595
|
+
*/
|
|
3596
|
+
async createGithubReleases(workspaces) {
|
|
3597
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3598
|
+
if (releaseWorkspaces.length === 0) {
|
|
3599
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3600
|
+
return;
|
|
3601
|
+
}
|
|
3602
|
+
this.logger.info(
|
|
3603
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3604
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3605
|
+
);
|
|
3606
|
+
await Promise.all(
|
|
3607
|
+
releaseWorkspaces.map(
|
|
3608
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3609
|
+
)
|
|
3610
|
+
);
|
|
3611
|
+
}
|
|
3537
3612
|
/**
|
|
3538
3613
|
* Create the release PR and optionally auto-merge it.
|
|
3539
3614
|
*
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qlover/fe-release",
|
|
3
3
|
"description": "A tool for releasing front-end projects, supporting multiple release modes and configurations, simplifying the release process and improving efficiency.",
|
|
4
|
-
"version": "5.0
|
|
4
|
+
"version": "5.1.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"homepage": "https://github.com/qlover/fe-base/tree/master/packages/fe-release",
|