Merge pull request #1322 from caarlos0/opts

feat: new git flags
This commit is contained in:
Tejal Desai 2020-08-13 15:08:36 -07:00 committed by GitHub
commit 0c7e1644cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 180 additions and 7 deletions

View File

@ -175,6 +175,7 @@ func addKanikoOptionsFlags() {
RootCmd.PersistentFlags().VarP(&opts.Labels, "label", "", "Set metadata for an image. Set it repeatedly for multiple labels.")
RootCmd.PersistentFlags().BoolVarP(&opts.SkipUnusedStages, "skip-unused-stages", "", false, "Build only used stages if defined to true. Otherwise it builds by default all stages, even the unnecessaries ones until it reaches the target stage / end of Dockerfile")
RootCmd.PersistentFlags().BoolVarP(&opts.RunV2, "use-new-run", "", false, "Experimental run command to detect file system changes. This new run command does no rely on snapshotting to detect changes.")
RootCmd.PersistentFlags().Var(&opts.Git, "git", "Branch to clone if build context is a git repository")
}
// addHiddenFlags marks certain flags as hidden from the executor help text
@ -266,7 +267,11 @@ func resolveSourceContext() error {
opts.SrcContext = opts.Bucket
}
}
contextExecutor, err := buildcontext.GetBuildContext(opts.SrcContext)
contextExecutor, err := buildcontext.GetBuildContext(opts.SrcContext, buildcontext.BuildOptions{
GitBranch: opts.Git.Branch,
GitSingleBranch: opts.Git.SingleBranch,
GitRecurseSubmodules: opts.Git.RecurseSubmodules,
})
if err != nil {
return err
}

View File

