diff --git a/.changeset/nasty-dolphins-prove.md b/.changeset/nasty-dolphins-prove.md new file mode 100644 index 000000000000..1653772ef09e --- /dev/null +++ b/.changeset/nasty-dolphins-prove.md @@ -0,0 +1,11 @@ +--- +"create-cloudflare": minor +--- + +add final commit when generating Pages projects + +before after the user would have completed the creation of a Pages project +they would find the Cloudflare added/modified files uncommitted, instead of +leaving these uncommitted this change adds an extra commit (on top of the +framework specific) which also contains some useful information about the +project diff --git a/packages/create-cloudflare/e2e-tests/pages.test.ts b/packages/create-cloudflare/e2e-tests/pages.test.ts index 41c22d248a1e..db60c4a5de5d 100644 --- a/packages/create-cloudflare/e2e-tests/pages.test.ts +++ b/packages/create-cloudflare/e2e-tests/pages.test.ts @@ -14,6 +14,7 @@ Areas for future improvement: type FrameworkTestConfig = RunnerConfig & { expectResponseToContain: string; + testCommitMessage: boolean; }; describe(`E2E: Web frameworks`, () => { @@ -89,7 +90,10 @@ describe(`E2E: Web frameworks`, () => { return { output }; }; - const runCliWithDeploy = async (framework: string) => { + const runCliWithDeploy = async ( + framework: string, + testCommitMessage: boolean + ) => { const { argv, overrides, promptHandlers, expectResponseToContain } = frameworkTests[framework]; @@ -119,15 +123,21 @@ describe(`E2E: Web frameworks`, () => { body, `(${framework}) Deployed page (${projectUrl}) didn't contain expected string: "${expectResponseToContain}"` ).toContain(expectResponseToContain); + + if (testCommitMessage) { + await testDeploymentCommitMessage(getName(framework), framework); + } }; // These are ordered based on speed and reliability for ease of debugging const frameworkTests: Record = { astro: { expectResponseToContain: "Hello, Astronaut!", + testCommitMessage: true, }, hono: { expectResponseToContain: "Hello Hono!", + testCommitMessage: false, }, qwik: { expectResponseToContain: "Welcome to Qwik", @@ -137,9 +147,11 @@ describe(`E2E: Web frameworks`, () => { input: [keys.enter], }, ], + testCommitMessage: true, }, remix: { expectResponseToContain: "Welcome to Remix", + testCommitMessage: true, }, next: { expectResponseToContain: "Create Next App", @@ -149,6 +161,7 @@ describe(`E2E: Web frameworks`, () => { input: ["y"], }, ], + testCommitMessage: true, }, nuxt: { expectResponseToContain: "Welcome to Nuxt!", @@ -157,9 +170,11 @@ describe(`E2E: Web frameworks`, () => { build: "NITRO_PRESET=cloudflare-pages nuxt build", }, }, + testCommitMessage: true, }, react: { expectResponseToContain: "React App", + testCommitMessage: true, }, solid: { expectResponseToContain: "Hello world", @@ -177,6 +192,7 @@ describe(`E2E: Web frameworks`, () => { input: [keys.enter], }, ], + testCommitMessage: true, }, svelte: { expectResponseToContain: "SvelteKit app", @@ -194,16 +210,18 @@ describe(`E2E: Web frameworks`, () => { input: [keys.enter], }, ], + testCommitMessage: true, }, vue: { expectResponseToContain: "Vite App", + testCommitMessage: true, }, }; test.concurrent.each(Object.keys(frameworkTests))( "%s", async (name) => { - await runCliWithDeploy(name); + await runCliWithDeploy(name, frameworkTests[name].testCommitMessage); }, { retry: 3 } ); @@ -212,3 +230,48 @@ describe(`E2E: Web frameworks`, () => { await runCli("hono", { argv: ["--wrangler-defaults"] }); }); }); + +const testDeploymentCommitMessage = async ( + projectName: string, + framework: string +) => { + // Note: we cannot simply run git and check the result since the commit can be part of the + // deployment even without git, so instead we fetch the deployment info from the pages api + const response = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.CLOUDFLARE_ACCOUNT_ID}/pages/projects`, + { + headers: { + Authorization: `Bearer ${process.env.CLOUDFLARE_API_TOKEN}`, + }, + } + ); + + const result = ( + (await response.json()) as { + result: { + name: string; + latest_deployment?: { + deployment_trigger: { + metadata?: { + commit_message: string; + }; + }; + }; + }[]; + } + ).result; + + const projectLatestCommitMessage = result.find( + (project) => project.name === projectName + )?.latest_deployment?.deployment_trigger?.metadata?.commit_message; + expect(projectLatestCommitMessage).toMatch( + /^Initialize web application via create-cloudflare CLI/ + ); + // TODO: add back checks the following when the commit message doesn't + // get truncated at 128 characters + // expect(projectLatestCommitMessage).toContain( + // `C3 = create-cloudflare@${version}` + // ); + // expect(projectLatestCommitMessage).toContain(`project name = ${projectName}`); + // expect(projectLatestCommitMessage).toContain(`framework = ${framework}`); +}; diff --git a/packages/create-cloudflare/src/common.ts b/packages/create-cloudflare/src/common.ts index 1b822fcfde2b..4f7ff425cd64 100644 --- a/packages/create-cloudflare/src/common.ts +++ b/packages/create-cloudflare/src/common.ts @@ -1,6 +1,7 @@ import { existsSync, mkdirSync, readdirSync } from "fs"; import { basename, dirname, resolve } from "path"; import { chdir } from "process"; +import { getFrameworkCli } from "frameworks/index"; import { crash, endSection, @@ -23,10 +24,12 @@ import { import { inputPrompt, processArgument, spinner } from "helpers/interactive"; import { detectPackageManager } from "helpers/packages"; import { poll } from "helpers/poll"; +import { version as wranglerVersion } from "wrangler/package.json"; +import { version } from "../package.json"; import { C3_DEFAULTS } from "./cli"; import type { C3Args, PagesGeneratorContext } from "types"; -const { npm } = detectPackageManager(); +const { name, npm } = detectPackageManager(); export const validateProjectDirectory = (relativePath: string) => { const path = resolve(relativePath); @@ -47,7 +50,7 @@ export const setupProjectDirectory = (args: C3Args) => { } const directory = dirname(path); - const name = basename(path); + const pathBasename = basename(path); // If the target is a nested directory, create the parent mkdirSync(directory, { recursive: true }); @@ -55,7 +58,7 @@ export const setupProjectDirectory = (args: C3Args) => { // Change to the parent directory chdir(directory); - return { name, path }; + return { name: pathBasename, path }; }; export const offerToDeploy = async (ctx: PagesGeneratorContext) => { @@ -87,15 +90,36 @@ export const runDeploy = async (ctx: PagesGeneratorContext) => { return; } - const deployCmd = `${npm} run ${ - ctx.framework?.config.deployCommand ?? "deploy" - }`; + const baseDeployCmd = [ + npm, + "run", + ctx.framework?.config.deployCommand ?? "deploy", + ]; + + const insideGitRepo = await isInsideGitRepo(ctx.project.path); + + const deployCmd = [ + ...baseDeployCmd, + // Important: the following assumes that all framework deploy commands terminate with `wrangler pages deploy` + ...(ctx.framework?.commitMessage && !insideGitRepo + ? [ + ...(name === "npm" ? ["--"] : []), + `--commit-message="${ctx.framework.commitMessage.replaceAll( + '"', + '\\"' + )}"`, + ] + : []), + ]; + const result = await runCommand(deployCmd, { silent: true, cwd: ctx.project.path, env: { CLOUDFLARE_ACCOUNT_ID: ctx.account.id, NODE_ENV: "production" }, - startText: `Deploying your application`, - doneText: `${brandColor("deployed")} ${dim(`via \`${deployCmd}\``)}`, + startText: "Deploying your application", + doneText: `${brandColor("deployed")} ${dim( + `via \`${baseDeployCmd.join(" ")}\`` + )}`, }); const deployedUrlRegex = /https:\/\/.+\.(pages|workers)\.dev/; @@ -130,10 +154,12 @@ export const chooseAccount = async (ctx: PagesGeneratorContext) => { s.stop( `${brandColor("account")} ${dim("more than one account available")}` ); - const accountOptions = Object.entries(accounts).map(([name, id]) => ({ - label: name, - value: id, - })); + const accountOptions = Object.entries(accounts).map( + ([accountName, id]) => ({ + label: accountName, + value: id, + }) + ); accountId = await inputPrompt({ type: "select", @@ -144,7 +170,7 @@ export const chooseAccount = async (ctx: PagesGeneratorContext) => { }); } const accountName = Object.keys(accounts).find( - (name) => accounts[name] == accountId + (account) => accounts[account] == accountId ) as string; ctx.account = { id: accountId, name: accountName }; @@ -250,33 +276,89 @@ export const offerGit = async (ctx: PagesGeneratorContext) => { }; export const gitCommit = async (ctx: PagesGeneratorContext) => { - if (!ctx.args.git) return; + // Note: createCommitMessage stores the message in ctx so that it can + // be used later even if we're not in a git repository, that's why + // we unconditionally run this command here + const commitMessage = await createCommitMessage(ctx); + + if (!(await isGitInstalled()) || !(await isInsideGitRepo(ctx.project.path))) + return; await runCommands({ silent: true, cwd: ctx.project.path, - commands: [ - "git add .", - ["git", "commit", "-m", "Initial commit (by Create-Cloudflare CLI)"], - ], + commands: ["git add .", ["git", "commit", "-m", commitMessage]], startText: "Committing new files", - doneText: `${brandColor("git")} ${dim(`initial commit`)}`, + doneText: `${brandColor("git")} ${dim(`commit`)}`, }); }; +const createCommitMessage = async (ctx: PagesGeneratorContext) => { + if (!ctx.framework) return "Initial commit (by create-cloudflare CLI)"; + + const header = "Initialize web application via create-cloudflare CLI"; + + const packageManager = detectPackageManager(); + + const gitVersion = await getGitVersion(); + const insideRepo = await isInsideGitRepo(ctx.project.path); + + const details = [ + { key: "C3", value: `create-cloudflare@${version}` }, + { key: "project name", value: ctx.project.name }, + { key: "framework", value: ctx.framework.name }, + { key: "framework cli", value: getFrameworkCli(ctx) }, + { + key: "package manager", + value: `${packageManager.name}@${packageManager.version}`, + }, + { + key: "wrangler", + value: `wrangler@${wranglerVersion}`, + }, + { + key: "git", + value: insideRepo ? gitVersion : "N/A", + }, + ]; + + const body = `Details:\n${details + .map(({ key, value }) => ` ${key} = ${value}`) + .join("\n")}\n`; + + const commitMessage = `${header}\n\n${body}\n`; + + if (ctx.type !== "workers") { + ctx.framework.commitMessage = commitMessage; + } + + return commitMessage; +}; + /** - * Check whether git is available on the user's machine. + * Return the version of git on the user's machine, or null if git is not available. */ -export async function isGitInstalled() { +async function getGitVersion() { try { - await runCommand("git -v", { useSpinner: false, silent: true }); - - return true; + const rawGitVersion = await runCommand("git --version", { + useSpinner: false, + silent: true, + }); + // let's remove the "git version " prefix as it isn't really helpful + const gitVersion = rawGitVersion.replace(/^git\s+version\s+/, ""); + return gitVersion; } catch { - return false; + return null; } } +/** + * Check whether git is available on the user's machine. + */ +async function isGitInstalled() { + return (await getGitVersion()) !== null; +} + /** * Check whether the given current working directory is within a git repository * by looking for a `.git` directory in this or an ancestor directory. diff --git a/packages/create-cloudflare/src/frameworks/angular/index.ts b/packages/create-cloudflare/src/frameworks/angular/index.ts index 30c597a46365..7676b9197bf8 100644 --- a/packages/create-cloudflare/src/frameworks/angular/index.ts +++ b/packages/create-cloudflare/src/frameworks/angular/index.ts @@ -10,25 +10,26 @@ import { import { readFile, readJSON, writeFile } from "helpers/files"; import { spinner } from "helpers/interactive"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { dlx, npx, npm } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); await runFrameworkGenerator( ctx, - `${dlx} @angular/cli@${version} new ${ctx.project.name} --standalone` + `${dlx} ${cli} new ${ctx.project.name} --standalone` ); logRaw(""); }; const configure = async (ctx: PagesGeneratorContext) => { + const cli = getFrameworkCli(ctx, false); process.chdir(ctx.project.path); - await runCommand(`${npx} @angular/cli@next analytics disable`, { + await runCommand(`${npx} ${cli}@next analytics disable`, { silent: true, }); await addSSRAdapter(); diff --git a/packages/create-cloudflare/src/frameworks/astro/index.ts b/packages/create-cloudflare/src/frameworks/astro/index.ts index 02004f0dc53d..916ac7304621 100644 --- a/packages/create-cloudflare/src/frameworks/astro/index.ts +++ b/packages/create-cloudflare/src/frameworks/astro/index.ts @@ -3,17 +3,17 @@ import { brandColor, dim } from "helpers/colors"; import { npmInstall, runCommand, runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npx, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); await runFrameworkGenerator( ctx, - `${dlx} create-astro@${version} ${ctx.project.name} --no-install` + `${dlx} ${cli} ${ctx.project.name} --no-install` ); logRaw(""); // newline diff --git a/packages/create-cloudflare/src/frameworks/docusaurus/index.ts b/packages/create-cloudflare/src/frameworks/docusaurus/index.ts index 8f2ae8bd29ac..06bc57b01e44 100644 --- a/packages/create-cloudflare/src/frameworks/docusaurus/index.ts +++ b/packages/create-cloudflare/src/frameworks/docusaurus/index.ts @@ -1,18 +1,15 @@ import { runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); - await runFrameworkGenerator( - ctx, - `${dlx} create-docusaurus@${version} ${ctx.project.name} classic` - ); + await runFrameworkGenerator(ctx, `${dlx} ${cli} ${ctx.project.name} classic`); }; const config: FrameworkConfig = { diff --git a/packages/create-cloudflare/src/frameworks/gatsby/index.ts b/packages/create-cloudflare/src/frameworks/gatsby/index.ts index ba51be6214a1..3370ea0f4632 100644 --- a/packages/create-cloudflare/src/frameworks/gatsby/index.ts +++ b/packages/create-cloudflare/src/frameworks/gatsby/index.ts @@ -2,7 +2,7 @@ import { runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { inputPrompt } from "helpers/interactive"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, dlx } = detectPackageManager(); @@ -27,10 +27,10 @@ const generate = async (ctx: PagesGeneratorContext) => { }); } - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); await runFrameworkGenerator( ctx, - `${dlx} gatsby@${version} new ${ctx.project.name} ${templateUrl}` + `${dlx} ${cli} new ${ctx.project.name} ${templateUrl}` ); }; diff --git a/packages/create-cloudflare/src/frameworks/hono/index.ts b/packages/create-cloudflare/src/frameworks/hono/index.ts index f37073000030..7f3bb0e0efe1 100644 --- a/packages/create-cloudflare/src/frameworks/hono/index.ts +++ b/packages/create-cloudflare/src/frameworks/hono/index.ts @@ -1,17 +1,17 @@ import { logRaw } from "helpers/cli"; import { runFrameworkGenerator } from "helpers/command"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); await runFrameworkGenerator( ctx, - `${dlx} create-hono@${version} ${ctx.project.name} --template cloudflare-workers` + `${dlx} ${cli} ${ctx.project.name} --template cloudflare-workers` ); logRaw(""); // newline diff --git a/packages/create-cloudflare/src/frameworks/index.ts b/packages/create-cloudflare/src/frameworks/index.ts index 5fa9552d5fac..d5f9e9520875 100644 --- a/packages/create-cloudflare/src/frameworks/index.ts +++ b/packages/create-cloudflare/src/frameworks/index.ts @@ -6,12 +6,12 @@ import gatsby from "./gatsby"; import hono from "./hono"; import next from "./next"; import nuxt from "./nuxt"; +import clisPackageJson from "./package.json"; import qwik from "./qwik"; import react from "./react"; import remix from "./remix"; import solid from "./solid"; import svelte from "./svelte"; -import versionMap from "./versionMap.json"; import vue from "./vue"; import type { FrameworkConfig, PagesGeneratorContext } from "types"; @@ -31,15 +31,23 @@ export const FrameworkMap: Record = { vue, }; -export const getFrameworkVersion = (ctx: PagesGeneratorContext) => { +export const supportedFramework = (framework: string) => { + return Object.keys(FrameworkMap).includes(framework); +}; + +export const getFrameworkCli = ( + ctx: PagesGeneratorContext, + withVersion = true +) => { if (!ctx.framework) { return crash("Framework not specified."); } - const framework = ctx.framework.name as keyof typeof versionMap; - return versionMap[framework]; -}; - -export const supportedFramework = (framework: string) => { - return Object.keys(FrameworkMap).includes(framework); + const framework = ctx.framework + .name as keyof typeof clisPackageJson.frameworkCliMap; + const frameworkCli = clisPackageJson.frameworkCliMap[ + framework + ] as keyof typeof clisPackageJson.dependencies; + const version = clisPackageJson.dependencies[frameworkCli]; + return withVersion ? `${frameworkCli}@${version}` : frameworkCli; }; diff --git a/packages/create-cloudflare/src/frameworks/next/index.ts b/packages/create-cloudflare/src/frameworks/next/index.ts index 56cb80919d52..617a85a3aa7c 100644 --- a/packages/create-cloudflare/src/frameworks/next/index.ts +++ b/packages/create-cloudflare/src/frameworks/next/index.ts @@ -12,7 +12,7 @@ import { } from "helpers/files"; import { processArgument } from "helpers/interactive"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import { apiAppDirHelloJs, apiAppDirHelloTs, @@ -25,12 +25,9 @@ const { npm, npx, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { const projectName = ctx.project.name; - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); - await runFrameworkGenerator( - ctx, - `${dlx} create-next-app@${version} ${projectName}` - ); + await runFrameworkGenerator(ctx, `${dlx} ${cli} ${projectName}`); }; const getApiTemplate = ( diff --git a/packages/create-cloudflare/src/frameworks/nuxt/index.ts b/packages/create-cloudflare/src/frameworks/nuxt/index.ts index b17f58c9e4ef..bf675c02f1d3 100644 --- a/packages/create-cloudflare/src/frameworks/nuxt/index.ts +++ b/packages/create-cloudflare/src/frameworks/nuxt/index.ts @@ -3,18 +3,15 @@ import { npmInstall, runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { writeFile } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from ".."; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); - await runFrameworkGenerator( - ctx, - `${dlx} nuxi@${version} init ${ctx.project.name}` - ); + await runFrameworkGenerator(ctx, `${dlx} ${cli} init ${ctx.project.name}`); logRaw(""); // newline }; diff --git a/packages/create-cloudflare/src/frameworks/package.json b/packages/create-cloudflare/src/frameworks/package.json new file mode 100644 index 000000000000..33eddcf257fd --- /dev/null +++ b/packages/create-cloudflare/src/frameworks/package.json @@ -0,0 +1,38 @@ +{ + "name": "frameworks_clis_info", + "description": [ + "this package.json is only used to keep track of the frameworks cli dependencies", + "so that we can use dependabot to update these dependencies automatically", + "additionally it also contains a map that maps frameworks to their respective clis" + ], + "dependencies": { + "@angular/cli": "^0.4.5", + "create-astro": "3.1.5", + "create-docusaurus": "2.4.1", + "create-hono": "0.2.6", + "create-next-app": "13.4.2", + "create-qwik": "1.2.7", + "create-react-app": "5.0.1", + "create-remix": "1.16.0", + "create-solid": "0.2.26", + "create-svelte": "4.2.0", + "create-vue": "3.6.4", + "gatsby": "5.10.0", + "nuxi": "3.4.2" + }, + "frameworkCliMap": { + "angular": "@angular/cli", + "astro": "create-astro", + "docusaurus": "create-docusaurus", + "gatsby": "gatsby", + "hono": "create-hono", + "next": "create-next-app", + "nuxt": "nuxi", + "qwik": "create-qwik", + "react": "create-react-app", + "remix": "create-remix", + "solid": "create-solid", + "svelte": "create-svelte", + "vue": "create-vue" + } +} diff --git a/packages/create-cloudflare/src/frameworks/qwik/index.ts b/packages/create-cloudflare/src/frameworks/qwik/index.ts index 8afdc55c621c..c66bc9f7bad7 100644 --- a/packages/create-cloudflare/src/frameworks/qwik/index.ts +++ b/packages/create-cloudflare/src/frameworks/qwik/index.ts @@ -2,20 +2,17 @@ import { endSection } from "helpers/cli"; import { npmInstall, runCommand, runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, npx, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); // TODO: make this interactive when its possible to specify the project name // to create-qwik in interactive mode - await runFrameworkGenerator( - ctx, - `${dlx} create-qwik@${version} basic ${ctx.project.name}` - ); + await runFrameworkGenerator(ctx, `${dlx} ${cli} basic ${ctx.project.name}`); }; const configure = async (ctx: PagesGeneratorContext) => { @@ -35,7 +32,7 @@ const config: FrameworkConfig = { displayName: "Qwik", packageScripts: { "pages:dev": `wrangler pages dev ${compatDateFlag()} -- ${npm} run dev`, - "pages:deploy": `${npm} run build && ${npm} run deploy`, + "pages:deploy": `${npm} run build && wrangler pages deploy ./dist`, }, }; export default config; diff --git a/packages/create-cloudflare/src/frameworks/react/index.ts b/packages/create-cloudflare/src/frameworks/react/index.ts index 221fe2ae8c34..dc50848f6cda 100644 --- a/packages/create-cloudflare/src/frameworks/react/index.ts +++ b/packages/create-cloudflare/src/frameworks/react/index.ts @@ -2,18 +2,15 @@ import { logRaw } from "helpers/cli"; import { resetPackageManager, runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); - await runFrameworkGenerator( - ctx, - `${dlx} create-react-app@${version} ${ctx.project.name}` - ); + await runFrameworkGenerator(ctx, `${dlx} ${cli} ${ctx.project.name}`); logRaw(""); }; diff --git a/packages/create-cloudflare/src/frameworks/remix/index.ts b/packages/create-cloudflare/src/frameworks/remix/index.ts index c8a030283763..5d48c339ce7a 100644 --- a/packages/create-cloudflare/src/frameworks/remix/index.ts +++ b/packages/create-cloudflare/src/frameworks/remix/index.ts @@ -1,17 +1,17 @@ import { logRaw } from "helpers/cli"; import { runFrameworkGenerator } from "helpers/command.js"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); + const cli = getFrameworkCli(ctx); await runFrameworkGenerator( ctx, - `${dlx} create-remix@${version} ${ctx.project.name} --template https://github.com/remix-run/remix/tree/main/templates/cloudflare-pages` + `${dlx} ${cli} ${ctx.project.name} --template https://github.com/remix-run/remix/tree/main/templates/cloudflare-pages` ); logRaw(""); // newline diff --git a/packages/create-cloudflare/src/frameworks/solid/index.ts b/packages/create-cloudflare/src/frameworks/solid/index.ts index cdfe281f2c3b..37aea0c3c6a6 100644 --- a/packages/create-cloudflare/src/frameworks/solid/index.ts +++ b/packages/create-cloudflare/src/frameworks/solid/index.ts @@ -4,7 +4,7 @@ import { blue, brandColor, dim } from "helpers/colors"; import { installPackages, runFrameworkGenerator } from "helpers/command"; import { compatDateFlag, usesTypescript, writeFile } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import { viteConfig } from "./templates"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; @@ -16,8 +16,8 @@ const generate = async (ctx: PagesGeneratorContext) => { process.chdir(ctx.project.path); // Run the create-solid command - const version = getFrameworkVersion(ctx); - await runFrameworkGenerator(ctx, `${dlx} create-solid@${version}`); + const cli = getFrameworkCli(ctx); + await runFrameworkGenerator(ctx, `${dlx} ${cli}`); logRaw(""); }; diff --git a/packages/create-cloudflare/src/frameworks/svelte/index.ts b/packages/create-cloudflare/src/frameworks/svelte/index.ts index 118ef29805ca..7830a67fff2b 100644 --- a/packages/create-cloudflare/src/frameworks/svelte/index.ts +++ b/packages/create-cloudflare/src/frameworks/svelte/index.ts @@ -8,7 +8,7 @@ import { } from "helpers/command"; import { compatDateFlag, usesTypescript } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import { platformInterface } from "./templates"; import type * as recast from "recast"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; @@ -16,11 +16,8 @@ import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); - await runFrameworkGenerator( - ctx, - `${dlx} create-svelte@${version} ${ctx.project.name}` - ); + const cli = getFrameworkCli(ctx); + await runFrameworkGenerator(ctx, `${dlx} ${cli} ${ctx.project.name}`); logRaw(""); }; diff --git a/packages/create-cloudflare/src/frameworks/versionMap.json b/packages/create-cloudflare/src/frameworks/versionMap.json deleted file mode 100644 index 109a9b8ddb3e..000000000000 --- a/packages/create-cloudflare/src/frameworks/versionMap.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "angular": "16.1.x", - "astro": "3.1.5", - "docusaurus": "2.4.1", - "gatsby": "5.10.0", - "hono": "0.2.6", - "next": "13.4.2", - "nuxt": "3.4.2", - "qwik": "1.2.7", - "react": "5.0.1", - "remix": "1.16.0", - "solid": "0.2.26", - "svelte": "4.2.0", - "vue": "3.6.4" -} diff --git a/packages/create-cloudflare/src/frameworks/vue/index.ts b/packages/create-cloudflare/src/frameworks/vue/index.ts index d8822e584f54..adbd4b6aeada 100644 --- a/packages/create-cloudflare/src/frameworks/vue/index.ts +++ b/packages/create-cloudflare/src/frameworks/vue/index.ts @@ -1,17 +1,14 @@ import { runFrameworkGenerator } from "helpers/command"; import { compatDateFlag } from "helpers/files"; import { detectPackageManager } from "helpers/packages"; -import { getFrameworkVersion } from "../index"; +import { getFrameworkCli } from "../index"; import type { PagesGeneratorContext, FrameworkConfig } from "types"; const { npm, dlx } = detectPackageManager(); const generate = async (ctx: PagesGeneratorContext) => { - const version = getFrameworkVersion(ctx); - await runFrameworkGenerator( - ctx, - `${dlx} create-vue@${version} ${ctx.project.name}` - ); + const cli = getFrameworkCli(ctx); + await runFrameworkGenerator(ctx, `${dlx} ${cli} ${ctx.project.name}`); }; const config: FrameworkConfig = { diff --git a/packages/create-cloudflare/src/helpers/command.ts b/packages/create-cloudflare/src/helpers/command.ts index 98dca36a58d9..a56233c6b035 100644 --- a/packages/create-cloudflare/src/helpers/command.ts +++ b/packages/create-cloudflare/src/helpers/command.ts @@ -47,7 +47,7 @@ export const runCommand = async ( opts: RunOptions = {} ): Promise => { if (typeof command === "string") { - command = command.trim().replace(/\s+/g, ` `).split(" "); + command = command.trim().replace(/\s+/g, " ").split(" "); } return printAsyncStatus({ diff --git a/packages/create-cloudflare/src/helpers/packages.ts b/packages/create-cloudflare/src/helpers/packages.ts index f8a84a3284fb..ea25cc897e7c 100644 --- a/packages/create-cloudflare/src/helpers/packages.ts +++ b/packages/create-cloudflare/src/helpers/packages.ts @@ -31,12 +31,16 @@ export const detectPackageManager = () => { case "pnpm": if (semver.gt(version, "6.0.0")) { return { + name, + version, npm: "pnpm", npx: "pnpm", dlx: "pnpm dlx", }; } return { + name, + version, npm: "pnpm", npx: "pnpx", dlx: "pnpx", @@ -44,12 +48,16 @@ export const detectPackageManager = () => { case "yarn": if (semver.gt(version, "2.0.0")) { return { + name, + version, npm: "yarn", npx: "yarn", dlx: "yarn dlx", }; } return { + name, + version, npm: "yarn", npx: "yarn", dlx: "yarn", @@ -57,6 +65,8 @@ export const detectPackageManager = () => { case "npm": default: return { + name, + version, npm: "npm", npx: "npx", dlx: "npx", diff --git a/packages/create-cloudflare/src/pages.ts b/packages/create-cloudflare/src/pages.ts index de88c48db3c3..3d546573299d 100644 --- a/packages/create-cloudflare/src/pages.ts +++ b/packages/create-cloudflare/src/pages.ts @@ -48,6 +48,7 @@ export const runPagesGenerator = async (args: C3Args) => { }, }, args, + type: frameworkConfig.type, }; // Generate diff --git a/packages/create-cloudflare/src/types.ts b/packages/create-cloudflare/src/types.ts index e213b9df3de0..ef1974912e71 100644 --- a/packages/create-cloudflare/src/types.ts +++ b/packages/create-cloudflare/src/types.ts @@ -29,11 +29,13 @@ export type PagesGeneratorContext = { framework?: { name: string; config: FrameworkConfig; + commitMessage?: string; }; project: { name: string; path: string; }; + type?: "pages" | "workers"; }; type UpdaterPackageScript = (cmd: string) => string; diff --git a/packages/create-cloudflare/turbo.json b/packages/create-cloudflare/turbo.json index 5b9b41f5e820..f91f0099985e 100644 --- a/packages/create-cloudflare/turbo.json +++ b/packages/create-cloudflare/turbo.json @@ -5,6 +5,9 @@ "pipeline": { "build": { "env": ["VITEST", "TEST_PM"] + }, + "test:e2e:*": { + "env": ["CLOUDFLARE_ACCOUNT_ID", "CLOUDFLARE_API_TOKEN"] } } }