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

Add @qwikdev/create-astro library #102

Merged
merged 19 commits into from
Apr 21, 2024
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
2 changes: 1 addition & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,5 @@
"enabled": true
},

"extends": ["./apps/website/biome.json"]
"extends": ["./apps/website/biome.json", "./libs/create-qwikdev-astro/biome.json"]
}
2 changes: 2 additions & 0 deletions libs/create-qwikdev-astro/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
src/
tsconfig.json
16 changes: 16 additions & 0 deletions libs/create-qwikdev-astro/biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"organizeImports": {
"ignore": ["dist", "stubs"]
},
"linter": {
"ignore": ["dist", "stubs"],
"rules": {
"style": {
"noParameterAssign": "off"
}
}
},
"formatter": {
"ignore": ["dist", "stubs"]
}
}
75 changes: 75 additions & 0 deletions libs/create-qwikdev-astro/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"name": "@qwikdev/create-astro",
"type": "module",
"license": "MIT",
"version": "0.0.0",
"description": "Interactive CLI for create @QwikDev/astro projects.",
"scripts": {
"build": "rimraf dist && tsc --build"
},
"contributors": [
{
"name": "Miško Hevery",
"email": "misko@hevery.com",
"url": "https://twitter.com/mhevery"
},
{
"name": "Jack Shelton",
"email": "me@jackshelton.com",
"url": "https://twitter.com/TheJackShelton"
},
{
"name": "Sigui Kessé Emmanuel",
"email": "contact@sigui.ci",
"url": "https://twitter.com/siguici"
}
],
"repository": {
"type": "git",
"url": "https://github.com/QwikDev/astro",
"directory": "libs/create-qwikdev-astro"
},
"types": "./dist/index.d.ts",
"main": "./dist/index.js",
"exports": {
".": "./dist/index.js",
"./package.json": "./package.json"
},
"files": ["dist", "stubs"],
"bin": {
"create-qwikdev-astro": "./dist/index.js"
},
"keywords": [
"astro-integration",
"astro-component",
"cli",
"console",
"create-qwik-astro",
"generator",
"optimization",
"perf",
"performance",
"qwik",
"qwikdev",
"qwik-astro",
"renderer",
"skeleton",
"starter-kit",
"template",
"withastro"
],
"publishConfig": {
"access": "public"
},
"bugs": "https://github.com/@QwikDev/astro/issues",
"devDependencies": {
"@clack/prompts": "^0.7.0",
"@types/which-pm-runs": "^1.0.2",
"@types/yargs": "^17.0.32",
"kleur": "^4.1.5",
"rimraf": "^5.0.5",
"typescript": "^5.4.5",
"which-pm-runs": "^1.1.0",
"yargs": "^17.7.2"
}
}
247 changes: 247 additions & 0 deletions libs/create-qwikdev-astro/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
#!/usr/bin/env node

