diff --git a/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/DocScaffolding.java b/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/DocScaffolding.java index cdb0b0f5e..c90b16b49 100644 --- a/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/DocScaffolding.java +++ b/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/DocScaffolding.java @@ -21,12 +21,15 @@ import org.testingisdocumenting.znai.utils.FileUtils; import org.testingisdocumenting.znai.utils.ResourceUtils; +import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import java.util.stream.Stream; public class DocScaffolding { private final Path workingDir; @@ -47,6 +50,28 @@ public void create() { createLookupPaths(); } + public void createFromFileSystem(Path templatePath) { + if (!Files.exists(templatePath)) { + throw new RuntimeException("template path does not exist: " + templatePath); + } + + if (!Files.isDirectory(templatePath)) { + throw new RuntimeException("template path is not a directory: " + templatePath); + } + + try (Stream discoveredFiles = Files.walk(templatePath)) { + discoveredFiles + .filter(Files::isRegularFile) + .forEach(f -> { + Path relativePath = templatePath.relativize(f); + Path targetPath = workingDir.resolve(relativePath); + FileUtils.copyFile(f, targetPath); + }); + } catch (IOException e) { + throw new RuntimeException("failed to copy files from template: " + templatePath, e); + } + } + private void createLookupPaths() { createFileFromResource("lookup-paths"); } diff --git a/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/ZnaiCliApp.java b/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/ZnaiCliApp.java index 9381557d2..129fa79af 100644 --- a/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/ZnaiCliApp.java +++ b/znai-cli/src/main/java/org/testingisdocumenting/znai/cli/ZnaiCliApp.java @@ -200,15 +200,41 @@ private PageModifiedTimeStrategy pageModifiedTimeStrategy() { }; } + private boolean maybeCreateNewFromTemplate(DocScaffolding scaffolding) { + String templatePathEnv = System.getenv("ZNAI_NEW_TEMPLATE_PATH"); + if (templatePathEnv == null) { + return false; + } + + if (templatePathEnv.trim().isEmpty()) { + ConsoleOutputs.out(Color.RED, "template path value is empty"); + return false; + } + + Path templatePath = Paths.get(templatePathEnv); + if (Files.exists(templatePath) && Files.isDirectory(templatePath)) { + ConsoleOutputs.out(Color.BLUE, "scaffolding from template: ", Color.PURPLE, templatePath); + scaffolding.createFromFileSystem(templatePath); + return true; + } else { + ConsoleOutputs.err(Color.RED, "template path does not exist or is not a directory: ", + Color.PURPLE, templatePath); + ConsoleOutputs.out(Color.YELLOW, "falling back to default scaffold"); + return false; + } + } + private void createNew() { Path pathToScaffold = (config.isSourceRootSet() ? config.getSourceRoot() : Paths.get("guide")).toAbsolutePath(); ConsoleOutputs.out(Color.BLUE, "scaffolding new documentation: ", Color.PURPLE, pathToScaffold); - DocScaffolding scaffolding = new DocScaffolding(pathToScaffold); - scaffolding.create(); + + if (!maybeCreateNewFromTemplate(scaffolding)) { + scaffolding.create(); + } } private void announceMode(String name) { diff --git a/znai-docs/znai/release-notes/1.81/add-2025-10-19-scaffold-custom-content.md b/znai-docs/znai/release-notes/1.81/add-2025-10-19-scaffold-custom-content.md new file mode 100644 index 000000000..594ca67db --- /dev/null +++ b/znai-docs/znai/release-notes/1.81/add-2025-10-19-scaffold-custom-content.md @@ -0,0 +1 @@ +* Add: `znai new` custom content scaffold \ No newline at end of file