Add historical redirects file (#1780)
Adds a file (and generation script) that links pages in historical API docs to pages in the latest API docs. The banner we show on historical docs pages can use this to link users to a more relevant page in the latest docs, rather than always linking to the top level. The file has the following form. ```json { "package-name": { "version": { "old.page.name": "new.page.name", } } } ``` If a page has no entry in the redirects file, we default to redirecting to the same page in the latest API docs. E.g. `/api/qiskit/0.33/qiskit.dagcircuit.DAGCircuit` will link to `/api/qiskit/qiskit.dagcircuit.DAGCircuit`. This PR only checks if a page with the same name exists in the latest API docs and redirects to the top level if it does not. A follow up PR could include more complicated logic to track moved classes or point to module names when the class is removed. <details><summary><b>Stats</b></summary> Here are some stats to give an idea of how many pages this affects. In total, 35% of historical API pages have a corresponding page in the latest API versions. Looking at the breakdown per version, the majority of recent pages will link to a more helpful page. The rest will behave the same as before. | Package | Page matches | |---------|--------------| | qiskit-ibm-provider/0.10 | 100% | | qiskit-ibm-provider/0.7 | 100% | | qiskit-ibm-provider/0.8 | 100% | | qiskit-ibm-provider/0.9 | 100% | | qiskit-ibm-runtime/0.14 | 90% | | qiskit-ibm-runtime/0.15 | 90% | | qiskit-ibm-runtime/0.16 | 100% | | qiskit-ibm-runtime/0.17 | 100% | | qiskit-ibm-runtime/0.18 | 98% | | qiskit-ibm-runtime/0.19 | 98% | | qiskit-ibm-runtime/0.20 | 98% | | qiskit-ibm-runtime/0.21 | 99% | | qiskit-ibm-runtime/0.22 | 99% | | qiskit-ibm-runtime/0.23 | 100% | | qiskit-ibm-runtime/0.24 | 100% | | qiskit-ibm-runtime/dev | 100% | | qiskit/0.19 | 23% | | qiskit/0.24 | 23% | | qiskit/0.25 | 20% | | qiskit/0.26 | 20% | | qiskit/0.27 | 20% | | qiskit/0.28 | 21% | | qiskit/0.29 | 21% | | qiskit/0.30 | 21% | | qiskit/0.31 | 21% | | qiskit/0.32 | 21% | | qiskit/0.33 | 33% | | qiskit/0.35 | 34% | | qiskit/0.36 | 34% | | qiskit/0.37 | 34% | | qiskit/0.38 | 34% | | qiskit/0.39 | 34% | | qiskit/0.40 | 33% | | qiskit/0.41 | 33% | | qiskit/0.42 | 33% | | qiskit/0.43 | 39% | | qiskit/0.44 | 53% | | qiskit/0.45 | 56% | | qiskit/0.46 | 57% | | qiskit/1.0 | 97% | | qiskit/dev | 100% | </details> --------- Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
This commit is contained in:
parent
95e358537e
commit
60c437d9e5
|
@ -29,6 +29,7 @@
|
|||
"regen-apis": "tsx scripts/js/commands/api/regenerateApiDocs.ts",
|
||||
"gen-api": "tsx scripts/js/commands/api/updateApiDocs.ts",
|
||||
"make-historical": "tsx scripts/js/commands/api/convertApiDocsToHistorical.ts",
|
||||
"generate-historical-redirects": "tsx scripts/js/commands/api/generateHistoricalRedirects.ts",
|
||||
"save-internal-links": "tsx scripts/js/commands/saveInternalLinks.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -21,6 +21,7 @@ import transformLinks from "transform-markdown-links";
|
|||
import { pathExists } from "../../lib/fs.js";
|
||||
import { zxMain } from "../../lib/zx.js";
|
||||
import { Pkg } from "../../lib/api/Pkg.js";
|
||||
import { generateHistoricalRedirects } from "./generateHistoricalRedirects.js";
|
||||
|
||||
interface Arguments {
|
||||
[x: string]: unknown;
|
||||
|
@ -75,6 +76,7 @@ zxMain(async () => {
|
|||
);
|
||||
await copyImages(pkgName, versionWithoutPatch);
|
||||
await copyObjectsInv(pkgName, versionWithoutPatch);
|
||||
await generateHistoricalRedirects();
|
||||
});
|
||||
|
||||
async function copyApiDocsAndUpdateLinks(
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
// This code is a Qiskit project.
|
||||
//
|
||||
// (C) Copyright IBM 2024.
|
||||
//
|
||||
// This code is licensed under the Apache License, Version 2.0. You may
|
||||
// obtain a copy of this license in the LICENSE file in the root directory
|
||||
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// Any modifications or derivative works of this code must retain this
|
||||
// copyright notice, and modified files need to carry a notice indicating
|
||||
// that they have been altered from the originals.
|
||||
|
||||
import { readdir, writeFile } from "fs/promises";
|
||||
import { basename, join } from "path";
|
||||
|
||||
import { Pkg } from "../../lib/api/Pkg.js";
|
||||
import { zxMain } from "../../lib/zx.js";
|
||||
import { removeSuffix } from "../../lib/stringUtils.js";
|
||||
|
||||
const OUTPUT_FILE = "./scripts/config/historical-pages-to-latest.json";
|
||||
|
||||
zxMain(async () => {
|
||||
await generateHistoricalRedirects();
|
||||
});
|
||||
|
||||
export async function generateHistoricalRedirects(): Promise<void> {
|
||||
console.log(`Generating ${OUTPUT_FILE}`);
|
||||
const redirectData: HistoricalRedirectData = {};
|
||||
for (const packageName of Pkg.VALID_NAMES) {
|
||||
redirectData[packageName] = await getRedirectsForPackage(
|
||||
join("docs/api", packageName),
|
||||
);
|
||||
}
|
||||
await writeFile(OUTPUT_FILE, JSON.stringify(redirectData, null, 2) + "\n");
|
||||
}
|
||||
/**
|
||||
* E.g.
|
||||
* {
|
||||
* "qiskit": {
|
||||
* "0.44": {
|
||||
* "qiskit.opflow.evolutions.TrotterizationBase": "/",
|
||||
* ...
|
||||
* }
|
||||
* ...
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
type HistoricalRedirectData = {
|
||||
[packageName: string]: {
|
||||
[version: string]: Redirects;
|
||||
};
|
||||
};
|
||||
|
||||
type Redirects = {
|
||||
// Key ("from") is page relative to old version (e.g. qiskit.opflow.evolutions.TrotterizationBase).
|
||||
// Value is new page relative to latest version (e.g. "/")
|
||||
// If redirect does not exist, we assume "to" and "from" are the same
|
||||
[from: string]: string;
|
||||
};
|
||||
|
||||
async function getRedirectsForPackage(
|
||||
packagePath: string,
|
||||
): Promise<{ [version: string]: Redirects }> {
|
||||
const latestPages: string[] = [];
|
||||
const versionPaths: string[] = [];
|
||||
for (const entry of await readdir(packagePath, { withFileTypes: true })) {
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name.endsWith("release-notes")) continue;
|
||||
versionPaths.push(entry.name);
|
||||
} else {
|
||||
latestPages.push(entry.name);
|
||||
}
|
||||
}
|
||||
const redirectsByVersion: { [api: string]: Redirects } = {};
|
||||
for (const path of versionPaths) {
|
||||
const version = basename(path);
|
||||
redirectsByVersion[version] = await getRedirectsForVersion(
|
||||
join(packagePath, path),
|
||||
latestPages,
|
||||
);
|
||||
}
|
||||
return redirectsByVersion;
|
||||
}
|
||||
|
||||
async function getRedirectsForVersion(
|
||||
versionPath: string,
|
||||
latestPages: string[],
|
||||
): Promise<Redirects> {
|
||||
const mdPaths = await readdir(versionPath);
|
||||
const redirects: { [from: string]: string } = {};
|
||||
for (const path of mdPaths) {
|
||||
if (latestPages.includes(basename(path))) {
|
||||
continue;
|
||||
}
|
||||
// For now, we always redirect to the top level. Future improvements could
|
||||
// try to identify the module name and redirect there if it exists.
|
||||
const pageName = removeSuffix(basename(path), ".mdx");
|
||||
redirects[pageName] = "/";
|
||||
}
|
||||
return redirects;
|
||||
}
|
|
@ -19,6 +19,7 @@ import { $ } from "zx";
|
|||
import { Pkg } from "../../lib/api/Pkg.js";
|
||||
import { zxMain } from "../../lib/zx.js";
|
||||
import { pathExists } from "../../lib/fs.js";
|
||||
import { generateHistoricalRedirects } from "./generateHistoricalRedirects.js";
|
||||
|
||||
interface Arguments {
|
||||
[x: string]: unknown;
|
||||
|
@ -82,6 +83,7 @@ zxMain(async () => {
|
|||
result.forEach((msg) => console.error(msg));
|
||||
console.log("");
|
||||
});
|
||||
await generateHistoricalRedirects();
|
||||
|
||||
console.log(`Each regenerated version has been saved as a distinct commit. If the changes are
|
||||
too large for one single PR, consider splitting it up into multiple PRs by using
|
||||
|
|
|
@ -18,6 +18,7 @@ import { zxMain } from "../../lib/zx.js";
|
|||
import { pathExists, rmFilesInFolder } from "../../lib/fs.js";
|
||||
import { downloadSphinxArtifact } from "../../lib/api/sphinxArtifacts.js";
|
||||
import { runConversionPipeline } from "../../lib/api/conversionPipeline.js";
|
||||
import { generateHistoricalRedirects } from "./generateHistoricalRedirects.js";
|
||||
|
||||
interface Arguments {
|
||||
[x: string]: unknown;
|
||||
|
@ -95,6 +96,7 @@ zxMain(async () => {
|
|||
|
||||
console.log(`Run pipeline for ${pkg.name}:${pkg.versionWithoutPatch}`);
|
||||
await runConversionPipeline(sphinxArtifactFolder, "docs", "public", pkg);
|
||||
await generateHistoricalRedirects();
|
||||
});
|
||||
|
||||
function determineMinorVersion(args: Arguments): string {
|
||||
|
|
Loading…
Reference in New Issue