Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[version-3-4] docs: add versioning logic to partials DOC-1198 (#3035) #3067

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading