diff --git a/cmd/document/document.go b/cmd/document/document.go index d0fd0b7a5..b9669d952 100644 --- a/cmd/document/document.go +++ b/cmd/document/document.go @@ -14,6 +14,7 @@ func NewDocumentCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Com Short: "manages deployment documents", } + documentRootCmd.AddCommand(NewDocumentPullCommand(rootSettings)) documentRootCmd.AddCommand(secret.NewSecretCommand(rootSettings)) return documentRootCmd diff --git a/cmd/document/pull.go b/cmd/document/pull.go new file mode 100644 index 000000000..37588e6a1 --- /dev/null +++ b/cmd/document/pull.go @@ -0,0 +1,22 @@ +package document + +import ( + "github.com/spf13/cobra" + + "opendev.org/airship/airshipctl/pkg/document/pull" + "opendev.org/airship/airshipctl/pkg/environment" +) + +// NewDocumentPullCommand creates a new command for pulling airship document repositories +func NewDocumentPullCommand(rootSettings *environment.AirshipCTLSettings) *cobra.Command { + settings := pull.Settings{AirshipCTLSettings: rootSettings} + documentPullCmd := &cobra.Command{ + Use: "pull", + Short: "pulls documents from remote git repository", + RunE: func(cmd *cobra.Command, args []string) error { + return settings.Pull() + }, + } + + return documentPullCmd +} diff --git a/cmd/document/pull_test.go b/cmd/document/pull_test.go new file mode 100644 index 000000000..cf190f0b1 --- /dev/null +++ b/cmd/document/pull_test.go @@ -0,0 +1,47 @@ +package document + +import ( + "testing" + + "opendev.org/airship/airshipctl/pkg/config" + "opendev.org/airship/airshipctl/pkg/environment" + + "opendev.org/airship/airshipctl/testutil" +) + +func getDummyAirshipSettings() *environment.AirshipCTLSettings { + settings := new(environment.AirshipCTLSettings) + conf := config.DummyConfig() + mfst := conf.Manifests["dummy_manifest"] + mfst.Repository = &config.Repository{ + URLString: "https://opendev.org/airship/treasuremap.git", + CheckoutOptions: &config.RepoCheckout{ + Branch: "master", + ForceCheckout: false, + }, + Auth: &config.RepoAuth{ + Type: "http-basic", + }, + } + settings.SetConfig(conf) + return settings +} + +func TestPull(t *testing.T) { + cmdTests := []*testutil.CmdTest{ + { + Name: "document-pull-cmd-with-defaults", + CmdLine: "", + Cmd: NewDocumentPullCommand(getDummyAirshipSettings()), + }, + { + Name: "document-pull-cmd-with-help", + CmdLine: "--help", + Cmd: NewDocumentPullCommand(nil), + }, + } + + for _, tt := range cmdTests { + testutil.RunTest(t, tt) + } +} diff --git a/cmd/document/testdata/TestPullGoldenOutput/document-pull-cmd-with-defaults.golden b/cmd/document/testdata/TestPullGoldenOutput/document-pull-cmd-with-defaults.golden new file mode 100644 index 000000000..e69de29bb diff --git a/cmd/document/testdata/TestPullGoldenOutput/document-pull-cmd-with-help.golden b/cmd/document/testdata/TestPullGoldenOutput/document-pull-cmd-with-help.golden new file mode 100644 index 000000000..efb4d2b57 --- /dev/null +++ b/cmd/document/testdata/TestPullGoldenOutput/document-pull-cmd-with-help.golden @@ -0,0 +1,7 @@ +pulls documents from remote git repository + +Usage: + pull [flags] + +Flags: + -h, --help help for pull diff --git a/go.sum b/go.sum index 4caa456a2..e0eb12bc3 100644 --- a/go.sum +++ b/go.sum @@ -536,6 +536,7 @@ golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a h1:mEQZbbaBjWyLNy0tmZmgEuQAR8XOQ3hL8GYi3J/NG64= golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= diff --git a/pkg/config/test_utils.go b/pkg/config/test_utils.go index ccffd3648..7be945b1d 100644 --- a/pkg/config/test_utils.go +++ b/pkg/config/test_utils.go @@ -94,7 +94,8 @@ func DummyRepository() *Repository { return &Repository{ URLString: "http://dummy.url.com", CheckoutOptions: &RepoCheckout{ - Tag: "v1.0.1", + Tag: "v1.0.1", + ForceCheckout: false, }, Auth: &RepoAuth{ Type: "ssh-key", @@ -112,7 +113,8 @@ func DummyRepoAuth() *RepoAuth { func DummyRepoCheckout() *RepoCheckout { return &RepoCheckout{ - Tag: "v1.0.1", + Tag: "v1.0.1", + ForceCheckout: false, } } diff --git a/pkg/config/testdata/config-string.yaml b/pkg/config/testdata/config-string.yaml index 4a29ec358..acd723b1d 100644 --- a/pkg/config/testdata/config-string.yaml +++ b/pkg/config/testdata/config-string.yaml @@ -22,6 +22,7 @@ manifests: type: ssh-key checkout: branch: "" + force: false remote-ref: "" tag: v1.0.1 url: http://dummy.url.com diff --git a/pkg/config/testdata/manifest-string.yaml b/pkg/config/testdata/manifest-string.yaml index df8299cd1..94a227771 100644 --- a/pkg/config/testdata/manifest-string.yaml +++ b/pkg/config/testdata/manifest-string.yaml @@ -4,6 +4,7 @@ repository: type: ssh-key checkout: branch: "" + force: false remote-ref: "" tag: v1.0.1 url: http://dummy.url.com diff --git a/pkg/config/testdata/repo-checkout-string.yaml b/pkg/config/testdata/repo-checkout-string.yaml index 4bb8a0a5b..9fca83c90 100644 --- a/pkg/config/testdata/repo-checkout-string.yaml +++ b/pkg/config/testdata/repo-checkout-string.yaml @@ -1,3 +1,4 @@ branch: "" +force: false remote-ref: "" tag: v1.0.1 diff --git a/pkg/config/testdata/repository-string.yaml b/pkg/config/testdata/repository-string.yaml index 580b6fd6b..c51d79b15 100644 --- a/pkg/config/testdata/repository-string.yaml +++ b/pkg/config/testdata/repository-string.yaml @@ -3,6 +3,7 @@ auth: type: ssh-key checkout: branch: "" + force: false remote-ref: "" tag: v1.0.1 url: http://dummy.url.com diff --git a/pkg/config/types.go b/pkg/config/types.go index 13d0bea71..c860cc019 100644 --- a/pkg/config/types.go +++ b/pkg/config/types.go @@ -167,6 +167,8 @@ type RepoCheckout struct { // for example refs/changes/04/691202/5 // TODO Add support for fetching remote refs RemoteRef string `json:"remote-ref"` + // ForceCheckout is a boolean to indicate whether to use the `--force` option when checking out + ForceCheckout bool `json:"force"` } // Holds the complex cluster name information diff --git a/pkg/document/pull/pull.go b/pkg/document/pull/pull.go new file mode 100644 index 000000000..be7f7970b --- /dev/null +++ b/pkg/document/pull/pull.go @@ -0,0 +1,53 @@ +package pull + +import ( + "opendev.org/airship/airshipctl/pkg/document/repo" + "opendev.org/airship/airshipctl/pkg/environment" +) + +type Settings struct { + *environment.AirshipCTLSettings +} + +func (s *Settings) Pull() error { + err := s.cloneRepositories() + if err != nil { + return err + } + + return nil +} + +func (s *Settings) cloneRepositories() error { + // Clone main repository + currentManifest, err := s.Config().CurrentContextManifest() + if err != nil { + return err + } + + mainRepoConfig := currentManifest.Repository + repository, err := repo.NewRepository(currentManifest.TargetPath, mainRepoConfig) + if err != nil { + return err + } + err = repository.Download(mainRepoConfig.ToCheckoutOptions(true).Force) + if err != nil { + return err + } + repository.Driver.Close() + + // Clone extra repositories + for _, extraRepoConfig := range currentManifest.ExtraRepositories { + repository, err := repo.NewRepository(currentManifest.TargetPath, extraRepoConfig) + if err != nil { + return err + } + err = repository.Download(extraRepoConfig.ToCheckoutOptions(true).Force) + if err != nil { + return err + } + repository.Driver.Close() + } + + return nil +} diff --git a/pkg/document/pull/pull_test.go b/pkg/document/pull/pull_test.go new file mode 100644 index 000000000..fd8555ecd --- /dev/null +++ b/pkg/document/pull/pull_test.go @@ -0,0 +1,110 @@ +package pull + +import ( + "io/ioutil" + "path" + "path/filepath" + "strings" + "testing" + + fixtures "gopkg.in/src-d/go-git-fixtures.v3" + + repo2 "opendev.org/airship/airshipctl/pkg/document/repo" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "opendev.org/airship/airshipctl/pkg/config" + "opendev.org/airship/airshipctl/pkg/environment" +) + +func getDummyPullSettings() *Settings { + mockPullSettings := &Settings{ + AirshipCTLSettings: new(environment.AirshipCTLSettings), + } + mockConf := config.DummyConfig() + mockPullSettings.AirshipCTLSettings.SetConfig(mockConf) + return mockPullSettings +} + +func TestPull(t *testing.T) { + require := require.New(t) + assert := assert.New(t) + + t.Run("cloneRepositories", func(t *testing.T) { + dummyPullSettings := getDummyPullSettings() + currentManifest, err := dummyPullSettings.Config().CurrentContextManifest() + require.NoError(err) + + err = fixtures.Init() + require.NoError(err) + fx := fixtures.Basic().One() + + dummyGitDir := fx.DotGit().Root() + currentManifest.Repository = &config.Repository{ + URLString: dummyGitDir, + CheckoutOptions: &config.RepoCheckout{ + Branch: "master", + ForceCheckout: false, + }, + Auth: &config.RepoAuth{ + Type: "http-basic", + }, + } + + tmpDir, err := ioutil.TempDir("", "airshipctlPullTest-") + require.NoError(err) + currentManifest.TargetPath = tmpDir + + _, err = repo2.NewRepository(".", currentManifest.Repository) + require.NoError(err) + + err = dummyPullSettings.cloneRepositories() + + require.NoError(err) + dummyRepoDirName := filepath.Base(dummyGitDir) + assert.FileExists(path.Join(tmpDir, dummyRepoDirName, "go/example.go")) + assert.FileExists(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) + contents, err := ioutil.ReadFile(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) + require.NoError(err) + assert.Equal("ref: refs/heads/master", strings.TrimRight(string(contents), "\t \n")) + }) + + t.Run("Pull", func(t *testing.T) { + dummyPullSettings := getDummyPullSettings() + conf := dummyPullSettings.AirshipCTLSettings.Config() + + err := fixtures.Init() + require.NoError(err) + fx := fixtures.Basic().One() + + mfst := conf.Manifests["dummy_manifest"] + dummyGitDir := fx.DotGit().Root() + mfst.Repository = &config.Repository{ + URLString: dummyGitDir, + CheckoutOptions: &config.RepoCheckout{ + Branch: "master", + ForceCheckout: false, + }, + Auth: &config.RepoAuth{ + Type: "http-basic", + }, + } + dummyPullSettings.SetConfig(conf) + + tmpDir, err := ioutil.TempDir("", "airshipctlPullTest-") + require.NoError(err) + mfst.TargetPath = tmpDir + require.NoError(err) + + err = dummyPullSettings.Pull() + require.NoError(err) + + dummyRepoDirName := filepath.Base(dummyGitDir) + assert.FileExists(path.Join(tmpDir, dummyRepoDirName, "go/example.go")) + assert.FileExists(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) + contents, err := ioutil.ReadFile(path.Join(tmpDir, dummyRepoDirName, ".git/HEAD")) + require.NoError(err) + assert.Equal("ref: refs/heads/master", strings.TrimRight(string(contents), "\t \n")) + }) +}