@qlover/fe-release 5.0.6 → 5.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.cjs +128 -7
- package/dist/cli.js +128 -7
- package/dist/index.cjs +108 -6
- package/dist/index.d.ts +63 -11
- package/dist/index.js +108 -6
- package/package.json +3 -3
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.
|
|
31
|
+
var version = "5.3.1";
|
|
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",
|
|
@@ -1606,6 +1610,22 @@ var ChangesetVersion = class extends import_scripts_context4.ScriptPlugin {
|
|
|
1606
1610
|
get ignoreNonUpdatedPackages() {
|
|
1607
1611
|
return !!this.config.ignoreNonUpdatedPackages;
|
|
1608
1612
|
}
|
|
1613
|
+
get useTrustedPublishing() {
|
|
1614
|
+
return !!(this.config.useTrustedPublishing || this.context.parameters.changesetVersion?.useTrustedPublishing);
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* True when publish should use npm Trusted Publishing (OIDC) instead of NPM_TOKEN.
|
|
1618
|
+
*/
|
|
1619
|
+
isTrustedPublishingEnv() {
|
|
1620
|
+
if (this.useTrustedPublishing) {
|
|
1621
|
+
return true;
|
|
1622
|
+
}
|
|
1623
|
+
const envFlag = this.context.getEnv("FE_RELEASE_TRUSTED_PUBLISHING");
|
|
1624
|
+
if (envFlag === "1" || envFlag === "true") {
|
|
1625
|
+
return true;
|
|
1626
|
+
}
|
|
1627
|
+
return Boolean(this.context.getEnv("ACTIONS_ID_TOKEN_REQUEST_URL"));
|
|
1628
|
+
}
|
|
1609
1629
|
shouldProcessWorkspace(workspace) {
|
|
1610
1630
|
return shouldProcessWorkspace(workspace, this.ignoreNonUpdatedPackages);
|
|
1611
1631
|
}
|
|
@@ -1627,15 +1647,26 @@ var ChangesetVersion = class extends import_scripts_context4.ScriptPlugin {
|
|
|
1627
1647
|
}
|
|
1628
1648
|
}
|
|
1629
1649
|
/**
|
|
1630
|
-
*
|
|
1650
|
+
* Configure npm auth before changeset publish.
|
|
1631
1651
|
*
|
|
1632
|
-
*
|
|
1633
|
-
* do not need
|
|
1652
|
+
* Uses Trusted Publishing (OIDC) when detected; otherwise requires `NPM_TOKEN`.
|
|
1653
|
+
* Version-only runs (release PR) do not need npm auth.
|
|
1634
1654
|
*/
|
|
1635
1655
|
async validateNpmToken() {
|
|
1656
|
+
if (this.isTrustedPublishingEnv()) {
|
|
1657
|
+
this.logger.info(
|
|
1658
|
+
"Using npm Trusted Publishing (OIDC); skip NPM_TOKEN auth setup"
|
|
1659
|
+
);
|
|
1660
|
+
if (this.context.dryRun) {
|
|
1661
|
+
this.logDryRun("Would publish via npm Trusted Publishing (OIDC)");
|
|
1662
|
+
}
|
|
1663
|
+
return;
|
|
1664
|
+
}
|
|
1636
1665
|
const npmToken = this.context.getEnv("NPM_TOKEN");
|
|
1637
1666
|
if (!npmToken) {
|
|
1638
|
-
throw new Error(
|
|
1667
|
+
throw new Error(
|
|
1668
|
+
"NPM_TOKEN is not set. Enable Trusted Publishing (OIDC) or provide NPM_TOKEN."
|
|
1669
|
+
);
|
|
1639
1670
|
}
|
|
1640
1671
|
if (this.context.dryRun) {
|
|
1641
1672
|
this.logDryRun(
|
|
@@ -2745,7 +2776,7 @@ var GithubManager = class {
|
|
|
2745
2776
|
*/
|
|
2746
2777
|
getOctokitReleaseOptions(options) {
|
|
2747
2778
|
const {
|
|
2748
|
-
releaseName,
|
|
2779
|
+
releaseName = releaseJson.github.releaseName,
|
|
2749
2780
|
draft = false,
|
|
2750
2781
|
preRelease = false,
|
|
2751
2782
|
autoGenerate = false,
|
|
@@ -2754,7 +2785,7 @@ var GithubManager = class {
|
|
|
2754
2785
|
discussionCategoryName = void 0
|
|
2755
2786
|
} = this.context.getParameters("github");
|
|
2756
2787
|
const name = releaseName;
|
|
2757
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2788
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2758
2789
|
return {
|
|
2759
2790
|
name,
|
|
2760
2791
|
make_latest: makeLatest.toString(),
|
|
@@ -3518,6 +3549,7 @@ var ReleaseFormatter = class {
|
|
|
3518
3549
|
var Github = class extends GitBase {
|
|
3519
3550
|
releaseFormatter;
|
|
3520
3551
|
githubManager;
|
|
3552
|
+
pather = new Pather();
|
|
3521
3553
|
constructor(context, props = {}) {
|
|
3522
3554
|
super(context, "github", props);
|
|
3523
3555
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3529,6 +3561,9 @@ var Github = class extends GitBase {
|
|
|
3529
3561
|
get mode() {
|
|
3530
3562
|
return this.config.mode || releaseJson.github.mode;
|
|
3531
3563
|
}
|
|
3564
|
+
get ignoreReleasePaths() {
|
|
3565
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3566
|
+
}
|
|
3532
3567
|
async onBefore() {
|
|
3533
3568
|
await super.onBefore();
|
|
3534
3569
|
await this.githubManager.validateToken();
|
|
@@ -3554,6 +3589,9 @@ var Github = class extends GitBase {
|
|
|
3554
3589
|
if (workspace.dependencyRelease) {
|
|
3555
3590
|
return workspace;
|
|
3556
3591
|
}
|
|
3592
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3593
|
+
return workspace;
|
|
3594
|
+
}
|
|
3557
3595
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3558
3596
|
})
|
|
3559
3597
|
)
|
|
@@ -3562,6 +3600,13 @@ var Github = class extends GitBase {
|
|
|
3562
3600
|
}
|
|
3563
3601
|
async onSuccess() {
|
|
3564
3602
|
const workspaces = this.context.requireWorkspaces();
|
|
3603
|
+
if (this.mode === "createRelease") {
|
|
3604
|
+
await this.step({
|
|
3605
|
+
label: "Create GitHub Releases",
|
|
3606
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3607
|
+
});
|
|
3608
|
+
return;
|
|
3609
|
+
}
|
|
3565
3610
|
const releaseBranchResult = await this.step({
|
|
3566
3611
|
label: "Create Release Branch",
|
|
3567
3612
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3578,6 +3623,63 @@ var Github = class extends GitBase {
|
|
|
3578
3623
|
}
|
|
3579
3624
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3580
3625
|
}
|
|
3626
|
+
/**
|
|
3627
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3628
|
+
*/
|
|
3629
|
+
isIgnoredReleasePath(workspace) {
|
|
3630
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3631
|
+
if (ignorePaths.length === 0) {
|
|
3632
|
+
return false;
|
|
3633
|
+
}
|
|
3634
|
+
return ignorePaths.some(
|
|
3635
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3636
|
+
);
|
|
3637
|
+
}
|
|
3638
|
+
/**
|
|
3639
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3640
|
+
*
|
|
3641
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3642
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3643
|
+
* when they have a tag.
|
|
3644
|
+
*/
|
|
3645
|
+
getReleaseWorkspaces(workspaces) {
|
|
3646
|
+
return workspaces.filter((workspace) => {
|
|
3647
|
+
if (!workspace.tagName) {
|
|
3648
|
+
return false;
|
|
3649
|
+
}
|
|
3650
|
+
if (workspace.dependencyRelease) {
|
|
3651
|
+
return false;
|
|
3652
|
+
}
|
|
3653
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3654
|
+
this.logger.info(
|
|
3655
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3656
|
+
);
|
|
3657
|
+
return false;
|
|
3658
|
+
}
|
|
3659
|
+
return true;
|
|
3660
|
+
});
|
|
3661
|
+
}
|
|
3662
|
+
/**
|
|
3663
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3664
|
+
*
|
|
3665
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3666
|
+
*/
|
|
3667
|
+
async createGithubReleases(workspaces) {
|
|
3668
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3669
|
+
if (releaseWorkspaces.length === 0) {
|
|
3670
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3671
|
+
return;
|
|
3672
|
+
}
|
|
3673
|
+
this.logger.info(
|
|
3674
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3675
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3676
|
+
);
|
|
3677
|
+
await Promise.all(
|
|
3678
|
+
releaseWorkspaces.map(
|
|
3679
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3680
|
+
)
|
|
3681
|
+
);
|
|
3682
|
+
}
|
|
3581
3683
|
/**
|
|
3582
3684
|
* Create the release PR and optionally auto-merge it.
|
|
3583
3685
|
*
|
|
@@ -3907,6 +4009,9 @@ function programArgs() {
|
|
|
3907
4009
|
).option(
|
|
3908
4010
|
"--changelog.ignore-non-updated-packages",
|
|
3909
4011
|
"Alias of --changesetVersion.ignore-non-updated-packages"
|
|
4012
|
+
).option(
|
|
4013
|
+
"--changesetVersion.use-trusted-publishing",
|
|
4014
|
+
"Use npm Trusted Publishing (OIDC) instead of NPM_TOKEN (fe-config: release.changesetVersion.useTrustedPublishing)"
|
|
3910
4015
|
).option(
|
|
3911
4016
|
"--changesetVersion.mode <mode>",
|
|
3912
4017
|
"ChangesetVersion mode: version (default), publish, or both (fe-config: release.changesetVersion.mode)",
|
|
@@ -3933,6 +4038,22 @@ function programArgs() {
|
|
|
3933
4038
|
).option(
|
|
3934
4039
|
"--workspaces.skip",
|
|
3935
4040
|
"Skip the Workspaces plugin"
|
|
4041
|
+
).option(
|
|
4042
|
+
"--github.mode <mode>",
|
|
4043
|
+
"Github mode: createPR (default) or createRelease (fe-config: release.github.mode)",
|
|
4044
|
+
(value) => {
|
|
4045
|
+
if (value !== "createPR" && value !== "createRelease") {
|
|
4046
|
+
throw new Error(
|
|
4047
|
+
'Invalid github.mode. Must be "createPR" or "createRelease"'
|
|
4048
|
+
);
|
|
4049
|
+
}
|
|
4050
|
+
return value;
|
|
4051
|
+
},
|
|
4052
|
+
"createPR"
|
|
4053
|
+
).option(
|
|
4054
|
+
"--github.ignore-release-paths <paths>",
|
|
4055
|
+
"Path prefixes to skip when creating GitHub Releases, comma-separated (fe-config: release.github.ignoreReleasePaths)",
|
|
4056
|
+
splitWithComma
|
|
3936
4057
|
).option(
|
|
3937
4058
|
"--github.skip [lifecycle]",
|
|
3938
4059
|
"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.
|
|
8
|
+
var version = "5.3.1";
|
|
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",
|
|
@@ -1586,6 +1590,22 @@ var ChangesetVersion = class extends ScriptPlugin2 {
|
|
|
1586
1590
|
get ignoreNonUpdatedPackages() {
|
|
1587
1591
|
return !!this.config.ignoreNonUpdatedPackages;
|
|
1588
1592
|
}
|
|
1593
|
+
get useTrustedPublishing() {
|
|
1594
|
+
return !!(this.config.useTrustedPublishing || this.context.parameters.changesetVersion?.useTrustedPublishing);
|
|
1595
|
+
}
|
|
1596
|
+
/**
|
|
1597
|
+
* True when publish should use npm Trusted Publishing (OIDC) instead of NPM_TOKEN.
|
|
1598
|
+
*/
|
|
1599
|
+
isTrustedPublishingEnv() {
|
|
1600
|
+
if (this.useTrustedPublishing) {
|
|
1601
|
+
return true;
|
|
1602
|
+
}
|
|
1603
|
+
const envFlag = this.context.getEnv("FE_RELEASE_TRUSTED_PUBLISHING");
|
|
1604
|
+
if (envFlag === "1" || envFlag === "true") {
|
|
1605
|
+
return true;
|
|
1606
|
+
}
|
|
1607
|
+
return Boolean(this.context.getEnv("ACTIONS_ID_TOKEN_REQUEST_URL"));
|
|
1608
|
+
}
|
|
1589
1609
|
shouldProcessWorkspace(workspace) {
|
|
1590
1610
|
return shouldProcessWorkspace(workspace, this.ignoreNonUpdatedPackages);
|
|
1591
1611
|
}
|
|
@@ -1607,15 +1627,26 @@ var ChangesetVersion = class extends ScriptPlugin2 {
|
|
|
1607
1627
|
}
|
|
1608
1628
|
}
|
|
1609
1629
|
/**
|
|
1610
|
-
*
|
|
1630
|
+
* Configure npm auth before changeset publish.
|
|
1611
1631
|
*
|
|
1612
|
-
*
|
|
1613
|
-
* do not need
|
|
1632
|
+
* Uses Trusted Publishing (OIDC) when detected; otherwise requires `NPM_TOKEN`.
|
|
1633
|
+
* Version-only runs (release PR) do not need npm auth.
|
|
1614
1634
|
*/
|
|
1615
1635
|
async validateNpmToken() {
|
|
1636
|
+
if (this.isTrustedPublishingEnv()) {
|
|
1637
|
+
this.logger.info(
|
|
1638
|
+
"Using npm Trusted Publishing (OIDC); skip NPM_TOKEN auth setup"
|
|
1639
|
+
);
|
|
1640
|
+
if (this.context.dryRun) {
|
|
1641
|
+
this.logDryRun("Would publish via npm Trusted Publishing (OIDC)");
|
|
1642
|
+
}
|
|
1643
|
+
return;
|
|
1644
|
+
}
|
|
1616
1645
|
const npmToken = this.context.getEnv("NPM_TOKEN");
|
|
1617
1646
|
if (!npmToken) {
|
|
1618
|
-
throw new Error(
|
|
1647
|
+
throw new Error(
|
|
1648
|
+
"NPM_TOKEN is not set. Enable Trusted Publishing (OIDC) or provide NPM_TOKEN."
|
|
1649
|
+
);
|
|
1619
1650
|
}
|
|
1620
1651
|
if (this.context.dryRun) {
|
|
1621
1652
|
this.logDryRun(
|
|
@@ -2725,7 +2756,7 @@ var GithubManager = class {
|
|
|
2725
2756
|
*/
|
|
2726
2757
|
getOctokitReleaseOptions(options) {
|
|
2727
2758
|
const {
|
|
2728
|
-
releaseName,
|
|
2759
|
+
releaseName = releaseJson.github.releaseName,
|
|
2729
2760
|
draft = false,
|
|
2730
2761
|
preRelease = false,
|
|
2731
2762
|
autoGenerate = false,
|
|
@@ -2734,7 +2765,7 @@ var GithubManager = class {
|
|
|
2734
2765
|
discussionCategoryName = void 0
|
|
2735
2766
|
} = this.context.getParameters("github");
|
|
2736
2767
|
const name = releaseName;
|
|
2737
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2768
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2738
2769
|
return {
|
|
2739
2770
|
name,
|
|
2740
2771
|
make_latest: makeLatest.toString(),
|
|
@@ -3498,6 +3529,7 @@ var ReleaseFormatter = class {
|
|
|
3498
3529
|
var Github = class extends GitBase {
|
|
3499
3530
|
releaseFormatter;
|
|
3500
3531
|
githubManager;
|
|
3532
|
+
pather = new Pather();
|
|
3501
3533
|
constructor(context, props = {}) {
|
|
3502
3534
|
super(context, "github", props);
|
|
3503
3535
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3509,6 +3541,9 @@ var Github = class extends GitBase {
|
|
|
3509
3541
|
get mode() {
|
|
3510
3542
|
return this.config.mode || releaseJson.github.mode;
|
|
3511
3543
|
}
|
|
3544
|
+
get ignoreReleasePaths() {
|
|
3545
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3546
|
+
}
|
|
3512
3547
|
async onBefore() {
|
|
3513
3548
|
await super.onBefore();
|
|
3514
3549
|
await this.githubManager.validateToken();
|
|
@@ -3534,6 +3569,9 @@ var Github = class extends GitBase {
|
|
|
3534
3569
|
if (workspace.dependencyRelease) {
|
|
3535
3570
|
return workspace;
|
|
3536
3571
|
}
|
|
3572
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3573
|
+
return workspace;
|
|
3574
|
+
}
|
|
3537
3575
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3538
3576
|
})
|
|
3539
3577
|
)
|
|
@@ -3542,6 +3580,13 @@ var Github = class extends GitBase {
|
|
|
3542
3580
|
}
|
|
3543
3581
|
async onSuccess() {
|
|
3544
3582
|
const workspaces = this.context.requireWorkspaces();
|
|
3583
|
+
if (this.mode === "createRelease") {
|
|
3584
|
+
await this.step({
|
|
3585
|
+
label: "Create GitHub Releases",
|
|
3586
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3587
|
+
});
|
|
3588
|
+
return;
|
|
3589
|
+
}
|
|
3545
3590
|
const releaseBranchResult = await this.step({
|
|
3546
3591
|
label: "Create Release Branch",
|
|
3547
3592
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3558,6 +3603,63 @@ var Github = class extends GitBase {
|
|
|
3558
3603
|
}
|
|
3559
3604
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3560
3605
|
}
|
|
3606
|
+
/**
|
|
3607
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3608
|
+
*/
|
|
3609
|
+
isIgnoredReleasePath(workspace) {
|
|
3610
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3611
|
+
if (ignorePaths.length === 0) {
|
|
3612
|
+
return false;
|
|
3613
|
+
}
|
|
3614
|
+
return ignorePaths.some(
|
|
3615
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3616
|
+
);
|
|
3617
|
+
}
|
|
3618
|
+
/**
|
|
3619
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3620
|
+
*
|
|
3621
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3622
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3623
|
+
* when they have a tag.
|
|
3624
|
+
*/
|
|
3625
|
+
getReleaseWorkspaces(workspaces) {
|
|
3626
|
+
return workspaces.filter((workspace) => {
|
|
3627
|
+
if (!workspace.tagName) {
|
|
3628
|
+
return false;
|
|
3629
|
+
}
|
|
3630
|
+
if (workspace.dependencyRelease) {
|
|
3631
|
+
return false;
|
|
3632
|
+
}
|
|
3633
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3634
|
+
this.logger.info(
|
|
3635
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3636
|
+
);
|
|
3637
|
+
return false;
|
|
3638
|
+
}
|
|
3639
|
+
return true;
|
|
3640
|
+
});
|
|
3641
|
+
}
|
|
3642
|
+
/**
|
|
3643
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3644
|
+
*
|
|
3645
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3646
|
+
*/
|
|
3647
|
+
async createGithubReleases(workspaces) {
|
|
3648
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3649
|
+
if (releaseWorkspaces.length === 0) {
|
|
3650
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3651
|
+
return;
|
|
3652
|
+
}
|
|
3653
|
+
this.logger.info(
|
|
3654
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3655
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3656
|
+
);
|
|
3657
|
+
await Promise.all(
|
|
3658
|
+
releaseWorkspaces.map(
|
|
3659
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3660
|
+
)
|
|
3661
|
+
);
|
|
3662
|
+
}
|
|
3561
3663
|
/**
|
|
3562
3664
|
* Create the release PR and optionally auto-merge it.
|
|
3563
3665
|
*
|
|
@@ -3887,6 +3989,9 @@ function programArgs() {
|
|
|
3887
3989
|
).option(
|
|
3888
3990
|
"--changelog.ignore-non-updated-packages",
|
|
3889
3991
|
"Alias of --changesetVersion.ignore-non-updated-packages"
|
|
3992
|
+
).option(
|
|
3993
|
+
"--changesetVersion.use-trusted-publishing",
|
|
3994
|
+
"Use npm Trusted Publishing (OIDC) instead of NPM_TOKEN (fe-config: release.changesetVersion.useTrustedPublishing)"
|
|
3890
3995
|
).option(
|
|
3891
3996
|
"--changesetVersion.mode <mode>",
|
|
3892
3997
|
"ChangesetVersion mode: version (default), publish, or both (fe-config: release.changesetVersion.mode)",
|
|
@@ -3913,6 +4018,22 @@ function programArgs() {
|
|
|
3913
4018
|
).option(
|
|
3914
4019
|
"--workspaces.skip",
|
|
3915
4020
|
"Skip the Workspaces plugin"
|
|
4021
|
+
).option(
|
|
4022
|
+
"--github.mode <mode>",
|
|
4023
|
+
"Github mode: createPR (default) or createRelease (fe-config: release.github.mode)",
|
|
4024
|
+
(value) => {
|
|
4025
|
+
if (value !== "createPR" && value !== "createRelease") {
|
|
4026
|
+
throw new Error(
|
|
4027
|
+
'Invalid github.mode. Must be "createPR" or "createRelease"'
|
|
4028
|
+
);
|
|
4029
|
+
}
|
|
4030
|
+
return value;
|
|
4031
|
+
},
|
|
4032
|
+
"createPR"
|
|
4033
|
+
).option(
|
|
4034
|
+
"--github.ignore-release-paths <paths>",
|
|
4035
|
+
"Path prefixes to skip when creating GitHub Releases, comma-separated (fe-config: release.github.ignoreReleasePaths)",
|
|
4036
|
+
splitWithComma
|
|
3916
4037
|
).option(
|
|
3917
4038
|
"--github.skip [lifecycle]",
|
|
3918
4039
|
"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",
|
|
@@ -1611,6 +1615,22 @@ var ChangesetVersion = class extends import_scripts_context4.ScriptPlugin {
|
|
|
1611
1615
|
get ignoreNonUpdatedPackages() {
|
|
1612
1616
|
return !!this.config.ignoreNonUpdatedPackages;
|
|
1613
1617
|
}
|
|
1618
|
+
get useTrustedPublishing() {
|
|
1619
|
+
return !!(this.config.useTrustedPublishing || this.context.parameters.changesetVersion?.useTrustedPublishing);
|
|
1620
|
+
}
|
|
1621
|
+
/**
|
|
1622
|
+
* True when publish should use npm Trusted Publishing (OIDC) instead of NPM_TOKEN.
|
|
1623
|
+
*/
|
|
1624
|
+
isTrustedPublishingEnv() {
|
|
1625
|
+
if (this.useTrustedPublishing) {
|
|
1626
|
+
return true;
|
|
1627
|
+
}
|
|
1628
|
+
const envFlag = this.context.getEnv("FE_RELEASE_TRUSTED_PUBLISHING");
|
|
1629
|
+
if (envFlag === "1" || envFlag === "true") {
|
|
1630
|
+
return true;
|
|
1631
|
+
}
|
|
1632
|
+
return Boolean(this.context.getEnv("ACTIONS_ID_TOKEN_REQUEST_URL"));
|
|
1633
|
+
}
|
|
1614
1634
|
shouldProcessWorkspace(workspace) {
|
|
1615
1635
|
return shouldProcessWorkspace(workspace, this.ignoreNonUpdatedPackages);
|
|
1616
1636
|
}
|
|
@@ -1632,15 +1652,26 @@ var ChangesetVersion = class extends import_scripts_context4.ScriptPlugin {
|
|
|
1632
1652
|
}
|
|
1633
1653
|
}
|
|
1634
1654
|
/**
|
|
1635
|
-
*
|
|
1655
|
+
* Configure npm auth before changeset publish.
|
|
1636
1656
|
*
|
|
1637
|
-
*
|
|
1638
|
-
* do not need
|
|
1657
|
+
* Uses Trusted Publishing (OIDC) when detected; otherwise requires `NPM_TOKEN`.
|
|
1658
|
+
* Version-only runs (release PR) do not need npm auth.
|
|
1639
1659
|
*/
|
|
1640
1660
|
async validateNpmToken() {
|
|
1661
|
+
if (this.isTrustedPublishingEnv()) {
|
|
1662
|
+
this.logger.info(
|
|
1663
|
+
"Using npm Trusted Publishing (OIDC); skip NPM_TOKEN auth setup"
|
|
1664
|
+
);
|
|
1665
|
+
if (this.context.dryRun) {
|
|
1666
|
+
this.logDryRun("Would publish via npm Trusted Publishing (OIDC)");
|
|
1667
|
+
}
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1641
1670
|
const npmToken = this.context.getEnv("NPM_TOKEN");
|
|
1642
1671
|
if (!npmToken) {
|
|
1643
|
-
throw new Error(
|
|
1672
|
+
throw new Error(
|
|
1673
|
+
"NPM_TOKEN is not set. Enable Trusted Publishing (OIDC) or provide NPM_TOKEN."
|
|
1674
|
+
);
|
|
1644
1675
|
}
|
|
1645
1676
|
if (this.context.dryRun) {
|
|
1646
1677
|
this.logDryRun(
|
|
@@ -2750,7 +2781,7 @@ var GithubManager = class {
|
|
|
2750
2781
|
*/
|
|
2751
2782
|
getOctokitReleaseOptions(options) {
|
|
2752
2783
|
const {
|
|
2753
|
-
releaseName,
|
|
2784
|
+
releaseName = releaseJson.github.releaseName,
|
|
2754
2785
|
draft = false,
|
|
2755
2786
|
preRelease = false,
|
|
2756
2787
|
autoGenerate = false,
|
|
@@ -2759,7 +2790,7 @@ var GithubManager = class {
|
|
|
2759
2790
|
discussionCategoryName = void 0
|
|
2760
2791
|
} = this.context.getParameters("github");
|
|
2761
2792
|
const name = releaseName;
|
|
2762
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2793
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2763
2794
|
return {
|
|
2764
2795
|
name,
|
|
2765
2796
|
make_latest: makeLatest.toString(),
|
|
@@ -3523,6 +3554,7 @@ var ReleaseFormatter = class {
|
|
|
3523
3554
|
var Github = class extends GitBase {
|
|
3524
3555
|
releaseFormatter;
|
|
3525
3556
|
githubManager;
|
|
3557
|
+
pather = new Pather();
|
|
3526
3558
|
constructor(context, props = {}) {
|
|
3527
3559
|
super(context, "github", props);
|
|
3528
3560
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3534,6 +3566,9 @@ var Github = class extends GitBase {
|
|
|
3534
3566
|
get mode() {
|
|
3535
3567
|
return this.config.mode || releaseJson.github.mode;
|
|
3536
3568
|
}
|
|
3569
|
+
get ignoreReleasePaths() {
|
|
3570
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3571
|
+
}
|
|
3537
3572
|
async onBefore() {
|
|
3538
3573
|
await super.onBefore();
|
|
3539
3574
|
await this.githubManager.validateToken();
|
|
@@ -3559,6 +3594,9 @@ var Github = class extends GitBase {
|
|
|
3559
3594
|
if (workspace.dependencyRelease) {
|
|
3560
3595
|
return workspace;
|
|
3561
3596
|
}
|
|
3597
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3598
|
+
return workspace;
|
|
3599
|
+
}
|
|
3562
3600
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3563
3601
|
})
|
|
3564
3602
|
)
|
|
@@ -3567,6 +3605,13 @@ var Github = class extends GitBase {
|
|
|
3567
3605
|
}
|
|
3568
3606
|
async onSuccess() {
|
|
3569
3607
|
const workspaces = this.context.requireWorkspaces();
|
|
3608
|
+
if (this.mode === "createRelease") {
|
|
3609
|
+
await this.step({
|
|
3610
|
+
label: "Create GitHub Releases",
|
|
3611
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3612
|
+
});
|
|
3613
|
+
return;
|
|
3614
|
+
}
|
|
3570
3615
|
const releaseBranchResult = await this.step({
|
|
3571
3616
|
label: "Create Release Branch",
|
|
3572
3617
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3583,6 +3628,63 @@ var Github = class extends GitBase {
|
|
|
3583
3628
|
}
|
|
3584
3629
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3585
3630
|
}
|
|
3631
|
+
/**
|
|
3632
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3633
|
+
*/
|
|
3634
|
+
isIgnoredReleasePath(workspace) {
|
|
3635
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3636
|
+
if (ignorePaths.length === 0) {
|
|
3637
|
+
return false;
|
|
3638
|
+
}
|
|
3639
|
+
return ignorePaths.some(
|
|
3640
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3641
|
+
);
|
|
3642
|
+
}
|
|
3643
|
+
/**
|
|
3644
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3645
|
+
*
|
|
3646
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3647
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3648
|
+
* when they have a tag.
|
|
3649
|
+
*/
|
|
3650
|
+
getReleaseWorkspaces(workspaces) {
|
|
3651
|
+
return workspaces.filter((workspace) => {
|
|
3652
|
+
if (!workspace.tagName) {
|
|
3653
|
+
return false;
|
|
3654
|
+
}
|
|
3655
|
+
if (workspace.dependencyRelease) {
|
|
3656
|
+
return false;
|
|
3657
|
+
}
|
|
3658
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3659
|
+
this.logger.info(
|
|
3660
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3661
|
+
);
|
|
3662
|
+
return false;
|
|
3663
|
+
}
|
|
3664
|
+
return true;
|
|
3665
|
+
});
|
|
3666
|
+
}
|
|
3667
|
+
/**
|
|
3668
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3669
|
+
*
|
|
3670
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3671
|
+
*/
|
|
3672
|
+
async createGithubReleases(workspaces) {
|
|
3673
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3674
|
+
if (releaseWorkspaces.length === 0) {
|
|
3675
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3676
|
+
return;
|
|
3677
|
+
}
|
|
3678
|
+
this.logger.info(
|
|
3679
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3680
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3681
|
+
);
|
|
3682
|
+
await Promise.all(
|
|
3683
|
+
releaseWorkspaces.map(
|
|
3684
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3685
|
+
)
|
|
3686
|
+
);
|
|
3687
|
+
}
|
|
3586
3688
|
/**
|
|
3587
3689
|
* Create the release PR and optionally auto-merge it.
|
|
3588
3690
|
*
|
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
|
*
|
|
@@ -850,7 +881,8 @@ interface ChangeLogInterface {
|
|
|
850
881
|
* Changesets CLI for monorepo version bumps.
|
|
851
882
|
*
|
|
852
883
|
* Pipeline phases:
|
|
853
|
-
* - **onBefore**: validate `.changeset` directory;
|
|
884
|
+
* - **onBefore**: validate `.changeset` directory; configure npm auth when mode includes publish
|
|
885
|
+
* (`NPM_TOKEN` for token auth, or skip when Trusted Publishing / OIDC is detected)
|
|
854
886
|
* - **onExec**: generate per-workspace git changelogs (skips `dependencyRelease`
|
|
855
887
|
* when `ignoreNonUpdatedPackages` is enabled)
|
|
856
888
|
* - **onSuccess**: run version and/or publish flow based on `mode`
|
|
@@ -963,6 +995,17 @@ interface ChangesetVersionProps extends GitChangelogOptions, ScriptPluginProps {
|
|
|
963
995
|
* @default false
|
|
964
996
|
*/
|
|
965
997
|
ignoreNonUpdatedPackages?: boolean;
|
|
998
|
+
/**
|
|
999
|
+
* Use npm Trusted Publishing (OIDC) instead of `NPM_TOKEN`.
|
|
1000
|
+
*
|
|
1001
|
+
* When enabled (or when GitHub Actions OIDC env is detected), publish skips
|
|
1002
|
+
* writing `_authToken` to npm config so the CLI can exchange OIDC credentials.
|
|
1003
|
+
*
|
|
1004
|
+
* CLI: `--changesetVersion.use-trusted-publishing`
|
|
1005
|
+
*
|
|
1006
|
+
* @default false
|
|
1007
|
+
*/
|
|
1008
|
+
useTrustedPublishing?: boolean;
|
|
966
1009
|
}
|
|
967
1010
|
/**
|
|
968
1011
|
* Manages changelog generation, changeset file creation, and Changesets CLI execution.
|
|
@@ -977,14 +1020,19 @@ declare class ChangesetVersion extends ScriptPlugin<ReleaseContext, ChangesetVer
|
|
|
977
1020
|
get changesetConfigPath(): string;
|
|
978
1021
|
protected get mode(): ChangesetVersionMode;
|
|
979
1022
|
protected get ignoreNonUpdatedPackages(): boolean;
|
|
1023
|
+
protected get useTrustedPublishing(): boolean;
|
|
1024
|
+
/**
|
|
1025
|
+
* True when publish should use npm Trusted Publishing (OIDC) instead of NPM_TOKEN.
|
|
1026
|
+
*/
|
|
1027
|
+
protected isTrustedPublishingEnv(): boolean;
|
|
980
1028
|
protected shouldProcessWorkspace(workspace: WorkspaceInterface): boolean;
|
|
981
1029
|
protected getProcessableWorkspaces(workspaces: WorkspaceInterface[]): WorkspaceInterface[];
|
|
982
1030
|
onBefore(): Promise<void>;
|
|
983
1031
|
/**
|
|
984
|
-
*
|
|
1032
|
+
* Configure npm auth before changeset publish.
|
|
985
1033
|
*
|
|
986
|
-
*
|
|
987
|
-
* do not need
|
|
1034
|
+
* Uses Trusted Publishing (OIDC) when detected; otherwise requires `NPM_TOKEN`.
|
|
1035
|
+
* Version-only runs (release PR) do not need npm auth.
|
|
988
1036
|
*/
|
|
989
1037
|
protected validateNpmToken(): Promise<void>;
|
|
990
1038
|
onExec(_context: ReleaseContext): Promise<void>;
|
|
@@ -1465,6 +1513,10 @@ declare const releaseJson: {
|
|
|
1465
1513
|
readonly branchName: "release/${repoName}-${releaseId}";
|
|
1466
1514
|
readonly releaseTagName: "release-tag-${count}-patch-${releaseId}";
|
|
1467
1515
|
readonly commitMessage: "chore(release): ${spaces}";
|
|
1516
|
+
/** GitHub release title template (createRelease mode) */
|
|
1517
|
+
readonly releaseName: "${name}@${version}";
|
|
1518
|
+
/** Path prefixes skipped when creating GitHub releases */
|
|
1519
|
+
readonly ignoreReleasePaths: readonly string[];
|
|
1468
1520
|
readonly label: {
|
|
1469
1521
|
readonly name: "CI-Release";
|
|
1470
1522
|
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",
|
|
@@ -1562,6 +1566,22 @@ var ChangesetVersion = class extends ScriptPlugin2 {
|
|
|
1562
1566
|
get ignoreNonUpdatedPackages() {
|
|
1563
1567
|
return !!this.config.ignoreNonUpdatedPackages;
|
|
1564
1568
|
}
|
|
1569
|
+
get useTrustedPublishing() {
|
|
1570
|
+
return !!(this.config.useTrustedPublishing || this.context.parameters.changesetVersion?.useTrustedPublishing);
|
|
1571
|
+
}
|
|
1572
|
+
/**
|
|
1573
|
+
* True when publish should use npm Trusted Publishing (OIDC) instead of NPM_TOKEN.
|
|
1574
|
+
*/
|
|
1575
|
+
isTrustedPublishingEnv() {
|
|
1576
|
+
if (this.useTrustedPublishing) {
|
|
1577
|
+
return true;
|
|
1578
|
+
}
|
|
1579
|
+
const envFlag = this.context.getEnv("FE_RELEASE_TRUSTED_PUBLISHING");
|
|
1580
|
+
if (envFlag === "1" || envFlag === "true") {
|
|
1581
|
+
return true;
|
|
1582
|
+
}
|
|
1583
|
+
return Boolean(this.context.getEnv("ACTIONS_ID_TOKEN_REQUEST_URL"));
|
|
1584
|
+
}
|
|
1565
1585
|
shouldProcessWorkspace(workspace) {
|
|
1566
1586
|
return shouldProcessWorkspace(workspace, this.ignoreNonUpdatedPackages);
|
|
1567
1587
|
}
|
|
@@ -1583,15 +1603,26 @@ var ChangesetVersion = class extends ScriptPlugin2 {
|
|
|
1583
1603
|
}
|
|
1584
1604
|
}
|
|
1585
1605
|
/**
|
|
1586
|
-
*
|
|
1606
|
+
* Configure npm auth before changeset publish.
|
|
1587
1607
|
*
|
|
1588
|
-
*
|
|
1589
|
-
* do not need
|
|
1608
|
+
* Uses Trusted Publishing (OIDC) when detected; otherwise requires `NPM_TOKEN`.
|
|
1609
|
+
* Version-only runs (release PR) do not need npm auth.
|
|
1590
1610
|
*/
|
|
1591
1611
|
async validateNpmToken() {
|
|
1612
|
+
if (this.isTrustedPublishingEnv()) {
|
|
1613
|
+
this.logger.info(
|
|
1614
|
+
"Using npm Trusted Publishing (OIDC); skip NPM_TOKEN auth setup"
|
|
1615
|
+
);
|
|
1616
|
+
if (this.context.dryRun) {
|
|
1617
|
+
this.logDryRun("Would publish via npm Trusted Publishing (OIDC)");
|
|
1618
|
+
}
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1592
1621
|
const npmToken = this.context.getEnv("NPM_TOKEN");
|
|
1593
1622
|
if (!npmToken) {
|
|
1594
|
-
throw new Error(
|
|
1623
|
+
throw new Error(
|
|
1624
|
+
"NPM_TOKEN is not set. Enable Trusted Publishing (OIDC) or provide NPM_TOKEN."
|
|
1625
|
+
);
|
|
1595
1626
|
}
|
|
1596
1627
|
if (this.context.dryRun) {
|
|
1597
1628
|
this.logDryRun(
|
|
@@ -2701,7 +2732,7 @@ var GithubManager = class {
|
|
|
2701
2732
|
*/
|
|
2702
2733
|
getOctokitReleaseOptions(options) {
|
|
2703
2734
|
const {
|
|
2704
|
-
releaseName,
|
|
2735
|
+
releaseName = releaseJson.github.releaseName,
|
|
2705
2736
|
draft = false,
|
|
2706
2737
|
preRelease = false,
|
|
2707
2738
|
autoGenerate = false,
|
|
@@ -2710,7 +2741,7 @@ var GithubManager = class {
|
|
|
2710
2741
|
discussionCategoryName = void 0
|
|
2711
2742
|
} = this.context.getParameters("github");
|
|
2712
2743
|
const name = releaseName;
|
|
2713
|
-
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes));
|
|
2744
|
+
const body = autoGenerate ? "" : this.truncateBody(String(releaseNotes ?? ""));
|
|
2714
2745
|
return {
|
|
2715
2746
|
name,
|
|
2716
2747
|
make_latest: makeLatest.toString(),
|
|
@@ -3474,6 +3505,7 @@ var ReleaseFormatter = class {
|
|
|
3474
3505
|
var Github = class extends GitBase {
|
|
3475
3506
|
releaseFormatter;
|
|
3476
3507
|
githubManager;
|
|
3508
|
+
pather = new Pather();
|
|
3477
3509
|
constructor(context, props = {}) {
|
|
3478
3510
|
super(context, "github", props);
|
|
3479
3511
|
this.releaseFormatter = new ReleaseFormatter(
|
|
@@ -3485,6 +3517,9 @@ var Github = class extends GitBase {
|
|
|
3485
3517
|
get mode() {
|
|
3486
3518
|
return this.config.mode || releaseJson.github.mode;
|
|
3487
3519
|
}
|
|
3520
|
+
get ignoreReleasePaths() {
|
|
3521
|
+
return this.config.ignoreReleasePaths ?? [...releaseJson.github.ignoreReleasePaths];
|
|
3522
|
+
}
|
|
3488
3523
|
async onBefore() {
|
|
3489
3524
|
await super.onBefore();
|
|
3490
3525
|
await this.githubManager.validateToken();
|
|
@@ -3510,6 +3545,9 @@ var Github = class extends GitBase {
|
|
|
3510
3545
|
if (workspace.dependencyRelease) {
|
|
3511
3546
|
return workspace;
|
|
3512
3547
|
}
|
|
3548
|
+
if (this.mode === "createRelease" && this.isIgnoredReleasePath(workspace)) {
|
|
3549
|
+
return workspace;
|
|
3550
|
+
}
|
|
3513
3551
|
return githubChangelog.enrichWorkspaceChangelog(workspace);
|
|
3514
3552
|
})
|
|
3515
3553
|
)
|
|
@@ -3518,6 +3556,13 @@ var Github = class extends GitBase {
|
|
|
3518
3556
|
}
|
|
3519
3557
|
async onSuccess() {
|
|
3520
3558
|
const workspaces = this.context.requireWorkspaces();
|
|
3559
|
+
if (this.mode === "createRelease") {
|
|
3560
|
+
await this.step({
|
|
3561
|
+
label: "Create GitHub Releases",
|
|
3562
|
+
task: () => this.createGithubReleases(workspaces)
|
|
3563
|
+
});
|
|
3564
|
+
return;
|
|
3565
|
+
}
|
|
3521
3566
|
const releaseBranchResult = await this.step({
|
|
3522
3567
|
label: "Create Release Branch",
|
|
3523
3568
|
task: () => this.createReleaseBranch(workspaces)
|
|
@@ -3534,6 +3579,63 @@ var Github = class extends GitBase {
|
|
|
3534
3579
|
}
|
|
3535
3580
|
await this.handleReleasePullRequest(workspaces, releaseBranchResult);
|
|
3536
3581
|
}
|
|
3582
|
+
/**
|
|
3583
|
+
* Whether this workspace path is under an ignoreReleasePaths entry.
|
|
3584
|
+
*/
|
|
3585
|
+
isIgnoredReleasePath(workspace) {
|
|
3586
|
+
const ignorePaths = this.ignoreReleasePaths;
|
|
3587
|
+
if (ignorePaths.length === 0) {
|
|
3588
|
+
return false;
|
|
3589
|
+
}
|
|
3590
|
+
return ignorePaths.some(
|
|
3591
|
+
(ignorePath) => this.pather.isSubPath(workspace.path, ignorePath)
|
|
3592
|
+
);
|
|
3593
|
+
}
|
|
3594
|
+
/**
|
|
3595
|
+
* Workspaces that should receive a GitHub Release in createRelease mode.
|
|
3596
|
+
*
|
|
3597
|
+
* Requires `tagName`. Skips dependency-release packages and paths matched
|
|
3598
|
+
* by {@link GithubProps.ignoreReleasePaths}. Private packages are included
|
|
3599
|
+
* when they have a tag.
|
|
3600
|
+
*/
|
|
3601
|
+
getReleaseWorkspaces(workspaces) {
|
|
3602
|
+
return workspaces.filter((workspace) => {
|
|
3603
|
+
if (!workspace.tagName) {
|
|
3604
|
+
return false;
|
|
3605
|
+
}
|
|
3606
|
+
if (workspace.dependencyRelease) {
|
|
3607
|
+
return false;
|
|
3608
|
+
}
|
|
3609
|
+
if (this.isIgnoredReleasePath(workspace)) {
|
|
3610
|
+
this.logger.info(
|
|
3611
|
+
`Skip GitHub Release for ignored path: ${workspace.path} (${workspace.tagName})`
|
|
3612
|
+
);
|
|
3613
|
+
return false;
|
|
3614
|
+
}
|
|
3615
|
+
return true;
|
|
3616
|
+
});
|
|
3617
|
+
}
|
|
3618
|
+
/**
|
|
3619
|
+
* Create a GitHub Release for each eligible workspace.
|
|
3620
|
+
*
|
|
3621
|
+
* Release notes use the enriched workspace changelog from `onExec`.
|
|
3622
|
+
*/
|
|
3623
|
+
async createGithubReleases(workspaces) {
|
|
3624
|
+
const releaseWorkspaces = this.getReleaseWorkspaces(workspaces);
|
|
3625
|
+
if (releaseWorkspaces.length === 0) {
|
|
3626
|
+
this.logger.warn("No workspaces eligible for GitHub Release creation");
|
|
3627
|
+
return;
|
|
3628
|
+
}
|
|
3629
|
+
this.logger.info(
|
|
3630
|
+
`Creating GitHub Releases (${releaseWorkspaces.length}):
|
|
3631
|
+
${releaseWorkspaces.map((w) => ` ${w.tagName}`).join("\n")}`
|
|
3632
|
+
);
|
|
3633
|
+
await Promise.all(
|
|
3634
|
+
releaseWorkspaces.map(
|
|
3635
|
+
(workspace) => this.githubManager.createRelease(workspace)
|
|
3636
|
+
)
|
|
3637
|
+
);
|
|
3638
|
+
}
|
|
3537
3639
|
/**
|
|
3538
3640
|
* Create the release PR and optionally auto-merge it.
|
|
3539
3641
|
*
|
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.
|
|
4
|
+
"version": "5.3.1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"homepage": "https://github.com/qlover/fe-base/tree/master/packages/fe-release",
|
|
@@ -59,8 +59,8 @@
|
|
|
59
59
|
"lodash-es": "^4.17.22",
|
|
60
60
|
"p-limit": "^6.2.0",
|
|
61
61
|
"semver": "^7.5.4",
|
|
62
|
-
"@qlover/env-loader": "1.0
|
|
63
|
-
"@qlover/fe-corekit": "3.4.
|
|
62
|
+
"@qlover/env-loader": "1.1.0",
|
|
63
|
+
"@qlover/fe-corekit": "3.4.6",
|
|
64
64
|
"@qlover/logger": "1.2.1",
|
|
65
65
|
"@qlover/scripts-context": "2.3.3"
|
|
66
66
|
},
|