mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
fix: stop amputating RC suffixes from docs URLs (#23903)
Fixes #23897 (docs link only — naming rename is in #23905) - Fix version stripping logic in both Go (`codersdk/deployment.go`) and TypeScript (`site/src/utils/docs.ts`) to preserve `-rc.X` suffixes instead of amputating them along with `-devel` - Add `v0.0.0` fallback in the TS frontend to match Go backend behavior for dev builds - Add tests covering RC, devel, and plain release version strings > 🤖 Written by a Coder Agent. Will be reviewed by a human.
This commit is contained in:
@@ -1251,7 +1251,11 @@ func DefaultSupportLinks(docsURL string) []LinkConfig {
|
||||
}
|
||||
|
||||
func removeTrailingVersionInfo(v string) string {
|
||||
return strings.Split(strings.Split(v, "-")[0], "+")[0]
|
||||
// Strip build metadata (everything after '+').
|
||||
v, _, _ = strings.Cut(v, "+")
|
||||
// Strip '-devel' suffix if present.
|
||||
v = strings.TrimSuffix(v, "-devel")
|
||||
return v
|
||||
}
|
||||
|
||||
func DefaultDocsURL() string {
|
||||
|
||||
@@ -25,10 +25,36 @@ func TestRemoveTrailingVersionInfo(t *testing.T) {
|
||||
Version: "v2.16.0+683a720-devel",
|
||||
ExpectedAfterStrippingInfo: "v2.16.0",
|
||||
},
|
||||
// RC versions: preserve the -rc.X suffix, strip build metadata.
|
||||
{
|
||||
Version: "v2.32.0-rc.1+abc123",
|
||||
ExpectedAfterStrippingInfo: "v2.32.0-rc.1",
|
||||
},
|
||||
{
|
||||
Version: "v2.32.0-rc.0",
|
||||
ExpectedAfterStrippingInfo: "v2.32.0-rc.0",
|
||||
},
|
||||
{
|
||||
Version: "v2.32.0-rc.1+683a720-devel",
|
||||
ExpectedAfterStrippingInfo: "v2.32.0-rc.1",
|
||||
},
|
||||
// Bare devel suffix, no build metadata.
|
||||
{
|
||||
Version: "v2.32.0-devel",
|
||||
ExpectedAfterStrippingInfo: "v2.32.0",
|
||||
},
|
||||
// Plain release, identity case.
|
||||
{
|
||||
Version: "v2.16.0",
|
||||
ExpectedAfterStrippingInfo: "v2.16.0",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
stripped := removeTrailingVersionInfo(tc.Version)
|
||||
require.Equal(t, tc.ExpectedAfterStrippingInfo, stripped)
|
||||
t.Run(tc.Version, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
stripped := removeTrailingVersionInfo(tc.Version)
|
||||
require.Equal(t, tc.ExpectedAfterStrippingInfo, stripped)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("defaultDocsUrl", () => {
|
||||
beforeEach(() => {
|
||||
// Reset module-level caches (CACHED_DOCS_URL in docs.ts and
|
||||
// CACHED_BUILD_INFO in buildInfo.ts) by forcing fresh imports.
|
||||
vi.resetModules();
|
||||
// Clean up meta tags from previous tests so each case starts fresh.
|
||||
document.querySelector('meta[property="docs-url"]')?.remove();
|
||||
document.querySelector('meta[property="build-info"]')?.remove();
|
||||
});
|
||||
|
||||
function setBuildInfoVersion(version: string) {
|
||||
const meta = document.createElement("meta");
|
||||
meta.setAttribute("property", "build-info");
|
||||
meta.setAttribute("content", JSON.stringify({ version }));
|
||||
document.head.appendChild(meta);
|
||||
}
|
||||
|
||||
async function getDocsUrl(path: string): Promise<string> {
|
||||
// Dynamic import so we get a fresh module with cleared caches.
|
||||
const { docs } = await import("./docs");
|
||||
return docs(path);
|
||||
}
|
||||
|
||||
it("should preserve RC prerelease and strip build metadata", async () => {
|
||||
setBuildInfoVersion("v2.32.0-rc.1+abc123");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/@v2.32.0-rc.1/admin/users");
|
||||
});
|
||||
|
||||
it("should preserve RC prerelease when no build metadata present", async () => {
|
||||
setBuildInfoVersion("v2.32.0-rc.0");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/@v2.32.0-rc.0/admin/users");
|
||||
});
|
||||
|
||||
it("should strip devel suffix and build metadata", async () => {
|
||||
setBuildInfoVersion("v2.16.0-devel+683a720");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/@v2.16.0/admin/users");
|
||||
});
|
||||
|
||||
it("should strip build metadata from release version", async () => {
|
||||
setBuildInfoVersion("v2.16.0+683a720");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/@v2.16.0/admin/users");
|
||||
});
|
||||
|
||||
it("should strip bare devel suffix with no build metadata", async () => {
|
||||
setBuildInfoVersion("v2.32.0-devel");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/@v2.32.0/admin/users");
|
||||
});
|
||||
|
||||
it("should use plain release version as-is", async () => {
|
||||
setBuildInfoVersion("v2.16.0");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/@v2.16.0/admin/users");
|
||||
});
|
||||
|
||||
it("should produce unversioned URL for v0.0.0 dev builds", async () => {
|
||||
setBuildInfoVersion("v0.0.0-devel+abc123");
|
||||
const url = await getDocsUrl("/admin/users");
|
||||
expect(url).toBe("https://coder.com/docs/admin/users");
|
||||
});
|
||||
});
|
||||
@@ -8,10 +8,12 @@ function defaultDocsUrl(): string {
|
||||
return docsUrl;
|
||||
}
|
||||
|
||||
// Strip the postfix version info that's not part of the link.
|
||||
const i = version?.match(/[+-]/)?.index ?? -1;
|
||||
if (i >= 0) {
|
||||
version = version.slice(0, i);
|
||||
// Strip build metadata after '+', then remove a '-devel' suffix
|
||||
// if present. Preserve '-rc.X' suffixes so versioned docs links
|
||||
// point at the correct release candidate.
|
||||
version = version.split("+")[0].replace(/-devel$/, "");
|
||||
if (version === "v0.0.0") {
|
||||
return docsUrl;
|
||||
}
|
||||
return `${docsUrl}/@${version}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user