From 04263c1590a846bfb27890280760b5b3692f7086 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 12 Mar 2024 17:45:35 +1100 Subject: [PATCH] Centralise versioning configuration (#176) The goal here is to centralise the logic around versions, creating a list of all the details about each version (e.g. full version number, whether it's a pre-release or unmaintained etc.), that downstream processing can reference directly rather than recompute. This, for instance, eliminates the duplicated logic around which versions are maintained. The goal here is to make changes like #174 (and maybe #159) easier. This PR doesn't/shouldn't change observable behaviour. This also removes the explicit `disableVersioning` flag, since that seems to require changing the contents of the `versions` map. Instead the existing use of `onlyIncludeVersions` seems to do what's intended: make dev builds faster. An `npm start` build takes about 10s both with the old `disableVersioning` setting, or just relying on `onlyIncludeVersions`. This includes some cut-and-paste rearrangement too that makes the diff harder to understand. The commits are individually reviewable. --- docusaurus.config.js | 173 +++++++++++++++++++++++++++++-------------- 1 file changed, 117 insertions(+), 56 deletions(-) diff --git a/docusaurus.config.js b/docusaurus.config.js index d3dbf6d1c..2dda7af78 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -11,11 +11,7 @@ import { themes as prismThemes } from "prism-react-renderer"; const organizationName = "pantsbuild"; const projectName = "pantsbuild.org"; -function getCurrentVersion() { - const lastReleasedVersion = versions[0]; - const version = parseInt(lastReleasedVersion.replace("2.", ""), 10); - return `2.${version + 1}`; -} +const numberOfSupportedStableVersions = 2; // Controls for how much to build: // - (No env vars set) -> Just uses the docs from `/docs/` (Docusaurus calls this "current version"), and no blog. @@ -23,8 +19,8 @@ function getCurrentVersion() { // - PANTSBUILD_ORG_INCLUDE_BLOG=1 -> Include the blog. // Note that `NODE_ENV === 'production' builds _everything_. const isDev = process.env.NODE_ENV === "development"; -const disableVersioning = - isDev && process.env.PANTSBUILD_ORG_INCLUDE_VERSIONS === undefined; + +// Versions const onlyIncludeVersions = isDev ? process.env.PANTSBUILD_ORG_INCLUDE_VERSIONS ? ["current"].concat( @@ -32,32 +28,23 @@ const onlyIncludeVersions = isDev ) : ["current"] : undefined; -const currentVersion = getCurrentVersion(); -const includeBlog = process.env.PANTSBUILD_ORG_INCLUDE_BLOG === "1" || !isDev; -const formatCopyright = () => { - const makeLink = (href, text) => `${text}`; - - const repoUrl = `https://github.com/${organizationName}/${projectName}`; - const repoLink = makeLink(repoUrl, "Website source"); +function getCurrentVersion() { + const lastReleasedVersion = versions[0]; + const version = parseInt(lastReleasedVersion.replace("2.", ""), 10); + return `2.${version + 1}`; +} - // Only set by CI, so fallback to just `local` for local dev - const docsCommit = process.env.GITHUB_SHA; - const commitLink = docsCommit - ? makeLink(`${repoUrl}/commit/${docsCommit}`, docsCommit.slice(0, 6)) - : "local"; +const currentVersion = getCurrentVersion(); - return `Copyright © Pants project contributors. ${repoLink} @ ${commitLink}.`; -}; +const isCurrentVersion = (shortVersion) => shortVersion === currentVersion; -const isPrerelease = (version) => { - const reference_dir = path.join( - "versioned_docs", - `version-${version}`, - "reference" - ); +const getFullVersion = (shortVersion) => { + const parentDir = isCurrentVersion(shortVersion) + ? "docs" + : path.join("versioned_docs", `version-${shortVersion}`); const helpAll = JSON.parse( - fs.readFileSync(path.join(reference_dir, "help-all.json"), "utf8") + fs.readFileSync(path.join(parentDir, "reference", "help-all.json"), "utf8") ); const pantsVersion = helpAll["scope_to_help_info"][""]["advanced"].find( @@ -68,12 +55,106 @@ const isPrerelease = (version) => { (value) => value["rank"] == "HARDCODED" ); + return hardcoded["value"]; +}; + +const isPrereleaseVersion = (fullVersion) => { // Check if it's one of xx.xx.0.dev0, xx.xx.0a0, xx.xx.0b0, xx.xx.0rc0, etc. // We don't treat patch versions pre-releases as pre-releases, since it looks weird. // Optimally we shouldn't sync those either way, but some have ended up here by accident. const rex = /^(\d+\.\d+\.0)(\.dev|a|b|rc)\d+$/; - return rex.test(hardcoded["value"]); + return rex.test(fullVersion); +}; + +const getVersionDetails = () => { + const versionDetails = []; + + let seenStableVersions = 0; + + // Construct the configuration for each version. NB. iterating from newest to oldest is important, + // to be able to label too-old stable versions as unsupported. + for (const shortVersion of [currentVersion, ...versions]) { + const fullVersion = getFullVersion(shortVersion); + + // NB. "maintained" versions includes pre-releases + const isMaintained = seenStableVersions < numberOfSupportedStableVersions; + const isPrerelease = isPrereleaseVersion(fullVersion); + const isCurrent = isCurrentVersion(shortVersion); + + // compute the appropriate configuration this version + let config; + if (isCurrent) { + // current version => dev + config = { + label: `${shortVersion} (dev)`, + }; + } else if (isPrerelease) { + // prerelease => prerelease + config = { + label: `${shortVersion} (prerelease)`, + banner: "unreleased", + noIndex: false, + }; + } else if (isMaintained) { + // a new-enough stable version => so still supported + config = { + label: shortVersion, + banner: "none", + noIndex: false, + }; + } else { + // stable, but too old => deprecated + config = { + label: `${shortVersion} (deprecated)`, + banner: "unmaintained", + noIndex: true, + }; + } + + versionDetails.push({ + shortVersion, + fullVersion, + isMaintained, + isPrerelease, + isCurrent, + config: { + ...config, + path: shortVersion, + }, + }); + + if (!isPrerelease) { + seenStableVersions += 1; + } + } + + return versionDetails; +}; + +const versionDetails = getVersionDetails(); + +const mostRecentStableVersion = versionDetails.find( + ({ isPrerelease }) => !isPrerelease +); + +// Blog +const includeBlog = process.env.PANTSBUILD_ORG_INCLUDE_BLOG === "1" || !isDev; + +// Other information +const formatCopyright = () => { + const makeLink = (href, text) => `${text}`; + + const repoUrl = `https://github.com/${organizationName}/${projectName}`; + const repoLink = makeLink(repoUrl, "Website source"); + + // Only set by CI, so fallback to just `local` for local dev + const docsCommit = process.env.GITHUB_SHA; + const commitLink = docsCommit + ? makeLink(`${repoUrl}/commit/${docsCommit}`, docsCommit.slice(0, 6)) + : "local"; + + return `Copyright © Pants project contributors. ${repoLink} @ ${commitLink}.`; }; const config = { @@ -331,36 +412,16 @@ const config = { { sidebarPath: require.resolve("./sidebars.js"), routeBasePath: "/", - disableVersioning, onlyIncludeVersions, lastVersion: onlyIncludeVersions ? undefined - : versions.find((v) => !isPrerelease(v)), - versions: { - current: { - label: `${currentVersion} (dev)`, - path: currentVersion, - }, - ...(disableVersioning - ? {} - : versions.reduce((acc, version, index) => { - acc[version] = { - label: isPrerelease(version) - ? `${version} (prerelease)` - : index < 2 + (isPrerelease(versions[0]) ? 1 : 0) - ? version - : `${version} (deprecated)`, - banner: isPrerelease(version) - ? "unreleased" - : index < 2 + (isPrerelease(versions[0]) ? 1 : 0) - ? "none" - : "unmaintained", - noIndex: index >= 2 + (isPrerelease(versions[0]) ? 1 : 0), - path: version, - }; - return acc; - }, {})), - }, + : mostRecentStableVersion.shortVersion, + versions: Object.fromEntries( + versionDetails.map(({ isCurrent, shortVersion, config }) => [ + isCurrent ? "current" : shortVersion, + config, + ]) + ), remarkPlugins: [captionedCode, tabBlocks], editUrl: ({ docPath }) => { if (docPath.startsWith("reference/")) {