Allow running the conversion pipeline in arbitrary locations (#959)
Part of https://github.com/Qiskit/documentation/issues/715. Before, we assumed a certain folder structure for the conversion pipeline. Now, you can set up the pipeline to run anywhere, such as a tmpdir.
This commit is contained in:
parent
aaec587777
commit
be142f5c0e
|
@ -10,13 +10,12 @@
|
||||||
// copyright notice, and modified files need to carry a notice indicating
|
// copyright notice, and modified files need to carry a notice indicating
|
||||||
// that they have been altered from the originals.
|
// that they have been altered from the originals.
|
||||||
|
|
||||||
import { mkdirp } from "mkdirp";
|
|
||||||
import yargs from "yargs/yargs";
|
import yargs from "yargs/yargs";
|
||||||
import { hideBin } from "yargs/helpers";
|
import { hideBin } from "yargs/helpers";
|
||||||
|
|
||||||
import { Pkg } from "../lib/api/Pkg";
|
import { Pkg } from "../lib/api/Pkg";
|
||||||
import { zxMain } from "../lib/zx";
|
import { zxMain } from "../lib/zx";
|
||||||
import { pathExists, getRoot, rmFilesInFolder } from "../lib/fs";
|
import { pathExists, rmFilesInFolder } from "../lib/fs";
|
||||||
import { downloadSphinxArtifact } from "../lib/api/sphinxArtifacts";
|
import { downloadSphinxArtifact } from "../lib/api/sphinxArtifacts";
|
||||||
import { runConversionPipeline } from "../lib/api/conversionPipeline";
|
import { runConversionPipeline } from "../lib/api/conversionPipeline";
|
||||||
|
|
||||||
|
@ -83,12 +82,13 @@ zxMain(async () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
const sphinxArtifactFolder = await prepareSphinxFolder(pkg, args);
|
const sphinxArtifactFolder = await prepareSphinxFolder(pkg, args);
|
||||||
const markdownOutputFolder = await prepareMarkdownOutputFolder(pkg);
|
await deleteExistingMarkdown(pkg);
|
||||||
|
|
||||||
console.log(`Run pipeline for ${pkg.name}:${pkg.versionWithoutPatch}`);
|
console.log(`Run pipeline for ${pkg.name}:${pkg.versionWithoutPatch}`);
|
||||||
await runConversionPipeline(
|
await runConversionPipeline(
|
||||||
`${sphinxArtifactFolder}/artifact`,
|
`${sphinxArtifactFolder}/artifact`,
|
||||||
markdownOutputFolder,
|
"docs",
|
||||||
|
"public",
|
||||||
pkg,
|
pkg,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -126,15 +126,12 @@ async function prepareSphinxFolder(pkg: Pkg, args: Arguments): Promise<string> {
|
||||||
return sphinxArtifactFolder;
|
return sphinxArtifactFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function prepareMarkdownOutputFolder(pkg: Pkg): Promise<string> {
|
async function deleteExistingMarkdown(pkg: Pkg): Promise<void> {
|
||||||
const outputDir = pkg.outputDir(`${getRoot()}/docs`);
|
const markdownDir = pkg.outputDir("docs");
|
||||||
if (!pkg.isLatest() && !(await pathExists(outputDir))) {
|
if (pkg.isLatest() || (await pathExists(markdownDir))) {
|
||||||
await mkdirp(outputDir);
|
|
||||||
} else {
|
|
||||||
console.log(
|
console.log(
|
||||||
`Deleting existing markdown for ${pkg.name}:${pkg.versionWithoutPatch}`,
|
`Deleting existing markdown for ${pkg.name}:${pkg.versionWithoutPatch}`,
|
||||||
);
|
);
|
||||||
await rmFilesInFolder(outputDir);
|
await rmFilesInFolder(markdownDir);
|
||||||
}
|
}
|
||||||
return outputDir;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
import { join, parse, relative } from "path";
|
import { join, parse, relative } from "path";
|
||||||
import { readFile, writeFile } from "fs/promises";
|
import { readFile, writeFile } from "fs/promises";
|
||||||
|
|
||||||
|
import { mkdirp } from "mkdirp";
|
||||||
import { globby } from "globby";
|
import { globby } from "globby";
|
||||||
import { uniqBy } from "lodash";
|
import { uniqBy } from "lodash";
|
||||||
import transformLinks from "transform-markdown-links";
|
import transformLinks from "transform-markdown-links";
|
||||||
|
@ -29,7 +30,7 @@ import { specialCaseResults } from "./specialCaseResults";
|
||||||
import addFrontMatter from "./addFrontMatter";
|
import addFrontMatter from "./addFrontMatter";
|
||||||
import { dedupeHtmlIdsFromResults } from "./dedupeHtmlIds";
|
import { dedupeHtmlIdsFromResults } from "./dedupeHtmlIds";
|
||||||
import { Pkg } from "./Pkg";
|
import { Pkg } from "./Pkg";
|
||||||
import { pathExists, getRoot } from "../fs";
|
import { pathExists } from "../fs";
|
||||||
import {
|
import {
|
||||||
addNewReleaseNotes,
|
addNewReleaseNotes,
|
||||||
generateReleaseNotesIndex,
|
generateReleaseNotesIndex,
|
||||||
|
@ -39,13 +40,19 @@ import {
|
||||||
|
|
||||||
export async function runConversionPipeline(
|
export async function runConversionPipeline(
|
||||||
htmlPath: string,
|
htmlPath: string,
|
||||||
markdownPath: string,
|
docsBaseFolder: string,
|
||||||
|
publicBaseFolder: string,
|
||||||
pkg: Pkg,
|
pkg: Pkg,
|
||||||
) {
|
) {
|
||||||
const [files, maybeObjectsInv] = await determineFilePaths(htmlPath, pkg);
|
const [files, markdownPath, maybeObjectsInv] = await determineFilePaths(
|
||||||
|
htmlPath,
|
||||||
|
docsBaseFolder,
|
||||||
|
pkg,
|
||||||
|
);
|
||||||
let initialResults = await convertFilesToMarkdown(
|
let initialResults = await convertFilesToMarkdown(
|
||||||
pkg,
|
pkg,
|
||||||
htmlPath,
|
htmlPath,
|
||||||
|
docsBaseFolder,
|
||||||
markdownPath,
|
markdownPath,
|
||||||
files,
|
files,
|
||||||
);
|
);
|
||||||
|
@ -55,9 +62,9 @@ export async function runConversionPipeline(
|
||||||
maybeObjectsInv,
|
maybeObjectsInv,
|
||||||
initialResults,
|
initialResults,
|
||||||
);
|
);
|
||||||
await writeMarkdownResults(pkg, results);
|
await writeMarkdownResults(pkg, docsBaseFolder, results);
|
||||||
await copyImages(pkg, htmlPath, results);
|
await copyImages(pkg, htmlPath, publicBaseFolder, results);
|
||||||
await maybeObjectsInv?.write(pkg.outputDir("public"));
|
await maybeObjectsInv?.write(pkg.outputDir(publicBaseFolder));
|
||||||
await writeTocFile(pkg, markdownPath, results);
|
await writeTocFile(pkg, markdownPath, results);
|
||||||
await writeVersionFile(pkg, markdownPath);
|
await writeVersionFile(pkg, markdownPath);
|
||||||
await maybeUpdateReleaseNotesFolder(pkg, markdownPath);
|
await maybeUpdateReleaseNotesFolder(pkg, markdownPath);
|
||||||
|
@ -65,8 +72,9 @@ export async function runConversionPipeline(
|
||||||
|
|
||||||
async function determineFilePaths(
|
async function determineFilePaths(
|
||||||
htmlPath: string,
|
htmlPath: string,
|
||||||
|
docsBaseFolder: string,
|
||||||
pkg: Pkg,
|
pkg: Pkg,
|
||||||
): Promise<[string[], ObjectsInv | undefined]> {
|
): Promise<[string[], string, ObjectsInv | undefined]> {
|
||||||
const maybeObjectsInv = await (pkg.hasObjectsInv()
|
const maybeObjectsInv = await (pkg.hasObjectsInv()
|
||||||
? ObjectsInv.fromFile(htmlPath)
|
? ObjectsInv.fromFile(htmlPath)
|
||||||
: undefined);
|
: undefined);
|
||||||
|
@ -81,12 +89,15 @@ async function determineFilePaths(
|
||||||
cwd: htmlPath,
|
cwd: htmlPath,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return [files, maybeObjectsInv];
|
const markdownPath = pkg.outputDir(docsBaseFolder);
|
||||||
|
await mkdirp(markdownPath);
|
||||||
|
return [files, markdownPath, maybeObjectsInv];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function convertFilesToMarkdown(
|
async function convertFilesToMarkdown(
|
||||||
pkg: Pkg,
|
pkg: Pkg,
|
||||||
htmlPath: string,
|
htmlPath: string,
|
||||||
|
docsBaseFolder: string,
|
||||||
markdownPath: string,
|
markdownPath: string,
|
||||||
filePaths: string[],
|
filePaths: string[],
|
||||||
): Promise<HtmlToMdResultWithUrl[]> {
|
): Promise<HtmlToMdResultWithUrl[]> {
|
||||||
|
@ -108,7 +119,7 @@ async function convertFilesToMarkdown(
|
||||||
}
|
}
|
||||||
|
|
||||||
const { dir, name } = parse(`${markdownPath}/${file}`);
|
const { dir, name } = parse(`${markdownPath}/${file}`);
|
||||||
let url = `/${relative(`${getRoot()}/docs`, dir)}/${name}`;
|
let url = `/${relative(docsBaseFolder, dir)}/${name}`;
|
||||||
results.push({ ...result, url });
|
results.push({ ...result, url });
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
|
@ -117,6 +128,7 @@ async function convertFilesToMarkdown(
|
||||||
async function copyImages(
|
async function copyImages(
|
||||||
pkg: Pkg,
|
pkg: Pkg,
|
||||||
htmlPath: string,
|
htmlPath: string,
|
||||||
|
publicBaseFolder: string,
|
||||||
results: HtmlToMdResultWithUrl[],
|
results: HtmlToMdResultWithUrl[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Some historical versions don't have the `_images` folder in the artifact store in Box (https://ibm.ent.box.com/folder/246867452622)
|
// Some historical versions don't have the `_images` folder in the artifact store in Box (https://ibm.ent.box.com/folder/246867452622)
|
||||||
|
@ -126,7 +138,7 @@ async function copyImages(
|
||||||
results.flatMap((result) => result.images),
|
results.flatMap((result) => result.images),
|
||||||
(image) => image.fileName,
|
(image) => image.fileName,
|
||||||
);
|
);
|
||||||
await saveImages(allImages, `${htmlPath}/_images`, pkg);
|
await saveImages(allImages, `${htmlPath}/_images`, publicBaseFolder, pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function postProcessResults(
|
async function postProcessResults(
|
||||||
|
@ -145,11 +157,11 @@ async function postProcessResults(
|
||||||
|
|
||||||
async function writeMarkdownResults(
|
async function writeMarkdownResults(
|
||||||
pkg: Pkg,
|
pkg: Pkg,
|
||||||
|
docsBaseFolder: string,
|
||||||
results: HtmlToMdResultWithUrl[],
|
results: HtmlToMdResultWithUrl[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
for (const result of results) {
|
for (const result of results) {
|
||||||
let path = urlToPath(result.url);
|
let path = `${docsBaseFolder}${result.url}.md`;
|
||||||
|
|
||||||
if (path.endsWith("release-notes.md")) {
|
if (path.endsWith("release-notes.md")) {
|
||||||
const shouldWriteResult = await handleReleaseNotesFile(result, pkg);
|
const shouldWriteResult = await handleReleaseNotesFile(result, pkg);
|
||||||
if (!shouldWriteResult) continue;
|
if (!shouldWriteResult) continue;
|
||||||
|
@ -235,7 +247,3 @@ async function writeVersionFile(pkg: Pkg, markdownPath: string): Promise<void> {
|
||||||
JSON.stringify(pkg_json, null, 2) + "\n",
|
JSON.stringify(pkg_json, null, 2) + "\n",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function urlToPath(url: string) {
|
|
||||||
return `${getRoot()}/docs${url}.md`;
|
|
||||||
}
|
|
||||||
|
|
|
@ -21,9 +21,10 @@ import { pathExists, rmFilesInFolder } from "../fs";
|
||||||
export async function saveImages(
|
export async function saveImages(
|
||||||
images: Image[],
|
images: Image[],
|
||||||
originalImagesFolderPath: string,
|
originalImagesFolderPath: string,
|
||||||
|
publicBaseFolder: string,
|
||||||
pkg: Pkg,
|
pkg: Pkg,
|
||||||
) {
|
) {
|
||||||
const destFolder = pkg.outputDir("public/images");
|
const destFolder = pkg.outputDir(`${publicBaseFolder}/images`);
|
||||||
if (!(await pathExists(destFolder))) {
|
if (!(await pathExists(destFolder))) {
|
||||||
await mkdirp(destFolder);
|
await mkdirp(destFolder);
|
||||||
} else if (pkg.isDev()) {
|
} else if (pkg.isDev()) {
|
||||||
|
@ -35,13 +36,13 @@ export async function saveImages(
|
||||||
await pMap(images, async (img) => {
|
await pMap(images, async (img) => {
|
||||||
// The release notes images are only saved in the current version to
|
// The release notes images are only saved in the current version to
|
||||||
// avoid having duplicate files.
|
// avoid having duplicate files.
|
||||||
if (img.fileName.includes("release_notes") && pkg.isHistorical()) {
|
if (pkg.isHistorical() && img.fileName.includes("release_notes")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await copyFile(
|
await copyFile(
|
||||||
`${originalImagesFolderPath}/${img.fileName}`,
|
`${originalImagesFolderPath}/${img.fileName}`,
|
||||||
`public/${img.dest}`,
|
`${publicBaseFolder}/${img.dest}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue