From 50bd5de60c8ad3706bc01120fb4b24b80211f6c3 Mon Sep 17 00:00:00 2001 From: Sascha Grunert Date: Mon, 7 Feb 2022 15:58:29 +0100 Subject: [PATCH] Clone tool repo on krel fast-forward If we're not in a repository, then we now clone the tool repo (k/release) to ensure that we can run Google Cloud Build jobs. Signed-off-by: Sascha Grunert --- pkg/fastforward/fastforward.go | 35 +- pkg/fastforward/fastforward_test.go | 49 +++ pkg/fastforward/fastforwardfakes/fake_impl.go | 303 ++++++++++++++++++ pkg/fastforward/impl.go | 22 ++ 4 files changed, 407 insertions(+), 2 deletions(-) diff --git a/pkg/fastforward/fastforward.go b/pkg/fastforward/fastforward.go index 28ddf8e4cf8..ebe5aaf93d1 100644 --- a/pkg/fastforward/fastforward.go +++ b/pkg/fastforward/fastforward.go @@ -74,6 +74,9 @@ Please only answer after you have validated the changes.` // Run starts the FastForward. func (f *FastForward) Run() (err error) { if f.options.Submit { + if err := f.prepareToolRepo(); err != nil { + return errors.Wrap(err, "prepare tool repo") + } logrus.Info("Submitting GCB job") options := gcb.NewDefaultOptions() options.FastForward = true @@ -82,7 +85,7 @@ func (f *FastForward) Run() (err error) { return f.Submit(options) } - repo, err := f.prepareRepo() + repo, err := f.prepareKubernetesRepo() if err != nil { return errors.Wrap(err, "prepare repository") } @@ -268,7 +271,7 @@ func (f *FastForward) noFastForwardRequired(repo *git.Repo, branch string) (bool return tagExists, nil } -func (f *FastForward) prepareRepo() (*git.Repo, error) { +func (f *FastForward) prepareKubernetesRepo() (*git.Repo, error) { logrus.Infof("Preparing to fast-forward from %s", f.options.MainRef) token := f.EnvDefault(github.TokenEnvKey, "") @@ -307,3 +310,31 @@ func (f *FastForward) prepareRepo() (*git.Repo, error) { return repo, nil } + +func (f *FastForward) prepareToolRepo() error { + if f.Exists(".git") { + return nil + } + + logrus.Info("Not in a git repo, preparing k/release clone") + + tmpPath, err := f.MkdirTemp("", "k-release-") + if err != nil { + return errors.Wrap(err, "create temp directory") + } + if err := f.RemoveAll(tmpPath); err != nil { + return errors.Wrap(err, "remove temp directory") + } + if _, err := f.CloneOrOpenGitHubRepo( + tmpPath, + release.DefaultToolOrg, + release.DefaultToolRepo, + false, + ); err != nil { + return errors.Wrap(err, "clone tool repository") + } + if err := f.Chdir(tmpPath); err != nil { + return errors.Wrap(err, "change directory") + } + return nil +} diff --git a/pkg/fastforward/fastforward_test.go b/pkg/fastforward/fastforward_test.go index cc54a5a5ff3..44d27e16207 100644 --- a/pkg/fastforward/fastforward_test.go +++ b/pkg/fastforward/fastforward_test.go @@ -103,6 +103,55 @@ func TestRun(t *testing.T) { require.Nil(t, err) }, }, + { // success prepare tool repo + prepare: func(mock *fastforwardfakes.FakeImpl) *Options { + mock.ExistsReturns(false) + return &Options{Submit: true} + }, + assert: func(err error) { + require.Nil(t, err) + }, + }, + { // failure prepare tool repo on Chdir + prepare: func(mock *fastforwardfakes.FakeImpl) *Options { + mock.ExistsReturns(false) + mock.ChdirReturns(errTest) + return &Options{Submit: true} + }, + assert: func(err error) { + require.NotNil(t, err) + }, + }, + { // failure prepare tool repo on CloneOrOpenGitHubRepo + prepare: func(mock *fastforwardfakes.FakeImpl) *Options { + mock.ExistsReturns(false) + mock.CloneOrOpenGitHubRepoReturns(nil, errTest) + return &Options{Submit: true} + }, + assert: func(err error) { + require.NotNil(t, err) + }, + }, + { // failure prepare tool repo on RemoveAll + prepare: func(mock *fastforwardfakes.FakeImpl) *Options { + mock.ExistsReturns(false) + mock.RemoveAllReturns(errTest) + return &Options{Submit: true} + }, + assert: func(err error) { + require.NotNil(t, err) + }, + }, + { // failure prepare tool repo on mkdirtemp + prepare: func(mock *fastforwardfakes.FakeImpl) *Options { + mock.ExistsReturns(false) + mock.MkdirTempReturns("", errTest) + return &Options{Submit: true} + }, + assert: func(err error) { + require.NotNil(t, err) + }, + }, { // success token prepare: func(mock *fastforwardfakes.FakeImpl) *Options { mock.IsReleaseBranchReturns(true) diff --git a/pkg/fastforward/fastforwardfakes/fake_impl.go b/pkg/fastforward/fastforwardfakes/fake_impl.go index 4ea9d798af5..c30280ba1a3 100644 --- a/pkg/fastforward/fastforwardfakes/fake_impl.go +++ b/pkg/fastforward/fastforwardfakes/fake_impl.go @@ -42,6 +42,17 @@ type FakeImpl struct { result2 bool result3 error } + ChdirStub func(string) error + chdirMutex sync.RWMutex + chdirArgsForCall []struct { + arg1 string + } + chdirReturns struct { + result1 error + } + chdirReturnsOnCall map[int]struct { + result1 error + } CloneOrOpenDefaultGitHubRepoSSHStub func(string) (*git.Repo, error) cloneOrOpenDefaultGitHubRepoSSHMutex sync.RWMutex cloneOrOpenDefaultGitHubRepoSSHArgsForCall []struct { @@ -83,6 +94,17 @@ type FakeImpl struct { envDefaultReturnsOnCall map[int]struct { result1 string } + ExistsStub func(string) bool + existsMutex sync.RWMutex + existsArgsForCall []struct { + arg1 string + } + existsReturns struct { + result1 bool + } + existsReturnsOnCall map[int]struct { + result1 bool + } IsDefaultK8sUpstreamStub func() bool isDefaultK8sUpstreamMutex sync.RWMutex isDefaultK8sUpstreamArgsForCall []struct { @@ -104,6 +126,31 @@ type FakeImpl struct { isReleaseBranchReturnsOnCall map[int]struct { result1 bool } + MkdirTempStub func(string, string) (string, error) + mkdirTempMutex sync.RWMutex + mkdirTempArgsForCall []struct { + arg1 string + arg2 string + } + mkdirTempReturns struct { + result1 string + result2 error + } + mkdirTempReturnsOnCall map[int]struct { + result1 string + result2 error + } + RemoveAllStub func(string) error + removeAllMutex sync.RWMutex + removeAllArgsForCall []struct { + arg1 string + } + removeAllReturns struct { + result1 error + } + removeAllReturnsOnCall map[int]struct { + result1 error + } RepoCheckoutStub func(*git.Repo, string, ...string) error repoCheckoutMutex sync.RWMutex repoCheckoutArgsForCall []struct { @@ -361,6 +408,67 @@ func (fake *FakeImpl) AskReturnsOnCall(i int, result1 string, result2 bool, resu }{result1, result2, result3} } +func (fake *FakeImpl) Chdir(arg1 string) error { + fake.chdirMutex.Lock() + ret, specificReturn := fake.chdirReturnsOnCall[len(fake.chdirArgsForCall)] + fake.chdirArgsForCall = append(fake.chdirArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.ChdirStub + fakeReturns := fake.chdirReturns + fake.recordInvocation("Chdir", []interface{}{arg1}) + fake.chdirMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeImpl) ChdirCallCount() int { + fake.chdirMutex.RLock() + defer fake.chdirMutex.RUnlock() + return len(fake.chdirArgsForCall) +} + +func (fake *FakeImpl) ChdirCalls(stub func(string) error) { + fake.chdirMutex.Lock() + defer fake.chdirMutex.Unlock() + fake.ChdirStub = stub +} + +func (fake *FakeImpl) ChdirArgsForCall(i int) string { + fake.chdirMutex.RLock() + defer fake.chdirMutex.RUnlock() + argsForCall := fake.chdirArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeImpl) ChdirReturns(result1 error) { + fake.chdirMutex.Lock() + defer fake.chdirMutex.Unlock() + fake.ChdirStub = nil + fake.chdirReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeImpl) ChdirReturnsOnCall(i int, result1 error) { + fake.chdirMutex.Lock() + defer fake.chdirMutex.Unlock() + fake.ChdirStub = nil + if fake.chdirReturnsOnCall == nil { + fake.chdirReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.chdirReturnsOnCall[i] = struct { + result1 error + }{result1} +} + func (fake *FakeImpl) CloneOrOpenDefaultGitHubRepoSSH(arg1 string) (*git.Repo, error) { fake.cloneOrOpenDefaultGitHubRepoSSHMutex.Lock() ret, specificReturn := fake.cloneOrOpenDefaultGitHubRepoSSHReturnsOnCall[len(fake.cloneOrOpenDefaultGitHubRepoSSHArgsForCall)] @@ -554,6 +662,67 @@ func (fake *FakeImpl) EnvDefaultReturnsOnCall(i int, result1 string) { }{result1} } +func (fake *FakeImpl) Exists(arg1 string) bool { + fake.existsMutex.Lock() + ret, specificReturn := fake.existsReturnsOnCall[len(fake.existsArgsForCall)] + fake.existsArgsForCall = append(fake.existsArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.ExistsStub + fakeReturns := fake.existsReturns + fake.recordInvocation("Exists", []interface{}{arg1}) + fake.existsMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeImpl) ExistsCallCount() int { + fake.existsMutex.RLock() + defer fake.existsMutex.RUnlock() + return len(fake.existsArgsForCall) +} + +func (fake *FakeImpl) ExistsCalls(stub func(string) bool) { + fake.existsMutex.Lock() + defer fake.existsMutex.Unlock() + fake.ExistsStub = stub +} + +func (fake *FakeImpl) ExistsArgsForCall(i int) string { + fake.existsMutex.RLock() + defer fake.existsMutex.RUnlock() + argsForCall := fake.existsArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeImpl) ExistsReturns(result1 bool) { + fake.existsMutex.Lock() + defer fake.existsMutex.Unlock() + fake.ExistsStub = nil + fake.existsReturns = struct { + result1 bool + }{result1} +} + +func (fake *FakeImpl) ExistsReturnsOnCall(i int, result1 bool) { + fake.existsMutex.Lock() + defer fake.existsMutex.Unlock() + fake.ExistsStub = nil + if fake.existsReturnsOnCall == nil { + fake.existsReturnsOnCall = make(map[int]struct { + result1 bool + }) + } + fake.existsReturnsOnCall[i] = struct { + result1 bool + }{result1} +} + func (fake *FakeImpl) IsDefaultK8sUpstream() bool { fake.isDefaultK8sUpstreamMutex.Lock() ret, specificReturn := fake.isDefaultK8sUpstreamReturnsOnCall[len(fake.isDefaultK8sUpstreamArgsForCall)] @@ -668,6 +837,132 @@ func (fake *FakeImpl) IsReleaseBranchReturnsOnCall(i int, result1 bool) { }{result1} } +func (fake *FakeImpl) MkdirTemp(arg1 string, arg2 string) (string, error) { + fake.mkdirTempMutex.Lock() + ret, specificReturn := fake.mkdirTempReturnsOnCall[len(fake.mkdirTempArgsForCall)] + fake.mkdirTempArgsForCall = append(fake.mkdirTempArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + stub := fake.MkdirTempStub + fakeReturns := fake.mkdirTempReturns + fake.recordInvocation("MkdirTemp", []interface{}{arg1, arg2}) + fake.mkdirTempMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1, ret.result2 + } + return fakeReturns.result1, fakeReturns.result2 +} + +func (fake *FakeImpl) MkdirTempCallCount() int { + fake.mkdirTempMutex.RLock() + defer fake.mkdirTempMutex.RUnlock() + return len(fake.mkdirTempArgsForCall) +} + +func (fake *FakeImpl) MkdirTempCalls(stub func(string, string) (string, error)) { + fake.mkdirTempMutex.Lock() + defer fake.mkdirTempMutex.Unlock() + fake.MkdirTempStub = stub +} + +func (fake *FakeImpl) MkdirTempArgsForCall(i int) (string, string) { + fake.mkdirTempMutex.RLock() + defer fake.mkdirTempMutex.RUnlock() + argsForCall := fake.mkdirTempArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *FakeImpl) MkdirTempReturns(result1 string, result2 error) { + fake.mkdirTempMutex.Lock() + defer fake.mkdirTempMutex.Unlock() + fake.MkdirTempStub = nil + fake.mkdirTempReturns = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeImpl) MkdirTempReturnsOnCall(i int, result1 string, result2 error) { + fake.mkdirTempMutex.Lock() + defer fake.mkdirTempMutex.Unlock() + fake.MkdirTempStub = nil + if fake.mkdirTempReturnsOnCall == nil { + fake.mkdirTempReturnsOnCall = make(map[int]struct { + result1 string + result2 error + }) + } + fake.mkdirTempReturnsOnCall[i] = struct { + result1 string + result2 error + }{result1, result2} +} + +func (fake *FakeImpl) RemoveAll(arg1 string) error { + fake.removeAllMutex.Lock() + ret, specificReturn := fake.removeAllReturnsOnCall[len(fake.removeAllArgsForCall)] + fake.removeAllArgsForCall = append(fake.removeAllArgsForCall, struct { + arg1 string + }{arg1}) + stub := fake.RemoveAllStub + fakeReturns := fake.removeAllReturns + fake.recordInvocation("RemoveAll", []interface{}{arg1}) + fake.removeAllMutex.Unlock() + if stub != nil { + return stub(arg1) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *FakeImpl) RemoveAllCallCount() int { + fake.removeAllMutex.RLock() + defer fake.removeAllMutex.RUnlock() + return len(fake.removeAllArgsForCall) +} + +func (fake *FakeImpl) RemoveAllCalls(stub func(string) error) { + fake.removeAllMutex.Lock() + defer fake.removeAllMutex.Unlock() + fake.RemoveAllStub = stub +} + +func (fake *FakeImpl) RemoveAllArgsForCall(i int) string { + fake.removeAllMutex.RLock() + defer fake.removeAllMutex.RUnlock() + argsForCall := fake.removeAllArgsForCall[i] + return argsForCall.arg1 +} + +func (fake *FakeImpl) RemoveAllReturns(result1 error) { + fake.removeAllMutex.Lock() + defer fake.removeAllMutex.Unlock() + fake.RemoveAllStub = nil + fake.removeAllReturns = struct { + result1 error + }{result1} +} + +func (fake *FakeImpl) RemoveAllReturnsOnCall(i int, result1 error) { + fake.removeAllMutex.Lock() + defer fake.removeAllMutex.Unlock() + fake.RemoveAllStub = nil + if fake.removeAllReturnsOnCall == nil { + fake.removeAllReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.removeAllReturnsOnCall[i] = struct { + result1 error + }{result1} +} + func (fake *FakeImpl) RepoCheckout(arg1 *git.Repo, arg2 string, arg3 ...string) error { fake.repoCheckoutMutex.Lock() ret, specificReturn := fake.repoCheckoutReturnsOnCall[len(fake.repoCheckoutArgsForCall)] @@ -1591,16 +1886,24 @@ func (fake *FakeImpl) Invocations() map[string][][]interface{} { defer fake.invocationsMutex.RUnlock() fake.askMutex.RLock() defer fake.askMutex.RUnlock() + fake.chdirMutex.RLock() + defer fake.chdirMutex.RUnlock() fake.cloneOrOpenDefaultGitHubRepoSSHMutex.RLock() defer fake.cloneOrOpenDefaultGitHubRepoSSHMutex.RUnlock() fake.cloneOrOpenGitHubRepoMutex.RLock() defer fake.cloneOrOpenGitHubRepoMutex.RUnlock() fake.envDefaultMutex.RLock() defer fake.envDefaultMutex.RUnlock() + fake.existsMutex.RLock() + defer fake.existsMutex.RUnlock() fake.isDefaultK8sUpstreamMutex.RLock() defer fake.isDefaultK8sUpstreamMutex.RUnlock() fake.isReleaseBranchMutex.RLock() defer fake.isReleaseBranchMutex.RUnlock() + fake.mkdirTempMutex.RLock() + defer fake.mkdirTempMutex.RUnlock() + fake.removeAllMutex.RLock() + defer fake.removeAllMutex.RUnlock() fake.repoCheckoutMutex.RLock() defer fake.repoCheckoutMutex.RUnlock() fake.repoCleanupMutex.RLock() diff --git a/pkg/fastforward/impl.go b/pkg/fastforward/impl.go index 20e8eb101b3..ad77d370e27 100644 --- a/pkg/fastforward/impl.go +++ b/pkg/fastforward/impl.go @@ -17,6 +17,8 @@ limitations under the License. package fastforward import ( + "os" + "k8s.io/release/pkg/gcp/gcb" "k8s.io/release/pkg/release" @@ -51,6 +53,10 @@ type impl interface { CloneOrOpenGitHubRepo(string, string, string, bool) (*git.Repo, error) IsDefaultK8sUpstream() bool RepoSetURL(*git.Repo, string, string) error + Chdir(string) error + RemoveAll(string) error + MkdirTemp(string, string) (string, error) + Exists(string) bool } func (*defaultImpl) CloneOrOpenDefaultGitHubRepoSSH(repo string) (*git.Repo, error) { @@ -136,3 +142,19 @@ func (*defaultImpl) IsDefaultK8sUpstream() bool { func (*defaultImpl) RepoSetURL(r *git.Repo, remote, newURL string) error { return r.SetURL(remote, newURL) } + +func (*defaultImpl) Chdir(dir string) error { + return os.Chdir(dir) +} + +func (*defaultImpl) RemoveAll(path string) error { + return os.RemoveAll(path) +} + +func (*defaultImpl) MkdirTemp(dir, pattern string) (string, error) { + return os.MkdirTemp(dir, pattern) +} + +func (*defaultImpl) Exists(path string) bool { + return util.Exists(path) +}