Skip to content

Commit 21c9eaf

Browse files
authored
Explicitly throw errors when executable files are found (#37)
* Add test for executable files * Throw an error when executable files are found
1 parent 231d400 commit 21c9eaf

File tree

3 files changed

+67
-0
lines changed

3 files changed

+67
-0
lines changed

.changeset/lazy-icons-cheer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@changesets/ghcommit": minor
3+
---
4+
5+
Throw an error when executable files are encountered

src/git.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ export const commitChangesFromRepo = async ({
6868
`Unexpected symlink at ${filepath}, GitHub API only supports files and directories. You may need to add this file to .gitignore`,
6969
);
7070
}
71+
if ((await workdir?.mode()) === FILE_MODES.executableFile) {
72+
throw new Error(
73+
`Unexpected executable file at ${filepath}, GitHub API only supports non-executable files and directories. You may need to add this file to .gitignore`,
74+
);
75+
}
7176
const prevOid = await commit?.oid();
7277
const currentOid = await workdir?.oid();
7378
// Don't include files that haven't changed, and exist in both trees

src/test/integration/git.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ const makeFileChanges = async (
8282
repoDirectory: string,
8383
changegroup:
8484
| "standard"
85+
| "with-executable-file"
8586
| "with-ignored-symlink"
8687
| "with-included-valid-symlink"
8788
| "with-included-invalid-symlink",
@@ -120,6 +121,17 @@ const makeFileChanges = async (
120121
path.join(repoDirectory, "coverage", "foo", "bar"),
121122
"This file should be ignored",
122123
);
124+
if (changegroup === "with-executable-file") {
125+
// Add an executable file
126+
await fs.promises.writeFile(
127+
path.join(repoDirectory, "executable-file.sh"),
128+
"#!/bin/bash\necho hello",
129+
);
130+
await fs.promises.chmod(
131+
path.join(repoDirectory, "executable-file.sh"),
132+
0o755,
133+
);
134+
}
123135
if (changegroup === "with-ignored-symlink") {
124136
// node_modules is ignored in this repo
125137
await fs.promises.mkdir(path.join(repoDirectory, "node_modules"), {
@@ -341,6 +353,51 @@ describe("git", () => {
341353
});
342354
});
343355

356+
it(`should throw appropriate error when executable file is present`, async () => {
357+
const branch = `${TEST_BRANCH_PREFIX}-executable-file`;
358+
branches.push(branch);
359+
360+
await fs.promises.mkdir(testDir, { recursive: true });
361+
const repoDirectory = path.join(testDir, `repo-executable-file`);
362+
363+
// Clone the git repo locally using the git cli and child-process
364+
await new Promise<void>((resolve, reject) => {
365+
const p = execFile(
366+
"git",
367+
["clone", process.cwd(), `repo-executable-file`],
368+
{ cwd: testDir },
369+
(error) => {
370+
if (error) {
371+
reject(error);
372+
} else {
373+
resolve();
374+
}
375+
},
376+
);
377+
p.stdout?.pipe(process.stdout);
378+
p.stderr?.pipe(process.stderr);
379+
});
380+
381+
await makeFileChanges(repoDirectory, "with-executable-file");
382+
383+
// Push the changes
384+
await expect(() =>
385+
commitChangesFromRepo({
386+
octokit,
387+
...REPO,
388+
branch,
389+
message: {
390+
headline: "Test commit",
391+
body: "This is a test commit",
392+
},
393+
repoDirectory,
394+
log,
395+
}),
396+
).rejects.toThrow(
397+
"Unexpected executable file at executable-file.sh, GitHub API only supports non-executable files and directories. You may need to add this file to .gitignore",
398+
);
399+
});
400+
344401
it("should correctly be able to base changes off specific commit", async () => {
345402
const branch = `${TEST_BRANCH_PREFIX}-specific-base`;
346403
branches.push(branch);

0 commit comments

Comments
 (0)