@@ -20,10 +20,13 @@ import (
2020 "context"
2121 "crypto/tls"
2222 "fmt"
23+ "io/ioutil"
2324 "net/http"
2425 "net/url"
2526 "os"
27+ "os/exec"
2628 "path"
29+ "path/filepath"
2730 "strings"
2831 "time"
2932
@@ -42,9 +45,10 @@ import (
4245 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
4346 "k8s.io/apimachinery/pkg/types"
4447
48+ "github.com/fluxcd/pkg/apis/meta"
4549 "github.com/fluxcd/pkg/gittestserver"
50+ "github.com/fluxcd/pkg/untar"
4651
47- "github.com/fluxcd/pkg/apis/meta"
4852 sourcev1 "github.com/fluxcd/source-controller/api/v1beta1"
4953)
5054
@@ -136,8 +140,6 @@ var _ = Describe("GitRepositoryReconciler", func() {
136140 }})
137141 Expect (err ).NotTo (HaveOccurred ())
138142
139- gitrepo .Worktree ()
140-
141143 for _ , ref := range t .createRefs {
142144 hRef := plumbing .NewHashReference (plumbing .ReferenceName (ref ), commit )
143145 err = gitrepo .Storer .SetReference (hRef )
@@ -410,5 +412,137 @@ var _ = Describe("GitRepositoryReconciler", func() {
410412 gitImplementation : sourcev1 .GoGitImplementation ,
411413 }),
412414 )
415+
416+ Context ("recurse submodules" , func () {
417+ It ("downloads submodules when asked" , func () {
418+ Expect (gitServer .StartHTTP ()).To (Succeed ())
419+ defer gitServer .StopHTTP ()
420+
421+ u , err := url .Parse (gitServer .HTTPAddress ())
422+ Expect (err ).NotTo (HaveOccurred ())
423+
424+ subRepoURL := * u
425+ subRepoURL .Path = path .Join (u .Path , fmt .Sprintf ("subrepository-%s.git" , randStringRunes (5 )))
426+
427+ // create the git repo to use as a submodule
428+ fs := memfs .New ()
429+ subRepo , err := git .Init (memory .NewStorage (), fs )
430+ Expect (err ).NotTo (HaveOccurred ())
431+
432+ wt , err := subRepo .Worktree ()
433+ Expect (err ).NotTo (HaveOccurred ())
434+
435+ ff , _ := fs .Create ("fixture" )
436+ _ = ff .Close ()
437+ _ , err = wt .Add (fs .Join ("fixture" ))
438+ Expect (err ).NotTo (HaveOccurred ())
439+
440+ _ , err = wt .Commit ("Sample" , & git.CommitOptions {Author : & object.Signature {
441+ Name : "John Doe" ,
442+ 443+ When : time .Now (),
444+ }})
445+ Expect (err ).NotTo (HaveOccurred ())
446+
447+ remote , err := subRepo .CreateRemote (& config.RemoteConfig {
448+ Name : "origin" ,
449+ URLs : []string {subRepoURL .String ()},
450+ })
451+ Expect (err ).NotTo (HaveOccurred ())
452+
453+ err = remote .Push (& git.PushOptions {
454+ RefSpecs : []config.RefSpec {"refs/heads/*:refs/heads/*" , "refs/tags/*:refs/tags/*" },
455+ })
456+ Expect (err ).NotTo (HaveOccurred ())
457+
458+ // this one is linked to a real directory, so that I can
459+ // exec `git submodule add` later
460+ tmp , err := ioutil .TempDir ("" , "flux-test" )
461+ Expect (err ).NotTo (HaveOccurred ())
462+ defer os .RemoveAll (tmp )
463+
464+ repoDir := filepath .Join (tmp , "git" )
465+ repo , err := git .PlainInit (repoDir , false )
466+ Expect (err ).NotTo (HaveOccurred ())
467+
468+ wt , err = repo .Worktree ()
469+ Expect (err ).NotTo (HaveOccurred ())
470+ _ , err = wt .Commit ("Initial revision" , & git.CommitOptions {
471+ Author : & object.Signature {
472+ Name : "John Doe" ,
473+ 474+ When : time .Now (),
475+ }})
476+ Expect (err ).NotTo (HaveOccurred ())
477+
478+ submodAdd := exec .Command ("git" , "submodule" , "add" , "-b" , "master" , subRepoURL .String (), "sub" )
479+ submodAdd .Dir = repoDir
480+ out , err := submodAdd .CombinedOutput ()
481+ os .Stdout .Write (out )
482+ Expect (err ).NotTo (HaveOccurred ())
483+
484+ _ , err = wt .Commit ("Add submodule" , & git.CommitOptions {
485+ Author : & object.Signature {
486+ Name : "John Doe" ,
487+ 488+ When : time .Now (),
489+ }})
490+ Expect (err ).NotTo (HaveOccurred ())
491+
492+ mainRepoURL := * u
493+ mainRepoURL .Path = path .Join (u .Path , fmt .Sprintf ("repository-%s.git" , randStringRunes (5 )))
494+ remote , err = repo .CreateRemote (& config.RemoteConfig {
495+ Name : "origin" ,
496+ URLs : []string {mainRepoURL .String ()},
497+ })
498+ Expect (err ).NotTo (HaveOccurred ())
499+
500+ err = remote .Push (& git.PushOptions {
501+ RefSpecs : []config.RefSpec {"refs/heads/*:refs/heads/*" , "refs/tags/*:refs/tags/*" },
502+ })
503+ Expect (err ).NotTo (HaveOccurred ())
504+
505+ key := types.NamespacedName {
506+ Name : fmt .Sprintf ("git-ref-test-%s" , randStringRunes (5 )),
507+ Namespace : namespace .Name ,
508+ }
509+ created := & sourcev1.GitRepository {
510+ ObjectMeta : metav1.ObjectMeta {
511+ Name : key .Name ,
512+ Namespace : key .Namespace ,
513+ },
514+ Spec : sourcev1.GitRepositorySpec {
515+ URL : mainRepoURL .String (),
516+ Interval : metav1.Duration {Duration : indexInterval },
517+ Reference : & sourcev1.GitRepositoryRef {Branch : "master" },
518+ GitImplementation : sourcev1 .GoGitImplementation , // only works with go-git
519+ RecurseSubmodules : true ,
520+ },
521+ }
522+ Expect (k8sClient .Create (context .Background (), created )).Should (Succeed ())
523+ defer k8sClient .Delete (context .Background (), created )
524+
525+ got := & sourcev1.GitRepository {}
526+ Eventually (func () bool {
527+ _ = k8sClient .Get (context .Background (), key , got )
528+ for _ , c := range got .Status .Conditions {
529+ if c .Reason == sourcev1 .GitOperationSucceedReason {
530+ return true
531+ }
532+ }
533+ return false
534+ }, timeout , interval ).Should (BeTrue ())
535+
536+ // check that the downloaded artifact includes the
537+ // file from the submodule
538+ res , err := http .Get (got .Status .URL )
539+ Expect (err ).NotTo (HaveOccurred ())
540+ Expect (res .StatusCode ).To (Equal (http .StatusOK ))
541+
542+ _ , err = untar .Untar (res .Body , filepath .Join (tmp , "tar" ))
543+ Expect (err ).NotTo (HaveOccurred ())
544+ Expect (filepath .Join (tmp , "tar" , "sub" , "fixture" )).To (BeAnExistingFile ())
545+ })
546+ })
413547 })
414548})
0 commit comments