create-svc 0.1.9 → 0.1.11
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 +138 -16
- package/bin/create-service.mjs +2 -0
- package/package.json +19 -11
- package/src/cli.test.ts +46 -7
- package/src/cli.ts +282 -84
- package/src/git-bootstrap.test.ts +40 -0
- package/src/git-bootstrap.ts +110 -0
- package/src/naming.test.ts +5 -2
- package/src/naming.ts +32 -1
- package/src/neon.ts +10 -8
- package/src/post-scaffold.test.ts +19 -0
- package/src/post-scaffold.ts +18 -26
- package/src/profiles.ts +25 -0
- package/src/scaffold.test.ts +320 -18
- package/src/scaffold.ts +154 -28
- package/src/vault.test.ts +94 -10
- package/src/vault.ts +81 -18
- package/templates/shared/.github/workflows/ci.yml +2 -1
- package/templates/shared/.github/workflows/deploy.yml +2 -0
- package/templates/shared/README.md +217 -29
- package/templates/shared/docker-compose.yml +19 -0
- package/templates/shared/grafana/alerts.yaml +54 -0
- package/templates/shared/grafana/waitlist-dashboard.json +63 -0
- package/templates/shared/scripts/authctl.ts +231 -0
- package/templates/shared/scripts/cloudrun/bootstrap.ts +24 -42
- package/templates/shared/scripts/cloudrun/cleanup.ts +81 -35
- package/templates/shared/scripts/cloudrun/cli.ts +324 -7
- package/templates/shared/scripts/cloudrun/config.ts +21 -19
- package/templates/shared/scripts/cloudrun/deploy.ts +16 -11
- package/templates/shared/scripts/cloudrun/lib.ts +232 -123
- package/templates/shared/scripts/cloudrun/neon.ts +127 -13
- package/templates/shared/scripts/dev.ts +22 -0
- package/templates/shared/scripts/ensure-local-db.ts +3 -0
- package/templates/shared/scripts/local-docker.ts +63 -0
- package/templates/shared/scripts/local-env.ts +27 -0
- package/templates/shared/scripts/seed.ts +73 -0
- package/templates/shared/scripts/wait-for-db.ts +32 -0
- package/templates/shared/service.config.ts +59 -0
- package/templates/shared/service.yaml +24 -1
- package/templates/targets/workers/.github/workflows/ci.yml +19 -0
- package/templates/targets/workers/.github/workflows/deploy.yml +19 -0
- package/templates/targets/workers/Makefile +33 -0
- package/templates/targets/workers/README.md +75 -0
- package/templates/targets/workers/package.json +35 -0
- package/templates/targets/workers/scripts/workers/cli.ts +397 -0
- package/templates/targets/workers/src/auth.ts +178 -0
- package/templates/targets/workers/src/index.ts +198 -0
- package/templates/targets/workers/src/storage.ts +370 -0
- package/templates/targets/workers/test/app.test.ts +108 -0
- package/templates/targets/workers/tsconfig.json +11 -0
- package/templates/targets/workers/wrangler.toml +24 -0
- package/templates/variants/bun-connectrpc/Dockerfile +1 -0
- package/templates/variants/bun-connectrpc/Makefile +17 -8
- package/templates/variants/bun-connectrpc/gen/protos/waitlist/v1/waitlist_pb.ts +424 -0
- package/templates/variants/bun-connectrpc/migrations/0000_init.sql +20 -0
- package/templates/variants/bun-connectrpc/package.json +25 -1
- package/templates/variants/bun-connectrpc/protos/waitlist/v1/waitlist.proto +91 -0
- package/templates/variants/bun-connectrpc/scripts/codegen.ts +31 -1
- package/templates/variants/bun-connectrpc/scripts/migrate.ts +49 -0
- package/templates/variants/bun-connectrpc/src/auth.ts +200 -0
- package/templates/variants/bun-connectrpc/src/db/client.ts +15 -0
- package/templates/variants/bun-connectrpc/src/db/repository.ts +126 -0
- package/templates/variants/bun-connectrpc/src/db/schema.ts +26 -0
- package/templates/variants/bun-connectrpc/src/index.ts +194 -22
- package/templates/variants/bun-connectrpc/src/temporal/activities.ts +14 -0
- package/templates/variants/bun-connectrpc/src/temporal/worker.ts +38 -0
- package/templates/variants/bun-connectrpc/src/temporal/workflows.ts +10 -0
- package/templates/variants/bun-connectrpc/src/waitlist/service.ts +172 -0
- package/templates/variants/bun-connectrpc/src/waitlist/types.ts +45 -0
- package/templates/variants/bun-connectrpc/test/app.test.ts +14 -13
- package/templates/variants/bun-connectrpc/test/waitlist.integration.test.ts +71 -0
- package/templates/variants/bun-connectrpc/tsconfig.json +2 -1
- package/templates/variants/bun-hono/Makefile +17 -8
- package/templates/variants/bun-hono/migrations/0000_init.sql +20 -0
- package/templates/variants/bun-hono/package.json +21 -1
- package/templates/variants/bun-hono/scripts/migrate.ts +49 -0
- package/templates/variants/bun-hono/src/auth.ts +181 -0
- package/templates/variants/bun-hono/src/db/client.ts +15 -0
- package/templates/variants/bun-hono/src/db/repository.ts +126 -0
- package/templates/variants/bun-hono/src/db/schema.ts +26 -0
- package/templates/variants/bun-hono/src/index.ts +141 -10
- package/templates/variants/bun-hono/src/temporal/activities.ts +14 -0
- package/templates/variants/bun-hono/src/temporal/worker.ts +38 -0
- package/templates/variants/bun-hono/src/temporal/workflows.ts +10 -0
- package/templates/variants/bun-hono/src/waitlist/service.ts +166 -0
- package/templates/variants/bun-hono/src/waitlist/types.ts +50 -0
- package/templates/variants/bun-hono/test/app.test.ts +90 -5
- package/templates/variants/bun-hono/test/waitlist.integration.test.ts +102 -0
- package/templates/variants/bun-hono/tsconfig.json +1 -0
- package/templates/variants/go-chi/Makefile +30 -10
- package/templates/variants/go-chi/atlas.hcl +8 -0
- package/templates/variants/go-chi/cmd/server/main.go +25 -13
- package/templates/variants/go-chi/go.mod +3 -2
- package/templates/variants/go-chi/internal/app/service.go +279 -70
- package/templates/variants/go-chi/internal/auth/middleware.go +289 -0
- package/templates/variants/go-chi/internal/auth/middleware_test.go +38 -0
- package/templates/variants/go-chi/internal/config/config.go +38 -7
- package/templates/variants/go-chi/internal/httpapi/routes.go +170 -47
- package/templates/variants/go-chi/internal/httpapi/waitlist_integration_test.go +199 -0
- package/templates/variants/go-chi/internal/temporal/activities.go +27 -0
- package/templates/variants/go-chi/internal/temporal/worker.go +42 -0
- package/templates/variants/go-chi/internal/temporal/workflows.go +18 -0
- package/templates/variants/go-chi/migrations/0000_init.sql +20 -0
- package/templates/variants/go-chi/migrations/atlas.sum +2 -0
- package/templates/variants/go-chi/package.json +7 -1
- package/templates/variants/go-chi/test/go.test.ts +4 -1
- package/templates/variants/go-connectrpc/Makefile +29 -8
- package/templates/variants/go-connectrpc/atlas.hcl +8 -0
- package/templates/variants/go-connectrpc/buf.gen.yaml +2 -0
- package/templates/variants/go-connectrpc/cmd/server/main.go +44 -9
- package/templates/variants/go-connectrpc/gen/waitlist/v1/waitlist.pb.go +960 -0
- package/templates/variants/go-connectrpc/gen/waitlist/v1/waitlistv1connect/waitlist.connect.go +283 -0
- package/templates/variants/go-connectrpc/go.mod +4 -0
- package/templates/variants/go-connectrpc/internal/app/service.go +279 -70
- package/templates/variants/go-connectrpc/internal/auth/middleware.go +289 -0
- package/templates/variants/go-connectrpc/internal/auth/middleware_test.go +38 -0
- package/templates/variants/go-connectrpc/internal/config/config.go +38 -7
- package/templates/variants/go-connectrpc/internal/connectapi/handler.go +129 -40
- package/templates/variants/go-connectrpc/internal/connectapi/waitlist_integration_test.go +122 -0
- package/templates/variants/go-connectrpc/internal/httpapi/routes.go +170 -47
- package/templates/variants/go-connectrpc/internal/temporal/activities.go +27 -0
- package/templates/variants/go-connectrpc/internal/temporal/worker.go +42 -0
- package/templates/variants/go-connectrpc/internal/temporal/workflows.go +18 -0
- package/templates/variants/go-connectrpc/migrations/0000_init.sql +20 -0
- package/templates/variants/go-connectrpc/migrations/atlas.sum +2 -0
- package/templates/variants/go-connectrpc/package.json +7 -1
- package/templates/variants/go-connectrpc/protos/waitlist/v1/waitlist.proto +93 -0
- package/templates/root/.github/workflows/buf-publish.yml +0 -19
- package/templates/root/.github/workflows/ci.yml +0 -26
- package/templates/root/.github/workflows/deploy.yml +0 -22
- package/templates/root/Dockerfile +0 -23
- package/templates/root/README.md +0 -69
- package/templates/root/buf.gen.yaml +0 -10
- package/templates/root/buf.yaml +0 -9
- package/templates/root/cmd/server/main.go +0 -44
- package/templates/root/gen/dns/v1/dns.pb.go +0 -623
- package/templates/root/gen/dns/v1/dnsv1connect/dns.connect.go +0 -192
- package/templates/root/go.mod +0 -10
- package/templates/root/internal/app/service.go +0 -152
- package/templates/root/internal/app/token_source.go +0 -50
- package/templates/root/internal/cloudflare/client.go +0 -160
- package/templates/root/internal/config/config.go +0 -55
- package/templates/root/internal/connectapi/handler.go +0 -79
- package/templates/root/internal/httpapi/routes.go +0 -93
- package/templates/root/internal/vault/client.go +0 -148
- package/templates/root/package.json +0 -12
- package/templates/root/protos/dns/v1/dns.proto +0 -58
- package/templates/root/scripts/cloudrun/bootstrap.ts +0 -65
- package/templates/root/scripts/cloudrun/config.ts +0 -50
- package/templates/root/scripts/cloudrun/deploy.ts +0 -41
- package/templates/root/scripts/cloudrun/lib.ts +0 -244
- package/templates/root/service.yaml +0 -50
- package/templates/root/test/go.test.ts +0 -19
- package/templates/shared/.env.example +0 -10
- package/templates/variants/go-chi/buf.gen.yaml +0 -10
- package/templates/variants/go-chi/buf.yaml +0 -9
- package/templates/variants/go-chi/gen/dns/v1/dns.pb.go +0 -623
- package/templates/variants/go-chi/gen/dns/v1/dnsv1connect/dns.connect.go +0 -192
- package/templates/variants/go-chi/internal/connectapi/handler.go +0 -79
- package/templates/variants/go-chi/protos/dns/v1/dns.proto +0 -58
- package/templates/variants/go-connectrpc/gen/dns/v1/dns.pb.go +0 -623
- package/templates/variants/go-connectrpc/gen/dns/v1/dnsv1connect/dns.connect.go +0 -192
- package/templates/variants/go-connectrpc/protos/dns/v1/dns.proto +0 -58
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
|
|
4
|
+
export type GitBootstrapConfig = {
|
|
5
|
+
enabled: boolean;
|
|
6
|
+
owner: string;
|
|
7
|
+
repository: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export type GitBootstrapResult =
|
|
11
|
+
| { status: "disabled" }
|
|
12
|
+
| { status: "skipped-existing-worktree"; root: string }
|
|
13
|
+
| { status: "created"; url: string };
|
|
14
|
+
|
|
15
|
+
export function buildGitBootstrapConfig(serviceName: string, noGit: boolean | undefined): GitBootstrapConfig {
|
|
16
|
+
return {
|
|
17
|
+
enabled: !noGit,
|
|
18
|
+
owner: "anmho",
|
|
19
|
+
repository: serviceName,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function bootstrapGitHubRepository(targetDir: string, config: GitBootstrapConfig): Promise<GitBootstrapResult> {
|
|
24
|
+
if (!config.enabled) {
|
|
25
|
+
return { status: "disabled" };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const existingRoot = findExistingGitWorktree(targetDir);
|
|
29
|
+
if (existingRoot) {
|
|
30
|
+
return { status: "skipped-existing-worktree", root: existingRoot };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
run(["git", "--version"], targetDir, "git is required to initialize the generated repository");
|
|
34
|
+
run(["gh", "--version"], targetDir, "GitHub CLI `gh` is required to create the generated repository");
|
|
35
|
+
run(["gh", "auth", "status"], targetDir, "Authenticate GitHub CLI with `gh auth login` before creating the repository");
|
|
36
|
+
|
|
37
|
+
run(["git", "init", "-b", "main"], targetDir);
|
|
38
|
+
run(["git", "add", "."], targetDir);
|
|
39
|
+
|
|
40
|
+
if (hasStagedChanges(targetDir)) {
|
|
41
|
+
run(["git", "commit", "-m", "Initial commit"], targetDir);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const repository = `${config.owner}/${config.repository}`;
|
|
45
|
+
run(["gh", "repo", "create", repository, "--private", "--source", ".", "--remote", "origin", "--push"], targetDir);
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
status: "created",
|
|
49
|
+
url: `https://github.com/${repository}`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function commitAndPushGeneratedArtifacts(targetDir: string, message: string) {
|
|
54
|
+
run(["git", "add", "."], targetDir);
|
|
55
|
+
if (!hasStagedChanges(targetDir)) {
|
|
56
|
+
return { committed: false };
|
|
57
|
+
}
|
|
58
|
+
run(["git", "commit", "-m", message], targetDir);
|
|
59
|
+
run(["git", "push"], targetDir);
|
|
60
|
+
return { committed: true };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function findExistingGitWorktree(targetDir: string) {
|
|
64
|
+
const cwd = existingPath(targetDir);
|
|
65
|
+
const result = Bun.spawnSync(["git", "-C", cwd, "rev-parse", "--show-toplevel"], {
|
|
66
|
+
stdout: "pipe",
|
|
67
|
+
stderr: "pipe",
|
|
68
|
+
});
|
|
69
|
+
if (result.exitCode !== 0) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return result.stdout.toString().trim() || undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function existingPath(path: string): string {
|
|
76
|
+
if (existsSync(path)) {
|
|
77
|
+
return path;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const parent = dirname(path);
|
|
81
|
+
if (parent === path) {
|
|
82
|
+
return path;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return existingPath(parent);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function hasStagedChanges(cwd: string) {
|
|
89
|
+
const result = Bun.spawnSync(["git", "diff", "--cached", "--quiet"], {
|
|
90
|
+
cwd,
|
|
91
|
+
stdout: "pipe",
|
|
92
|
+
stderr: "pipe",
|
|
93
|
+
});
|
|
94
|
+
return result.exitCode === 1;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function run(command: string[], cwd: string, message?: string) {
|
|
98
|
+
const result = Bun.spawnSync(command, {
|
|
99
|
+
cwd,
|
|
100
|
+
stdin: "inherit",
|
|
101
|
+
stdout: "inherit",
|
|
102
|
+
stderr: "pipe",
|
|
103
|
+
});
|
|
104
|
+
if (result.exitCode === 0) {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const detail = result.stderr.toString().trim();
|
|
109
|
+
throw new Error([message, `Command failed: ${command.join(" ")}`, detail].filter(Boolean).join("\n"));
|
|
110
|
+
}
|
package/src/naming.test.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { expect, test } from "bun:test";
|
|
2
|
-
import { buildGcpProjectOptions, compactDatabaseName, compactIdentifier, deriveDefaults } from "./naming";
|
|
2
|
+
import { buildGcpProjectOptions, compactDatabaseName, compactIdentifier, deriveDefaults, deriveLocalPostgresPort } from "./naming";
|
|
3
3
|
|
|
4
4
|
test("deriveDefaults uses the service name for project, repo, and database naming", () => {
|
|
5
5
|
expect(deriveDefaults("edge-api")).toEqual({
|
|
6
|
+
serviceId: "edge-api",
|
|
6
7
|
serviceName: "edge-api",
|
|
7
8
|
projectName: "edge-api",
|
|
8
9
|
projectId: "anmho-edge-api",
|
|
9
|
-
githubRepo: "anmho/edge-api",
|
|
10
10
|
cloudRunService: "edge-api",
|
|
11
11
|
neonDatabaseName: "edge_api",
|
|
12
|
+
localDatabasePort: deriveLocalPostgresPort("edge-api"),
|
|
13
|
+
apiHostname: "api.edge-api.anmho.com",
|
|
14
|
+
modulePath: "example.com/edge-api",
|
|
12
15
|
});
|
|
13
16
|
});
|
|
14
17
|
|
package/src/naming.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
export const BILLING_ACCOUNT_DEFAULT = "billingAccounts/01BD2E-3A6949-8F4C84";
|
|
2
2
|
export const QUOTA_PROJECT_DEFAULT = "anmho-infra-prod";
|
|
3
3
|
|
|
4
|
+
export const DEPLOY_TARGETS = ["cloudrun", "workers"] as const;
|
|
5
|
+
|
|
6
|
+
export type DeployTarget = (typeof DEPLOY_TARGETS)[number];
|
|
7
|
+
|
|
4
8
|
export const FRAMEWORKS_BY_RUNTIME = {
|
|
5
9
|
go: ["chi", "connectrpc"],
|
|
6
10
|
bun: ["hono", "connectrpc"],
|
|
@@ -10,6 +14,24 @@ export type Runtime = keyof typeof FRAMEWORKS_BY_RUNTIME;
|
|
|
10
14
|
export type Framework = (typeof FRAMEWORKS_BY_RUNTIME)[Runtime][number];
|
|
11
15
|
export type GcpProjectMode = "create_new" | "use_existing";
|
|
12
16
|
|
|
17
|
+
export function parseDeployTarget(value: string): DeployTarget {
|
|
18
|
+
if (DEPLOY_TARGETS.includes(value as DeployTarget)) {
|
|
19
|
+
return value as DeployTarget;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
throw new Error(`Unknown target: ${value}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function frameworksForTargetRuntime(target: DeployTarget, runtime: Runtime): readonly Framework[] {
|
|
26
|
+
if (target === "workers") {
|
|
27
|
+
if (runtime === "bun") {
|
|
28
|
+
return ["hono"];
|
|
29
|
+
}
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
return FRAMEWORKS_BY_RUNTIME[runtime];
|
|
33
|
+
}
|
|
34
|
+
|
|
13
35
|
export function slugify(value: string, maxLength = 63) {
|
|
14
36
|
return value
|
|
15
37
|
.trim()
|
|
@@ -54,16 +76,25 @@ export function compactDatabaseName(serviceName: string) {
|
|
|
54
76
|
});
|
|
55
77
|
}
|
|
56
78
|
|
|
79
|
+
export function deriveLocalPostgresPort(serviceName: string) {
|
|
80
|
+
const normalized = slugify(serviceName) || "my-service";
|
|
81
|
+
const hash = Number.parseInt(shortHash(normalized).slice(0, 4), 16);
|
|
82
|
+
return String(55000 + (hash % 1000));
|
|
83
|
+
}
|
|
84
|
+
|
|
57
85
|
export function deriveDefaults(serviceName: string) {
|
|
58
86
|
const normalizedServiceName = slugify(serviceName) || "my-service";
|
|
59
87
|
|
|
60
88
|
return {
|
|
89
|
+
serviceId: normalizedServiceName,
|
|
61
90
|
serviceName: normalizedServiceName,
|
|
62
91
|
projectName: normalizedServiceName,
|
|
63
92
|
projectId: compactIdentifier(`anmho-${normalizedServiceName}`, 30),
|
|
64
|
-
githubRepo: `anmho/${normalizedServiceName}`,
|
|
65
93
|
cloudRunService: normalizedServiceName,
|
|
66
94
|
neonDatabaseName: compactDatabaseName(normalizedServiceName),
|
|
95
|
+
localDatabasePort: deriveLocalPostgresPort(normalizedServiceName),
|
|
96
|
+
apiHostname: `api.${normalizedServiceName}.anmho.com`,
|
|
97
|
+
modulePath: `example.com/${normalizedServiceName}`,
|
|
67
98
|
};
|
|
68
99
|
}
|
|
69
100
|
|
package/src/neon.ts
CHANGED
|
@@ -21,25 +21,27 @@ export function createNeonApi(apiKey = process.env.NEON_API_KEY): NeonApi {
|
|
|
21
21
|
async listProjects() {
|
|
22
22
|
const client = createApiClient({ apiKey: (apiKey?.trim() || (await resolveNeonApiKey())) });
|
|
23
23
|
const payload = await client.listProjects({ limit: 100 });
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
const projects = ((payload.data as { projects?: Array<{ id?: string; name?: string }> } | undefined)?.projects ?? []);
|
|
25
|
+
return projects
|
|
26
|
+
.map((project: { id?: string; name?: string }) => ({
|
|
26
27
|
id: project.id ?? "",
|
|
27
28
|
name: project.name ?? project.id ?? "",
|
|
28
29
|
}))
|
|
29
|
-
.filter((project) => project.id)
|
|
30
|
-
.sort((left, right) => left.name.localeCompare(right.name));
|
|
30
|
+
.filter((project: NeonProject) => Boolean(project.id))
|
|
31
|
+
.sort((left: NeonProject, right: NeonProject) => left.name.localeCompare(right.name));
|
|
31
32
|
},
|
|
32
33
|
|
|
33
34
|
async listBranches(projectId: string) {
|
|
34
35
|
const client = createApiClient({ apiKey: (apiKey?.trim() || (await resolveNeonApiKey())) });
|
|
35
36
|
const payload = await client.listProjectBranches({ projectId });
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
const branches = ((payload.data as { branches?: Array<{ id?: string; name?: string }> } | undefined)?.branches ?? []);
|
|
38
|
+
return branches
|
|
39
|
+
.map((branch: { id?: string; name?: string }) => ({
|
|
38
40
|
id: branch.id ?? "",
|
|
39
41
|
name: branch.name ?? branch.id ?? "",
|
|
40
42
|
}))
|
|
41
|
-
.filter((branch) => branch.id)
|
|
42
|
-
.sort((left, right) => left.name.localeCompare(right.name));
|
|
43
|
+
.filter((branch: NeonBranch) => Boolean(branch.id))
|
|
44
|
+
.sort((left: NeonBranch, right: NeonBranch) => left.name.localeCompare(right.name));
|
|
43
45
|
},
|
|
44
46
|
};
|
|
45
47
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { buildPostScaffoldCommands } from "./post-scaffold";
|
|
3
|
+
|
|
4
|
+
describe("buildPostScaffoldCommands", () => {
|
|
5
|
+
test("runs create and deploy for HTTP services", () => {
|
|
6
|
+
expect(buildPostScaffoldCommands({ framework: "hono" })).toEqual([
|
|
7
|
+
{ command: "bun", args: ["run", "service", "--", "create"] },
|
|
8
|
+
{ command: "bun", args: ["run", "service", "--", "deploy"] },
|
|
9
|
+
]);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
test("builds SDK artifacts before create and deploy for ConnectRPC services", () => {
|
|
13
|
+
expect(buildPostScaffoldCommands({ framework: "connectrpc" })).toEqual([
|
|
14
|
+
{ command: "bun", args: ["run", "service", "--", "sdk", "build"] },
|
|
15
|
+
{ command: "bun", args: ["run", "service", "--", "create"] },
|
|
16
|
+
{ command: "bun", args: ["run", "service", "--", "deploy"] },
|
|
17
|
+
]);
|
|
18
|
+
});
|
|
19
|
+
});
|
package/src/post-scaffold.ts
CHANGED
|
@@ -12,40 +12,32 @@ type CommandResult = {
|
|
|
12
12
|
stderr: string;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
type PostScaffoldCommand = {
|
|
16
|
+
command: string;
|
|
17
|
+
args: string[];
|
|
18
|
+
};
|
|
19
|
+
|
|
15
20
|
const decoder = new TextDecoder();
|
|
21
|
+
const encoder = new TextEncoder();
|
|
16
22
|
|
|
17
23
|
export async function runPostScaffoldFlow(config: ScaffoldConfig, cwd: string) {
|
|
18
|
-
if (config.createGithubRepo) {
|
|
19
|
-
initializeRepository(cwd);
|
|
20
|
-
createGitHubRepo(config, cwd);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
24
|
if (config.autoDeploy) {
|
|
24
25
|
installProjectDependencies(cwd);
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
for (const command of buildPostScaffoldCommands(config)) {
|
|
27
|
+
run(command.command, command.args, { cwd });
|
|
28
|
+
}
|
|
29
|
+
return { message: "Dependencies installed, service created, and service deployed" };
|
|
28
30
|
}
|
|
29
31
|
|
|
30
|
-
return { message: "
|
|
32
|
+
return { message: "Backend package generated" };
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
function createGitHubRepo(config: ScaffoldConfig, cwd: string) {
|
|
41
|
-
requireCommand("gh");
|
|
42
|
-
|
|
43
|
-
const existing = run("gh", ["repo", "view", config.githubRepo], { cwd, allowFailure: true });
|
|
44
|
-
if (!existing.success) {
|
|
45
|
-
run("gh", ["repo", "create", config.githubRepo, `--${config.githubVisibility}`, "--source=.", "--remote=origin"], { cwd });
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
run("git", ["push", "-u", "origin", "main"], { cwd, allowFailure: true });
|
|
35
|
+
export function buildPostScaffoldCommands(config: Pick<ScaffoldConfig, "framework">): PostScaffoldCommand[] {
|
|
36
|
+
return [
|
|
37
|
+
...(config.framework === "connectrpc" ? [{ command: "bun", args: ["run", "service", "--", "sdk", "build"] }] : []),
|
|
38
|
+
{ command: "bun", args: ["run", "service", "--", "create"] },
|
|
39
|
+
{ command: "bun", args: ["run", "service", "--", "deploy"] },
|
|
40
|
+
];
|
|
49
41
|
}
|
|
50
42
|
|
|
51
43
|
function installProjectDependencies(cwd: string) {
|
|
@@ -63,7 +55,7 @@ function run(command: string, args: string[], options: CommandOptions): CommandR
|
|
|
63
55
|
const result = Bun.spawnSync([command, ...args], {
|
|
64
56
|
cwd: options.cwd,
|
|
65
57
|
env: process.env,
|
|
66
|
-
stdin: options.input,
|
|
58
|
+
stdin: options.input === undefined ? undefined : encoder.encode(options.input),
|
|
67
59
|
stdout: options.allowFailure ? "pipe" : "inherit",
|
|
68
60
|
stderr: options.allowFailure ? "pipe" : "inherit",
|
|
69
61
|
});
|
package/src/profiles.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const PROFILES = ["microservice"] as const;
|
|
2
|
+
|
|
3
|
+
export type Profile = (typeof PROFILES)[number];
|
|
4
|
+
|
|
5
|
+
export function parseProfile(value: string): Profile {
|
|
6
|
+
if (PROFILES.includes(value as Profile)) {
|
|
7
|
+
return value as Profile;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (value === "app") {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"The app profile has moved out of create-service. Use the private create-app template repositories instead."
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
throw new Error(`Unknown profile: ${value}`);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function exampleForProfile(_profile: Profile) {
|
|
20
|
+
return {
|
|
21
|
+
kind: "microservice",
|
|
22
|
+
domain: "waitlist",
|
|
23
|
+
label: "waitlist/launch service",
|
|
24
|
+
};
|
|
25
|
+
}
|