import { type ChildProcess, exec, spawn } from "node:child_process";
import { cpSync, existsSync, mkdirSync } from "node:fs";
import fs from "node:fs";
import os from "node:os";
import path, { join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import {
cancel,
confirm,
intro,
isCancel,
log,
outro,
select,
spinner,
text
} from "@clack/prompts";
import { gray, red } from "kleur/colors";
import detectPackageManager from "which-pm-runs";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

export function resolveRelativeDir(dir: string) {
return dir.startsWith("~/") ? resolve(os.homedir(), dir) : resolve(process.cwd(), dir);
}

export function $(cmd: string, args: string[], cwd: string) {
let child: ChildProcess;

const install = new Promise<boolean>((resolve) => {
try {
child = spawn(cmd, args, {
cwd,
stdio: "ignore"
});

child.on("error", (e) => {
if (e) {
log.error(`${red(String(e.message || e))}\n\n`);
}
resolve(false);
});

child.on("close", (code) => {
resolve(code === 0);
});
} catch (e) {
resolve(false);
}
});

const abort = async () => {
if (child) {
child.kill("SIGINT");
}
};

return { abort, install };
}

export function getPackageManager() {
return detectPackageManager()?.name || "npm";
}

export const isPackageManagerInstalled = (packageManager: string) => {
return new Promise((resolve) => {
exec(`${packageManager} --version`, (error, _, stderr) => {
resolve(!(error || stderr));
});
});
};

export const $pm = async (
args: string | string[],
cwd = process.cwd(),
env = process.env
) => {
const packageManager = getPackageManager();
args = Array.isArray(args) ? args : [args];

return new Promise((resolve, reject) => {
const child = spawn(packageManager, args, {
cwd,
stdio: "inherit",
env
});

child.on("close", (code) => {
if (code !== 0) {
reject({ command: `${packageManager} ${args.join(" ")}` });
return;
}
resolve(true);
});
});
};

export const installDependencies = async (cwd: string) => {
await $pm("install", cwd);
};

const createProject = async () => {
try {
intro("QwikDev/astro project creation");

const packageManager = getPackageManager();

const defaultProjectName = "./qwik-astro-app";
const projectNameAnswer = await text({
message: `Where would you like to create your new project? ${gray(
`(Use '.' or './' for current directory)`
)}`,
placeholder: defaultProjectName,
validate(value) {
if (value.length === 0) {
return "Value is required!";
}
}
});

if (typeof projectNameAnswer === "symbol") {
cancel("Operation canceled.");
return process.exit(0);
}

if (isCancel([projectNameAnswer, packageManager])) {
cancel("Operation canceled.");
process.exit(0);
}

const adapter = await select({
message: "Which adapter do you prefer?",
options: [
{
value: "node",
label: "Node"
},
{
value: "deno",
label: "Deno"
}
]
});

const favoriteLinterFormatter = await select({
message: "What is your favorite linter/formatter?",
options: [
{
value: "0",
label: "ESLint/Prettier"
},
{
value: "1",
label: "Biome"
}
]
});

log.step("Creating project directories and copying files...");

const kit = `${adapter}-${
favoriteLinterFormatter === "0" ? "eslint+prettier" : "biome"
}`;
const templatePath = path.join(__dirname, "..", "stubs", "templates", kit);
const outDir: string = resolveRelativeDir(projectNameAnswer.trim());

if (!existsSync(outDir)) {
mkdirSync(outDir, { recursive: true });
}
cpSync(templatePath, outDir, { recursive: true });

const addCIWorkflow = await confirm({
message: "Would you like to add CI workflow?",
initialValue: true
});

if (addCIWorkflow) {
const starterCIPath = join(
__dirname,
"..",
"stubs",
".github",
"workflows",
"ci.yml"
);
const projectCIPath = join(outDir, ".github", "workflows", "ci.yml");
cpSync(starterCIPath, projectCIPath, { force: true });
}

const runDepInstallAnswer = await confirm({
message: `Would you like to install ${packageManager} dependencies?`,
initialValue: true
});

const gitInitAnswer = await confirm({
message: "Initialize a new git repository?",
initialValue: true
});

if (gitInitAnswer) {
const s = spinner();

if (fs.existsSync(join(outDir, ".git"))) {
log.info("Git has already been initialized before. Skipping...");
} else {
s.start("Git initializing...");

try {
const res = [];
res.push(await $("git", ["init"], outDir).install);
res.push(await $("git", ["add", "-A"], outDir).install);
res.push(await $("git", ["commit", "-m", "Initial commit 🎉"], outDir).install);

if (res.some((r) => r === false)) {
throw "";
}

s.stop("Git initialized ✨");
} catch (e) {
s.stop("Git failed to initialize");
log.error(
red("Git failed to initialize. You can do this manually by running: git init")
);
}
}
}

if (typeof runDepInstallAnswer !== "symbol" && runDepInstallAnswer) {
log.step("Installing dependencies...");
await installDependencies(projectNameAnswer);
}

outro("QwikDev/astro project created successfully! 🍻");
} catch (err) {
console.error("An error occurred during QwikDev/astro project creation:", err);
process.exit(1);
}
};

async function main() {
await createProject();
}

main().catch(console.error);
34 changes: 34 additions & 0 deletions libs/create-qwikdev-astro/stubs/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: CI

permissions:
contents: read

on: ["push", "pull_request"]

jobs:
ci:
runs-on: ${{ matrix.os }}
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest]
node: [20.11]
experimental: [false]
name: 👷 CI @qwikdev/astro Node-${{ matrix.node }} under ${{ matrix.os }}

steps:
- name: 🚚 Get latest code
uses: actions/checkout@v4

- name: 🎉 Setup Node.js
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}

- name: ✨ Install dependencies
run: |
corepack enable
pnpm install
- name: ✅ Check code style
run: pnpm check
Loading