Skip to content

Commit bd31534

Browse files
committed
tests: Add more tests for symlinks
1 parent 0ffa653 commit bd31534

1 file changed

Lines changed: 182 additions & 58 deletions

File tree

src/test/integration/git.test.ts

Lines changed: 182 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,14 @@ const expectParentHasOid = async ({
7878
expect(commit.parents.nodes).toEqual([{ oid }]);
7979
};
8080

81-
const makeFileChanges = async (repoDirectory: string) => {
81+
const makeFileChanges = async (
82+
repoDirectory: string,
83+
changegroup:
84+
| "standard"
85+
| "with-ignored-symlink"
86+
| "with-included-valid-symlink"
87+
| "with-included-invalid-symlink",
88+
) => {
8289
// Update an existing file
8390
await fs.promises.writeFile(
8491
path.join(repoDirectory, "LICENSE"),
@@ -113,11 +120,34 @@ const makeFileChanges = async (repoDirectory: string) => {
113120
path.join(repoDirectory, "coverage", "foo", "bar"),
114121
"This file should be ignored",
115122
);
116-
// Add a symlink in ignored directory
117-
await fs.promises.symlink(
118-
path.join(repoDirectory, "nested"),
119-
path.join(repoDirectory, "node_modules", "nested")
120-
);
123+
if (changegroup === "with-ignored-symlink") {
124+
// node_modules is ignored in this repo
125+
await fs.promises.mkdir(path.join(repoDirectory, "node_modules"), {
126+
recursive: true,
127+
});
128+
await fs.promises.symlink(
129+
path.join(repoDirectory, "non-existent"),
130+
path.join(repoDirectory, "node_modules", "nested"),
131+
);
132+
}
133+
if (changegroup === "with-included-valid-symlink") {
134+
await fs.promises.mkdir(path.join(repoDirectory, "some-dir"), {
135+
recursive: true,
136+
});
137+
await fs.promises.symlink(
138+
path.join(repoDirectory, "README.md"),
139+
path.join(repoDirectory, "some-dir", "nested"),
140+
);
141+
}
142+
if (changegroup === "with-included-invalid-symlink") {
143+
await fs.promises.mkdir(path.join(repoDirectory, "some-dir"), {
144+
recursive: true,
145+
});
146+
await fs.promises.symlink(
147+
path.join(repoDirectory, "non-existent"),
148+
path.join(repoDirectory, "some-dir", "nested"),
149+
);
150+
}
121151
};
122152

123153
const makeFileChangeAssertions = async (branch: string) => {
@@ -159,62 +189,156 @@ describe("git", () => {
159189
describe("commitChangesFromRepo", () => {
160190
const testDir = path.join(ROOT_TEMP_DIRECTORY, "commitChangesFromRepo");
161191

162-
it("should correctly commit all changes", async () => {
163-
const branch = `${TEST_BRANCH_PREFIX}-multiple-changes`;
164-
branches.push(branch);
165-
166-
await fs.promises.mkdir(testDir, { recursive: true });
167-
const repoDirectory = path.join(testDir, "repo-1");
168-
169-
// Clone the git repo locally using the git cli and child-process
170-
await new Promise<void>((resolve, reject) => {
171-
const p = execFile(
172-
"git",
173-
["clone", process.cwd(), "repo-1"],
174-
{ cwd: testDir },
175-
(error) => {
176-
if (error) {
177-
reject(error);
178-
} else {
179-
resolve();
180-
}
192+
for (const group of ["standard", "with-ignored-symlink"] as const) {
193+
it(`should correctly commit all changes for group: ${group}`, async () => {
194+
const branch = `${TEST_BRANCH_PREFIX}-multiple-changes-${group}`;
195+
branches.push(branch);
196+
197+
await fs.promises.mkdir(testDir, { recursive: true });
198+
const repoDirectory = path.join(testDir, `repo-1-${group}`);
199+
200+
// Clone the git repo locally using the git cli and child-process
201+
await new Promise<void>((resolve, reject) => {
202+
const p = execFile(
203+
"git",
204+
["clone", process.cwd(), `repo-1-${group}`],
205+
{ cwd: testDir },
206+
(error) => {
207+
if (error) {
208+
reject(error);
209+
} else {
210+
resolve();
211+
}
212+
},
213+
);
214+
p.stdout?.pipe(process.stdout);
215+
p.stderr?.pipe(process.stderr);
216+
});
217+
218+
await makeFileChanges(repoDirectory, group);
219+
220+
// Push the changes
221+
await commitChangesFromRepo({
222+
octokit,
223+
...REPO,
224+
branch,
225+
message: {
226+
headline: "Test commit",
227+
body: "This is a test commit",
181228
},
229+
repoDirectory,
230+
log,
231+
});
232+
233+
await waitForGitHubToBeReady();
234+
235+
await makeFileChangeAssertions(branch);
236+
237+
// Expect the OID to be the HEAD commit
238+
const oid =
239+
(
240+
await git.log({
241+
fs,
242+
dir: repoDirectory,
243+
ref: "HEAD",
244+
depth: 1,
245+
})
246+
)[0]?.oid ?? "NO_OID";
247+
248+
await expectParentHasOid({ branch, oid });
249+
});
250+
}
251+
252+
describe(`should throw appropriate error when symlink is present`, () => {
253+
it(`and file does not exist`, async () => {
254+
const branch = `${TEST_BRANCH_PREFIX}-invalid-symlink-error`;
255+
branches.push(branch);
256+
257+
await fs.promises.mkdir(testDir, { recursive: true });
258+
const repoDirectory = path.join(testDir, `repo-invalid-symlink`);
259+
260+
// Clone the git repo locally using the git cli and child-process
261+
await new Promise<void>((resolve, reject) => {
262+
const p = execFile(
263+
"git",
264+
["clone", process.cwd(), `repo-invalid-symlink`],
265+
{ cwd: testDir },
266+
(error) => {
267+
if (error) {
268+
reject(error);
269+
} else {
270+
resolve();
271+
}
272+
},
273+
);
274+
p.stdout?.pipe(process.stdout);
275+
p.stderr?.pipe(process.stderr);
276+
});
277+
278+
await makeFileChanges(repoDirectory, "with-included-invalid-symlink");
279+
280+
// Push the changes
281+
await expect(() =>
282+
commitChangesFromRepo({
283+
octokit,
284+
...REPO,
285+
branch,
286+
message: {
287+
headline: "Test commit",
288+
body: "This is a test commit",
289+
},
290+
repoDirectory,
291+
log,
292+
}),
293+
).rejects.toThrow(
294+
"Unexpected symlink at some-dir/nested, GitHub API only supports files and directories. You may need to add this file to .gitignore",
182295
);
183-
p.stdout?.pipe(process.stdout);
184-
p.stderr?.pipe(process.stderr);
185296
});
186297

187-
await makeFileChanges(repoDirectory);
188-
189-
// Push the changes
190-
await commitChangesFromRepo({
191-
octokit,
192-
...REPO,
193-
branch,
194-
message: {
195-
headline: "Test commit",
196-
body: "This is a test commit",
197-
},
198-
repoDirectory,
199-
log,
298+
it(`and file exists`, async () => {
299+
const branch = `${TEST_BRANCH_PREFIX}-valid-symlink-error`;
300+
branches.push(branch);
301+
302+
await fs.promises.mkdir(testDir, { recursive: true });
303+
const repoDirectory = path.join(testDir, `repo-valid-symlink`);
304+
305+
// Clone the git repo locally using the git cli and child-process
306+
await new Promise<void>((resolve, reject) => {
307+
const p = execFile(
308+
"git",
309+
["clone", process.cwd(), `repo-valid-symlink`],
310+
{ cwd: testDir },
311+
(error) => {
312+
if (error) {
313+
reject(error);
314+
} else {
315+
resolve();
316+
}
317+
},
318+
);
319+
p.stdout?.pipe(process.stdout);
320+
p.stderr?.pipe(process.stderr);
321+
});
322+
323+
await makeFileChanges(repoDirectory, "with-included-valid-symlink");
324+
325+
// Push the changes
326+
await expect(() =>
327+
commitChangesFromRepo({
328+
octokit,
329+
...REPO,
330+
branch,
331+
message: {
332+
headline: "Test commit",
333+
body: "This is a test commit",
334+
},
335+
repoDirectory,
336+
log,
337+
}),
338+
).rejects.toThrow(
339+
"Unexpected symlink at some-dir/nested, GitHub API only supports files and directories. You may need to add this file to .gitignore",
340+
);
200341
});
201-
202-
await waitForGitHubToBeReady();
203-
204-
await makeFileChangeAssertions(branch);
205-
206-
// Expect the OID to be the HEAD commit
207-
const oid =
208-
(
209-
await git.log({
210-
fs,
211-
dir: repoDirectory,
212-
ref: "HEAD",
213-
depth: 1,
214-
})
215-
)[0]?.oid ?? "NO_OID";
216-
217-
await expectParentHasOid({ branch, oid });
218342
});
219343

220344
it("should correctly be able to base changes off specific commit", async () => {
@@ -242,7 +366,7 @@ describe("git", () => {
242366
p.stderr?.pipe(process.stderr);
243367
});
244368

245-
makeFileChanges(repoDirectory);
369+
makeFileChanges(repoDirectory, "standard");
246370

247371
// Determine the previous commit hash
248372
const gitLog = await git.log({

0 commit comments

Comments
 (0)