Skip to content

Commit 37f733e

Browse files
committed
ci(release): tolerate forced preview latest tags
1 parent dea6634 commit 37f733e

3 files changed

Lines changed: 64 additions & 8 deletions

File tree

.github/workflows/publish.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ jobs:
172172
173173
if [ "${CURRENT_LATEST}" = "${PACKAGE_VERSION}" ]; then
174174
echo "Removing unintended latest tag from ${WORKSPACE_NAME}@${PACKAGE_VERSION}"
175-
npm dist-tag rm "${WORKSPACE_NAME}" latest
175+
if ! npm dist-tag rm "${WORKSPACE_NAME}" latest; then
176+
echo "::warning::npm did not allow removing latest from ${WORKSPACE_NAME}. This is expected for a new package with no stable version yet; release verification will fail if a stable latest was overwritten."
177+
fi
176178
else
177179
echo "Leaving ${WORKSPACE_NAME} latest tag unchanged (${CURRENT_LATEST:-missing})."
178180
fi

scripts/check-npm-publish-state.mjs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const readJson = async (filePath) =>
1111
export const npmViewPackage = ({ name, version }) => {
1212
const result = spawnSync(
1313
"npm",
14-
["view", `${name}@${version}`, "version", "dist-tags", "--json"],
14+
["view", `${name}@${version}`, "version", "dist-tags", "versions", "--json"],
1515
{
1616
encoding: "utf8"
1717
}
@@ -36,14 +36,16 @@ const normalizeNpmView = (viewResult) => {
3636
return {
3737
distTags: {},
3838
published: false,
39-
version: undefined
39+
version: undefined,
40+
versions: []
4041
};
4142
}
4243

4344
return {
4445
distTags: viewResult.value?.["dist-tags"] ?? {},
4546
published: true,
46-
version: viewResult.value?.version
47+
version: viewResult.value?.version,
48+
versions: viewResult.value?.versions ?? []
4749
};
4850
};
4951

@@ -71,11 +73,21 @@ export const buildNpmPublishState = async ({
7173
);
7274
const taggedVersion = viewResult.distTags[distTag];
7375
const latestVersion = viewResult.distTags.latest;
76+
const hasStableVersion = viewResult.versions.some(
77+
(publishedVersion) => !publishedVersion.includes("-")
78+
);
7479
const hasUnexpectedLatestTag =
7580
packageInfo.publishInBeta &&
7681
distTag !== "latest" &&
7782
version.includes("-") &&
78-
latestVersion === version;
83+
latestVersion === version &&
84+
hasStableVersion;
85+
const hasForcedPreviewLatestTag =
86+
packageInfo.publishInBeta &&
87+
distTag !== "latest" &&
88+
version.includes("-") &&
89+
latestVersion === version &&
90+
!hasStableVersion;
7991

8092
let status = "pass";
8193
const expected = packageInfo.publishInBeta
@@ -95,6 +107,8 @@ export const buildNpmPublishState = async ({
95107
entries.push({
96108
distTag,
97109
expected,
110+
hasForcedPreviewLatestTag,
111+
hasStableVersion,
98112
name: packageInfo.name,
99113
publishInBeta: packageInfo.publishInBeta === true,
100114
published: viewResult.published,
@@ -142,11 +156,21 @@ const formatState = (state) => {
142156
return `- ${entry.name}@${entry.version}: ${entry.status} (${publishedText}, ${tagText}${latestText}; expected ${entry.expected})`;
143157
});
144158

159+
const forcedLatestRows = state.entries
160+
.filter((entry) => entry.hasForcedPreviewLatestTag)
161+
.map(
162+
(entry) =>
163+
`- ${entry.name}: npm keeps latest=${entry.version} because no stable version has been published yet.`
164+
);
165+
145166
return [
146167
`NPM publish state: ${state.status}`,
147168
`Version: ${state.version}`,
148169
`Dist-tag: ${state.distTag}`,
149-
...rows
170+
...rows,
171+
...(forcedLatestRows.length > 0
172+
? ["Preview latest-tag notes:", ...forcedLatestRows]
173+
: [])
150174
].join("\n");
151175
};
152176

scripts/check-npm-publish-state.test.mjs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ const createNpmView = (publishedPackages) => async ({ name, version }) => {
3737
exists: true,
3838
value: {
3939
"dist-tags": value.distTags ?? { next: version },
40-
version: value.version ?? version
40+
version: value.version ?? version,
41+
versions: value.versions ?? [value.version ?? version]
4142
}
4243
};
4344
};
@@ -111,7 +112,8 @@ describe("npm publish state checker", () => {
111112
manifest,
112113
npmView: createNpmView({
113114
"@chart-kit/core": {
114-
distTags: { latest: "7.0.0-next.0", next: "7.0.0-next.0" }
115+
distTags: { latest: "7.0.0-next.0", next: "7.0.0-next.0" },
116+
versions: ["6.12.2", "7.0.0-next.0"]
115117
},
116118
"@chart-kit/react-native": {},
117119
"react-native-chart-kit": {
@@ -129,4 +131,32 @@ describe("npm publish state checker", () => {
129131
["@chart-kit/pro", "pass"]
130132
]);
131133
});
134+
135+
it("allows npm's forced latest tag when a scoped preview package has no stable version yet", async () => {
136+
const state = await buildNpmPublishState({
137+
distTag: "next",
138+
manifest,
139+
npmView: createNpmView({
140+
"@chart-kit/core": {
141+
distTags: { latest: "7.0.0-next.0", next: "7.0.0-next.0" },
142+
versions: ["7.0.0-next.0"]
143+
},
144+
"@chart-kit/react-native": {},
145+
"react-native-chart-kit": {
146+
distTags: { latest: "6.12.2", next: "7.0.0-next.0" },
147+
versions: ["6.12.2", "7.0.0-next.0"]
148+
}
149+
}),
150+
version: "7.0.0-next.0"
151+
});
152+
153+
expect(state.status).toBe("complete");
154+
expect(state.entries.map((entry) => [entry.name, entry.status])).toEqual([
155+
["@chart-kit/core", "pass"],
156+
["@chart-kit/react-native", "pass"],
157+
["react-native-chart-kit", "pass"],
158+
["@chart-kit/pro", "pass"]
159+
]);
160+
expect(state.entries[0].hasForcedPreviewLatestTag).toBe(true);
161+
});
132162
});

0 commit comments

Comments
 (0)