@@ -141,6 +141,13 @@ test("names worktree-only checkout changes without comparing a branch to itself"
141141
142142 try {
143143 await writeFile ( join ( fixture . repo , "working.txt" ) , "working tree work\n" ) ;
144+ git (
145+ fixture . repo ,
146+ "remote" ,
147+ "set-url" ,
148+ "origin" ,
149+ "https://github.com/example/diffsplain.git" ,
150+ ) ;
144151
145152 run ( fixture . repo , [ "--checkout" , "--output" , output ] ) ;
146153 const payload = JSON . parse ( await readFile ( output , "utf8" ) ) ;
@@ -152,6 +159,10 @@ test("names worktree-only checkout changes without comparing a branch to itself"
152159 payload . change . summary ,
153160 "Shows staged, unstaged, and untracked changes in the current checkout." ,
154161 ) ;
162+ assert . ok (
163+ payload . files . every ( ( file ) => file . comparisonUrl === undefined ) ,
164+ "uncommitted work must not link to a commit-only comparison" ,
165+ ) ;
155166
156167 git ( fixture . repo , "add" , "working.txt" ) ;
157168 git ( fixture . repo , "commit" , "-qm" , "local main work" ) ;
@@ -161,6 +172,10 @@ test("names worktree-only checkout changes without comparing a branch to itself"
161172
162173 assert . notEqual ( committed . repo . base , committed . repo . head ) ;
163174 assert . equal ( committed . change . title , "Local changes on main" ) ;
175+ assert . match (
176+ committed . files [ 0 ] . comparisonUrl ,
177+ / ^ h t t p s : \/ \/ g i t h u b \. c o m \/ e x a m p l e \/ d i f f s p l a i n \/ c o m p a r e \/ / ,
178+ ) ;
164179 } finally {
165180 await rm ( fixture . root , { recursive : true , force : true } ) ;
166181 }
@@ -199,6 +214,104 @@ test("builds a remote repo target without a local checkout", async () => {
199214 }
200215} ) ;
201216
217+ test ( "renders uncommon range entries with the right content and GitHub links" , async ( ) => {
218+ const fixture = await makeRemoteRepo ( ) ;
219+ const output = join ( fixture . root , "uncommon-range.json" ) ;
220+
221+ try {
222+ await writeFile ( join ( fixture . repo , "deleted.txt" ) , "remove me\n" ) ;
223+ await writeFile ( join ( fixture . repo , "moved-from.txt" ) , "move me\n" ) ;
224+ await writeFile ( join ( fixture . repo , "changed.bin" ) , Buffer . from ( [ 0 , 1 ] ) ) ;
225+ await writeFile (
226+ join ( fixture . repo , "long.txt" ) ,
227+ Array . from ( { length : 240 } , ( _ , index ) => `before ${ index } \n` ) . join ( "" ) ,
228+ ) ;
229+ git ( fixture . repo , "add" , "." ) ;
230+ git ( fixture . repo , "commit" , "-qm" , "uncommon base" ) ;
231+ const base = git ( fixture . repo , "rev-parse" , "HEAD" ) ;
232+
233+ await writeFile ( join ( fixture . repo , "changed.bin" ) , Buffer . from ( [ 0 , 2 ] ) ) ;
234+ await writeFile ( join ( fixture . repo , "added.bin" ) , Buffer . from ( [ 0 , 4 ] ) ) ;
235+ await rm ( join ( fixture . repo , "deleted.txt" ) ) ;
236+ git ( fixture . repo , "mv" , "moved-from.txt" , "moved-to.txt" ) ;
237+ await writeFile (
238+ join ( fixture . repo , "long.txt" ) ,
239+ Array . from ( { length : 240 } , ( _ , index ) => `after ${ index } \n` ) . join ( "" ) ,
240+ ) ;
241+ git ( fixture . repo , "add" , "." ) ;
242+ git ( fixture . repo , "commit" , "-qm" , "uncommon changes" ) ;
243+ const head = git ( fixture . repo , "rev-parse" , "HEAD" ) ;
244+ git ( fixture . repo , "remote" , "set-url" , "origin" , "https://github.com/example/diffsplain.git" ) ;
245+ const before = checkoutState ( fixture . repo ) ;
246+
247+ run ( fixture . repo , [ "--base" , base , "--head" , head , "--output" , output ] ) ;
248+ const payload = JSON . parse ( await readFile ( output , "utf8" ) ) ;
249+ const files = Object . fromEntries ( payload . files . map ( ( file ) => [ file . path , file ] ) ) ;
250+ const source = ( ref , path ) =>
251+ `https://github.com/example/diffsplain/blob/${ ref } /${ path } ` ;
252+ const comparison = `https://github.com/example/diffsplain/compare/${ base } ...${ head } ` ;
253+
254+ assert . deepEqual (
255+ payload . files . map ( ( file ) => file . path ) ,
256+ [ "added.bin" , "changed.bin" , "deleted.txt" , "long.txt" , "moved-to.txt" ] ,
257+ ) ;
258+ assert . equal ( files [ "added.bin" ] . status , "binary" ) ;
259+ assert . equal ( files [ "added.bin" ] . isBinary , true ) ;
260+ assert . equal ( files [ "added.bin" ] . patch , "" ) ;
261+ assert . equal ( files [ "added.bin" ] . sourceUrl , source ( head , "added.bin" ) ) ;
262+ assert . equal ( files [ "added.bin" ] . comparisonUrl , comparison ) ;
263+ assert . equal ( files [ "changed.bin" ] . status , "binary" ) ;
264+ assert . equal ( files [ "changed.bin" ] . isBinary , true ) ;
265+ assert . equal ( files [ "changed.bin" ] . patch , "" ) ;
266+ assert . equal ( files [ "changed.bin" ] . sourceUrl , source ( head , "changed.bin" ) ) ;
267+ assert . equal ( files [ "changed.bin" ] . comparisonUrl , comparison ) ;
268+ assert . equal ( files [ "deleted.txt" ] . status , "deleted" ) ;
269+ assert . equal ( files [ "deleted.txt" ] . isBinary , false ) ;
270+ assert . match ( files [ "deleted.txt" ] . patch , / - r e m o v e m e / ) ;
271+ assert . equal ( files [ "deleted.txt" ] . sourceUrl , source ( base , "deleted.txt" ) ) ;
272+ assert . equal ( files [ "deleted.txt" ] . comparisonUrl , comparison ) ;
273+ assert . equal ( files [ "moved-to.txt" ] . status , "renamed" ) ;
274+ assert . equal ( files [ "moved-to.txt" ] . oldPath , "moved-from.txt" ) ;
275+ assert . match ( files [ "moved-to.txt" ] . patch , / s i m i l a r i t y i n d e x 1 0 0 % / ) ;
276+ assert . equal ( files [ "moved-to.txt" ] . sourceUrl , source ( head , "moved-to.txt" ) ) ;
277+ assert . equal ( files [ "moved-to.txt" ] . comparisonUrl , comparison ) ;
278+ assert . equal ( files [ "long.txt" ] . status , "modified" ) ;
279+ assert . equal ( files [ "long.txt" ] . isBinary , false ) ;
280+ assert . equal ( files [ "long.txt" ] . isTruncated , true ) ;
281+ assert . ok ( files [ "long.txt" ] . snippet . split ( "\n" ) . length <= 180 ) ;
282+ assert . match ( files [ "long.txt" ] . snippet , / ^ @ @ / m) ;
283+ assert . equal ( files [ "long.txt" ] . sourceUrl , source ( head , "long.txt" ) ) ;
284+ assert . equal ( files [ "long.txt" ] . comparisonUrl , comparison ) ;
285+ assert . deepEqual ( checkoutState ( fixture . repo ) , before ) ;
286+ } finally {
287+ await rm ( fixture . root , { recursive : true , force : true } ) ;
288+ }
289+ } ) ;
290+
291+ test ( "keeps links out of worktree entries and leaves the checkout untouched" , async ( ) => {
292+ const fixture = await makeRemoteRepo ( ) ;
293+ const output = join ( fixture . root , "uncommon-worktree.json" ) ;
294+
295+ try {
296+ await writeFile ( join ( fixture . repo , "worktree.bin" ) , Buffer . from ( [ 0 , 1 ] ) ) ;
297+ const before = checkoutState ( fixture . repo ) ;
298+
299+ run ( fixture . repo , [ "--worktree" , "--output" , output ] ) ;
300+ const payload = JSON . parse ( await readFile ( output , "utf8" ) ) ;
301+ const [ file ] = payload . files ;
302+
303+ assert . equal ( file . path , "worktree.bin" ) ;
304+ assert . equal ( file . status , "binary" ) ;
305+ assert . equal ( file . isBinary , true ) ;
306+ assert . equal ( file . patch , "" ) ;
307+ assert . equal ( file . sourceUrl , undefined ) ;
308+ assert . equal ( file . comparisonUrl , undefined ) ;
309+ assert . deepEqual ( checkoutState ( fixture . repo ) , before ) ;
310+ } finally {
311+ await rm ( fixture . root , { recursive : true , force : true } ) ;
312+ }
313+ } ) ;
314+
202315test ( "builds a pull request range through gh without changing the checkout" , async ( ) => {
203316 const fixture = await makeRemoteRepo ( ) ;
204317 const bin = join ( fixture . root , "bin" ) ;
0 commit comments