@@ -78,7 +78,14 @@ const expectParentHasOid = async ({
78
78
expect ( commit . parents . nodes ) . toEqual ( [ { oid } ] ) ;
79
79
} ;
80
80
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
+ ) => {
82
89
// Update an existing file
83
90
await fs . promises . writeFile (
84
91
path . join ( repoDirectory , "LICENSE" ) ,
@@ -113,6 +120,34 @@ const makeFileChanges = async (repoDirectory: string) => {
113
120
path . join ( repoDirectory , "coverage" , "foo" , "bar" ) ,
114
121
"This file should be ignored" ,
115
122
) ;
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
+ }
116
151
} ;
117
152
118
153
const makeFileChangeAssertions = async ( branch : string ) => {
@@ -154,62 +189,156 @@ describe("git", () => {
154
189
describe ( "commitChangesFromRepo" , ( ) => {
155
190
const testDir = path . join ( ROOT_TEMP_DIRECTORY , "commitChangesFromRepo" ) ;
156
191
157
- it ( "should correctly commit all changes" , async ( ) => {
158
- const branch = `${ TEST_BRANCH_PREFIX } -multiple-changes` ;
159
- branches . push ( branch ) ;
160
-
161
- await fs . promises . mkdir ( testDir , { recursive : true } ) ;
162
- const repoDirectory = path . join ( testDir , "repo-1" ) ;
163
-
164
- // Clone the git repo locally using the git cli and child-process
165
- await new Promise < void > ( ( resolve , reject ) => {
166
- const p = execFile (
167
- "git" ,
168
- [ "clone" , process . cwd ( ) , "repo-1" ] ,
169
- { cwd : testDir } ,
170
- ( error ) => {
171
- if ( error ) {
172
- reject ( error ) ;
173
- } else {
174
- resolve ( ) ;
175
- }
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" ,
176
228
} ,
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" ,
177
295
) ;
178
- p . stdout ?. pipe ( process . stdout ) ;
179
- p . stderr ?. pipe ( process . stderr ) ;
180
296
} ) ;
181
297
182
- await makeFileChanges ( repoDirectory ) ;
183
-
184
- // Push the changes
185
- await commitChangesFromRepo ( {
186
- octokit,
187
- ...REPO ,
188
- branch,
189
- message : {
190
- headline : "Test commit" ,
191
- body : "This is a test commit" ,
192
- } ,
193
- repoDirectory,
194
- 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
+ ) ;
195
341
} ) ;
196
-
197
- await waitForGitHubToBeReady ( ) ;
198
-
199
- await makeFileChangeAssertions ( branch ) ;
200
-
201
- // Expect the OID to be the HEAD commit
202
- const oid =
203
- (
204
- await git . log ( {
205
- fs,
206
- dir : repoDirectory ,
207
- ref : "HEAD" ,
208
- depth : 1 ,
209
- } )
210
- ) [ 0 ] ?. oid ?? "NO_OID" ;
211
-
212
- await expectParentHasOid ( { branch, oid } ) ;
213
342
} ) ;
214
343
215
344
it ( "should correctly be able to base changes off specific commit" , async ( ) => {
@@ -237,7 +366,7 @@ describe("git", () => {
237
366
p . stderr ?. pipe ( process . stderr ) ;
238
367
} ) ;
239
368
240
- makeFileChanges ( repoDirectory ) ;
369
+ makeFileChanges ( repoDirectory , "standard" ) ;
241
370
242
371
// Determine the previous commit hash
243
372
const gitLog = await git . log ( {
0 commit comments