From 9319edfe72fce92577b16b06be41248b4ac4d132 Mon Sep 17 00:00:00 2001
From: Adelina Simion <43963729+addetz@users.noreply.github.com>
Date: Wed, 12 Jun 2024 19:24:41 +0200
Subject: [PATCH] docs: add versioning logic to partials DOC-1198 (#3035)
---
.gitignore | 1 +
Makefile | 2 +-
README.md | 11 +++--
scripts/generate-partials.sh | 6 ++-
scripts/versions.sh | 10 ++++
.../PartialsComponent/GetAllVersions.tsx | 16 ++++++
.../PartialsComponent/GetVersion.tsx | 10 ++++
.../PartialsComponent-Versioned.test.tsx | 47 ++++++++++++++++++
.../PartialsComponent.test.tsx | 16 ++++--
.../PartialsComponent/PartialsComponent.tsx | 31 ++++++++++--
.../PartialsComponent/PartialsImporter.tsx | 49 ++++++++++++++++---
11 files changed, 177 insertions(+), 22 deletions(-)
create mode 100644 src/components/PartialsComponent/GetAllVersions.tsx
create mode 100644 src/components/PartialsComponent/GetVersion.tsx
create mode 100644 src/components/PartialsComponent/PartialsComponent-Versioned.test.tsx
diff --git a/.gitignore b/.gitignore
index 0b62a66222..2ca1efff5e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -44,6 +44,7 @@ docs/api-content/api-docs/edge-v1/sidebar.*
versions.json
versioned_docs/
versioned_sidebars/
+versioned_partials/
api_versions.json
api_versioned_docs/
api_versioned_sidebars/
diff --git a/Makefile b/Makefile
index 53ee1da193..89160dcfac 100644
--- a/Makefile
+++ b/Makefile
@@ -35,7 +35,7 @@ deep-clean: ## Clean all artifacts
clean-versions: ## Clean Docusarus content versions
@echo "cleaning versions"
- rm -rf api_versions.json versions.json versioned_docs versioned_sidebars api_versioned_sidebars api_versioned_docs
+ rm -rf api_versions.json versions.json versioned_docs versioned_sidebars api_versioned_sidebars api_versioned_docs versioned_partials
git checkout -- docusaurus.config.js static/robots.txt
clean-api: ## Clean API docs
diff --git a/README.md b/README.md
index 0cc8232b57..7fe0feb179 100644
--- a/README.md
+++ b/README.md
@@ -585,13 +585,16 @@ category and name of the partial:
```md
```
-Note that the `cloud` field corresponds to the `{props.cloud}` reference in the `*.mdx` file.
+The snippet above will work with the example partial we have in our repository, so you can use it for testing.
+
+Note that the `message` field corresponds to the `{props.message}` reference in the `_partials/_partial_example.mdx`
+file.
### Internal Links
diff --git a/scripts/generate-partials.sh b/scripts/generate-partials.sh
index a2e14dc9ee..12968d7c84 100755
--- a/scripts/generate-partials.sh
+++ b/scripts/generate-partials.sh
@@ -12,6 +12,9 @@ rm -f _partials/index.ts
mkdir -p _partials
touch _partials/index.ts
+# Make the versioned partials folder to satisfy compiler.
+mkdir -p versioned_partials
+
# Create the file and add the generated warning.
echo "// This file is generated. DO NOT EDIT!" >> _partials/index.ts
@@ -20,7 +23,8 @@ echo "// This file is generated. DO NOT EDIT!" >> _partials/index.ts
find _partials -name "*.mdx" -print0 | while read -d $'\0' path
do
module_name=$(basename ${path} .mdx | tr -d '_' | tr -d '-')
- echo "export * as ${module_name}${RANDOM} from '@site/${path}';" >> _partials/index.ts
+ file_name=$(basename ${path})
+ echo "export * as ${module_name}${RANDOM} from './${file_name}';" >> _partials/index.ts
done
echo "Completed generation of _partials/index.ts."
diff --git a/scripts/versions.sh b/scripts/versions.sh
index b03dae2712..f6070c0f5c 100755
--- a/scripts/versions.sh
+++ b/scripts/versions.sh
@@ -53,12 +53,15 @@ for b in $branches; do
git fetch origin $b:$b
done
+# Make sure we are in a clean state for repeatable runs.
+make clean-versions
# Remove the existing versioned directories in the temp directory.
rm -rf $tempdir/staging_docs
rm -rf $tempdir/staging_api_docs
rm -rf $tempdir/staging_sidebars
rm -rf $tempdir/staging_api_docs_sidebars
+rm -rf $tempdir/staging_partials
rm -rf $tempdir/temp_versions.json
rm -rf $tempdir/temp_api_versions.json
@@ -68,6 +71,7 @@ mkdir -p $tempdir/staging_docs
mkdir -p $tempdir/staging_api_docs
mkdir -p $tempdir/staging_sidebars
mkdir -p $tempdir/staging_api_docs_sidebars
+mkdir -p $tempdir/staging_partials
touch $tempdir/temp_versions.json
touch $tempdir/temp_api_versions.json
echo '[]' > $tempdir/temp_versions.json # Initialize as an empty array if it doesn't exist
@@ -119,6 +123,9 @@ for item in $(git branch --format '%(refname:short)'); do
# Pull the latest changes
git pull origin $item
+ # Generate the partials once we are on the version branch
+ make generate-partials
+
# Run the npm command
echo "Running: npm run docusaurus docs:version $extracted_versionX"
npm run docusaurus docs:version $extracted_versionX
@@ -139,6 +146,8 @@ for item in $(git branch --format '%(refname:short)'); do
cp -R api_versioned_docs/version-$extracted_versionX $tempdir/staging_api_docs/
cp -R api_versioned_sidebars/version-$extracted_versionX $tempdir/staging_api_docs_sidebars/ || true
cp api_versioned_sidebars/version-$extracted_versionX-sidebars.json $tempdir/staging_api_docs_sidebars/version-$extracted_versionX-sidebars.json
+ # Copy the partials folder
+ cp -R _partials $tempdir/staging_partials/version-$extracted_versionX
rm -rf versioned_docs/
@@ -163,6 +172,7 @@ cp -R $tempdir/staging_docs $baseDir/versioned_docs
cp -R $tempdir/staging_sidebars $baseDir/versioned_sidebars
cp -R $tempdir/staging_api_docs $baseDir/api_versioned_docs
cp -R $tempdir/staging_api_docs_sidebars $baseDir/api_versioned_sidebars
+cp -R $tempdir/staging_partials/. $baseDir/versioned_partials
# Remove the existing versions.json if it exists
[ -e versions.json ] && rm versions.json
diff --git a/src/components/PartialsComponent/GetAllVersions.tsx b/src/components/PartialsComponent/GetAllVersions.tsx
new file mode 100644
index 0000000000..b356171045
--- /dev/null
+++ b/src/components/PartialsComponent/GetAllVersions.tsx
@@ -0,0 +1,16 @@
+import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
+import { Config } from "@docusaurus/types";
+
+export default function GetVersions(): string[] {
+ const { siteConfig } = useDocusaurusContext();
+ const cfg = siteConfig as Config;
+ if (cfg.presets != undefined) {
+ // Linting is disabled for next line, as there is no type for docs config.
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-argument
+ const versions = cfg.presets[0][1]["docs"]["versions"] as object;
+ const versionNames: string[] = Object.keys(versions);
+ return versionNames;
+ }
+ // if no presets, then default to "current"
+ return ["current"];
+}
diff --git a/src/components/PartialsComponent/GetVersion.tsx b/src/components/PartialsComponent/GetVersion.tsx
new file mode 100644
index 0000000000..7087305f99
--- /dev/null
+++ b/src/components/PartialsComponent/GetVersion.tsx
@@ -0,0 +1,10 @@
+import { useActivePluginAndVersion } from "@docusaurus/plugin-content-docs/client";
+
+export default function GetVersion(): string {
+ const activePlugin = useActivePluginAndVersion();
+ if (activePlugin != undefined && activePlugin.activeVersion != undefined) {
+ return activePlugin.activeVersion.name;
+ }
+
+ return "";
+}
diff --git a/src/components/PartialsComponent/PartialsComponent-Versioned.test.tsx b/src/components/PartialsComponent/PartialsComponent-Versioned.test.tsx
new file mode 100644
index 0000000000..35664bbdca
--- /dev/null
+++ b/src/components/PartialsComponent/PartialsComponent-Versioned.test.tsx
@@ -0,0 +1,47 @@
+import React, { FunctionComponent } from "react";
+import { render, screen } from "@testing-library/react";
+
+let category = "testCat1";
+let name = "nameCat1";
+let propValue = "testValue1";
+
+const Partial: React.FunctionComponent<{}> = ({}) => (
+
+
{category}
+
{name}
+
{propValue}
+
+);
+
+jest.mock("./PartialsImporter", () => {
+ return jest.fn(() => {
+ const allPartials: PartialsMap = {};
+ const mapKey = "version-4.3.x".concat("#").concat(category).concat("#").concat(name);
+ allPartials[mapKey] = Partial as FunctionComponent;
+ return allPartials;
+ });
+});
+
+jest.mock("./GetVersion", () => {
+ return jest.fn(() => {
+ return "4.3.x";
+ });
+});
+
+import PartialsComponent from "./PartialsComponent";
+import { PartialsMap } from "./PartialsImporter";
+
+describe("Partials Component", () => {
+ it("partial exists", () => {
+ render();
+ expect(screen.getByText(category)).toBeInTheDocument();
+ expect(screen.getByText(name)).toBeInTheDocument();
+ expect(screen.getByText(propValue)).toBeInTheDocument();
+ });
+
+ it("partial does not exist", () => {
+ expect(() => render()).toThrow(
+ "No partial found for name unknownName in category unknownCat for version 4.3.x."
+ );
+ });
+});
diff --git a/src/components/PartialsComponent/PartialsComponent.test.tsx b/src/components/PartialsComponent/PartialsComponent.test.tsx
index ca1588ab16..6f1d8ad8f6 100644
--- a/src/components/PartialsComponent/PartialsComponent.test.tsx
+++ b/src/components/PartialsComponent/PartialsComponent.test.tsx
@@ -15,10 +15,16 @@ const Partial: React.FunctionComponent<{}> = ({}) => (
jest.mock("./PartialsImporter", () => {
return jest.fn(() => {
- const mapKey = category.concat("#").concat(name);
- const pmap: PartialsMap = {};
- pmap[mapKey] = Partial as FunctionComponent;
- return pmap;
+ const allPartials: PartialsMap = {};
+ const mapKey = "current".concat("#").concat(category).concat("#").concat(name);
+ allPartials[mapKey] = Partial as FunctionComponent;
+ return allPartials;
+ });
+});
+
+jest.mock("./GetVersion", () => {
+ return jest.fn(() => {
+ return "current";
});
});
@@ -35,7 +41,7 @@ describe("Partials Component", () => {
it("partial does not exist", () => {
expect(() => render()).toThrow(
- "No partial found for name unknownName in category unknownCat."
+ "No partial found for name unknownName in category unknownCat for version current."
);
});
});
diff --git a/src/components/PartialsComponent/PartialsComponent.tsx b/src/components/PartialsComponent/PartialsComponent.tsx
index 3c5b180109..5e344ca134 100644
--- a/src/components/PartialsComponent/PartialsComponent.tsx
+++ b/src/components/PartialsComponent/PartialsComponent.tsx
@@ -1,18 +1,34 @@
import React from "react";
-import ImportPartials from "./PartialsImporter";
+import ImportPartials, { PartialsMap } from "./PartialsImporter";
+import GetVersion from "./GetVersion";
interface ComponentProperties {
[key: string]: string;
}
-const AllPartials = ImportPartials();
+let AllPartials: PartialsMap = {};
+let firstLoad = true;
export default function PartialsComponent(details: ComponentProperties): React.ReactElement {
- const mapKey = details.category.concat("#").concat(details.name);
+ // Hooks can only be invoked inside the body of the component, so we cannot load this beforehand.
+ if (firstLoad) {
+ AllPartials = ImportPartials();
+ firstLoad = false;
+ }
+ // Get the version this page is on.
+ const ver: string = GetVersion();
+ // Construct the map key including the version
+ const mapKey = getMapKey(ver, details.category, details.name);
if (!AllPartials[mapKey]) {
throw new Error(
- "No partial found for name ".concat(details.name).concat(" in category ").concat(details.category).concat(".")
+ "No partial found for name "
+ .concat(details.name)
+ .concat(" in category ")
+ .concat(details.category)
+ .concat(" for version ")
+ .concat(ver)
+ .concat(".")
);
}
@@ -28,3 +44,10 @@ export default function PartialsComponent(details: ComponentProperties): React.R
return React.createElement(AllPartials[mapKey], propAttribute);
}
+
+function getMapKey(ver: string, category: string, name: string): string {
+ if (ver == "current") {
+ return ver.concat("#").concat(category).concat("#").concat(name);
+ }
+ return "version-".concat(ver).concat("#").concat(category).concat("#").concat(name);
+}
diff --git a/src/components/PartialsComponent/PartialsImporter.tsx b/src/components/PartialsComponent/PartialsImporter.tsx
index b9441d67a7..7f05b8893c 100644
--- a/src/components/PartialsComponent/PartialsImporter.tsx
+++ b/src/components/PartialsComponent/PartialsImporter.tsx
@@ -1,12 +1,11 @@
import { FunctionComponent } from "react";
-// Import all the partials as one module.
-import * as PartialModules from "@site/_partials";
+import GetAllVersions from "./GetAllVersions";
export interface PartialsMap {
[key: string]: FunctionComponent;
}
-interface Modules {
+export interface Modules {
[key: string]: Module;
}
@@ -20,12 +19,46 @@ interface Module {
export default function ImportPartials(): PartialsMap {
const pmap: PartialsMap = {};
- const allPartialModules: Modules = PartialModules;
+ const versions: string[] = GetAllVersions();
+ versions.map((ver) => {
+ if (ver == "current") {
+ importLatestHelper(ver, pmap);
+ } else {
+ //Import all the versioned partials if this is the first time we visit this version.
+ importVersionedHelper("version-" + ver, pmap);
+ }
+ });
+
+ return pmap;
+}
+
+function importLatestHelper(prefix: string, existingPartials: PartialsMap) {
+ try {
+ // Linting is disabled for next line, as we need the ability to dynamically import partials.
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const modules: Modules = require("@site/_partials");
+ MapPartials(prefix, modules, existingPartials);
+ } catch {
+ console.log("No partials found for " + prefix + ". Skipping imports for it.");
+ }
+}
+
+function importVersionedHelper(prefix: string, existingPartials: PartialsMap) {
+ try {
+ // Linting is disabled for next line, as we need the ability to dynamically import partials.
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
+ const modules: Modules = require("@site/versioned_partials/" + prefix + "/");
+ MapPartials(prefix, modules, existingPartials);
+ } catch {
+ console.log("No partials found for " + prefix + ". Skipping imports for it.");
+ }
+}
+export function MapPartials(ver: string, module: Modules, pmap: PartialsMap) {
// The keys are the names of each exported module in _partials/index.ts
- const partialKeys: string[] = Object.keys(allPartialModules);
+ const partialKeys: string[] = Object.keys(module);
partialKeys.map(function (pkey) {
- const currentPartial: Module = allPartialModules[pkey];
+ const currentPartial: Module = module[pkey];
const catFrontMatter = currentPartial.frontMatter.partial_category;
const nameFrontMatter = currentPartial.frontMatter.partial_name;
@@ -33,13 +66,15 @@ export default function ImportPartials(): PartialsMap {
throw new Error("Please specify partial_category and partial_name for ".concat(pkey).concat("."));
}
- const mapKey = catFrontMatter.concat("#").concat(nameFrontMatter);
+ const mapKey = ver.concat("#").concat(catFrontMatter).concat("#").concat(nameFrontMatter);
if (pmap[mapKey]) {
throw new Error(
"Duplicate partial defined for name "
.concat(nameFrontMatter)
.concat(" in category ")
.concat(catFrontMatter)
+ .concat("for version")
+ .concat(ver)
.concat(".")
);
}