@ -28,6 +28,12 @@ const (
TarBuildContextPrefix = "tar://"
)
type BuildOptions struct {
GitBranch string
GitSingleBranch bool
GitRecurseSubmodules bool
}
// BuildContext unifies calls to download and unpack the build context.
type BuildContext interface {
// Unpacks a build context and returns the directory where it resides
@ -36,7 +42,7 @@ type BuildContext interface {
// GetBuildContext parses srcContext for the prefix and returns related buildcontext
// parser
func GetBuildContext(srcContext string) (BuildContext, error) {
func GetBuildContext(srcContext string, opts BuildOptions) (BuildContext, error) {
split := strings.SplitAfter(srcContext, "://")
if len(split) > 1 {
prefix := split[0]
@ -50,7 +56,7 @@ func GetBuildContext(srcContext string) (BuildContext, error) {
case constants.LocalDirBuildContextPrefix:
return &Dir{context: context}, nil
case constants.GitBuildContextPrefix:
return &Git{context: context}, nil
return &Git{context: context, opts: opts}, nil
case constants.HTTPSBuildContextPrefix:
if util.ValidAzureBlobStorageHost(srcContext) {
return &AzureBlob{context: srcContext}, nil

View File

@ -17,14 +17,21 @@ limitations under the License.
package buildcontext
import (
"fmt"
"os"
"strings"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/go-git/go-billy/v5/osfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/go-git/go-git/v5/storage/filesystem"
"github.com/sirupsen/logrus"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
)
const (
@ -44,21 +51,34 @@ var (
// Git unifies calls to download and unpack the build context.
type Git struct {
context string
opts BuildOptions
}
// UnpackTarFromBuildContext will provide the directory where Git Repository is Cloned
func (g *Git) UnpackTarFromBuildContext() (string, error) {
directory := constants.BuildContextDir
parts := strings.Split(g.context, "#")
url := getGitPullMethod() + "://" + parts[0]
options := git.CloneOptions{
URL: getGitPullMethod() + "://" + parts[0],
URL: url,
Auth: getGitAuth(),
Progress: os.Stdout,
RecurseSubmodules: git.DefaultSubmoduleRecursionDepth,
SingleBranch: g.opts.GitSingleBranch,
RecurseSubmodules: getRecurseSubmodules(g.opts.GitRecurseSubmodules),
}
if len(parts) > 1 {
options.ReferenceName = plumbing.ReferenceName(parts[1])
}
if branch := g.opts.GitBranch; branch != "" {
ref, err := getGitReferenceName(directory, url, branch)
if err != nil {
return directory, err
}
options.ReferenceName = ref
}
logrus.Debugf("Getting source from reference %s", options.ReferenceName)
r, err := git.PlainClone(directory, false, &options)
if err == nil && len(parts) > 2 {
@ -81,10 +101,54 @@ func (g *Git) UnpackTarFromBuildContext() (string, error) {
return directory, err
}
}
return directory, err
}
func getGitReferenceName(directory string, url string, branch string) (plumbing.ReferenceName, error) {
var remote = git.NewRemote(
filesystem.NewStorage(
osfs.New(directory),
cache.NewObjectLRUDefault(),
),
&config.RemoteConfig{
URLs: []string{url},
},
)
refs, err := remote.List(&git.ListOptions{
Auth: getGitAuth(),
})
if err != nil {
return plumbing.HEAD, err
}
if ref := plumbing.NewBranchReferenceName(branch); gitRefExists(ref, refs) {
return ref, nil
}
if ref := plumbing.NewTagReferenceName(branch); gitRefExists(ref, refs) {
return ref, nil
}
return plumbing.HEAD, fmt.Errorf("invalid branch: %s", branch)
}
func gitRefExists(ref plumbing.ReferenceName, refs []*plumbing.Reference) bool {
for _, ref2 := range refs {
if ref.String() == ref2.Name().String() {
return true
}
}
return false
}
func getRecurseSubmodules(v bool) git.SubmoduleRescursivity {
if v {
return git.DefaultSubmoduleRecursionDepth
}
return git.NoRecurseSubmodules
}
func getGitAuth() transport.AuthMethod {
username := os.Getenv(gitAuthUsernameEnvKey)
password := os.Getenv(gitAuthPasswordEnvKey)

View File

@ -17,6 +17,10 @@ limitations under the License.
package config
import (
"errors"
"fmt"
"strconv"
"strings"
"time"
)
@ -58,6 +62,47 @@ type KanikoOptions struct {
IgnoreVarRun bool
SkipUnusedStages bool
RunV2 bool
Git KanikoGitOptions
}
type KanikoGitOptions struct {
Branch string
SingleBranch bool
RecurseSubmodules bool
}
var ErrInvalidGitFlag = errors.New("invalid git flag, must be in the key=value format")
func (k *KanikoGitOptions) Type() string {
return "gitoptions"
}
func (k *KanikoGitOptions) String() string {
return fmt.Sprintf("branch=%s,single-branch=%t,recurse-submodules=%t", k.Branch, k.SingleBranch, k.RecurseSubmodules)
}
func (k *KanikoGitOptions) Set(s string) error {
var parts = strings.SplitN(s, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("%w: %s", ErrInvalidGitFlag, s)
}
switch parts[0] {
case "branch":
k.Branch = parts[1]
case "single-branch":
v, err := strconv.ParseBool(parts[1])
if err != nil {
return err
}
k.SingleBranch = v
case "recurse-submodules":
v, err := strconv.ParseBool(parts[1])
if err != nil {
return err
}
k.RecurseSubmodules = v
}
return nil
}
// WarmerOptions are options that are set by command line arguments to the cache warmer.

View File

@ -0,0 +1,53 @@
/*
Copyright 2020 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package config
import (
"testing"
"github.com/GoogleContainerTools/kaniko/testutil"
)
func TestKanikoGitOptions(t *testing.T) {
t.Run("invalid pair", func(t *testing.T) {
var g = &KanikoGitOptions{}
testutil.CheckError(t, true, g.Set("branch"))
})
t.Run("sets values", func(t *testing.T) {
var g = &KanikoGitOptions{}
testutil.CheckNoError(t, g.Set("branch=foo"))
testutil.CheckNoError(t, g.Set("recurse-submodules=true"))
testutil.CheckNoError(t, g.Set("single-branch=true"))
testutil.CheckDeepEqual(t, KanikoGitOptions{
Branch: "foo",
SingleBranch: true,
RecurseSubmodules: true,
}, *g)
})
t.Run("sets bools other than true", func(t *testing.T) {
var g = KanikoGitOptions{}
testutil.CheckError(t, true, g.Set("recurse-submodules="))
testutil.CheckError(t, true, g.Set("single-branch=zaza"))
testutil.CheckNoError(t, g.Set("recurse-submodules=false"))
testutil.CheckDeepEqual(t, KanikoGitOptions{
SingleBranch: false,
RecurseSubmodules: false,
}, g)
})
}