feat: introduce Gatekeeper application, Directus utilities, and monorepo configuration for linting, testing, and husky hooks.
This commit is contained in:
@@ -12,7 +12,8 @@
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --format esm --target es2020",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "tsup src/index.ts --format esm --watch --target es2020"
|
||||
"dev": "tsup src/index.ts --format esm --watch --target es2020",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "^11.0.0",
|
||||
|
||||
7
packages/cli/src/index.test.ts
Normal file
7
packages/cli/src/index.test.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
describe("cli", () => {
|
||||
it("should have a working environment", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -44,6 +44,7 @@ program
|
||||
react: "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"@mintel/next-utils": "workspace:*",
|
||||
"@directus/sdk": "^21.0.0",
|
||||
},
|
||||
devDependencies: {
|
||||
"@types/node": "^20.0.0",
|
||||
@@ -53,6 +54,7 @@ program
|
||||
"@mintel/tsconfig": "workspace:*",
|
||||
"@mintel/eslint-config": "workspace:*",
|
||||
"@mintel/next-config": "workspace:*",
|
||||
"@mintel/husky-config": "workspace:*",
|
||||
},
|
||||
};
|
||||
await fs.writeJson(path.join(fullPath, "package.json"), pkgJson, {
|
||||
@@ -96,7 +98,17 @@ export default nextConfig;
|
||||
`;
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "eslint.config.mjs"),
|
||||
eslintConfig
|
||||
eslintConfig,
|
||||
);
|
||||
|
||||
// Create Husky/Linting configs
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "commitlint.config.js"),
|
||||
`export { default } from "@mintel/husky-config/commitlint";\n`,
|
||||
);
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, ".lintstagedrc.js"),
|
||||
`export { default } from "@mintel/husky-config/lint-staged";\n`,
|
||||
);
|
||||
|
||||
// Create env validation script
|
||||
@@ -111,7 +123,7 @@ try {
|
||||
} catch (error) {
|
||||
process.exit(1);
|
||||
}
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
// Create basic src structure
|
||||
@@ -129,7 +141,7 @@ export default createMintelMiddleware({
|
||||
export const config = {
|
||||
matcher: ["/((?!api|_next|_vercel|health|.*\\\\..*).*)", "/", "/(de|en)/:path*"]
|
||||
};
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
// Create i18n/request.ts
|
||||
@@ -143,21 +155,29 @@ export default createMintelI18nRequestConfig(
|
||||
"en",
|
||||
(locale) => import(\`../../messages/\${locale}.json\`)
|
||||
);
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
// Create messages directory
|
||||
await fs.ensureDir(path.join(fullPath, "messages"));
|
||||
await fs.writeJson(path.join(fullPath, "messages/en.json"), {
|
||||
Index: {
|
||||
title: "Welcome"
|
||||
}
|
||||
}, { spaces: 2 });
|
||||
await fs.writeJson(path.join(fullPath, "messages/de.json"), {
|
||||
Index: {
|
||||
title: "Willkommen"
|
||||
}
|
||||
}, { spaces: 2 });
|
||||
await fs.writeJson(
|
||||
path.join(fullPath, "messages/en.json"),
|
||||
{
|
||||
Index: {
|
||||
title: "Welcome",
|
||||
},
|
||||
},
|
||||
{ spaces: 2 },
|
||||
);
|
||||
await fs.writeJson(
|
||||
path.join(fullPath, "messages/de.json"),
|
||||
{
|
||||
Index: {
|
||||
title: "Willkommen",
|
||||
},
|
||||
},
|
||||
{ spaces: 2 },
|
||||
);
|
||||
|
||||
// Create instrumentation.ts
|
||||
await fs.writeFile(
|
||||
@@ -171,7 +191,7 @@ export async function register() {
|
||||
}
|
||||
|
||||
export const onRequestError = Sentry.captureRequestError;
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
@@ -192,11 +212,11 @@ export default function RootLayout({
|
||||
}) {
|
||||
return (
|
||||
<html lang={locale}>
|
||||
<body>{children}</body>
|
||||
<body className="antialiased">{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
await fs.writeFile(
|
||||
@@ -212,7 +232,7 @@ export default function Home() {
|
||||
</main>
|
||||
);
|
||||
}
|
||||
`
|
||||
`,
|
||||
);
|
||||
|
||||
// Copy infra templates
|
||||
@@ -220,21 +240,75 @@ export default function Home() {
|
||||
if (await fs.pathExists(infraPath)) {
|
||||
await fs.copy(
|
||||
path.join(infraPath, "docker/Dockerfile.nextjs"),
|
||||
path.join(fullPath, "Dockerfile")
|
||||
path.join(fullPath, "Dockerfile"),
|
||||
);
|
||||
await fs.copy(
|
||||
path.join(infraPath, "docker/docker-compose.template.yml"),
|
||||
path.join(fullPath, "docker-compose.yml")
|
||||
path.join(fullPath, "docker-compose.yml"),
|
||||
);
|
||||
await fs.ensureDir(path.join(fullPath, ".gitea/workflows"));
|
||||
await fs.copy(
|
||||
path.join(infraPath, "gitea/deploy-action.yml"),
|
||||
path.join(fullPath, ".gitea/workflows/deploy.yml")
|
||||
path.join(fullPath, ".gitea/workflows/deploy.yml"),
|
||||
);
|
||||
|
||||
// Create Directus structure
|
||||
await fs.ensureDir(path.join(fullPath, "directus/uploads"));
|
||||
await fs.ensureDir(path.join(fullPath, "directus/extensions"));
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "directus/uploads/.gitkeep"),
|
||||
"",
|
||||
);
|
||||
await fs.writeFile(
|
||||
path.join(fullPath, "directus/extensions/.gitkeep"),
|
||||
"",
|
||||
);
|
||||
|
||||
// Create .env.example
|
||||
const envExample = `# Project
|
||||
PROJECT_NAME=${projectName}
|
||||
PROJECT_COLOR=#82ed20
|
||||
|
||||
# Authentication
|
||||
GATEKEEPER_PASSWORD=mintel
|
||||
AUTH_COOKIE_NAME=mintel_gatekeeper_session
|
||||
|
||||
# Host Config (Local)
|
||||
TRAEFIK_HOST=\`${projectName}.localhost\`
|
||||
DIRECTUS_HOST=\`cms.${projectName}.localhost\`
|
||||
|
||||
# Next.js
|
||||
NEXT_PUBLIC_BASE_URL=http://${projectName}.localhost
|
||||
|
||||
# Directus
|
||||
DIRECTUS_URL=http://cms.${projectName}.localhost
|
||||
DIRECTUS_KEY=$(openssl rand -hex 32 2>/dev/null || echo "mintel-key")
|
||||
DIRECTUS_SECRET=$(openssl rand -hex 32 2>/dev/null || echo "mintel-secret")
|
||||
DIRECTUS_ADMIN_EMAIL=admin@mintel.me
|
||||
DIRECTUS_ADMIN_PASSWORD=mintel-admin-pass
|
||||
DIRECTUS_DB_NAME=directus
|
||||
DIRECTUS_DB_USER=directus
|
||||
DIRECTUS_DB_PASSWORD=mintel-db-pass
|
||||
|
||||
# Sentry / Glitchtip
|
||||
SENTRY_DSN=
|
||||
|
||||
# Analytics (Umami)
|
||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID=
|
||||
NEXT_PUBLIC_UMAMI_SCRIPT_URL=https://analytics.infra.mintel.me/script.js
|
||||
`;
|
||||
await fs.writeFile(path.join(fullPath, ".env.example"), envExample);
|
||||
|
||||
// Copy premium templates (globals.css, lib/directus.ts, scripts/setup-directus.ts)
|
||||
const templatePath = path.join(infraPath, "templates/website");
|
||||
if (await fs.pathExists(templatePath)) {
|
||||
console.log(chalk.blue("Applying premium templates..."));
|
||||
await fs.copy(templatePath, fullPath, { overwrite: true });
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
chalk.green(`Successfully initialized ${projectName} at ${fullPath}`)
|
||||
chalk.green(`Successfully initialized ${projectName} at ${fullPath}`),
|
||||
);
|
||||
console.log(chalk.yellow("\nNext steps:"));
|
||||
console.log(chalk.cyan("1. pnpm install"));
|
||||
|
||||
Reference in New Issue
Block a user