Skip to content

Commit

Permalink
[C3] fix: make sure that all C3 projects include in their `.gitignore…
Browse files Browse the repository at this point in the history
…` the wrangler files (#5129)

---------

Co-authored-by: Pete Bacon Darwin <[email protected]>
  • Loading branch information
dario-piotrowicz and petebacondarwin authored Mar 4, 2024
1 parent 040be5d commit 23074c7
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .changeset/stale-needles-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"create-cloudflare": patch
---

fix: make sure that all C3 projects include in their `.gitignore` the wrangler files

Previously only the worker templates included in their `.gitignore` the wrangler files (those being `.dev.vars` and `.wrangler`). Make sure to instead include such files in the `.gitignore` files of all the templates including the full stack ones.
242 changes: 242 additions & 0 deletions packages/create-cloudflare/src/__tests__/templates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import { existsSync, statSync } from "fs";
import {
appendFile,
directoryExists,
readFile,
writeFile,
} from "helpers/files";
import { beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
import { addWranglerToGitIgnore } from "../templates";
import type { PathLike } from "fs";
import type { C3Context } from "types";

vi.mock("fs");
vi.mock("helpers/files");

describe("addWranglerToGitIgnore", () => {
const writeFileResults: {
file: string | undefined;
content: string | undefined;
} = { file: undefined, content: undefined };
const appendFileResults: {
file: string | undefined;
content: string | undefined;
} = { file: undefined, content: undefined };

beforeAll(() => {
vi.mocked(writeFile).mockImplementation((file: string, content: string) => {
writeFileResults.file = file;
writeFileResults.content = content;
});
vi.mocked(appendFile).mockImplementation(
(file: string, content: string) => {
appendFileResults.file = file;
appendFileResults.content = content;
}
);
});

beforeEach(() => {
vi.mocked(statSync).mockImplementation(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(path: string) => ({
isDirectory() {
return path.endsWith(".git");
},
})
);
vi.mocked(existsSync).mockReset();
vi.mocked(readFile).mockReset();
vi.mocked(directoryExists).mockReset();
appendFileResults.file = undefined;
appendFileResults.content = undefined;
writeFileResults.file = undefined;
writeFileResults.content = undefined;
});

test("should append the wrangler section to a standard gitignore file", () => {
mockGitIgnore(
"my-project/.gitignore",
`
node_modules
.vscode`
);
addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(appendFileResults.file).toMatchInlineSnapshot(
`"my-project/.gitignore"`
);
expect(appendFileResults.content).toMatchInlineSnapshot(`
"
# wrangler files
.wrangler
.dev.vars
"
`);
});

test("should not touch the gitignore file if it already contains all wrangler files", () => {
mockGitIgnore(
"my-project/.gitignore",
`
node_modules
.dev.vars
.vscode
.wrangler
`
);
addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(appendFileResults.file).toBeUndefined();
expect(appendFileResults.content).toBeUndefined();
});

test("should not touch the gitignore file if contains all wrangler files (and can cope with comments)", () => {
mockGitIgnore(
"my-project/.gitignore",
`
node_modules
.wrangler # This is for wrangler
.dev.vars # this is for wrangler and getPlatformProxy
.vscode
`
);
addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(appendFileResults.file).toBeUndefined();
expect(appendFileResults.content).toBeUndefined();
});

test("should append to the gitignore file the missing wrangler files when some is already present (without including the section heading)", () => {
mockGitIgnore(
"my-project/.gitignore",
`
node_modules
.dev.vars
.vscode`
);
addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(appendFileResults.file).toMatchInlineSnapshot(
`"my-project/.gitignore"`
);
expect(appendFileResults.content).toMatchInlineSnapshot(`
"
.wrangler
"
`);
});

test("when it appends to the gitignore file it doesn't include an empty line only if there was one already", () => {
mockGitIgnore(
"my-project/.gitignore",
`
node_modules
.dev.vars
.vscode
`
);
addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(appendFileResults.file).toMatchInlineSnapshot(
`"my-project/.gitignore"`
);
expect(appendFileResults.content).toMatchInlineSnapshot(`
"
.wrangler
"
`);
});

test("should create the gitignore file if it didn't exist already", () => {
// let's mock a gitignore file to be read by readFile
mockGitIgnore("my-project/.gitignore", "");
// but let's pretend that it doesn't exist
vi.mocked(existsSync).mockImplementation(() => false);
// let's also pretend that the .git directory exists
vi.mocked(directoryExists).mockImplementation(() => true);

addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

// writeFile wrote the (empty) gitignore file
expect(writeFileResults.file).toMatchInlineSnapshot(
`"my-project/.gitignore"`
);
expect(writeFileResults.content).toMatchInlineSnapshot(`""`);

// and the correct lines were then added to it
expect(appendFileResults.file).toMatchInlineSnapshot(
`"my-project/.gitignore"`
);
expect(appendFileResults.content).toMatchInlineSnapshot(`
"
# wrangler files
.wrangler
.dev.vars
"
`);
});

test("should not create the gitignore file the project doesn't use git", () => {
// no .gitignore file exists
vi.mocked(existsSync).mockImplementation(() => false);
// neither a .git directory does
vi.mocked(directoryExists).mockImplementation(() => false);

addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(writeFileResults.file).toBeUndefined();
expect(writeFileResults.content).toBeUndefined();
});

test("should not add the .wrangler entry if a .wrangler/ is already included)", () => {
mockGitIgnore(
"my-project/.gitignore",
`
node_modules
.wrangler/ # This is for wrangler
.vscode
`
);
addWranglerToGitIgnore({
project: { path: "my-project" },
} as unknown as C3Context);

expect(appendFileResults.file).toMatchInlineSnapshot(
`"my-project/.gitignore"`
);
expect(appendFileResults.content).toMatchInlineSnapshot(`
"
.dev.vars
"
`);
});

function mockGitIgnore(path: string, content: string) {
vi.mocked(existsSync).mockImplementation(
(filePath: PathLike) => filePath === path
);
vi.mocked(readFile).mockImplementation((filePath: string) =>
filePath === path ? content.replace(/\n\s*/g, "\n") : ""
);
}
});
3 changes: 3 additions & 0 deletions packages/create-cloudflare/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
} from "./common";
import { createProject } from "./pages";
import {
addWranglerToGitIgnore,
copyTemplateFiles,
selectTemplate,
updatePackageName,
Expand Down Expand Up @@ -147,6 +148,8 @@ const configure = async (ctx: C3Context) => {
await template.configure({ ...ctx });
}

addWranglerToGitIgnore(ctx);

await updatePackageScripts(ctx);

await offerGit(ctx);
Expand Down
14 changes: 13 additions & 1 deletion packages/create-cloudflare/src/helpers/files.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import fs, { existsSync } from "fs";
import fs, { existsSync, statSync } from "fs";
import { join } from "path";
import { crash } from "@cloudflare/cli";
import TOML from "@iarna/toml";
Expand Down Expand Up @@ -37,6 +37,18 @@ export const readFile = (path: string) => {
}
};

export const directoryExists = (path: string): boolean => {
try {
const stat = statSync(path);
return stat.isDirectory();
} catch (error) {
if ((error as { code: string }).code === "ENOENT") {
return false;
}
return crash(error as string);
}
};

export const readJSON = (path: string) => {
const contents = readFile(path);
return contents ? JSON.parse(contents) : contents;
Expand Down
65 changes: 64 additions & 1 deletion packages/create-cloudflare/src/templates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,15 @@ import { spinner } from "@cloudflare/cli/interactive";
import deepmerge from "deepmerge";
import degit from "degit";
import { C3_DEFAULTS } from "helpers/cli";
import { readJSON, usesTypescript, writeJSON } from "helpers/files";
import {
appendFile,
directoryExists,
readFile,
readJSON,
usesTypescript,
writeFile,
writeJSON,
} from "helpers/files";
import { validateTemplateUrl } from "./validators";
import type { C3Args, C3Context, PackageJson } from "types";

Expand Down Expand Up @@ -469,3 +477,58 @@ export const getCopyFilesDestinationDir = (

return copyFiles.destinationDir(ctx);
};

export const addWranglerToGitIgnore = (ctx: C3Context) => {
const gitIgnorePath = `${ctx.project.path}/.gitignore`;
const gitIgnorePreExisted = existsSync(gitIgnorePath);

const gitDirExists = directoryExists(`${ctx.project.path}/.git`);

if (!gitIgnorePreExisted && !gitDirExists) {
// if there is no .gitignore file and neither a .git directory
// then bail as the project is likely not targeting/using git
return;
}

if (!gitIgnorePreExisted) {
writeFile(gitIgnorePath, "");
}

const existingGitIgnoreContent = readFile(gitIgnorePath);

const wranglerGitIgnoreFiles = [".wrangler", ".dev.vars"] as const;
const wranglerGitIgnoreFilesToAdd = wranglerGitIgnoreFiles.filter(
(file) =>
!existingGitIgnoreContent.match(
new RegExp(`\n${file}${file === ".wrangler" ? "/?" : ""}\\s+(#'*)?`)
)
);

if (wranglerGitIgnoreFilesToAdd.length === 0) {
return;
}

const s = spinner();
s.start("Adding Wrangler files to the .gitignore file");

const linesToAppend = [
"",
...(!existingGitIgnoreContent.match(/\n\s*$/) ? [""] : []),
];

if (wranglerGitIgnoreFilesToAdd.length === wranglerGitIgnoreFiles.length) {
linesToAppend.push("# wrangler files");
}

wranglerGitIgnoreFilesToAdd.forEach((line) => linesToAppend.push(line));

linesToAppend.push("");

appendFile(gitIgnorePath, linesToAppend.join("\n"));

s.stop(
`${brandColor(gitIgnorePreExisted ? "updated" : "created")} ${dim(
".gitignore file"
)}`
);
};
5 changes: 0 additions & 5 deletions packages/wrangler/templates/gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,3 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.\*

# wrangler project

.dev.vars
.wrangler/

0 comments on commit 23074c7

Please sign in to comment.