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

Feature/docs template #207

Merged
merged 4 commits into from
Jul 6, 2023
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
8 changes: 8 additions & 0 deletions default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,13 @@ pkgs.mkShell {
pkgs.azure-cli
pkgs.google-cloud-sdk

# terraform
pkgs.terraform
pkgs.terragrunt
pkgs.tflint
pkgs.terraform-docs

# for collie foundation docs
pkgs.nodejs
];
}
44 changes: 36 additions & 8 deletions src/commands/foundation/docs.command.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as fs from "std/fs";
import { CliApiFacadeFactory } from "../../api/CliApiFacadeFactory.ts";
import { DirectoryGenerator, WriteMode } from "../../cli/DirectoryGenerator.ts";
import { Logger } from "../../cli/Logger.ts";
Expand All @@ -8,7 +9,6 @@ import { DocumentationGenerator } from "../../docs/DocumentationGenerator.ts";
import { DocumentationRepository } from "../../docs/DocumentationRepository.ts";
import { KitModuleDocumentationGenerator } from "../../docs/KitModuleDocumentationGenerator.ts";
import { PlatformDocumentationGenerator } from "../../docs/PlatformDocumentationGenerator.ts";
import { VuepressDocumentationSiteGenerator } from "../../docs/VuepressDocumentationSiteGenerator.ts";
import { KitDependencyAnalyzer } from "../../kit/KitDependencyAnalyzer.ts";
import { KitModuleRepository } from "../../kit/KitModuleRepository.ts";
import { CollieRepository } from "../../model/CollieRepository.ts";
Expand Down Expand Up @@ -46,7 +46,7 @@ export function registerDocsCmd(program: TopLevelCommand) {
const factory = new CliApiFacadeFactory(repo, logger);
// todo: instead of flags, maybe these should be subcommands?
if (opts.update) {
await updateDocumentation(repo, foundationRepo, factory, logger);
await updateDocumentation(repo, foundationRepo, logger);
}

if (opts.preview) {
Expand All @@ -69,7 +69,6 @@ export function registerDocsCmd(program: TopLevelCommand) {
async function updateDocumentation(
repo: CollieRepository,
foundation: FoundationRepository,
factory: CliApiFacadeFactory,
logger: Logger,
) {
const foundationProgress = new ProgressReporter(
Expand All @@ -79,9 +78,7 @@ async function updateDocumentation(
);

const dir = new DirectoryGenerator(WriteMode.overwrite, logger);
const siteGenerator = new VuepressDocumentationSiteGenerator(dir, foundation);

const tfDocs = factory.buildTerraformDocs();
const validator = new ModelValidator(logger);
const modules = await KitModuleRepository.load(repo, validator, logger);
const controls = await ComplianceControlRepository.load(
Expand All @@ -93,7 +90,6 @@ async function updateDocumentation(
repo,
modules,
controls,
tfDocs,
logger,
);

Expand All @@ -114,8 +110,9 @@ async function updateDocumentation(

const docsRepo = new DocumentationRepository(foundation);

await prepareSiteTemplate(docsRepo, repo, logger);

const generator = new DocumentationGenerator(
siteGenerator,
moduleDocumentation,
complianceDocumentation,
platformDocumentation,
Expand All @@ -131,10 +128,41 @@ async function previewDocumentation(
factory: CliApiFacadeFactory,
) {
const docsRepo = new DocumentationRepository(foundation);
const dir = foundation.resolvePath(docsRepo.docsRootDir);
const dir = docsRepo.docsRootPath;

const npm = factory.buildNpm();

await npm.run(["install"], { cwd: dir });
await npm.run(["run", "docs:dev"], { cwd: dir });
}

async function prepareSiteTemplate(
docsRepo: DocumentationRepository,
repo: CollieRepository,
logger: Logger,
) {
// TODO: throw if it doesn't work
const srcDir = repo.resolvePath("kit", "foundation", "docs", "template");

try {
await fs.copy(srcDir, docsRepo.docsRootPath, { overwrite: true });
} catch (e) {
if (e instanceof Deno.errors.NotFound) {
logger.error(
(fmt) =>
`could not find kit module with template for documentation site at ${
fmt.kitPath(
srcDir,
)
}`,
);

logger.tipCommand(
"This module is essential for documentation generation. To import this module run",
"kit import foundation/docs",
);
Deno.exit(1);
}
throw e;
}
}
42 changes: 42 additions & 0 deletions src/commands/kit/compile.command.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { CollieRepository } from "../../model/CollieRepository.ts";
import { GlobalCommandOptions } from "../GlobalCommandOptions.ts";
import { Logger } from "../../cli/Logger.ts";
import { ModelValidator } from "../../model/schemas/ModelValidator.ts";
import { KitModuleRepository } from "../../kit/KitModuleRepository.ts";
import { TopLevelCommand } from "../TopLevelCommand.ts";
import { CliApiFacadeFactory } from "../../api/CliApiFacadeFactory.ts";
import { ProgressReporter } from "../../cli/ProgressReporter.ts";

export function registerCompileCmd(program: TopLevelCommand) {
program
.command("compile [module]")
.description("Compile kit modules, updating their documentation")
.action(async (opts: GlobalCommandOptions, module?: string) => {
const collie = new CollieRepository("./");
const logger = new Logger(collie, opts);
const validator = new ModelValidator(logger);
const moduleRepo = await KitModuleRepository.load(
collie,
validator,
logger,
);

const progress = new ProgressReporter(
"compiling",
"kit modules",
logger,
);

// todo: should compiling a kit module also run tflint and other stuff?
const factory = new CliApiFacadeFactory(collie, logger);
const tfDocs = factory.buildTerraformDocs();

const tasks = moduleRepo.all
.filter((x) => !module || module == x.id)
.map(async (x) => await tfDocs.updateReadme(x.kitModulePath));

await Promise.all(tasks);

progress.done();
});
}
6 changes: 4 additions & 2 deletions src/commands/kit/kit.command.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { makeTopLevelCommand, TopLevelCommand } from "../TopLevelCommand.ts";
import { registerApplyCmd } from "./apply.command.ts";
import { registerBundledKitCmd } from "./bundle.command.ts";
import { registerCompileCmd } from "./compile.command.ts";
import { registerImportCmd } from "./import.command.ts";
import { registerNewCmd } from "./new.command.ts";
import { registerTreeCmd } from "./tree.command.ts";

export function registerKitCommand(program: TopLevelCommand) {
const kitCommands = makeTopLevelCommand();
registerNewCmd(kitCommands);
registerBundledKitCmd(kitCommands);
registerImportCmd(kitCommands);
registerApplyCmd(kitCommands);
registerImportCmd(kitCommands);
registerTreeCmd(kitCommands);
registerBundledKitCmd(kitCommands);
registerCompileCmd(kitCommands);

program
.command("kit", kitCommands)
Expand Down
4 changes: 0 additions & 4 deletions src/docs/DocumentationGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,15 @@ import { ComplianceDocumentationGenerator } from "./ComplianceDocumentationGener
import { DocumentationRepository } from "./DocumentationRepository.ts";
import { KitModuleDocumentationGenerator } from "./KitModuleDocumentationGenerator.ts";
import { PlatformDocumentationGenerator } from "./PlatformDocumentationGenerator.ts";
import { VuepressDocumentationSiteGenerator } from "./VuepressDocumentationSiteGenerator.ts";

export class DocumentationGenerator {
constructor(
private readonly siteGenerator: VuepressDocumentationSiteGenerator,
private readonly kitModuleDocumentation: KitModuleDocumentationGenerator,
private readonly complianceDocumentation: ComplianceDocumentationGenerator,
private readonly platformDocumentation: PlatformDocumentationGenerator,
) {}

async generateFoundationDocumentation(docsRepo: DocumentationRepository) {
await this.siteGenerator.generateSite(docsRepo);

// todo: can we flatten the duplicate docs/ folder nesting?
await this.complianceDocumentation.generate(docsRepo);
await this.kitModuleDocumentation.generate(docsRepo);
Expand Down
7 changes: 5 additions & 2 deletions src/docs/DocumentationRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,23 @@ export class DocumentationRepository {
// we use a "hidden" directory with a leading "." because terragrunt excludes hidden files and dirs
// when building a terragrunt-cache folder, see https://terragrunt.gruntwork.io/docs/reference/config-blocks-and-attributes/#terraform "include_in_copy"
// > By default, Terragrunt excludes hidden files and folders during the copy step.
public readonly docsRootDir = ".docs";
public readonly docsContentDir = "docs";
private readonly docsRootDir = ".docs";
private readonly docsContentDir = "docs";

// these paths are the same in collie repository and docs content
public readonly platformsDir = "platforms";
public readonly complianceDir = "compliance";
public readonly kitDir = "kit";

public readonly docsRootPath: string;
public readonly docsContentPath: string;
public readonly kitPath: string;
public readonly compliancePath: string;
public readonly platformsPath: string;

constructor(foundation: FoundationRepository) {
this.docsRootPath = foundation.resolvePath(this.docsRootDir);

this.docsContentPath = foundation.resolvePath(
this.docsRootDir,
this.docsContentDir,
Expand Down
8 changes: 2 additions & 6 deletions src/docs/KitModuleDocumentationGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as fs from "std/fs";
import * as path from "std/path";
import { TerraformDocsCliFacade } from "../api/terraform-docs/TerraformDocsCliFacade.ts";

import { Logger } from "../cli/Logger.ts";
import { ProgressReporter } from "../cli/ProgressReporter.ts";
Expand All @@ -15,7 +14,6 @@ export class KitModuleDocumentationGenerator {
private readonly collie: CollieRepository,
private readonly kitModules: KitModuleRepository,
private readonly controls: ComplianceControlRepository,
private readonly tfdocs: TerraformDocsCliFacade,
private readonly logger: Logger,
) {}

Expand All @@ -34,7 +32,7 @@ export class KitModuleDocumentationGenerator {

this.logger.verbose((fmt) => `generating ${fmt.kitPath(dest)}`);

const md = await this.generateModuleDocumentation(x, docsRepo);
const md = this.generateModuleDocumentation(x, docsRepo);

await Deno.mkdir(path.dirname(dest), { recursive: true });
await Deno.writeTextFile(dest, md);
Expand All @@ -57,12 +55,10 @@ export class KitModuleDocumentationGenerator {
await fs.copy(source, dest, { overwrite: true });
}

private async generateModuleDocumentation(
private generateModuleDocumentation(
parsed: ParsedKitModule,
docsRepo: DocumentationRepository,
) {
await this.tfdocs.updateReadme(parsed.kitModulePath);

const complianceStatements = this.generateComplianceStatements(
parsed,
docsRepo,
Expand Down
Loading