@qlover/fe-release 5.0.5 → 5.0.6
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 +93 -12
- package/dist/cli.js +93 -12
- package/dist/index.cjs +92 -11
- package/dist/index.d.ts +25 -4
- package/dist/index.js +92 -11
- package/package.json +2 -2
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.0.6";
|
|
32
32
|
|
|
33
33
|
// src/cli.ts
|
|
34
34
|
var import_semver = __toESM(require("semver"), 1);
|
|
@@ -592,6 +592,9 @@ function workspaceVersionSummary(workspace) {
|
|
|
592
592
|
function shouldProcessWorkspace(workspace, ignoreNonUpdatedPackages) {
|
|
593
593
|
return !(ignoreNonUpdatedPackages && workspace.dependencyRelease);
|
|
594
594
|
}
|
|
595
|
+
function isPrivateWorkspace(workspace) {
|
|
596
|
+
return workspace.packageJson?.private === true;
|
|
597
|
+
}
|
|
595
598
|
function readJson(path) {
|
|
596
599
|
const packageJsonContent = (0, import_fs.readFileSync)(path, "utf-8");
|
|
597
600
|
return JSON.parse(packageJsonContent);
|
|
@@ -1733,9 +1736,18 @@ ${workspaces?.map((workspace) => workspace.toString()).join("\n")}`
|
|
|
1733
1736
|
this.logDryRun("Would run: changeset publish, publish packages and tags");
|
|
1734
1737
|
const preview = this.mergeWorkspaces(workspaces);
|
|
1735
1738
|
this.context.setWorkspaces(preview);
|
|
1736
|
-
const previewTags =
|
|
1737
|
-
|
|
1739
|
+
const previewTags = this.collectPushableReleaseTags(preview);
|
|
1740
|
+
const privateTags = preview.filter(
|
|
1741
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1738
1742
|
).map((workspace) => workspace.tagName);
|
|
1743
|
+
if (privateTags.length > 0) {
|
|
1744
|
+
this.logDryRun(
|
|
1745
|
+
`Would create local tag(s) for private package(s):
|
|
1746
|
+
${[
|
|
1747
|
+
...new Set(privateTags)
|
|
1748
|
+
].map((tag) => ` ${tag}`).join("\n")}`
|
|
1749
|
+
);
|
|
1750
|
+
}
|
|
1739
1751
|
this.logDryRun(
|
|
1740
1752
|
previewTags.length === 0 ? "Would push release tag(s) from workspace.tagName: none" : `Would push release tag(s) from workspace.tagName:
|
|
1741
1753
|
${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
@@ -1749,37 +1761,106 @@ ${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
|
1749
1761
|
if (workspaces.length > 0) {
|
|
1750
1762
|
this.syncWorkspaces(workspaces);
|
|
1751
1763
|
}
|
|
1764
|
+
const syncedWorkspaces = this.context.workspaces ?? workspaces;
|
|
1765
|
+
await this.step({
|
|
1766
|
+
label: "Create Private Package Tags",
|
|
1767
|
+
task: () => this.ensurePrivateReleaseTags(syncedWorkspaces)
|
|
1768
|
+
});
|
|
1752
1769
|
await this.step({
|
|
1753
1770
|
label: "Push Release Tags",
|
|
1754
|
-
task: () => this.pushWorkspaceReleaseTags(
|
|
1771
|
+
task: () => this.pushWorkspaceReleaseTags(syncedWorkspaces)
|
|
1755
1772
|
});
|
|
1756
1773
|
}
|
|
1757
1774
|
/**
|
|
1758
|
-
*
|
|
1775
|
+
* Collect tag names that should be pushed after `changeset publish`.
|
|
1759
1776
|
*
|
|
1760
|
-
*
|
|
1761
|
-
*
|
|
1777
|
+
* Includes public packages (tagged by changesets) and private packages
|
|
1778
|
+
* (tagged by {@link ensurePrivateReleaseTags}). Skips dependency-release
|
|
1779
|
+
* workspaces.
|
|
1762
1780
|
*/
|
|
1763
|
-
|
|
1781
|
+
collectPushableReleaseTags(workspaces) {
|
|
1764
1782
|
const tags = workspaces.filter(
|
|
1765
1783
|
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && !!workspace.tagName
|
|
1766
1784
|
).map((workspace) => workspace.tagName);
|
|
1767
|
-
|
|
1785
|
+
return [...new Set(tags)];
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* List local git tag names (short refs under `refs/tags/`).
|
|
1789
|
+
*/
|
|
1790
|
+
async listLocalTags() {
|
|
1791
|
+
const output = await this.shell.exec(
|
|
1792
|
+
'git for-each-ref --format="%(refname:short)" refs/tags/',
|
|
1793
|
+
{ dryRun: false, silent: true }
|
|
1794
|
+
);
|
|
1795
|
+
const tags = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
1796
|
+
return new Set(tags);
|
|
1797
|
+
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Create local git tags for private packages after `changeset publish`.
|
|
1800
|
+
*
|
|
1801
|
+
* Changesets skips npm publish and tagging for `private: true` packages.
|
|
1802
|
+
* Release still needs those tags as changelog baselines, so create them here.
|
|
1803
|
+
*/
|
|
1804
|
+
async ensurePrivateReleaseTags(workspaces) {
|
|
1805
|
+
const privateWorkspaces = workspaces.filter(
|
|
1806
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1807
|
+
);
|
|
1808
|
+
if (privateWorkspaces.length === 0) {
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1811
|
+
const localTags = await this.listLocalTags();
|
|
1812
|
+
for (const workspace of privateWorkspaces) {
|
|
1813
|
+
const tagName = workspace.tagName;
|
|
1814
|
+
if (localTags.has(tagName)) {
|
|
1815
|
+
this.logger.debug(`Private package tag already exists: ${tagName}`);
|
|
1816
|
+
continue;
|
|
1817
|
+
}
|
|
1818
|
+
this.logger.info(
|
|
1819
|
+
`Create local release tag for private package: ${tagName}`
|
|
1820
|
+
);
|
|
1821
|
+
await this.shell.exec(["git", "tag", tagName]);
|
|
1822
|
+
localTags.add(tagName);
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
/**
|
|
1826
|
+
* Push release tags from synced workspaces' `tagName` fields.
|
|
1827
|
+
*
|
|
1828
|
+
* After {@link syncWorkspaces} and {@link ensurePrivateReleaseTags}, push
|
|
1829
|
+
* tags that exist as local refs. Missing public-package tags are skipped
|
|
1830
|
+
* (changeset may have skipped publish); they are not invented here.
|
|
1831
|
+
*/
|
|
1832
|
+
async pushWorkspaceReleaseTags(workspaces) {
|
|
1833
|
+
const uniqueTags = this.collectPushableReleaseTags(workspaces);
|
|
1768
1834
|
if (uniqueTags.length === 0) {
|
|
1769
1835
|
this.logger.warn(
|
|
1770
1836
|
"No workspace.tagName found after publish sync; skip tag push"
|
|
1771
1837
|
);
|
|
1772
1838
|
return;
|
|
1773
1839
|
}
|
|
1840
|
+
const localTags = await this.listLocalTags();
|
|
1841
|
+
const existingTags = uniqueTags.filter((tag) => localTags.has(tag));
|
|
1842
|
+
const missingTags = uniqueTags.filter((tag) => !localTags.has(tag));
|
|
1843
|
+
if (missingTags.length > 0) {
|
|
1844
|
+
this.logger.warn(
|
|
1845
|
+
`Skip push for missing local tag(s):
|
|
1846
|
+
${missingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1847
|
+
);
|
|
1848
|
+
}
|
|
1849
|
+
if (existingTags.length === 0) {
|
|
1850
|
+
this.logger.warn(
|
|
1851
|
+
"No local release tags found to push after publish; skip tag push"
|
|
1852
|
+
);
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1774
1855
|
this.logger.info(
|
|
1775
|
-
`Pushing ${
|
|
1776
|
-
${
|
|
1856
|
+
`Pushing ${existingTags.length} release tag(s) to origin:
|
|
1857
|
+
${existingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1777
1858
|
);
|
|
1778
1859
|
await this.shell.exec([
|
|
1779
1860
|
"git",
|
|
1780
1861
|
"push",
|
|
1781
1862
|
"origin",
|
|
1782
|
-
...
|
|
1863
|
+
...existingTags.map((tag) => `"refs/tags/${tag}"`)
|
|
1783
1864
|
]);
|
|
1784
1865
|
}
|
|
1785
1866
|
syncWorkspaces(workspaces) {
|
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.0.6";
|
|
9
9
|
|
|
10
10
|
// src/cli.ts
|
|
11
11
|
import semver from "semver";
|
|
@@ -572,6 +572,9 @@ function workspaceVersionSummary(workspace) {
|
|
|
572
572
|
function shouldProcessWorkspace(workspace, ignoreNonUpdatedPackages) {
|
|
573
573
|
return !(ignoreNonUpdatedPackages && workspace.dependencyRelease);
|
|
574
574
|
}
|
|
575
|
+
function isPrivateWorkspace(workspace) {
|
|
576
|
+
return workspace.packageJson?.private === true;
|
|
577
|
+
}
|
|
575
578
|
function readJson(path) {
|
|
576
579
|
const packageJsonContent = readFileSync(path, "utf-8");
|
|
577
580
|
return JSON.parse(packageJsonContent);
|
|
@@ -1713,9 +1716,18 @@ ${workspaces?.map((workspace) => workspace.toString()).join("\n")}`
|
|
|
1713
1716
|
this.logDryRun("Would run: changeset publish, publish packages and tags");
|
|
1714
1717
|
const preview = this.mergeWorkspaces(workspaces);
|
|
1715
1718
|
this.context.setWorkspaces(preview);
|
|
1716
|
-
const previewTags =
|
|
1717
|
-
|
|
1719
|
+
const previewTags = this.collectPushableReleaseTags(preview);
|
|
1720
|
+
const privateTags = preview.filter(
|
|
1721
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1718
1722
|
).map((workspace) => workspace.tagName);
|
|
1723
|
+
if (privateTags.length > 0) {
|
|
1724
|
+
this.logDryRun(
|
|
1725
|
+
`Would create local tag(s) for private package(s):
|
|
1726
|
+
${[
|
|
1727
|
+
...new Set(privateTags)
|
|
1728
|
+
].map((tag) => ` ${tag}`).join("\n")}`
|
|
1729
|
+
);
|
|
1730
|
+
}
|
|
1719
1731
|
this.logDryRun(
|
|
1720
1732
|
previewTags.length === 0 ? "Would push release tag(s) from workspace.tagName: none" : `Would push release tag(s) from workspace.tagName:
|
|
1721
1733
|
${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
@@ -1729,37 +1741,106 @@ ${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
|
1729
1741
|
if (workspaces.length > 0) {
|
|
1730
1742
|
this.syncWorkspaces(workspaces);
|
|
1731
1743
|
}
|
|
1744
|
+
const syncedWorkspaces = this.context.workspaces ?? workspaces;
|
|
1745
|
+
await this.step({
|
|
1746
|
+
label: "Create Private Package Tags",
|
|
1747
|
+
task: () => this.ensurePrivateReleaseTags(syncedWorkspaces)
|
|
1748
|
+
});
|
|
1732
1749
|
await this.step({
|
|
1733
1750
|
label: "Push Release Tags",
|
|
1734
|
-
task: () => this.pushWorkspaceReleaseTags(
|
|
1751
|
+
task: () => this.pushWorkspaceReleaseTags(syncedWorkspaces)
|
|
1735
1752
|
});
|
|
1736
1753
|
}
|
|
1737
1754
|
/**
|
|
1738
|
-
*
|
|
1755
|
+
* Collect tag names that should be pushed after `changeset publish`.
|
|
1739
1756
|
*
|
|
1740
|
-
*
|
|
1741
|
-
*
|
|
1757
|
+
* Includes public packages (tagged by changesets) and private packages
|
|
1758
|
+
* (tagged by {@link ensurePrivateReleaseTags}). Skips dependency-release
|
|
1759
|
+
* workspaces.
|
|
1742
1760
|
*/
|
|
1743
|
-
|
|
1761
|
+
collectPushableReleaseTags(workspaces) {
|
|
1744
1762
|
const tags = workspaces.filter(
|
|
1745
1763
|
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && !!workspace.tagName
|
|
1746
1764
|
).map((workspace) => workspace.tagName);
|
|
1747
|
-
|
|
1765
|
+
return [...new Set(tags)];
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* List local git tag names (short refs under `refs/tags/`).
|
|
1769
|
+
*/
|
|
1770
|
+
async listLocalTags() {
|
|
1771
|
+
const output = await this.shell.exec(
|
|
1772
|
+
'git for-each-ref --format="%(refname:short)" refs/tags/',
|
|
1773
|
+
{ dryRun: false, silent: true }
|
|
1774
|
+
);
|
|
1775
|
+
const tags = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
1776
|
+
return new Set(tags);
|
|
1777
|
+
}
|
|
1778
|
+
/**
|
|
1779
|
+
* Create local git tags for private packages after `changeset publish`.
|
|
1780
|
+
*
|
|
1781
|
+
* Changesets skips npm publish and tagging for `private: true` packages.
|
|
1782
|
+
* Release still needs those tags as changelog baselines, so create them here.
|
|
1783
|
+
*/
|
|
1784
|
+
async ensurePrivateReleaseTags(workspaces) {
|
|
1785
|
+
const privateWorkspaces = workspaces.filter(
|
|
1786
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1787
|
+
);
|
|
1788
|
+
if (privateWorkspaces.length === 0) {
|
|
1789
|
+
return;
|
|
1790
|
+
}
|
|
1791
|
+
const localTags = await this.listLocalTags();
|
|
1792
|
+
for (const workspace of privateWorkspaces) {
|
|
1793
|
+
const tagName = workspace.tagName;
|
|
1794
|
+
if (localTags.has(tagName)) {
|
|
1795
|
+
this.logger.debug(`Private package tag already exists: ${tagName}`);
|
|
1796
|
+
continue;
|
|
1797
|
+
}
|
|
1798
|
+
this.logger.info(
|
|
1799
|
+
`Create local release tag for private package: ${tagName}`
|
|
1800
|
+
);
|
|
1801
|
+
await this.shell.exec(["git", "tag", tagName]);
|
|
1802
|
+
localTags.add(tagName);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Push release tags from synced workspaces' `tagName` fields.
|
|
1807
|
+
*
|
|
1808
|
+
* After {@link syncWorkspaces} and {@link ensurePrivateReleaseTags}, push
|
|
1809
|
+
* tags that exist as local refs. Missing public-package tags are skipped
|
|
1810
|
+
* (changeset may have skipped publish); they are not invented here.
|
|
1811
|
+
*/
|
|
1812
|
+
async pushWorkspaceReleaseTags(workspaces) {
|
|
1813
|
+
const uniqueTags = this.collectPushableReleaseTags(workspaces);
|
|
1748
1814
|
if (uniqueTags.length === 0) {
|
|
1749
1815
|
this.logger.warn(
|
|
1750
1816
|
"No workspace.tagName found after publish sync; skip tag push"
|
|
1751
1817
|
);
|
|
1752
1818
|
return;
|
|
1753
1819
|
}
|
|
1820
|
+
const localTags = await this.listLocalTags();
|
|
1821
|
+
const existingTags = uniqueTags.filter((tag) => localTags.has(tag));
|
|
1822
|
+
const missingTags = uniqueTags.filter((tag) => !localTags.has(tag));
|
|
1823
|
+
if (missingTags.length > 0) {
|
|
1824
|
+
this.logger.warn(
|
|
1825
|
+
`Skip push for missing local tag(s):
|
|
1826
|
+
${missingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
if (existingTags.length === 0) {
|
|
1830
|
+
this.logger.warn(
|
|
1831
|
+
"No local release tags found to push after publish; skip tag push"
|
|
1832
|
+
);
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1754
1835
|
this.logger.info(
|
|
1755
|
-
`Pushing ${
|
|
1756
|
-
${
|
|
1836
|
+
`Pushing ${existingTags.length} release tag(s) to origin:
|
|
1837
|
+
${existingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1757
1838
|
);
|
|
1758
1839
|
await this.shell.exec([
|
|
1759
1840
|
"git",
|
|
1760
1841
|
"push",
|
|
1761
1842
|
"origin",
|
|
1762
|
-
...
|
|
1843
|
+
...existingTags.map((tag) => `"refs/tags/${tag}"`)
|
|
1763
1844
|
]);
|
|
1764
1845
|
}
|
|
1765
1846
|
syncWorkspaces(workspaces) {
|
package/dist/index.cjs
CHANGED
|
@@ -597,6 +597,9 @@ function workspaceVersionSummary(workspace) {
|
|
|
597
597
|
function shouldProcessWorkspace(workspace, ignoreNonUpdatedPackages) {
|
|
598
598
|
return !(ignoreNonUpdatedPackages && workspace.dependencyRelease);
|
|
599
599
|
}
|
|
600
|
+
function isPrivateWorkspace(workspace) {
|
|
601
|
+
return workspace.packageJson?.private === true;
|
|
602
|
+
}
|
|
600
603
|
function readJson(path) {
|
|
601
604
|
const packageJsonContent = (0, import_fs.readFileSync)(path, "utf-8");
|
|
602
605
|
return JSON.parse(packageJsonContent);
|
|
@@ -1738,9 +1741,18 @@ ${workspaces?.map((workspace) => workspace.toString()).join("\n")}`
|
|
|
1738
1741
|
this.logDryRun("Would run: changeset publish, publish packages and tags");
|
|
1739
1742
|
const preview = this.mergeWorkspaces(workspaces);
|
|
1740
1743
|
this.context.setWorkspaces(preview);
|
|
1741
|
-
const previewTags =
|
|
1742
|
-
|
|
1744
|
+
const previewTags = this.collectPushableReleaseTags(preview);
|
|
1745
|
+
const privateTags = preview.filter(
|
|
1746
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1743
1747
|
).map((workspace) => workspace.tagName);
|
|
1748
|
+
if (privateTags.length > 0) {
|
|
1749
|
+
this.logDryRun(
|
|
1750
|
+
`Would create local tag(s) for private package(s):
|
|
1751
|
+
${[
|
|
1752
|
+
...new Set(privateTags)
|
|
1753
|
+
].map((tag) => ` ${tag}`).join("\n")}`
|
|
1754
|
+
);
|
|
1755
|
+
}
|
|
1744
1756
|
this.logDryRun(
|
|
1745
1757
|
previewTags.length === 0 ? "Would push release tag(s) from workspace.tagName: none" : `Would push release tag(s) from workspace.tagName:
|
|
1746
1758
|
${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
@@ -1754,37 +1766,106 @@ ${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
|
1754
1766
|
if (workspaces.length > 0) {
|
|
1755
1767
|
this.syncWorkspaces(workspaces);
|
|
1756
1768
|
}
|
|
1769
|
+
const syncedWorkspaces = this.context.workspaces ?? workspaces;
|
|
1770
|
+
await this.step({
|
|
1771
|
+
label: "Create Private Package Tags",
|
|
1772
|
+
task: () => this.ensurePrivateReleaseTags(syncedWorkspaces)
|
|
1773
|
+
});
|
|
1757
1774
|
await this.step({
|
|
1758
1775
|
label: "Push Release Tags",
|
|
1759
|
-
task: () => this.pushWorkspaceReleaseTags(
|
|
1776
|
+
task: () => this.pushWorkspaceReleaseTags(syncedWorkspaces)
|
|
1760
1777
|
});
|
|
1761
1778
|
}
|
|
1762
1779
|
/**
|
|
1763
|
-
*
|
|
1780
|
+
* Collect tag names that should be pushed after `changeset publish`.
|
|
1764
1781
|
*
|
|
1765
|
-
*
|
|
1766
|
-
*
|
|
1782
|
+
* Includes public packages (tagged by changesets) and private packages
|
|
1783
|
+
* (tagged by {@link ensurePrivateReleaseTags}). Skips dependency-release
|
|
1784
|
+
* workspaces.
|
|
1767
1785
|
*/
|
|
1768
|
-
|
|
1786
|
+
collectPushableReleaseTags(workspaces) {
|
|
1769
1787
|
const tags = workspaces.filter(
|
|
1770
1788
|
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && !!workspace.tagName
|
|
1771
1789
|
).map((workspace) => workspace.tagName);
|
|
1772
|
-
|
|
1790
|
+
return [...new Set(tags)];
|
|
1791
|
+
}
|
|
1792
|
+
/**
|
|
1793
|
+
* List local git tag names (short refs under `refs/tags/`).
|
|
1794
|
+
*/
|
|
1795
|
+
async listLocalTags() {
|
|
1796
|
+
const output = await this.shell.exec(
|
|
1797
|
+
'git for-each-ref --format="%(refname:short)" refs/tags/',
|
|
1798
|
+
{ dryRun: false, silent: true }
|
|
1799
|
+
);
|
|
1800
|
+
const tags = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
1801
|
+
return new Set(tags);
|
|
1802
|
+
}
|
|
1803
|
+
/**
|
|
1804
|
+
* Create local git tags for private packages after `changeset publish`.
|
|
1805
|
+
*
|
|
1806
|
+
* Changesets skips npm publish and tagging for `private: true` packages.
|
|
1807
|
+
* Release still needs those tags as changelog baselines, so create them here.
|
|
1808
|
+
*/
|
|
1809
|
+
async ensurePrivateReleaseTags(workspaces) {
|
|
1810
|
+
const privateWorkspaces = workspaces.filter(
|
|
1811
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1812
|
+
);
|
|
1813
|
+
if (privateWorkspaces.length === 0) {
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
1816
|
+
const localTags = await this.listLocalTags();
|
|
1817
|
+
for (const workspace of privateWorkspaces) {
|
|
1818
|
+
const tagName = workspace.tagName;
|
|
1819
|
+
if (localTags.has(tagName)) {
|
|
1820
|
+
this.logger.debug(`Private package tag already exists: ${tagName}`);
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
this.logger.info(
|
|
1824
|
+
`Create local release tag for private package: ${tagName}`
|
|
1825
|
+
);
|
|
1826
|
+
await this.shell.exec(["git", "tag", tagName]);
|
|
1827
|
+
localTags.add(tagName);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
/**
|
|
1831
|
+
* Push release tags from synced workspaces' `tagName` fields.
|
|
1832
|
+
*
|
|
1833
|
+
* After {@link syncWorkspaces} and {@link ensurePrivateReleaseTags}, push
|
|
1834
|
+
* tags that exist as local refs. Missing public-package tags are skipped
|
|
1835
|
+
* (changeset may have skipped publish); they are not invented here.
|
|
1836
|
+
*/
|
|
1837
|
+
async pushWorkspaceReleaseTags(workspaces) {
|
|
1838
|
+
const uniqueTags = this.collectPushableReleaseTags(workspaces);
|
|
1773
1839
|
if (uniqueTags.length === 0) {
|
|
1774
1840
|
this.logger.warn(
|
|
1775
1841
|
"No workspace.tagName found after publish sync; skip tag push"
|
|
1776
1842
|
);
|
|
1777
1843
|
return;
|
|
1778
1844
|
}
|
|
1845
|
+
const localTags = await this.listLocalTags();
|
|
1846
|
+
const existingTags = uniqueTags.filter((tag) => localTags.has(tag));
|
|
1847
|
+
const missingTags = uniqueTags.filter((tag) => !localTags.has(tag));
|
|
1848
|
+
if (missingTags.length > 0) {
|
|
1849
|
+
this.logger.warn(
|
|
1850
|
+
`Skip push for missing local tag(s):
|
|
1851
|
+
${missingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1852
|
+
);
|
|
1853
|
+
}
|
|
1854
|
+
if (existingTags.length === 0) {
|
|
1855
|
+
this.logger.warn(
|
|
1856
|
+
"No local release tags found to push after publish; skip tag push"
|
|
1857
|
+
);
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1779
1860
|
this.logger.info(
|
|
1780
|
-
`Pushing ${
|
|
1781
|
-
${
|
|
1861
|
+
`Pushing ${existingTags.length} release tag(s) to origin:
|
|
1862
|
+
${existingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1782
1863
|
);
|
|
1783
1864
|
await this.shell.exec([
|
|
1784
1865
|
"git",
|
|
1785
1866
|
"push",
|
|
1786
1867
|
"origin",
|
|
1787
|
-
...
|
|
1868
|
+
...existingTags.map((tag) => `"refs/tags/${tag}"`)
|
|
1788
1869
|
]);
|
|
1789
1870
|
}
|
|
1790
1871
|
syncWorkspaces(workspaces) {
|
package/dist/index.d.ts
CHANGED
|
@@ -856,9 +856,10 @@ interface ChangeLogInterface {
|
|
|
856
856
|
* - **onSuccess**: run version and/or publish flow based on `mode`
|
|
857
857
|
*
|
|
858
858
|
* Publish flow (`mode: 'publish'` or second half of `'both'`):
|
|
859
|
-
* 1. Run `changeset publish` (npm publish + local `git tag`
|
|
859
|
+
* 1. Run `changeset publish` (npm publish + local `git tag` for public packages)
|
|
860
860
|
* 2. Sync workspaces from disk so `tagName` is set from the release version
|
|
861
|
-
* 3.
|
|
861
|
+
* 3. Create local tags for `private` packages (changesets skips tagging them)
|
|
862
|
+
* 4. Push `workspace.tagName` refs that exist locally to `origin`
|
|
862
863
|
*
|
|
863
864
|
* Version flow (`mode: 'version'` or first half of `'both'`):
|
|
864
865
|
* 1. Write `.changeset/*.md` files for directly changed packages only
|
|
@@ -992,11 +993,31 @@ declare class ChangesetVersion extends ScriptPlugin<ReleaseContext, ChangesetVer
|
|
|
992
993
|
protected logDryRun(message: string): void;
|
|
993
994
|
protected runVersionFlow(): Promise<void>;
|
|
994
995
|
protected runChangesetPublish(): Promise<void>;
|
|
996
|
+
/**
|
|
997
|
+
* Collect tag names that should be pushed after `changeset publish`.
|
|
998
|
+
*
|
|
999
|
+
* Includes public packages (tagged by changesets) and private packages
|
|
1000
|
+
* (tagged by {@link ensurePrivateReleaseTags}). Skips dependency-release
|
|
1001
|
+
* workspaces.
|
|
1002
|
+
*/
|
|
1003
|
+
protected collectPushableReleaseTags(workspaces: WorkspaceInterface[]): string[];
|
|
1004
|
+
/**
|
|
1005
|
+
* List local git tag names (short refs under `refs/tags/`).
|
|
1006
|
+
*/
|
|
1007
|
+
protected listLocalTags(): Promise<Set<string>>;
|
|
1008
|
+
/**
|
|
1009
|
+
* Create local git tags for private packages after `changeset publish`.
|
|
1010
|
+
*
|
|
1011
|
+
* Changesets skips npm publish and tagging for `private: true` packages.
|
|
1012
|
+
* Release still needs those tags as changelog baselines, so create them here.
|
|
1013
|
+
*/
|
|
1014
|
+
protected ensurePrivateReleaseTags(workspaces: WorkspaceInterface[]): Promise<void>;
|
|
995
1015
|
/**
|
|
996
1016
|
* Push release tags from synced workspaces' `tagName` fields.
|
|
997
1017
|
*
|
|
998
|
-
*
|
|
999
|
-
*
|
|
1018
|
+
* After {@link syncWorkspaces} and {@link ensurePrivateReleaseTags}, push
|
|
1019
|
+
* tags that exist as local refs. Missing public-package tags are skipped
|
|
1020
|
+
* (changeset may have skipped publish); they are not invented here.
|
|
1000
1021
|
*/
|
|
1001
1022
|
protected pushWorkspaceReleaseTags(workspaces: WorkspaceInterface[]): Promise<void>;
|
|
1002
1023
|
protected syncWorkspaces(workspaces: WorkspaceInterface[]): void;
|
package/dist/index.js
CHANGED
|
@@ -548,6 +548,9 @@ function workspaceVersionSummary(workspace) {
|
|
|
548
548
|
function shouldProcessWorkspace(workspace, ignoreNonUpdatedPackages) {
|
|
549
549
|
return !(ignoreNonUpdatedPackages && workspace.dependencyRelease);
|
|
550
550
|
}
|
|
551
|
+
function isPrivateWorkspace(workspace) {
|
|
552
|
+
return workspace.packageJson?.private === true;
|
|
553
|
+
}
|
|
551
554
|
function readJson(path) {
|
|
552
555
|
const packageJsonContent = readFileSync(path, "utf-8");
|
|
553
556
|
return JSON.parse(packageJsonContent);
|
|
@@ -1689,9 +1692,18 @@ ${workspaces?.map((workspace) => workspace.toString()).join("\n")}`
|
|
|
1689
1692
|
this.logDryRun("Would run: changeset publish, publish packages and tags");
|
|
1690
1693
|
const preview = this.mergeWorkspaces(workspaces);
|
|
1691
1694
|
this.context.setWorkspaces(preview);
|
|
1692
|
-
const previewTags =
|
|
1693
|
-
|
|
1695
|
+
const previewTags = this.collectPushableReleaseTags(preview);
|
|
1696
|
+
const privateTags = preview.filter(
|
|
1697
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1694
1698
|
).map((workspace) => workspace.tagName);
|
|
1699
|
+
if (privateTags.length > 0) {
|
|
1700
|
+
this.logDryRun(
|
|
1701
|
+
`Would create local tag(s) for private package(s):
|
|
1702
|
+
${[
|
|
1703
|
+
...new Set(privateTags)
|
|
1704
|
+
].map((tag) => ` ${tag}`).join("\n")}`
|
|
1705
|
+
);
|
|
1706
|
+
}
|
|
1695
1707
|
this.logDryRun(
|
|
1696
1708
|
previewTags.length === 0 ? "Would push release tag(s) from workspace.tagName: none" : `Would push release tag(s) from workspace.tagName:
|
|
1697
1709
|
${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
@@ -1705,37 +1717,106 @@ ${previewTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
|
1705
1717
|
if (workspaces.length > 0) {
|
|
1706
1718
|
this.syncWorkspaces(workspaces);
|
|
1707
1719
|
}
|
|
1720
|
+
const syncedWorkspaces = this.context.workspaces ?? workspaces;
|
|
1721
|
+
await this.step({
|
|
1722
|
+
label: "Create Private Package Tags",
|
|
1723
|
+
task: () => this.ensurePrivateReleaseTags(syncedWorkspaces)
|
|
1724
|
+
});
|
|
1708
1725
|
await this.step({
|
|
1709
1726
|
label: "Push Release Tags",
|
|
1710
|
-
task: () => this.pushWorkspaceReleaseTags(
|
|
1727
|
+
task: () => this.pushWorkspaceReleaseTags(syncedWorkspaces)
|
|
1711
1728
|
});
|
|
1712
1729
|
}
|
|
1713
1730
|
/**
|
|
1714
|
-
*
|
|
1731
|
+
* Collect tag names that should be pushed after `changeset publish`.
|
|
1715
1732
|
*
|
|
1716
|
-
*
|
|
1717
|
-
*
|
|
1733
|
+
* Includes public packages (tagged by changesets) and private packages
|
|
1734
|
+
* (tagged by {@link ensurePrivateReleaseTags}). Skips dependency-release
|
|
1735
|
+
* workspaces.
|
|
1718
1736
|
*/
|
|
1719
|
-
|
|
1737
|
+
collectPushableReleaseTags(workspaces) {
|
|
1720
1738
|
const tags = workspaces.filter(
|
|
1721
1739
|
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && !!workspace.tagName
|
|
1722
1740
|
).map((workspace) => workspace.tagName);
|
|
1723
|
-
|
|
1741
|
+
return [...new Set(tags)];
|
|
1742
|
+
}
|
|
1743
|
+
/**
|
|
1744
|
+
* List local git tag names (short refs under `refs/tags/`).
|
|
1745
|
+
*/
|
|
1746
|
+
async listLocalTags() {
|
|
1747
|
+
const output = await this.shell.exec(
|
|
1748
|
+
'git for-each-ref --format="%(refname:short)" refs/tags/',
|
|
1749
|
+
{ dryRun: false, silent: true }
|
|
1750
|
+
);
|
|
1751
|
+
const tags = output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
1752
|
+
return new Set(tags);
|
|
1753
|
+
}
|
|
1754
|
+
/**
|
|
1755
|
+
* Create local git tags for private packages after `changeset publish`.
|
|
1756
|
+
*
|
|
1757
|
+
* Changesets skips npm publish and tagging for `private: true` packages.
|
|
1758
|
+
* Release still needs those tags as changelog baselines, so create them here.
|
|
1759
|
+
*/
|
|
1760
|
+
async ensurePrivateReleaseTags(workspaces) {
|
|
1761
|
+
const privateWorkspaces = workspaces.filter(
|
|
1762
|
+
(workspace) => this.shouldProcessWorkspace(workspace) && !workspace.dependencyRelease && isPrivateWorkspace(workspace) && !!workspace.tagName
|
|
1763
|
+
);
|
|
1764
|
+
if (privateWorkspaces.length === 0) {
|
|
1765
|
+
return;
|
|
1766
|
+
}
|
|
1767
|
+
const localTags = await this.listLocalTags();
|
|
1768
|
+
for (const workspace of privateWorkspaces) {
|
|
1769
|
+
const tagName = workspace.tagName;
|
|
1770
|
+
if (localTags.has(tagName)) {
|
|
1771
|
+
this.logger.debug(`Private package tag already exists: ${tagName}`);
|
|
1772
|
+
continue;
|
|
1773
|
+
}
|
|
1774
|
+
this.logger.info(
|
|
1775
|
+
`Create local release tag for private package: ${tagName}`
|
|
1776
|
+
);
|
|
1777
|
+
await this.shell.exec(["git", "tag", tagName]);
|
|
1778
|
+
localTags.add(tagName);
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Push release tags from synced workspaces' `tagName` fields.
|
|
1783
|
+
*
|
|
1784
|
+
* After {@link syncWorkspaces} and {@link ensurePrivateReleaseTags}, push
|
|
1785
|
+
* tags that exist as local refs. Missing public-package tags are skipped
|
|
1786
|
+
* (changeset may have skipped publish); they are not invented here.
|
|
1787
|
+
*/
|
|
1788
|
+
async pushWorkspaceReleaseTags(workspaces) {
|
|
1789
|
+
const uniqueTags = this.collectPushableReleaseTags(workspaces);
|
|
1724
1790
|
if (uniqueTags.length === 0) {
|
|
1725
1791
|
this.logger.warn(
|
|
1726
1792
|
"No workspace.tagName found after publish sync; skip tag push"
|
|
1727
1793
|
);
|
|
1728
1794
|
return;
|
|
1729
1795
|
}
|
|
1796
|
+
const localTags = await this.listLocalTags();
|
|
1797
|
+
const existingTags = uniqueTags.filter((tag) => localTags.has(tag));
|
|
1798
|
+
const missingTags = uniqueTags.filter((tag) => !localTags.has(tag));
|
|
1799
|
+
if (missingTags.length > 0) {
|
|
1800
|
+
this.logger.warn(
|
|
1801
|
+
`Skip push for missing local tag(s):
|
|
1802
|
+
${missingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
if (existingTags.length === 0) {
|
|
1806
|
+
this.logger.warn(
|
|
1807
|
+
"No local release tags found to push after publish; skip tag push"
|
|
1808
|
+
);
|
|
1809
|
+
return;
|
|
1810
|
+
}
|
|
1730
1811
|
this.logger.info(
|
|
1731
|
-
`Pushing ${
|
|
1732
|
-
${
|
|
1812
|
+
`Pushing ${existingTags.length} release tag(s) to origin:
|
|
1813
|
+
${existingTags.map((tag) => ` ${tag}`).join("\n")}`
|
|
1733
1814
|
);
|
|
1734
1815
|
await this.shell.exec([
|
|
1735
1816
|
"git",
|
|
1736
1817
|
"push",
|
|
1737
1818
|
"origin",
|
|
1738
|
-
...
|
|
1819
|
+
...existingTags.map((tag) => `"refs/tags/${tag}"`)
|
|
1739
1820
|
]);
|
|
1740
1821
|
}
|
|
1741
1822
|
syncWorkspaces(workspaces) {
|
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.0.6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
7
7
|
"homepage": "https://github.com/qlover/fe-base/tree/master/packages/fe-release",
|
|
@@ -60,7 +60,7 @@
|
|
|
60
60
|
"p-limit": "^6.2.0",
|
|
61
61
|
"semver": "^7.5.4",
|
|
62
62
|
"@qlover/env-loader": "1.0.2",
|
|
63
|
-
"@qlover/fe-corekit": "3.
|
|
63
|
+
"@qlover/fe-corekit": "3.4.4",
|
|
64
64
|
"@qlover/logger": "1.2.1",
|
|
65
65
|
"@qlover/scripts-context": "2.3.3"
|
|
66
66
|
},
|