@portosaur/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -0
- package/bin/porto.mjs +71 -0
- package/package.json +36 -0
- package/src/commands/build.mjs +85 -0
- package/src/commands/dev.mjs +61 -0
- package/src/commands/init.mjs +523 -0
- package/src/commands/initCi.mjs +227 -0
- package/src/commands/providers.mjs +170 -0
- package/src/commands/schema.mjs +208 -0
- package/src/commands/serve.mjs +29 -0
- package/src/index.d.ts +49 -0
- package/src/index.mjs +8 -0
- package/src/templates/README.md +58 -0
- package/src/templates/blog/authors.yml +4 -0
- package/src/templates/blog/welcome.md +11 -0
- package/src/templates/config.yml +150 -0
- package/src/templates/gitignore +9 -0
- package/src/templates/notes/index.mdx +9 -0
- package/src/templates/notes/welcome.mdx +9 -0
- package/src/templates/package.json +14 -0
- package/src/templates/registry.yml +107 -0
- package/src/templates/static/.nojekyll +0 -0
- package/src/templates/static/README.md +1 -0
- package/src/templates/workflows/codeberg/.forgejo/workflows/deploy.yml +39 -0
- package/src/templates/workflows/github/.github/workflows/deploy.yml +55 -0
- package/src/templates/workflows/gitlab/.gitlab-ci.yml +13 -0
- package/src/templates/workflows/netlify/netlify.toml +6 -0
- package/src/templates/workflows/surge/codeberg/.forgejo/workflows/deploy.yml +23 -0
- package/src/templates/workflows/surge/github/.github/workflows/deploy.yml +23 -0
- package/src/templates/workflows/surge/gitlab/.gitlab-ci.yml +16 -0
- package/src/templates/workflows/surge/sourcehut/.build.yml +26 -0
- package/src/templates/workflows/woodpecker/.woodpecker/deploy.yml +21 -0
- package/src/utils/git.mjs +52 -0
- package/src/utils/index.mjs +7 -0
- package/src/utils/interaction.mjs +24 -0
- package/src/utils/packageManager.mjs +85 -0
- package/src/utils/paths.mjs +33 -0
- package/src/utils/platforms.mjs +130 -0
- package/src/utils/projectName.mjs +20 -0
- package/src/utils/runner.mjs +192 -0
package/README.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# porto
|
|
2
|
+
|
|
3
|
+
The primary command-line interface for Portosaur.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Global installation
|
|
9
|
+
bun install -g @portosaur/cli # or npm install -g @portosaur/cli
|
|
10
|
+
|
|
11
|
+
# Or use directly with bunx/npx
|
|
12
|
+
bunx @portosaur/cli@latest # or npx @portosaur/cli@latest
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Commands
|
|
16
|
+
|
|
17
|
+
- `porto init [-P name]` — Initialize a new project (interactive mode recommended).
|
|
18
|
+
- `porto init-ci [-h id]` — Set up CI/CD for an existing project.
|
|
19
|
+
- `porto dev` — Start the development server.
|
|
20
|
+
- `porto build` — Generate a static production build.
|
|
21
|
+
- `porto serve` — Preview a production build locally.
|
|
22
|
+
- `porto schema` — Output the JSON schema for validation.
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Interactive mode (recommended)
|
|
28
|
+
porto init
|
|
29
|
+
|
|
30
|
+
# Or with project name
|
|
31
|
+
porto init -P my-portfolio
|
|
32
|
+
|
|
33
|
+
# With all options (non-interactive)
|
|
34
|
+
porto init -P my-site -p github -h github-pages -u myusername -n "My Name"
|
|
35
|
+
|
|
36
|
+
# Start development
|
|
37
|
+
cd my-portfolio
|
|
38
|
+
bun run dev
|
|
39
|
+
|
|
40
|
+
# Build for production
|
|
41
|
+
bun run build
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Library Usage
|
|
45
|
+
|
|
46
|
+
If you want to use Portosaur programmatically, install `@portosaur/core`:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npm install @portosaur/core
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
See `@portosaur/core` for API documentation.
|
package/bin/porto.mjs
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command, Argument } from "commander";
|
|
4
|
+
import { porto } from "@portosaur/core";
|
|
5
|
+
import { initCommand } from "../src/commands/init.mjs";
|
|
6
|
+
import { initCiCommand } from "../src/commands/initCi.mjs";
|
|
7
|
+
import { devCommand } from "../src/commands/dev.mjs";
|
|
8
|
+
import { buildCommand } from "../src/commands/build.mjs";
|
|
9
|
+
import { serveCommand } from "../src/commands/serve.mjs";
|
|
10
|
+
import { schemaCommand } from "../src/commands/schema.mjs";
|
|
11
|
+
import { providersCommand } from "../src/commands/providers.mjs";
|
|
12
|
+
|
|
13
|
+
const program = new Command();
|
|
14
|
+
|
|
15
|
+
program
|
|
16
|
+
.name("porto")
|
|
17
|
+
.description("CLI for Portosaur — The complete portfolio solution")
|
|
18
|
+
.version(porto.version, "-v, --version", "output the current version")
|
|
19
|
+
.helpOption("--help", "output usage information");
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.command("init")
|
|
23
|
+
.description("Initialize a new Portosaur project")
|
|
24
|
+
.option("-p, --vcs-provider <id>", "VCS Provider ID")
|
|
25
|
+
.option("-h, --hosting <id>", "Hosting Platform ID")
|
|
26
|
+
.option("-u, --username <user>", "VCS username")
|
|
27
|
+
.option("-n, --name <name>", "Full name for portfolio")
|
|
28
|
+
.option("-P, --project-name <name>", "Project name")
|
|
29
|
+
.option("-k, --no-install", "Skip dependency installation")
|
|
30
|
+
.action((options) => initCommand(options));
|
|
31
|
+
|
|
32
|
+
program
|
|
33
|
+
.command("init-ci")
|
|
34
|
+
.description("Setup CI/CD workflows for an existing project")
|
|
35
|
+
.option("-h, --hosting <id>", "Hosting Platform ID")
|
|
36
|
+
.action((options) => initCiCommand(options));
|
|
37
|
+
|
|
38
|
+
program
|
|
39
|
+
.command("providers")
|
|
40
|
+
.description("List available VCS providers and hosting platforms")
|
|
41
|
+
.addArgument(
|
|
42
|
+
new Argument("[type]", "Filter list by type").choices(["vcs", "hosting"]),
|
|
43
|
+
)
|
|
44
|
+
.action((type) => providersCommand(type));
|
|
45
|
+
|
|
46
|
+
program
|
|
47
|
+
.command("dev [siteDir] [extraArgs...]")
|
|
48
|
+
.alias("start")
|
|
49
|
+
.description("Start the development server")
|
|
50
|
+
.allowUnknownOption()
|
|
51
|
+
.action(devCommand);
|
|
52
|
+
|
|
53
|
+
program
|
|
54
|
+
.command("build [siteDir] [extraArgs...]")
|
|
55
|
+
.description("Build the static site")
|
|
56
|
+
.allowUnknownOption()
|
|
57
|
+
.action(buildCommand);
|
|
58
|
+
|
|
59
|
+
program
|
|
60
|
+
.command("serve [siteDir]")
|
|
61
|
+
.description("Serve the built static site locally")
|
|
62
|
+
.action(serveCommand);
|
|
63
|
+
|
|
64
|
+
program
|
|
65
|
+
.command("schema", { hidden: true })
|
|
66
|
+
.description("Generate the config schema")
|
|
67
|
+
.option("-c, --config <path>", "Path to the source file to scan")
|
|
68
|
+
.option("-o, --output <path>", "Path to output the schema file")
|
|
69
|
+
.action(schemaCommand);
|
|
70
|
+
|
|
71
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@portosaur/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Portosaur CLI: Personal portfolio site generator.",
|
|
5
|
+
"license": "GPL-3.0-only",
|
|
6
|
+
"author": "soymadip",
|
|
7
|
+
"homepage": "https://soymadip.github.io/portosaur",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "https://github.com/soymadip/portosaur"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"bin",
|
|
15
|
+
"templates"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"bin": {
|
|
19
|
+
"porto": "./bin/porto.mjs"
|
|
20
|
+
},
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": "./src/index.mjs",
|
|
24
|
+
"default": "./src/index.mjs"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"types": "./src/index.d.ts",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@portosaur/core": "workspace:*",
|
|
30
|
+
"@portosaur/theme": "workspace:*",
|
|
31
|
+
"@portosaur/logger": "workspace:*",
|
|
32
|
+
"@portosaur/wizard": "workspace:*",
|
|
33
|
+
"commander": "^13.1.0",
|
|
34
|
+
"js-yaml": "^4.1.1"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import {
|
|
4
|
+
Paths,
|
|
5
|
+
writeConfigShim,
|
|
6
|
+
runDocusaurus,
|
|
7
|
+
validateProject,
|
|
8
|
+
ensureContentDirs,
|
|
9
|
+
} from "../utils/index.mjs";
|
|
10
|
+
import { logger } from "@portosaur/logger";
|
|
11
|
+
import {
|
|
12
|
+
loadUserConfig,
|
|
13
|
+
generateFavicons,
|
|
14
|
+
generateRobotsTxt,
|
|
15
|
+
} from "@portosaur/core";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Builds the static Portosaur site.
|
|
19
|
+
*
|
|
20
|
+
* This involves:
|
|
21
|
+
* 1. Validating the project structure.
|
|
22
|
+
* 2. Generating dynamic assets (favicons, robots.txt).
|
|
23
|
+
* 3. Compiling the site via Docusaurus.
|
|
24
|
+
*/
|
|
25
|
+
export async function buildCommand(siteDir, extraArgs = []) {
|
|
26
|
+
const UserRoot = siteDir
|
|
27
|
+
? path.resolve(process.cwd(), siteDir)
|
|
28
|
+
: process.cwd();
|
|
29
|
+
|
|
30
|
+
// ------- Setup -------
|
|
31
|
+
|
|
32
|
+
validateProject(UserRoot);
|
|
33
|
+
ensureContentDirs(UserRoot);
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* ====================== Path Resolution ======================
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
const portoPaths = {
|
|
40
|
+
root: Paths.root,
|
|
41
|
+
assets: path.join(Paths.theme, "assets"),
|
|
42
|
+
theme: path.join(Paths.theme, "theme"),
|
|
43
|
+
plugins: path.join(Paths.theme, "src/plugins"),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const userConfig = loadUserConfig(UserRoot);
|
|
48
|
+
|
|
49
|
+
// ------- Asset Generation -------
|
|
50
|
+
|
|
51
|
+
logger.info("Generating site assets...");
|
|
52
|
+
|
|
53
|
+
const faviconRes = await generateFavicons(UserRoot, {
|
|
54
|
+
imagePath: userConfig.home_page?.hero?.profile_pic,
|
|
55
|
+
siteTitle: userConfig.site?.title,
|
|
56
|
+
siteTagline: userConfig.site?.tagline,
|
|
57
|
+
staticDirs: ["static"],
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const configPath = writeConfigShim(UserRoot, portoPaths, {
|
|
61
|
+
extraHeadTags: faviconRes.html,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// ------- Docusaurus Build -------
|
|
65
|
+
|
|
66
|
+
logger.info("Building static site...");
|
|
67
|
+
|
|
68
|
+
await runDocusaurus("build", UserRoot, configPath, extraArgs);
|
|
69
|
+
|
|
70
|
+
// ------- Post Build -------
|
|
71
|
+
|
|
72
|
+
await generateRobotsTxt(UserRoot, {
|
|
73
|
+
enable: userConfig.site?.robots_txt?.enable,
|
|
74
|
+
rules: userConfig.site?.robots_txt?.rules,
|
|
75
|
+
customLines: userConfig.site?.robots_txt?.custom_lines,
|
|
76
|
+
siteUrl: userConfig.site?.url,
|
|
77
|
+
baseUrl: userConfig.site?.path,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
logger.success("Build completed successfully!");
|
|
81
|
+
} catch (error) {
|
|
82
|
+
logger.error(`Build failed: ${error.message}`);
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import {
|
|
4
|
+
Paths,
|
|
5
|
+
writeConfigShim,
|
|
6
|
+
runDocusaurus,
|
|
7
|
+
validateProject,
|
|
8
|
+
ensureContentDirs,
|
|
9
|
+
} from "../utils/index.mjs";
|
|
10
|
+
import { logger } from "@portosaur/logger";
|
|
11
|
+
|
|
12
|
+
export async function devCommand(siteDir, extraArgs = []) {
|
|
13
|
+
const UserRoot = siteDir
|
|
14
|
+
? path.resolve(process.cwd(), siteDir)
|
|
15
|
+
: process.cwd();
|
|
16
|
+
|
|
17
|
+
validateProject(UserRoot);
|
|
18
|
+
ensureContentDirs(UserRoot);
|
|
19
|
+
|
|
20
|
+
const configYaml = ["config.yaml", "config.yml"].find((file) =>
|
|
21
|
+
fs.existsSync(path.join(UserRoot, file)),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* ====================== Path Resolution ======================
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const portoPaths = {
|
|
29
|
+
root: Paths.root,
|
|
30
|
+
assets: path.join(Paths.theme, "assets"),
|
|
31
|
+
theme: path.join(Paths.theme, "theme"),
|
|
32
|
+
plugins: path.join(Paths.theme, "src/plugins"),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const configPath = writeConfigShim(UserRoot, portoPaths);
|
|
37
|
+
|
|
38
|
+
// Watch for config.yml changes to trigger Docusaurus reload
|
|
39
|
+
if (configYaml) {
|
|
40
|
+
const configYamlPath = path.join(UserRoot, configYaml);
|
|
41
|
+
const watcher = fs.watch(configYamlPath, (eventType) => {
|
|
42
|
+
if (eventType === "change") {
|
|
43
|
+
logger.info(`Detected change in ${configYaml}, reloading...`);
|
|
44
|
+
// Touch the shim config to trigger Docusaurus reload
|
|
45
|
+
const now = new Date();
|
|
46
|
+
fs.utimesSync(configPath, now, now);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
process.on("SIGINT", () => {
|
|
51
|
+
watcher.close();
|
|
52
|
+
process.exit();
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await runDocusaurus("start", UserRoot, configPath, extraArgs);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
logger.error(`Failed to start dev server: ${error.message}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|