@@ -2,6 +2,7 @@ package dockerfile
22
33import (
44 "bytes"
5+ "fmt"
56 "net/http"
67 "net/http/httptest"
78 "os"
@@ -22,6 +23,7 @@ import (
2223var addGitTests = integration .TestFuncs (
2324 testAddGit ,
2425 testAddGitChecksumCache ,
26+ testGitQueryString ,
2527)
2628
2729func init () {
@@ -350,6 +352,179 @@ COPY --from=src /repo/unique.txt /
350352 require .Equal (t , string (unique1 ), string (unique2 ), "cache should be matched and unique file content should be the same" )
351353}
352354
355+ func testGitQueryString (t * testing.T , sb integration.Sandbox ) {
356+ integration .SkipOnPlatform (t , "windows" )
357+ f := getFrontend (t , sb )
358+
359+ gitDir , err := os .MkdirTemp ("" , "buildkit" )
360+ require .NoError (t , err )
361+ defer os .RemoveAll (gitDir )
362+ err = runShell (gitDir , []string {
363+ "git init" ,
364+ "git config --local user.email test" ,
365+ "git config --local user.name test" ,
366+ "echo base >foo" ,
367+ }... )
368+ require .NoError (t , err )
369+
370+ err = os .WriteFile (filepath .Join (gitDir , "Dockerfile" ), []byte (`
371+ FROM scratch
372+ COPY foo out
373+ ` ), 0600 )
374+ require .NoError (t , err )
375+
376+ err = runShell (gitDir , []string {
377+ "git add Dockerfile foo" ,
378+ "git commit -m initial" ,
379+ "git tag v0.0.1" ,
380+ "git branch base" ,
381+ "echo feature >foo" ,
382+ "mkdir sub" ,
383+ "echo subfeature >sub/foo" ,
384+ "cp Dockerfile sub/" ,
385+ "git add foo sub" ,
386+ "git commit -m feature" ,
387+ "git branch feature" ,
388+ "git checkout -B master base" ,
389+ "echo v0.0.2 >foo" ,
390+ "git add foo" ,
391+ "git commit -m v0.0.2" ,
392+ "git tag v0.0.2" ,
393+ "echo latest >foo" ,
394+ "git add foo" ,
395+ "git commit -m latest" ,
396+ "git tag latest" ,
397+ "git update-server-info" ,
398+ }... )
399+ require .NoError (t , err )
400+
401+ server := httptest .NewServer (http .FileServer (http .Dir (filepath .Clean (gitDir ))))
402+ defer server .Close ()
403+ serverURL := server .URL
404+
405+ c , err := client .New (sb .Context (), sb .Address ())
406+ require .NoError (t , err )
407+ defer c .Close ()
408+
409+ type tcase struct {
410+ name string
411+ url string
412+ expectOut string
413+ expectErr string
414+ }
415+
416+ tcases := []tcase {
417+ {
418+ name : "old style ref" ,
419+ url : serverURL + "/.git#v0.0.2" ,
420+ expectOut : "v0.0.2\n " ,
421+ },
422+ {
423+ name : "querystring ref" ,
424+ url : serverURL + "/.git?ref=base" ,
425+ expectOut : "base\n " ,
426+ },
427+ {
428+ name : "querystring branch" ,
429+ url : serverURL + "/.git?branch=base" ,
430+ expectOut : "base\n " ,
431+ },
432+ {
433+ name : "querystring invalid branch" ,
434+ url : serverURL + "/.git?branch=invalid" ,
435+ expectErr : "repository does not contain ref" ,
436+ },
437+ {
438+ name : "tag as branch" ,
439+ url : serverURL + "/.git?branch=v0.0.2" ,
440+ expectErr : "repository does not contain ref" ,
441+ },
442+ {
443+ name : "allowed mixed refs" ,
444+ url : serverURL + "/.git?tag=v0.0.2#refs/tags/v0.0.2" ,
445+ expectOut : "v0.0.2\n " ,
446+ },
447+ {
448+ name : "mismatch refs" ,
449+ url : serverURL + "/.git?tag=v0.0.2#refs/heads/master" ,
450+ expectErr : "ref conflicts" ,
451+ },
452+ {
453+ name : "sub old-style" ,
454+ url : serverURL + "/.git#feature:sub" ,
455+ expectOut : "subfeature\n " ,
456+ },
457+ {
458+ name : "sub query" ,
459+ url : serverURL + "/.git?subdir=sub&ref=feature" ,
460+ expectOut : "subfeature\n " ,
461+ },
462+ }
463+
464+ for _ , tc := range tcases {
465+ t .Run ("context_" + tc .name , func (t * testing.T ) {
466+ dest := t .TempDir ()
467+ _ , err = f .Solve (sb .Context (), c , client.SolveOpt {
468+ FrontendAttrs : map [string ]string {
469+ "context" : tc .url ,
470+ },
471+ Exports : []client.ExportEntry {
472+ {
473+ Type : client .ExporterLocal ,
474+ OutputDir : dest ,
475+ },
476+ },
477+ }, nil )
478+ if tc .expectErr != "" {
479+ require .Error (t , err )
480+ require .Contains (t , err .Error (), tc .expectErr )
481+ return
482+ }
483+ require .NoError (t , err )
484+
485+ dt , err := os .ReadFile (filepath .Join (dest , "out" ))
486+ require .NoError (t , err )
487+ require .Equal (t , tc .expectOut , string (dt ))
488+ })
489+ }
490+
491+ for _ , tc := range tcases {
492+ dockerfile2 := fmt .Sprintf (`
493+ FROM scratch
494+ ADD %s /repo/
495+ ` , tc .url )
496+ inDir := integration .Tmpdir (t ,
497+ fstest .CreateFile ("Dockerfile" , []byte (dockerfile2 ), 0600 ),
498+ )
499+ t .Run ("add_" + tc .name , func (t * testing.T ) {
500+ dest := t .TempDir ()
501+ _ , err = f .Solve (sb .Context (), c , client.SolveOpt {
502+ Exports : []client.ExportEntry {
503+ {
504+ Type : client .ExporterLocal ,
505+ OutputDir : dest ,
506+ },
507+ },
508+ LocalMounts : map [string ]fsutil.FS {
509+ dockerui .DefaultLocalNameDockerfile : inDir ,
510+ dockerui .DefaultLocalNameContext : inDir ,
511+ },
512+ }, nil )
513+ if tc .expectErr != "" {
514+ require .Error (t , err )
515+ require .Contains (t , err .Error (), tc .expectErr )
516+ return
517+ }
518+ require .NoError (t , err )
519+
520+ dt , err := os .ReadFile (filepath .Join (dest , "/repo/foo" ))
521+ require .NoError (t , err )
522+ require .Equal (t , tc .expectOut , string (dt ))
523+ })
524+ }
525+
526+ }
527+
353528func applyTemplate (tmpl string , x any ) (string , error ) {
354529 var buf bytes.Buffer
355530 parsed , err := template .New ("" ).Parse (tmpl )
0 commit comments