Skip to content

Commit

Permalink
docs: add versioning logic to partials DOC-1198 (#3035) (#3066)
Browse files Browse the repository at this point in the history
(cherry picked from commit 9319edf)

Co-authored-by: Adelina Simion <[email protected]>
  • Loading branch information
1 parent 4c6a8f4 commit 7f9505b
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,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/
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -561,13 +561,16 @@ category and name of the partial:
```md
<PartialsComponent
category="public-cloud"
name="palette-setup"
cloud="AWS"
category="example-cat"
name="example-name"
message="Hello!"
/>
```
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
Expand Down
6 changes: 5 additions & 1 deletion scripts/generate-partials.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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."
10 changes: 10 additions & 0 deletions scripts/versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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/
Expand All @@ -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
Expand Down
16 changes: 16 additions & 0 deletions src/components/PartialsComponent/GetAllVersions.tsx
Original file line number Diff line number Diff line change
@@ -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"];
}
10 changes: 10 additions & 0 deletions src/components/PartialsComponent/GetVersion.tsx
Original file line number Diff line number Diff line change
@@ -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 "";
}
Original file line number Diff line number Diff line change
@@ -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<{}> = ({}) => (
<div>
<p>{category}</p>
<p>{name}</p>
<p>{propValue}</p>
</div>
);

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(<PartialsComponent category={category} name={name} propTest={propValue} />);
expect(screen.getByText(category)).toBeInTheDocument();
expect(screen.getByText(name)).toBeInTheDocument();
expect(screen.getByText(propValue)).toBeInTheDocument();
});

it("partial does not exist", () => {
expect(() => render(<PartialsComponent category="unknownCat" name="unknownName" propTest={propValue} />)).toThrow(
"No partial found for name unknownName in category unknownCat for version 4.3.x."
);
});
});
16 changes: 11 additions & 5 deletions src/components/PartialsComponent/PartialsComponent.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
});
});

Expand All @@ -35,7 +41,7 @@ describe("Partials Component", () => {

it("partial does not exist", () => {
expect(() => render(<PartialsComponent category="unknownCat" name="unknownName" propTest={propValue} />)).toThrow(
"No partial found for name unknownName in category unknownCat."
"No partial found for name unknownName in category unknownCat for version current."
);
});
});
31 changes: 27 additions & 4 deletions src/components/PartialsComponent/PartialsComponent.tsx
Original file line number Diff line number Diff line change
@@ -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(".")
);
}

Expand All @@ -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);
}
49 changes: 42 additions & 7 deletions src/components/PartialsComponent/PartialsImporter.tsx
Original file line number Diff line number Diff line change
@@ -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;
}

Expand All @@ -20,26 +19,62 @@ 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;

if (!catFrontMatter || !nameFrontMatter) {
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(".")
);
}
Expand Down

0 comments on commit 7f9505b

Please sign in to comment.