From 7948084487aadd79af5f6ef0bd10dd26a0f07fac Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 6 Oct 2023 19:04:25 -0700 Subject: [PATCH 01/20] add dev clone to cli Signed-off-by: Oscar Ward --- go.mod | 2 +- pkg/apis/internal.acorn.io/v1/appimage.go | 3 +- pkg/build/build_test.go | 2 +- pkg/cli/dev.go | 88 +++++++++++++++++++++-- pkg/client/build.go | 2 +- pkg/vcs/vcs.go | 14 +++- 6 files changed, 102 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 7a7961e10..3eea29790 100644 --- a/go.mod +++ b/go.mod @@ -63,6 +63,7 @@ require ( golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sync v0.4.0 google.golang.org/grpc v1.57.0 + gopkg.in/src-d/go-billy.v4 v4.3.2 gopkg.in/src-d/go-git.v4 v4.13.1 inet.af/tcpproxy v0.0.0-20221017015627-91f861402626 k8s.io/api v0.27.3 @@ -289,7 +290,6 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/src-d/go-billy.v4 v4.3.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/pkg/apis/internal.acorn.io/v1/appimage.go b/pkg/apis/internal.acorn.io/v1/appimage.go index 05f722f99..294f071e2 100644 --- a/pkg/apis/internal.acorn.io/v1/appimage.go +++ b/pkg/apis/internal.acorn.io/v1/appimage.go @@ -28,7 +28,8 @@ type VCS struct { // Modified a true value indicates the build contained modified files according to git Modified bool `json:"modified,omitempty"` // Untracked a true value indicates the build contained untracked files according to git - Untracked bool `json:"untracked,omitempty"` + Untracked bool `json:"untracked,omitempty"` + Acornfile string `json:"acornfile,omitempty"` } type Platform struct { diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index 249593c51..c41a0a7ae 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -8,7 +8,7 @@ import ( ) func TestVCS(t *testing.T) { - vcs := vcs2.VCS(".") + vcs := vcs2.VCS(".", "Acornfile") assert.NotEqual(t, "", vcs.Revision) } diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index aaf2e5742..09d071ddd 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -1,7 +1,13 @@ package cli import ( + "errors" + "fmt" "io" + "net/url" + "os" + "path/filepath" + "strings" "github.com/acorn-io/runtime/pkg/autoupgrade" cli "github.com/acorn-io/runtime/pkg/cli/builder" @@ -9,6 +15,10 @@ import ( "github.com/acorn-io/runtime/pkg/imagesource" "github.com/acorn-io/z" "github.com/spf13/cobra" + "gopkg.in/src-d/go-billy.v4/osfs" + "gopkg.in/src-d/go-git.v4" + "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" + "gopkg.in/src-d/go-git.v4/storage/memory" ) func NewDev(c CommandContext) *cobra.Command { @@ -42,9 +52,10 @@ acorn dev --name wandering-sound type Dev struct { RunArgs - BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` - Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults - HelpAdvanced bool `usage:"Show verbose help text"` + BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` + Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults + Clone string `usage:"Clone a running app"` + HelpAdvanced bool `usage:"Show verbose help text"` out io.Writer client ClientFactory } @@ -59,7 +70,76 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { return err } - imageSource := imagesource.NewImageSource(s.client.AcornConfigFile(), s.File, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) + var imageSource imagesource.ImageSource + if s.Clone == "" { + imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), s.File, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) + } else { + // Get info from the running app + app, err := c.AppGet(cmd.Context(), s.Clone) + if err != nil { + return err + } + vcs := app.Status.Staged.AppImage.VCS + + if len(vcs.Remotes) == 0 { + return fmt.Errorf("clone can only be done on an app built from a git repository") + } + + for _, remote := range vcs.Remotes { + var gitUrl string + httpUrl, err := url.Parse(remote) + if err == nil { + gitUrl = fmt.Sprintf("git@%s:%s", httpUrl.Host, httpUrl.Path[1:]) + } else { + gitUrl = remote + } + + // TODO workdir named after git repo, cloned app name, or just this app's name? + idx := strings.LastIndex(gitUrl, "/") + if idx < 0 || idx >= len(gitUrl) { + fmt.Fprintf(os.Stderr, "failed to determine repository name %q\n", gitUrl) + continue + } + workdir := strings.TrimSuffix(gitUrl[idx+1:], ".git") + + // Clone git repo + auth, _ := ssh.NewSSHAgentAuth("git") + _, err = git.CloneContext(cmd.Context(), memory.NewStorage(), osfs.New(workdir), &git.CloneOptions{ + URL: gitUrl, + // TODO print progress to somewhere maybe + // Progress: os.Stderr/os.Stdout, + Auth: auth, + }) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to resolve repository %q\n", gitUrl) + continue + } + + acornfile := filepath.Join(workdir, vcs.Acornfile) + if _, err := os.Stat(acornfile); err == nil { + // Acornfile exists + } else if errors.Is(err, os.ErrNotExist) { + // Acornfile does not exist so we should create it + err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create file %q in repository %q", acornfile, gitUrl) + // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? + continue + } + } else { + fmt.Fprintf(os.Stderr, "could not check for file %q in repository %q", acornfile, gitUrl) + // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? + continue + } + + imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), acornfile, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) + break + } + } + + if !imageSource.IsImageSet() { + return fmt.Errorf("failed to resolve image") + } opts, err := s.ToOpts() if err != nil { diff --git a/pkg/client/build.go b/pkg/client/build.go index 5740a02b4..d4abc521a 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -69,7 +69,7 @@ func (c *DefaultClient) AcornImageBuild(ctx context.Context, file string, opts * return nil, err } - vcs := vcs.VCS(filepath.Dir(file)) + vcs := vcs.VCS(filepath.Dir(file), filepath.Base(file)) builder, err := c.getOrCreateBuilder(ctx, opts.BuilderName) if err != nil { diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index c364c6b81..3f2ce9d91 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -1,11 +1,14 @@ package vcs import ( + "path/filepath" + "strings" + v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" "gopkg.in/src-d/go-git.v4" ) -func VCS(path string) (result v1.VCS) { +func VCS(path, fileName string) (result v1.VCS) { repo, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{ DetectDotGit: true, }) @@ -24,6 +27,14 @@ func VCS(path string) (result v1.VCS) { if err != nil { return } + absPath, err := filepath.Abs(path) + if err != nil { + return + } + var sb strings.Builder + sb.WriteString(w.Filesystem.Root()) + sb.WriteRune(filepath.Separator) + acornfile := strings.TrimPrefix(filepath.Join(absPath, fileName), sb.String()) var ( modified, untracked bool @@ -44,6 +55,7 @@ func VCS(path string) (result v1.VCS) { Clean: !modified && !untracked, Modified: modified, Untracked: untracked, + Acornfile: acornfile, } // Set optional remotes field From 11edc4d8fbbc6e7598c7a9aec7e65b4e7facb64f Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Tue, 10 Oct 2023 10:04:13 -0700 Subject: [PATCH 02/20] bump the git package version to newest supported train Signed-off-by: Oscar Ward --- go.mod | 22 +++++++---- go.sum | 87 +++++++++++++++++++++++------------------ pkg/build/build_test.go | 4 +- pkg/cli/dev.go | 16 ++++---- pkg/client/build.go | 2 +- pkg/vcs/vcs.go | 17 ++++---- 6 files changed, 81 insertions(+), 67 deletions(-) diff --git a/go.mod b/go.mod index 3eea29790..895db6a2a 100644 --- a/go.mod +++ b/go.mod @@ -31,6 +31,7 @@ require ( github.com/docker/cli v24.0.0+incompatible github.com/docker/docker-credential-helpers v0.7.0 github.com/go-acme/lego/v4 v4.9.1 + github.com/go-git/go-git/v5 v5.9.0 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.5.9 github.com/google/go-containerregistry v0.16.1 @@ -63,8 +64,6 @@ require ( golang.org/x/exp v0.0.0-20231006140011-7918f672742d golang.org/x/sync v0.4.0 google.golang.org/grpc v1.57.0 - gopkg.in/src-d/go-billy.v4 v4.3.2 - gopkg.in/src-d/go-git.v4 v4.13.1 inet.af/tcpproxy v0.0.0-20221017015627-91f861402626 k8s.io/api v0.27.3 k8s.io/apiextensions-apiserver v0.27.3 @@ -84,12 +83,14 @@ require ( require ( atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/keyboard v0.2.8 // indirect + dario.cat/mergo v1.0.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/NYTimes/gziphandler v1.1.1 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 // indirect github.com/ThalesIgnite/crypto11 v1.2.5 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect + github.com/acomagu/bufpipe v1.0.4 // indirect github.com/acorn-io/cmd v0.0.0-20230929053520-ebe1b9879b38 // indirect github.com/agnivade/levenshtein v1.1.1 // indirect github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect @@ -121,6 +122,7 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 // indirect + github.com/cyphar/filepath-securejoin v0.2.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/digitorus/timestamp v0.0.0-20230821155606-d1ad5ca9624c // indirect @@ -128,7 +130,7 @@ require ( github.com/docker/docker v24.0.0+incompatible // indirect github.com/emicklei/go-restful/v3 v3.10.2 // indirect github.com/emicklei/proto v1.10.0 // indirect - github.com/emirpasic/gods v1.12.0 // indirect + github.com/emirpasic/gods v1.18.1 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/color v1.15.0 // indirect @@ -138,6 +140,8 @@ require ( github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect + github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect + github.com/go-git/go-billy/v5 v5.5.0 // indirect github.com/go-logr/logr v1.2.4 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-openapi/analysis v0.21.4 // indirect @@ -179,12 +183,12 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b // indirect - github.com/jessevdk/go-flags v1.4.0 // indirect + github.com/jessevdk/go-flags v1.5.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd // indirect + github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.16.5 // indirect github.com/leodido/go-urn v1.2.4 // indirect github.com/letsencrypt/boulder v0.0.0-20221109233200-85aa52084eaf // indirect @@ -218,9 +222,11 @@ require ( github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/onsi/ginkgo/v2 v2.11.0 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/otiai10/copy v1.7.0 // indirect github.com/pelletier/go-toml/v2 v2.0.8 // indirect + github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.16.0 // indirect github.com/prometheus/client_model v0.4.0 // indirect @@ -236,11 +242,11 @@ require ( github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/sigstore/rekor v1.2.2 // indirect github.com/sigstore/timestamp-authority v1.1.2 // indirect + github.com/skeema/knownhosts v1.2.0 // indirect github.com/spf13/afero v1.9.5 // indirect github.com/spf13/cast v1.5.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/viper v1.16.0 // indirect - github.com/src-d/gcfg v1.4.0 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect github.com/subosito/gotenv v1.4.2 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect @@ -255,7 +261,7 @@ require ( github.com/transparency-dev/merkle v0.0.2 // indirect github.com/vbatts/tar-split v0.11.3 // indirect github.com/xanzy/go-gitlab v0.90.0 // indirect - github.com/xanzy/ssh-agent v0.2.1 // indirect + github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect go.etcd.io/etcd/api/v3 v3.5.9 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect diff --git a/go.sum b/go.sum index 1312b829d..e179c0c68 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cuelang.org/go v0.4.3 h1:W3oBBjDTm7+IZfCKZAmC8uDG0eYfJL4Pp/xbbCMKaVo= cuelang.org/go v0.4.3/go.mod h1:7805vR9H+VoBNdWFdI7jyDR3QLUPp4+naHfbcgp55HI= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -85,6 +87,7 @@ github.com/MarvinJWendt/testza v0.3.0/go.mod h1:eFcL4I0idjtIx8P9C6KkAuLgATNKpX4/ github.com/MarvinJWendt/testza v0.4.2/go.mod h1:mSdhXiKH8sg/gQehJ63bINcCKp7RtYewEjXsvsVUPbE= github.com/MarvinJWendt/testza v0.4.3 h1:u2XaM4IqGp9dsdUmML8/Z791fu4yjQYzOiufOtJwTII= github.com/MarvinJWendt/testza v0.4.3/go.mod h1:CpXaOfceNEYnLDtNIyTrPPcCpDJYqzZnu2aiA2Wp33U= +github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= github.com/Microsoft/hcsshim v0.9.8 h1:lf7xxK2+Ikbj9sVf2QZsouGjRjEp2STj1yDHgoVtU5k= @@ -94,14 +97,16 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek= -github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371 h1:kkhsdkhsCvIsutKu5zLMgWtgh9YxGCNAw8Ad8hjwfYg= +github.com/ProtonMail/go-crypto v0.0.0-20230828082145-3c4c8a2d2371/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= +github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ= +github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/acorn-io/aml v0.0.0-20231009045340-a31c45f6d100 h1:BXiQnq8aT780sd6T3Hs1+BJgsJcl/MTz00QZbiJfylE= github.com/acorn-io/aml v0.0.0-20231009045340-a31c45f6d100/go.mod h1:I1qN++bfN+6sOV/FiACluqj2Eu5YaHOy82cTAnjLMf0= github.com/acorn-io/aml/cli v0.0.0-20231009055509-3c83c1247cf8 h1:eQhRTIMBGbufCcww4Shqenh3nhPjl2l87Itxecl9Qjk= @@ -124,11 +129,8 @@ github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= github.com/adrg/xdg v0.4.0/go.mod h1:N6ag73EX4wyxeaoeHctc1mas01KZgsj5tYiAIwqJE/E= github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= @@ -194,7 +196,7 @@ github.com/bombsimon/logrusr/v4 v4.0.0/go.mod h1:pjfHC5e59CvjTBIU3V3sGhFWFAnsnhO github.com/bufbuild/connect-go v1.7.0 h1:MGp82v7SCza+3RhsVhV7aMikwxvI3ZfD72YiGt8FYJo= github.com/bufbuild/connect-go v1.7.0/go.mod h1:GmMJYR6orFqD0Y6ZgX8pwQ8j9baizDrIQMm1/a6LnHk= github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= -github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= @@ -208,7 +210,6 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I= github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs= github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= @@ -249,13 +250,14 @@ github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8 github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7 h1:vU+EP9ZuFUCYE0NYLwTSob+3LNEJATzNfP/DC7SWGWI= github.com/cyberphone/json-canonicalization v0.0.0-20220623050100-57a0ce2678a7/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= +github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= +github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/danieljoos/wincred v1.1.2 h1:QLdCxFs1/Yl4zduvBdcHB8goaYk9RARS2SgLLRuAyr0= github.com/danieljoos/wincred v1.1.2/go.mod h1:GijpziifJoIBfYh+S7BbkdUTU4LfM+QnGqR5Vl2tAx0= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -290,12 +292,14 @@ github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU= +github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/emicklei/go-restful/v3 v3.10.2 h1:hIovbnmBTLjHXkqEBUz3HGpXZdM7ZrE9fJIZIqlJLqE= github.com/emicklei/go-restful/v3 v3.10.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/emicklei/proto v1.10.0 h1:pDGyFRVV5RvV+nkBK9iy3q67FBy9Xa7vwrOTE+g5aGw= github.com/emicklei/proto v1.10.0/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= -github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -321,7 +325,6 @@ github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBD github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/frankban/quicktest v1.14.4/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= @@ -336,13 +339,20 @@ github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4= github.com/go-acme/lego/v4 v4.9.1 h1:n9Z5MQwANeGSQKlVE3bEh9SDvAySK9oVYOKCGCESqQE= github.com/go-acme/lego/v4 v4.9.1/go.mod h1:g3JRUyWS3L/VObpp4bCxzJftKyf/Wba8QrSSnoiqjg4= github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec= github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= +github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= +github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= +github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8= +github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo= +github.com/go-git/go-git/v5 v5.9.0 h1:cD9SFA7sHVRdJ7AYck1ZaAa/yeuBvGPxwXDL8cxrObY= +github.com/go-git/go-git/v5 v5.9.0/go.mod h1:RKIqga24sWdMGZF+1Ekv9kylsDz6LzdTSI2s/OsZWE0= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -633,8 +643,9 @@ github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b h1:ZGiXF8sz7P github.com/jedisct1/go-minisign v0.0.0-20211028175153-1c139d1cc84b/go.mod h1:hQmNrgofl+IY/8L+n20H6E6PWBBTokdsv+q49j0QhsU= github.com/jellydator/ttlcache/v3 v3.0.1 h1:cHgCSMS7TdQcoprXnWUptJZzyFsqs18Lt8VVhRuZYVU= github.com/jellydator/ttlcache/v3 v3.0.1/go.mod h1:WwTaEmcXQ3MTjOm4bsZoDFiCu/hMvNWLO1w67RXz6h4= -github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= +github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= +github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= @@ -655,8 +666,8 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY= -github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= +github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= @@ -677,7 +688,6 @@ github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NB github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= @@ -708,6 +718,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= +github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= +github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= @@ -783,14 +795,14 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= -github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/ginkgo/v2 v2.11.0 h1:WgqUCUt/lT6yXoQ8Wef0fsNn5cAuMK7+KT9UFRz2tcU= +github.com/onsi/ginkgo/v2 v2.11.0/go.mod h1:ZhrRA5XmEE3x3rhlzamx/JJvujdZoJ2uvgI7kR0iZvM= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= -github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg= +github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI= +github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0= @@ -813,12 +825,13 @@ github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI= github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170 h1:DiLBVp4DAcZlBVBEtJpNWZpZVq0AEeCY7Hqk8URVs4o= github.com/package-url/packageurl-go v0.1.1-0.20220428063043-89078438f170/go.mod h1:uQd4a7Rh3ZsVg5j0lNyAfyxIeGde9yrlhjF78GzeW0c= -github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= +github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4= +github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -866,8 +879,9 @@ github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= +github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk= @@ -880,7 +894,6 @@ github.com/sassoftware/relic/v7 v7.5.5 h1:2ZUM6ovo3STCAp0hZnO9nQY9lOB8OyfneeYIi4 github.com/sassoftware/relic/v7 v7.5.5/go.mod h1:NxwtWxWxlUa9as2qZi635Ye6bBT/tGnMALLq7dSfOOU= github.com/secure-systems-lab/go-securesystemslib v0.7.0 h1:OwvJ5jQf9LnIAS83waAjPbcMsODrTQUpJ02eNLUoxBg= github.com/secure-systems-lab/go-securesystemslib v0.7.0/go.mod h1:/2gYnlnHVQ6xeGtfIqFy7Do03K4cdCY0A/GlJLDKLHI= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= @@ -905,9 +918,12 @@ github.com/sigstore/timestamp-authority v1.1.2/go.mod h1:7rGe/e6ZJNMqPiwFiv7w+qN github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM= +github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= @@ -927,13 +943,10 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= -github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4= -github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI= github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -991,8 +1004,8 @@ github.com/wI2L/jsondiff v0.3.0 h1:iTzQ9u/d86GE9RsBzVHX88f2EA1vQUboHwLhSQFc1s4= github.com/wI2L/jsondiff v0.3.0/go.mod h1:y1IMzNNjlSsk3IUoJdRJO7VRBtzMvRgyo4Vu0LdHpTc= github.com/xanzy/go-gitlab v0.90.0 h1:j8ZUHfLfXdnC+B8njeNaW/kM44c1zw8fiuNj7D+qQN8= github.com/xanzy/go-gitlab v0.90.0/go.mod h1:5ryv+MnpZStBH8I/77HuQBsMbBGANtVpLWC15qOjWAw= -github.com/xanzy/ssh-agent v0.2.1 h1:TCbipTQL2JiiCprBWx9frJ2eJlCYT00NmctrHxVAr70= -github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= +github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= +github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= @@ -1077,12 +1090,10 @@ go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= go.uber.org/zap v1.25.0 h1:4Hvk6GtkucQ790dqmj7l1eEnRdKm3k3ZUrUMS2d5+5c= go.uber.org/zap v1.25.0/go.mod h1:JIAUzQIH94IC4fOJQm7gMmBJP5k7wQfdcnYdPoEXJYk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1090,6 +1101,7 @@ golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= @@ -1180,6 +1192,7 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= @@ -1223,7 +1236,6 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190221075227-b4e8571b14e0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1239,6 +1251,7 @@ golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1264,6 +1277,7 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1273,7 +1287,6 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1287,6 +1300,7 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1300,6 +1314,7 @@ golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= @@ -1317,6 +1332,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= @@ -1347,7 +1363,6 @@ golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/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-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -1535,12 +1550,6 @@ gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXL gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg= -gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg= -gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= -gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE= -gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index c41a0a7ae..8513df8eb 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -3,12 +3,12 @@ package build import ( "testing" - vcs2 "github.com/acorn-io/runtime/pkg/vcs" + "github.com/acorn-io/runtime/pkg/vcs" "github.com/stretchr/testify/assert" ) func TestVCS(t *testing.T) { - vcs := vcs2.VCS(".", "Acornfile") + vcs := vcs.VCS(".") assert.NotEqual(t, "", vcs.Revision) } diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index 09d071ddd..6660ef9ec 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -14,11 +14,9 @@ import ( "github.com/acorn-io/runtime/pkg/dev" "github.com/acorn-io/runtime/pkg/imagesource" "github.com/acorn-io/z" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/spf13/cobra" - "gopkg.in/src-d/go-billy.v4/osfs" - "gopkg.in/src-d/go-git.v4" - "gopkg.in/src-d/go-git.v4/plumbing/transport/ssh" - "gopkg.in/src-d/go-git.v4/storage/memory" ) func NewDev(c CommandContext) *cobra.Command { @@ -97,21 +95,21 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { // TODO workdir named after git repo, cloned app name, or just this app's name? idx := strings.LastIndex(gitUrl, "/") if idx < 0 || idx >= len(gitUrl) { - fmt.Fprintf(os.Stderr, "failed to determine repository name %q\n", gitUrl) + fmt.Printf("failed to determine repository name %q\n", gitUrl) continue } workdir := strings.TrimSuffix(gitUrl[idx+1:], ".git") // Clone git repo auth, _ := ssh.NewSSHAgentAuth("git") - _, err = git.CloneContext(cmd.Context(), memory.NewStorage(), osfs.New(workdir), &git.CloneOptions{ + _, err = git.PlainCloneContext(cmd.Context(), workdir, false, &git.CloneOptions{ URL: gitUrl, // TODO print progress to somewhere maybe // Progress: os.Stderr/os.Stdout, Auth: auth, }) if err != nil { - fmt.Fprintf(os.Stderr, "failed to resolve repository %q\n", gitUrl) + fmt.Printf("failed to resolve repository %q\n", gitUrl) continue } @@ -122,12 +120,12 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { // Acornfile does not exist so we should create it err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) if err != nil { - fmt.Fprintf(os.Stderr, "failed to create file %q in repository %q", acornfile, gitUrl) + fmt.Printf("failed to create file %q in repository %q", acornfile, gitUrl) // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? continue } } else { - fmt.Fprintf(os.Stderr, "could not check for file %q in repository %q", acornfile, gitUrl) + fmt.Printf("could not check for file %q in repository %q", acornfile, gitUrl) // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? continue } diff --git a/pkg/client/build.go b/pkg/client/build.go index d4abc521a..fd84013c6 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -69,7 +69,7 @@ func (c *DefaultClient) AcornImageBuild(ctx context.Context, file string, opts * return nil, err } - vcs := vcs.VCS(filepath.Dir(file), filepath.Base(file)) + vcs := vcs.VCS(file) builder, err := c.getOrCreateBuilder(ctx, opts.BuilderName) if err != nil { diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 3f2ce9d91..c852e848a 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -5,11 +5,15 @@ import ( "strings" v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" - "gopkg.in/src-d/go-git.v4" + "github.com/go-git/go-git/v5" ) -func VCS(path, fileName string) (result v1.VCS) { - repo, err := git.PlainOpenWithOptions(path, &git.PlainOpenOptions{ +func VCS(filePath string) (result v1.VCS) { + absPath, err := filepath.Abs(filePath) + if err != nil { + return + } + repo, err := git.PlainOpenWithOptions(filepath.Dir(absPath), &git.PlainOpenOptions{ DetectDotGit: true, }) if err != nil { @@ -27,14 +31,11 @@ func VCS(path, fileName string) (result v1.VCS) { if err != nil { return } - absPath, err := filepath.Abs(path) - if err != nil { - return - } + var sb strings.Builder sb.WriteString(w.Filesystem.Root()) sb.WriteRune(filepath.Separator) - acornfile := strings.TrimPrefix(filepath.Join(absPath, fileName), sb.String()) + acornfile := strings.TrimPrefix(absPath, sb.String()) var ( modified, untracked bool From a4ce1e8ab9f6668713641c9bb1c564fee0e9e3ac Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Tue, 10 Oct 2023 11:08:50 -0700 Subject: [PATCH 03/20] update docs Signed-off-by: Oscar Ward --- docs/docs/100-reference/01-command-line/acorn_dev.md | 1 + pkg/openapi/generated/openapi_generated.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/docs/docs/100-reference/01-command-line/acorn_dev.md b/docs/docs/100-reference/01-command-line/acorn_dev.md index 9c145a94c..d92908c3a 100644 --- a/docs/docs/100-reference/01-command-line/acorn_dev.md +++ b/docs/docs/100-reference/01-command-line/acorn_dev.md @@ -26,6 +26,7 @@ acorn dev --name wandering-sound --args-file string Default args to apply to run/update command (default ".args.acorn") --auto-upgrade Enabled automatic upgrades. -b, --bidirectional-sync In interactive mode download changes in addition to uploading + --clone string Clone a running app -f, --file string Name of the build file (default "DIRECTORY/Acornfile") -h, --help help for dev --help-advanced Show verbose help text diff --git a/pkg/openapi/generated/openapi_generated.go b/pkg/openapi/generated/openapi_generated.go index ec4f9677e..ae0034b0d 100644 --- a/pkg/openapi/generated/openapi_generated.go +++ b/pkg/openapi/generated/openapi_generated.go @@ -12330,6 +12330,12 @@ func schema_pkg_apis_internalacornio_v1_VCS(ref common.ReferenceCallback) common Format: "", }, }, + "acornfile": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, }, }, }, From b6cb7f0ba2ea6c89a1b78bd12c40c4ec3d5a6a17 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Wed, 11 Oct 2023 09:56:11 -0700 Subject: [PATCH 04/20] PR comments Signed-off-by: Oscar Ward --- pkg/apis/internal.acorn.io/v1/appimage.go | 3 +- pkg/cli/dev.go | 70 ++-------------------- pkg/openapi/generated/openapi_generated.go | 5 +- pkg/vcs/vcs.go | 69 +++++++++++++++++++++ 4 files changed, 79 insertions(+), 68 deletions(-) diff --git a/pkg/apis/internal.acorn.io/v1/appimage.go b/pkg/apis/internal.acorn.io/v1/appimage.go index 294f071e2..738968223 100644 --- a/pkg/apis/internal.acorn.io/v1/appimage.go +++ b/pkg/apis/internal.acorn.io/v1/appimage.go @@ -28,7 +28,8 @@ type VCS struct { // Modified a true value indicates the build contained modified files according to git Modified bool `json:"modified,omitempty"` // Untracked a true value indicates the build contained untracked files according to git - Untracked bool `json:"untracked,omitempty"` + Untracked bool `json:"untracked,omitempty"` + // Acornfile contains the path and filename within the git repository that was used to build the running app Acornfile string `json:"acornfile,omitempty"` } diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index 6660ef9ec..1afdf1fed 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -1,21 +1,14 @@ package cli import ( - "errors" - "fmt" "io" - "net/url" - "os" - "path/filepath" - "strings" "github.com/acorn-io/runtime/pkg/autoupgrade" cli "github.com/acorn-io/runtime/pkg/cli/builder" "github.com/acorn-io/runtime/pkg/dev" "github.com/acorn-io/runtime/pkg/imagesource" + "github.com/acorn-io/runtime/pkg/vcs" "github.com/acorn-io/z" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/spf13/cobra" ) @@ -77,66 +70,13 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { if err != nil { return err } - vcs := app.Status.Staged.AppImage.VCS - if len(vcs.Remotes) == 0 { - return fmt.Errorf("clone can only be done on an app built from a git repository") - } - - for _, remote := range vcs.Remotes { - var gitUrl string - httpUrl, err := url.Parse(remote) - if err == nil { - gitUrl = fmt.Sprintf("git@%s:%s", httpUrl.Host, httpUrl.Path[1:]) - } else { - gitUrl = remote - } - - // TODO workdir named after git repo, cloned app name, or just this app's name? - idx := strings.LastIndex(gitUrl, "/") - if idx < 0 || idx >= len(gitUrl) { - fmt.Printf("failed to determine repository name %q\n", gitUrl) - continue - } - workdir := strings.TrimSuffix(gitUrl[idx+1:], ".git") - - // Clone git repo - auth, _ := ssh.NewSSHAgentAuth("git") - _, err = git.PlainCloneContext(cmd.Context(), workdir, false, &git.CloneOptions{ - URL: gitUrl, - // TODO print progress to somewhere maybe - // Progress: os.Stderr/os.Stdout, - Auth: auth, - }) - if err != nil { - fmt.Printf("failed to resolve repository %q\n", gitUrl) - continue - } - - acornfile := filepath.Join(workdir, vcs.Acornfile) - if _, err := os.Stat(acornfile); err == nil { - // Acornfile exists - } else if errors.Is(err, os.ErrNotExist) { - // Acornfile does not exist so we should create it - err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) - if err != nil { - fmt.Printf("failed to create file %q in repository %q", acornfile, gitUrl) - // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? - continue - } - } else { - fmt.Printf("could not check for file %q in repository %q", acornfile, gitUrl) - // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? - continue - } - - imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), acornfile, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) - break + acornfile, err := vcs.AcornfileFromApp(cmd.Context(), app) + if err != nil { + return err } - } - if !imageSource.IsImageSet() { - return fmt.Errorf("failed to resolve image") + imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), acornfile, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) } opts, err := s.ToOpts() diff --git a/pkg/openapi/generated/openapi_generated.go b/pkg/openapi/generated/openapi_generated.go index ae0034b0d..4ac647dd7 100644 --- a/pkg/openapi/generated/openapi_generated.go +++ b/pkg/openapi/generated/openapi_generated.go @@ -12332,8 +12332,9 @@ func schema_pkg_apis_internalacornio_v1_VCS(ref common.ReferenceCallback) common }, "acornfile": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "Acornfile contains the path and filename within the git repository that was used to build the running app", + Type: []string{"string"}, + Format: "", }, }, }, diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index c852e848a..2cd1203fd 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -1,11 +1,18 @@ package vcs import ( + "context" + "errors" + "fmt" + "net/url" + "os" "path/filepath" "strings" + apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1" v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" ) func VCS(filePath string) (result v1.VCS) { @@ -71,3 +78,65 @@ func VCS(filePath string) (result v1.VCS) { return } + +func AcornfileFromApp(ctx context.Context, app *apiv1.App) (string, error) { + + vcs := app.Status.Staged.AppImage.VCS + + if len(vcs.Remotes) == 0 { + return "", fmt.Errorf("clone can only be done on an app built from a git repository") + } + + auth, err := ssh.NewSSHAgentAuth("git") + if err != nil { + return "", err + } + + for _, remote := range vcs.Remotes { + var gitUrl string + httpUrl, err := url.Parse(remote) + if err == nil { + gitUrl = fmt.Sprintf("git@%s:%s", httpUrl.Host, httpUrl.Path[1:]) + } else { + gitUrl = remote + } + + // TODO workdir named after git repo, cloned app name, or just this app's name? + idx := strings.LastIndex(gitUrl, "/") + if idx < 0 || idx >= len(gitUrl) { + fmt.Printf("failed to determine repository name %q\n", gitUrl) + continue + } + workdir := filepath.Clean(strings.TrimSuffix(gitUrl[idx+1:], ".git")) + + // Clone git repo + _, err = git.PlainCloneContext(ctx, workdir, false, &git.CloneOptions{ + URL: gitUrl, + Progress: os.Stderr, + Auth: auth, + }) + // TODO handle ErrRepositoryAlreadyExists some way + if err != nil { + fmt.Printf("failed to clone repository %q: %s\n", gitUrl, err.Error()) + continue + } + + acornfile := filepath.Join(workdir, vcs.Acornfile) + // TODO if acornfile exists but is different than what is cached should we overwrite? + if _, err := os.Stat(acornfile); errors.Is(err, os.ErrNotExist) { + // Acornfile does not exist so we should create it + err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) + if err != nil { + fmt.Printf("failed to create file %q in repository %q: %s", acornfile, gitUrl, err.Error()) + // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? + continue + } + } else { + fmt.Printf("could not check for file %q in repository %q: %s", acornfile, gitUrl, err.Error()) + // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? + continue + } + return acornfile, nil + } + return "", fmt.Errorf("failed to resolve an acornfile from the app") +} From 35dfb02dad68abdb4196c893b61782477dc1ff91 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Wed, 11 Oct 2023 16:23:48 -0700 Subject: [PATCH 05/20] store build context ; clone becomes a bool and require appname Signed-off-by: Oscar Ward --- pkg/apis/internal.acorn.io/v1/appimage.go | 4 +- pkg/cli/dev.go | 21 +++-- pkg/client/build.go | 2 +- pkg/openapi/generated/openapi_generated.go | 9 +- pkg/vcs/vcs.go | 102 ++++++++++++++------- 5 files changed, 94 insertions(+), 44 deletions(-) diff --git a/pkg/apis/internal.acorn.io/v1/appimage.go b/pkg/apis/internal.acorn.io/v1/appimage.go index 738968223..f3885318f 100644 --- a/pkg/apis/internal.acorn.io/v1/appimage.go +++ b/pkg/apis/internal.acorn.io/v1/appimage.go @@ -29,8 +29,10 @@ type VCS struct { Modified bool `json:"modified,omitempty"` // Untracked a true value indicates the build contained untracked files according to git Untracked bool `json:"untracked,omitempty"` - // Acornfile contains the path and filename within the git repository that was used to build the running app + // Acornfile the path and filename within the vcs repository that was used to build the running app Acornfile string `json:"acornfile,omitempty"` + // BuildContext the context provided + BuildContext string `json:"buildContext,omitempty"` } type Platform struct { diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index 1afdf1fed..183f45e4c 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -1,6 +1,7 @@ package cli import ( + "fmt" "io" "github.com/acorn-io/runtime/pkg/autoupgrade" @@ -43,10 +44,10 @@ acorn dev --name wandering-sound type Dev struct { RunArgs - BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` - Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults - Clone string `usage:"Clone a running app"` - HelpAdvanced bool `usage:"Show verbose help text"` + BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` + Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults + Clone bool `usage:"Clone the vcs repository for the given app"` + HelpAdvanced bool `usage:"Show verbose help text"` out io.Writer client ClientFactory } @@ -62,20 +63,26 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { } var imageSource imagesource.ImageSource - if s.Clone == "" { + if !s.Clone { imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), s.File, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) + } else if s.Name == "" { + return fmt.Errorf("clone option must be used when running dev on an existing app") } else { // Get info from the running app - app, err := c.AppGet(cmd.Context(), s.Clone) + app, err := c.AppGet(cmd.Context(), s.Name) if err != nil { return err } - acornfile, err := vcs.AcornfileFromApp(cmd.Context(), app) + acornfile, buildContext, err := vcs.ImageInfoFromApp(cmd.Context(), app) if err != nil { return err } + bc := app.Status.Staged.AppImage.VCS.BuildContext + if bc != "" { + args = append(args, buildContext) + } imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), acornfile, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) } diff --git a/pkg/client/build.go b/pkg/client/build.go index fd84013c6..2d20b0c0e 100644 --- a/pkg/client/build.go +++ b/pkg/client/build.go @@ -69,7 +69,7 @@ func (c *DefaultClient) AcornImageBuild(ctx context.Context, file string, opts * return nil, err } - vcs := vcs.VCS(file) + vcs := vcs.VCS(file, opts.Cwd) builder, err := c.getOrCreateBuilder(ctx, opts.BuilderName) if err != nil { diff --git a/pkg/openapi/generated/openapi_generated.go b/pkg/openapi/generated/openapi_generated.go index 4ac647dd7..e0d8a6280 100644 --- a/pkg/openapi/generated/openapi_generated.go +++ b/pkg/openapi/generated/openapi_generated.go @@ -12332,7 +12332,14 @@ func schema_pkg_apis_internalacornio_v1_VCS(ref common.ReferenceCallback) common }, "acornfile": { SchemaProps: spec.SchemaProps{ - Description: "Acornfile contains the path and filename within the git repository that was used to build the running app", + Description: "Acornfile the path and filename within the vcs repository that was used to build the running app", + Type: []string{"string"}, + Format: "", + }, + }, + "buildContext": { + SchemaProps: spec.SchemaProps{ + Description: "BuildContext the context provided", Type: []string{"string"}, Format: "", }, diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 2cd1203fd..f27501c0c 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -2,7 +2,6 @@ package vcs import ( "context" - "errors" "fmt" "net/url" "os" @@ -12,14 +11,19 @@ import ( apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1" v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing/transport/ssh" ) -func VCS(filePath string) (result v1.VCS) { +func VCS(filePath, buildContextPath string) (result v1.VCS) { absPath, err := filepath.Abs(filePath) if err != nil { return } + buildContext, err := filepath.Abs(buildContextPath) + if err != nil { + return + } repo, err := git.PlainOpenWithOptions(filepath.Dir(absPath), &git.PlainOpenOptions{ DetectDotGit: true, }) @@ -43,6 +47,11 @@ func VCS(filePath string) (result v1.VCS) { sb.WriteString(w.Filesystem.Root()) sb.WriteRune(filepath.Separator) acornfile := strings.TrimPrefix(absPath, sb.String()) + if buildContext == w.Filesystem.Root() { + buildContext = "." + } else { + buildContext = strings.TrimPrefix(buildContext, sb.String()) + } var ( modified, untracked bool @@ -59,11 +68,12 @@ func VCS(filePath string) (result v1.VCS) { } result = v1.VCS{ - Revision: head.Hash().String(), - Clean: !modified && !untracked, - Modified: modified, - Untracked: untracked, - Acornfile: acornfile, + Revision: head.Hash().String(), + Clean: !modified && !untracked, + Modified: modified, + Untracked: untracked, + Acornfile: acornfile, + BuildContext: buildContext, } // Set optional remotes field @@ -79,17 +89,19 @@ func VCS(filePath string) (result v1.VCS) { return } -func AcornfileFromApp(ctx context.Context, app *apiv1.App) (string, error) { - +func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, error) { vcs := app.Status.Staged.AppImage.VCS - if len(vcs.Remotes) == 0 { - return "", fmt.Errorf("clone can only be done on an app built from a git repository") + return "", "", fmt.Errorf("clone can only be done on an app built from a git repository") + } + if vcs.Acornfile == "" { + return "", "", fmt.Errorf("app has no acornfile information in vcs") } + // Create auth object to use when fetching and cloning git repos auth, err := ssh.NewSSHAgentAuth("git") if err != nil { - return "", err + return "", "", err } for _, remote := range vcs.Remotes { @@ -101,42 +113,64 @@ func AcornfileFromApp(ctx context.Context, app *apiv1.App) (string, error) { gitUrl = remote } - // TODO workdir named after git repo, cloned app name, or just this app's name? - idx := strings.LastIndex(gitUrl, "/") - if idx < 0 || idx >= len(gitUrl) { - fmt.Printf("failed to determine repository name %q\n", gitUrl) + idx := strings.LastIndex(remote, "/") + if idx < 0 || idx >= len(remote) { + fmt.Printf("failed to determine repository name %q\n", remote) continue } - workdir := filepath.Clean(strings.TrimSuffix(gitUrl[idx+1:], ".git")) + workdir := filepath.Clean(strings.TrimSuffix(remote[idx+1:], ".git")) - // Clone git repo - _, err = git.PlainCloneContext(ctx, workdir, false, &git.CloneOptions{ + // Clone git repo and checkout revision + fmt.Printf("# Cloning repository %q into directory %q\n", gitUrl, workdir) + repo, err := git.PlainCloneContext(ctx, workdir, false, &git.CloneOptions{ URL: gitUrl, - Progress: os.Stderr, Auth: auth, + Progress: os.Stderr, }) - // TODO handle ErrRepositoryAlreadyExists some way if err != nil { fmt.Printf("failed to clone repository %q: %s\n", gitUrl, err.Error()) continue } + w, err := repo.Worktree() + if err != nil { + fmt.Printf("failed to get worktree from repository %q: %s\n", workdir, err.Error()) + continue + } + err = w.Checkout(&git.CheckoutOptions{ + Hash: plumbing.NewHash(vcs.Revision), + }) + if err != nil { + fmt.Printf("failed to checkout revision %q for repository %q: %s\n", vcs.Revision, workdir, err.Error()) + continue + } + // Create the Acornfile in the repository acornfile := filepath.Join(workdir, vcs.Acornfile) - // TODO if acornfile exists but is different than what is cached should we overwrite? - if _, err := os.Stat(acornfile); errors.Is(err, os.ErrNotExist) { - // Acornfile does not exist so we should create it - err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) - if err != nil { - fmt.Printf("failed to create file %q in repository %q: %s", acornfile, gitUrl, err.Error()) - // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? - continue + err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) + if err != nil { + fmt.Printf("failed to create file %q in repository %q: %s\n", acornfile, workdir, err.Error()) + continue + } + + // Determine if the Acornfile is dirty or not + s, err := w.Status() + if err == nil { + if !s.IsClean() { + fmt.Printf("running with a dirty Acornfile %q\n", acornfile) } } else { - fmt.Printf("could not check for file %q in repository %q: %s", acornfile, gitUrl, err.Error()) - // TODO we hit an error state but already cloned the repo, should we clean up the repo we cloned? - continue + fmt.Printf("failed to get status from worktree %q: %s\n", workdir, err.Error()) + } + + // Get the build context + var buildContext string + if vcs.BuildContext == "." { + buildContext = workdir + } else { + buildContext = filepath.Join(workdir, vcs.BuildContext) } - return acornfile, nil + + return acornfile, buildContext, nil } - return "", fmt.Errorf("failed to resolve an acornfile from the app") + return "", "", fmt.Errorf("failed to resolve an acornfile from the app") } From b219fdcced7a7f47b0514e931af7716fb8a59005 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 08:50:08 -0700 Subject: [PATCH 06/20] update buildcontext api string Signed-off-by: Oscar Ward --- pkg/apis/internal.acorn.io/v1/appimage.go | 2 +- pkg/openapi/generated/openapi_generated.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/apis/internal.acorn.io/v1/appimage.go b/pkg/apis/internal.acorn.io/v1/appimage.go index f3885318f..4526edcde 100644 --- a/pkg/apis/internal.acorn.io/v1/appimage.go +++ b/pkg/apis/internal.acorn.io/v1/appimage.go @@ -31,7 +31,7 @@ type VCS struct { Untracked bool `json:"untracked,omitempty"` // Acornfile the path and filename within the vcs repository that was used to build the running app Acornfile string `json:"acornfile,omitempty"` - // BuildContext the context provided + // BuildContext the context within the vcs repository that was used when building the running app BuildContext string `json:"buildContext,omitempty"` } diff --git a/pkg/openapi/generated/openapi_generated.go b/pkg/openapi/generated/openapi_generated.go index e0d8a6280..10034ba24 100644 --- a/pkg/openapi/generated/openapi_generated.go +++ b/pkg/openapi/generated/openapi_generated.go @@ -12339,7 +12339,7 @@ func schema_pkg_apis_internalacornio_v1_VCS(ref common.ReferenceCallback) common }, "buildContext": { SchemaProps: spec.SchemaProps{ - Description: "BuildContext the context provided", + Description: "BuildContext the context within the vcs repository that was used when building the running app", Type: []string{"string"}, Format: "", }, From 31cb0f9445668280149554cfdf014c3607680948 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 08:55:52 -0700 Subject: [PATCH 07/20] doc update Signed-off-by: Oscar Ward --- docs/docs/100-reference/01-command-line/acorn_dev.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/100-reference/01-command-line/acorn_dev.md b/docs/docs/100-reference/01-command-line/acorn_dev.md index d92908c3a..75dde52f1 100644 --- a/docs/docs/100-reference/01-command-line/acorn_dev.md +++ b/docs/docs/100-reference/01-command-line/acorn_dev.md @@ -26,7 +26,7 @@ acorn dev --name wandering-sound --args-file string Default args to apply to run/update command (default ".args.acorn") --auto-upgrade Enabled automatic upgrades. -b, --bidirectional-sync In interactive mode download changes in addition to uploading - --clone string Clone a running app + --clone Clone the vcs repository for the given app -f, --file string Name of the build file (default "DIRECTORY/Acornfile") -h, --help help for dev --help-advanced Show verbose help text From 635f88db5d9ac59a86da41fecfd8a011aa3e04cf Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 09:04:22 -0700 Subject: [PATCH 08/20] test update Signed-off-by: Oscar Ward --- pkg/build/build_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index 8513df8eb..2c5bb012b 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -8,7 +8,7 @@ import ( ) func TestVCS(t *testing.T) { - vcs := vcs.VCS(".") + vcs := vcs.VCS(".", ".") assert.NotEqual(t, "", vcs.Revision) } From bc084f48f3c423104398a2c3b45f6a1ade1a262a Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 10:19:05 -0700 Subject: [PATCH 09/20] update build context usage ; comments and docs Signed-off-by: Oscar Ward --- docs/docs/100-reference/01-command-line/acorn_dev.md | 3 ++- pkg/cli/dev.go | 11 +++++------ pkg/vcs/vcs.go | 9 +++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/docs/docs/100-reference/01-command-line/acorn_dev.md b/docs/docs/100-reference/01-command-line/acorn_dev.md index 75dde52f1..6c7b3c581 100644 --- a/docs/docs/100-reference/01-command-line/acorn_dev.md +++ b/docs/docs/100-reference/01-command-line/acorn_dev.md @@ -17,6 +17,7 @@ acorn dev acorn dev . acorn dev --name wandering-sound acorn dev --name wandering-sound +acorn dev --name wandering-sound --clone [acorn args] ``` @@ -26,7 +27,7 @@ acorn dev --name wandering-sound --args-file string Default args to apply to run/update command (default ".args.acorn") --auto-upgrade Enabled automatic upgrades. -b, --bidirectional-sync In interactive mode download changes in addition to uploading - --clone Clone the vcs repository for the given app + --clone Clone the vcs repository and infer the build context for the given app allowing for local development -f, --file string Name of the build file (default "DIRECTORY/Acornfile") -h, --help help for dev --help-advanced Show verbose help text diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index 183f45e4c..f261a0985 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -24,6 +24,7 @@ acorn dev acorn dev . acorn dev --name wandering-sound acorn dev --name wandering-sound +acorn dev --name wandering-sound --clone [acorn args] `}) // This will produce an error if the volume flag doesn't exist or a completion function has already @@ -46,7 +47,7 @@ type Dev struct { RunArgs BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults - Clone bool `usage:"Clone the vcs repository for the given app"` + Clone bool `usage:"Clone the vcs repository and infer the build context for the given app allowing for local development"` HelpAdvanced bool `usage:"Show verbose help text"` out io.Writer client ClientFactory @@ -73,16 +74,14 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { if err != nil { return err } - acornfile, buildContext, err := vcs.ImageInfoFromApp(cmd.Context(), app) if err != nil { return err } - bc := app.Status.Staged.AppImage.VCS.BuildContext - if bc != "" { - args = append(args, buildContext) - } + // We append the build context to the start of the args so that it gets set, and we can pass any args down to the running app + args = append([]string{buildContext}, args...) + imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), acornfile, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) } diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index f27501c0c..f022b52a1 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -105,6 +105,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, erro } for _, remote := range vcs.Remotes { + // Since we use ssh auth to clone the repo we need a git url but will sometimes get http urls var gitUrl string httpUrl, err := url.Parse(remote) if err == nil { @@ -113,6 +114,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, erro gitUrl = remote } + // Determine the repository name from the repo url idx := strings.LastIndex(remote, "/") if idx < 0 || idx >= len(remote) { fmt.Printf("failed to determine repository name %q\n", remote) @@ -163,12 +165,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, erro } // Get the build context - var buildContext string - if vcs.BuildContext == "." { - buildContext = workdir - } else { - buildContext = filepath.Join(workdir, vcs.BuildContext) - } + buildContext := filepath.Join(workdir, vcs.BuildContext) return acornfile, buildContext, nil } From f1de5bce8feec3028b0989029fcd5a9d8f30b117 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 12:25:07 -0700 Subject: [PATCH 10/20] move vcs tests to vcs dir and expand cases ; use filepath rel rather than string trim Signed-off-by: Oscar Ward --- pkg/build/build_test.go | 6 --- pkg/vcs/vcs.go | 17 ++++--- pkg/vcs/vcs_test.go | 100 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 15 deletions(-) create mode 100644 pkg/vcs/vcs_test.go diff --git a/pkg/build/build_test.go b/pkg/build/build_test.go index 2c5bb012b..753e64081 100644 --- a/pkg/build/build_test.go +++ b/pkg/build/build_test.go @@ -3,15 +3,9 @@ package build import ( "testing" - "github.com/acorn-io/runtime/pkg/vcs" "github.com/stretchr/testify/assert" ) -func TestVCS(t *testing.T) { - vcs := vcs.VCS(".", ".") - assert.NotEqual(t, "", vcs.Revision) -} - func Test_toContextCopyDockerFile(t *testing.T) { type args struct { baseImage string diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index f022b52a1..a05330f9f 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -20,7 +20,7 @@ func VCS(filePath, buildContextPath string) (result v1.VCS) { if err != nil { return } - buildContext, err := filepath.Abs(buildContextPath) + buildContextAbs, err := filepath.Abs(buildContextPath) if err != nil { return } @@ -43,14 +43,13 @@ func VCS(filePath, buildContextPath string) (result v1.VCS) { return } - var sb strings.Builder - sb.WriteString(w.Filesystem.Root()) - sb.WriteRune(filepath.Separator) - acornfile := strings.TrimPrefix(absPath, sb.String()) - if buildContext == w.Filesystem.Root() { - buildContext = "." - } else { - buildContext = strings.TrimPrefix(buildContext, sb.String()) + acornfile, err := filepath.Rel(w.Filesystem.Root(), absPath) + if err != nil { + return + } + buildContext, err := filepath.Rel(w.Filesystem.Root(), buildContextAbs) + if err != nil { + return } var ( diff --git a/pkg/vcs/vcs_test.go b/pkg/vcs/vcs_test.go new file mode 100644 index 000000000..162ed7c05 --- /dev/null +++ b/pkg/vcs/vcs_test.go @@ -0,0 +1,100 @@ +package vcs + +import ( + "fmt" + "os" + "path/filepath" + "testing" + + "github.com/go-git/go-git/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestVCS(t *testing.T) { + // Because this test gets ran from potentially different working dirs we do everything relative to the curDir and repoRoot + curDir, err := os.Getwd() + require.NoError(t, err) + repo, err := git.PlainOpenWithOptions(curDir, &git.PlainOpenOptions{DetectDotGit: true}) + require.NoError(t, err) + w, err := repo.Worktree() + require.NoError(t, err) + repoRoot := w.Filesystem.Root() + fmt.Println(repoRoot) + dir, err := filepath.Rel(repoRoot, curDir) + require.NoError(t, err) + + type args struct { + acornfile string + buildContext string + } + tests := []struct { + name string + args args + expected args + }{ + { + name: "simple", + args: args{ + acornfile: "Acornfile", + buildContext: ".", + }, + expected: args{ + acornfile: filepath.Join(dir, "Acornfile"), + buildContext: dir, + }, + }, + { + name: "given filename", + args: args{ + acornfile: "test.acorn", + buildContext: ".", + }, + expected: args{ + acornfile: filepath.Join(dir, "test.acorn"), + buildContext: dir, + }, + }, + { + name: "given nested filename", + args: args{ + acornfile: "nested/test.acorn", + buildContext: ".", + }, + expected: args{ + acornfile: filepath.Join(dir, "nested/test.acorn"), + buildContext: dir, + }, + }, + { + name: "given build context", + args: args{ + acornfile: "Acornfile", + buildContext: "nested", + }, + expected: args{ + acornfile: filepath.Join(dir, "Acornfile"), + buildContext: filepath.Join(dir, "nested"), + }, + }, + { + name: "given build context and filename", + args: args{ + acornfile: "test.acorn", + buildContext: "nested", + }, + expected: args{ + acornfile: filepath.Join(dir, "test.acorn"), + buildContext: filepath.Join(dir, "nested"), + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + vcs := VCS(tt.args.acornfile, tt.args.buildContext) + assert.NotEqual(t, "", vcs.Revision) + assert.Equal(t, tt.expected.acornfile, vcs.Acornfile) + assert.Equal(t, tt.expected.buildContext, vcs.BuildContext) + }) + } +} From 679d366990aac36508f813574e4a11ea9d8c2505 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 12:29:42 -0700 Subject: [PATCH 11/20] clean up some variable naming Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index a05330f9f..e1e96b4e6 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -16,15 +16,15 @@ import ( ) func VCS(filePath, buildContextPath string) (result v1.VCS) { - absPath, err := filepath.Abs(filePath) + filePath, err := filepath.Abs(filePath) if err != nil { return } - buildContextAbs, err := filepath.Abs(buildContextPath) + buildContextPath, err = filepath.Abs(buildContextPath) if err != nil { return } - repo, err := git.PlainOpenWithOptions(filepath.Dir(absPath), &git.PlainOpenOptions{ + repo, err := git.PlainOpenWithOptions(filePath, &git.PlainOpenOptions{ DetectDotGit: true, }) if err != nil { @@ -43,11 +43,11 @@ func VCS(filePath, buildContextPath string) (result v1.VCS) { return } - acornfile, err := filepath.Rel(w.Filesystem.Root(), absPath) + acornfile, err := filepath.Rel(w.Filesystem.Root(), filePath) if err != nil { return } - buildContext, err := filepath.Rel(w.Filesystem.Root(), buildContextAbs) + buildContext, err := filepath.Rel(w.Filesystem.Root(), buildContextPath) if err != nil { return } From 8922212c69eab740183a967a6ac505524ef9ce5d Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Thu, 12 Oct 2023 15:35:52 -0700 Subject: [PATCH 12/20] add hidden clone dir flag ; pr comments Signed-off-by: Oscar Ward --- pkg/cli/dev.go | 11 ++++++----- pkg/vcs/vcs.go | 14 +++++++------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index f261a0985..2be5de238 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -45,10 +45,11 @@ acorn dev --name wandering-sound --clone [acorn args] type Dev struct { RunArgs - BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` - Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults - Clone bool `usage:"Clone the vcs repository and infer the build context for the given app allowing for local development"` - HelpAdvanced bool `usage:"Show verbose help text"` + BidirectionalSync bool `usage:"In interactive mode download changes in addition to uploading" short:"b"` + Replace bool `usage:"Replace the app with only defined values, resetting undefined fields to default values" json:"replace,omitempty"` // Replace sets patchMode to false, resulting in a full update, resetting all undefined fields to their defaults + Clone bool `usage:"Clone the vcs repository and infer the build context for the given app allowing for local development"` + CloneDir string `usage:"Provide a directory to clone the repository into, use in conjunction with clone flag" default:"." hidden:"true"` + HelpAdvanced bool `usage:"Show verbose help text"` out io.Writer client ClientFactory } @@ -74,7 +75,7 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { if err != nil { return err } - acornfile, buildContext, err := vcs.ImageInfoFromApp(cmd.Context(), app) + acornfile, buildContext, err := vcs.ImageInfoFromApp(cmd.Context(), app, s.CloneDir) if err != nil { return err } diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index e1e96b4e6..59cbe9924 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -88,13 +88,13 @@ func VCS(filePath, buildContextPath string) (result v1.VCS) { return } -func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, error) { - vcs := app.Status.Staged.AppImage.VCS +func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (string, string, error) { + vcs := app.Status.AppImage.VCS if len(vcs.Remotes) == 0 { return "", "", fmt.Errorf("clone can only be done on an app built from a git repository") } - if vcs.Acornfile == "" { - return "", "", fmt.Errorf("app has no acornfile information in vcs") + if vcs.Acornfile == "" || vcs.BuildContext == "" { + return "", "", fmt.Errorf("app is missing required vcs information, image must be rebuilt with a newer acorn cli") } // Create auth object to use when fetching and cloning git repos @@ -115,11 +115,11 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, erro // Determine the repository name from the repo url idx := strings.LastIndex(remote, "/") - if idx < 0 || idx >= len(remote) { + if idx < 0 || idx >= len(remote)-1 { fmt.Printf("failed to determine repository name %q\n", remote) continue } - workdir := filepath.Clean(strings.TrimSuffix(remote[idx+1:], ".git")) + workdir := filepath.Join(cloneDir, strings.TrimSuffix(remote[idx+1:], ".git")) // Clone git repo and checkout revision fmt.Printf("# Cloning repository %q into directory %q\n", gitUrl, workdir) @@ -147,7 +147,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App) (string, string, erro // Create the Acornfile in the repository acornfile := filepath.Join(workdir, vcs.Acornfile) - err = os.WriteFile(acornfile, []byte(app.Status.Staged.AppImage.Acornfile), 0666) + err = os.WriteFile(acornfile, []byte(app.Status.AppImage.Acornfile), 0666) if err != nil { fmt.Printf("failed to create file %q in repository %q: %s\n", acornfile, workdir, err.Error()) continue From eb9f6c92bd333537150bc9fb5cce5ef88cf9f01b Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 11:30:49 -0700 Subject: [PATCH 13/20] swap to git cli Signed-off-by: Oscar Ward --- pkg/cli/dev.go | 2 +- pkg/vcs/vcs.go | 78 ++++++++++++++++++++++---------------------------- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/pkg/cli/dev.go b/pkg/cli/dev.go index 2be5de238..a15732187 100644 --- a/pkg/cli/dev.go +++ b/pkg/cli/dev.go @@ -68,7 +68,7 @@ func (s *Dev) Run(cmd *cobra.Command, args []string) error { if !s.Clone { imageSource = imagesource.NewImageSource(s.client.AcornConfigFile(), s.File, s.ArgsFile, args, nil, z.Dereference(s.AutoUpgrade)) } else if s.Name == "" { - return fmt.Errorf("clone option must be used when running dev on an existing app") + return fmt.Errorf("clone option can only be used when running dev on an existing app") } else { // Get info from the running app app, err := c.AppGet(cmd.Context(), s.Name) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 59cbe9924..4a72f95ea 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -3,16 +3,14 @@ package vcs import ( "context" "fmt" - "net/url" "os" + "os/exec" "path/filepath" "strings" apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1" v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/transport/ssh" ) func VCS(filePath, buildContextPath string) (result v1.VCS) { @@ -97,22 +95,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str return "", "", fmt.Errorf("app is missing required vcs information, image must be rebuilt with a newer acorn cli") } - // Create auth object to use when fetching and cloning git repos - auth, err := ssh.NewSSHAgentAuth("git") - if err != nil { - return "", "", err - } - for _, remote := range vcs.Remotes { - // Since we use ssh auth to clone the repo we need a git url but will sometimes get http urls - var gitUrl string - httpUrl, err := url.Parse(remote) - if err == nil { - gitUrl = fmt.Sprintf("git@%s:%s", httpUrl.Host, httpUrl.Path[1:]) - } else { - gitUrl = remote - } - // Determine the repository name from the repo url idx := strings.LastIndex(remote, "/") if idx < 0 || idx >= len(remote)-1 { @@ -121,27 +104,36 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str } workdir := filepath.Join(cloneDir, strings.TrimSuffix(remote[idx+1:], ".git")) - // Clone git repo and checkout revision - fmt.Printf("# Cloning repository %q into directory %q\n", gitUrl, workdir) - repo, err := git.PlainCloneContext(ctx, workdir, false, &git.CloneOptions{ - URL: gitUrl, - Auth: auth, - Progress: os.Stderr, - }) - if err != nil { - fmt.Printf("failed to clone repository %q: %s\n", gitUrl, err.Error()) - continue - } - w, err := repo.Worktree() - if err != nil { - fmt.Printf("failed to get worktree from repository %q: %s\n", workdir, err.Error()) + // Check if we've cloned the repo already + if _, err := os.Stat(workdir); os.IsNotExist(err) { + // Clone the repo + args := []string{"clone", remote, workdir} + cmd := exec.CommandContext(ctx, "git", args...) + err = cmd.Run() + if err != nil { + fmt.Printf("failed to clone repository %q: %v", remote, err) + continue + } + } else if os.IsExist(err) { + // Fetch the remote in the repo + args := []string{"-C", workdir, "fetch", remote} + cmd := exec.CommandContext(ctx, "git", args...) + err = cmd.Run() + if err != nil { + fmt.Printf("failed to fetch remote %q in repository %q: %v", remote, workdir, err) + continue + } + } else if err != nil { + fmt.Printf("failed to check for the existence of directory %q: %v", workdir, err) continue } - err = w.Checkout(&git.CheckoutOptions{ - Hash: plumbing.NewHash(vcs.Revision), - }) + + // Try to checkout the revision + args := []string{"-C", workdir, "checkout", vcs.Revision} + cmd := exec.CommandContext(ctx, "git", args...) + err := cmd.Run() if err != nil { - fmt.Printf("failed to checkout revision %q for repository %q: %s\n", vcs.Revision, workdir, err.Error()) + fmt.Printf("failed to checkout revision %q: %v", vcs.Revision, err) continue } @@ -149,18 +141,16 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str acornfile := filepath.Join(workdir, vcs.Acornfile) err = os.WriteFile(acornfile, []byte(app.Status.AppImage.Acornfile), 0666) if err != nil { - fmt.Printf("failed to create file %q in repository %q: %s\n", acornfile, workdir, err.Error()) + fmt.Printf("failed to create file %q in repository %q: %v\n", acornfile, workdir, err) continue } // Determine if the Acornfile is dirty or not - s, err := w.Status() - if err == nil { - if !s.IsClean() { - fmt.Printf("running with a dirty Acornfile %q\n", acornfile) - } - } else { - fmt.Printf("failed to get status from worktree %q: %s\n", workdir, err.Error()) + args = []string{"-C", workdir, "diff", "--quiet"} + cmd = exec.CommandContext(ctx, "git", args...) + err = cmd.Run() + if err != nil { + fmt.Printf("running with a dirty Acornfile %q\n", acornfile) } // Get the build context From 4706fe03a50a847672466d32df4ca2e4c9c8eca3 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 11:43:56 -0700 Subject: [PATCH 14/20] handle the case of the directory existing but being empty before clone Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 4a72f95ea..7249bf427 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -104,26 +104,40 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str } workdir := filepath.Join(cloneDir, strings.TrimSuffix(remote[idx+1:], ".git")) - // Check if we've cloned the repo already - if _, err := os.Stat(workdir); os.IsNotExist(err) { - // Clone the repo - args := []string{"clone", remote, workdir} - cmd := exec.CommandContext(ctx, "git", args...) - err = cmd.Run() + // Check for the directory we want to use + f, err := os.Open(workdir) + if err == nil { + // Directory exists, check if empty + _, err = f.ReadDir(1) if err != nil { - fmt.Printf("failed to clone repository %q: %v", remote, err) - continue + // Directory is empty, clone the repo + args := []string{"clone", remote, workdir} + cmd := exec.CommandContext(ctx, "git", args...) + err = cmd.Run() + if err != nil { + fmt.Printf("failed to clone repository %q: %v", remote, err) + continue + } + } else { + // Directory is not empty, try to fetch + args := []string{"-C", workdir, "fetch", remote} + cmd := exec.CommandContext(ctx, "git", args...) + err = cmd.Run() + if err != nil { + fmt.Printf("failed to fetch remote %q in repository %q: %v", remote, workdir, err) + continue + } } - } else if os.IsExist(err) { - // Fetch the remote in the repo - args := []string{"-C", workdir, "fetch", remote} + } else if os.IsNotExist(err) { + // Directory does not exist, just clone to create it + args := []string{"clone", remote, workdir} cmd := exec.CommandContext(ctx, "git", args...) err = cmd.Run() if err != nil { - fmt.Printf("failed to fetch remote %q in repository %q: %v", remote, workdir, err) + fmt.Printf("failed to clone repository %q: %v", remote, err) continue } - } else if err != nil { + } else { fmt.Printf("failed to check for the existence of directory %q: %v", workdir, err) continue } @@ -131,7 +145,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str // Try to checkout the revision args := []string{"-C", workdir, "checkout", vcs.Revision} cmd := exec.CommandContext(ctx, "git", args...) - err := cmd.Run() + err = cmd.Run() if err != nil { fmt.Printf("failed to checkout revision %q: %v", vcs.Revision, err) continue From a171577ec8080572c9b72c3f879b42042ae3f03d Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 11:53:53 -0700 Subject: [PATCH 15/20] pull git calls into their own functions Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 69 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 7249bf427..8a47536f7 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -111,30 +111,24 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str _, err = f.ReadDir(1) if err != nil { // Directory is empty, clone the repo - args := []string{"clone", remote, workdir} - cmd := exec.CommandContext(ctx, "git", args...) - err = cmd.Run() + err = gitClone(ctx, workdir, remote) if err != nil { - fmt.Printf("failed to clone repository %q: %v", remote, err) + fmt.Printf("%v\n", err) continue } } else { // Directory is not empty, try to fetch - args := []string{"-C", workdir, "fetch", remote} - cmd := exec.CommandContext(ctx, "git", args...) - err = cmd.Run() + err = gitFetch(ctx, workdir, remote) if err != nil { - fmt.Printf("failed to fetch remote %q in repository %q: %v", remote, workdir, err) + fmt.Printf("%v\n", err) continue } } } else if os.IsNotExist(err) { // Directory does not exist, just clone to create it - args := []string{"clone", remote, workdir} - cmd := exec.CommandContext(ctx, "git", args...) - err = cmd.Run() + err = gitClone(ctx, workdir, remote) if err != nil { - fmt.Printf("failed to clone repository %q: %v", remote, err) + fmt.Printf("%v\n", err) continue } } else { @@ -143,11 +137,9 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str } // Try to checkout the revision - args := []string{"-C", workdir, "checkout", vcs.Revision} - cmd := exec.CommandContext(ctx, "git", args...) - err = cmd.Run() + err = gitCheckout(ctx, workdir, vcs.Revision) if err != nil { - fmt.Printf("failed to checkout revision %q: %v", vcs.Revision, err) + fmt.Printf("%v\n", err) continue } @@ -160,10 +152,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str } // Determine if the Acornfile is dirty or not - args = []string{"-C", workdir, "diff", "--quiet"} - cmd = exec.CommandContext(ctx, "git", args...) - err = cmd.Run() - if err != nil { + if gitDirty(ctx, workdir) { fmt.Printf("running with a dirty Acornfile %q\n", acornfile) } @@ -174,3 +163,43 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str } return "", "", fmt.Errorf("failed to resolve an acornfile from the app") } + +func gitClone(ctx context.Context, workdir, remote string) (err error) { + args := []string{"clone", remote, workdir} + cmd := exec.CommandContext(ctx, "git", args...) + cmdErr := cmd.Run() + if cmdErr != nil { + err = fmt.Errorf("failed to clone repository %q: %v", remote, err) + } + return +} + +func gitFetch(ctx context.Context, workdir, remote string) (err error) { + args := []string{"-C", workdir, "fetch", remote} + cmd := exec.CommandContext(ctx, "git", args...) + cmdErr := cmd.Run() + if cmdErr != nil { + err = fmt.Errorf("failed to fetch remote %q in repository %q: %v", remote, workdir, err) + } + return +} + +func gitCheckout(ctx context.Context, workdir, revision string) (err error) { + args := []string{"-C", workdir, "checkout", revision} + cmd := exec.CommandContext(ctx, "git", args...) + cmdErr := cmd.Run() + if cmdErr != nil { + err = fmt.Errorf("failed to checkout revision %q: %v", revision, err) + } + return +} + +func gitDirty(ctx context.Context, workdir string) bool { + args := []string{"-C", workdir, "diff", "--quiet"} + cmd := exec.CommandContext(ctx, "git", args...) + cmdErr := cmd.Run() + if cmdErr != nil { + return true + } + return false +} From d18fb8554894922a5a23a47fab8e9fc280711efc Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 12:00:43 -0700 Subject: [PATCH 16/20] appease the linting gods Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 8a47536f7..cf30c9506 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -197,9 +197,5 @@ func gitCheckout(ctx context.Context, workdir, revision string) (err error) { func gitDirty(ctx context.Context, workdir string) bool { args := []string{"-C", workdir, "diff", "--quiet"} cmd := exec.CommandContext(ctx, "git", args...) - cmdErr := cmd.Run() - if cmdErr != nil { - return true - } - return false + return cmd.Run() != nil } From 253eb2d9f4948525638d365ec79780e70eb417f6 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 13:12:44 -0700 Subject: [PATCH 17/20] pr comments Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index cf30c9506..7c2821807 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -6,7 +6,6 @@ import ( "os" "os/exec" "path/filepath" - "strings" apiv1 "github.com/acorn-io/runtime/pkg/apis/api.acorn.io/v1" v1 "github.com/acorn-io/runtime/pkg/apis/internal.acorn.io/v1" @@ -95,15 +94,9 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str return "", "", fmt.Errorf("app is missing required vcs information, image must be rebuilt with a newer acorn cli") } - for _, remote := range vcs.Remotes { - // Determine the repository name from the repo url - idx := strings.LastIndex(remote, "/") - if idx < 0 || idx >= len(remote)-1 { - fmt.Printf("failed to determine repository name %q\n", remote) - continue - } - workdir := filepath.Join(cloneDir, strings.TrimSuffix(remote[idx+1:], ".git")) + workdir := filepath.Join(cloneDir, app.Name) + for i, remote := range vcs.Remotes { // Check for the directory we want to use f, err := os.Open(workdir) if err == nil { @@ -117,8 +110,13 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str continue } } else { - // Directory is not empty, try to fetch - err = gitFetch(ctx, workdir, remote) + // Directory is not empty so we assume it exists, add a new remote and try to fetch + remoteName := fmt.Sprintf("remote%d", i) + err = gitRemoteAdd(ctx, workdir, remoteName, remote) + if err != nil { + fmt.Printf("%v\n", err) + } + err = gitFetch(ctx, workdir, remoteName) if err != nil { fmt.Printf("%v\n", err) continue @@ -153,7 +151,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str // Determine if the Acornfile is dirty or not if gitDirty(ctx, workdir) { - fmt.Printf("running with a dirty Acornfile %q\n", acornfile) + fmt.Printf("NOTE: The Acornfile used for this acorn differs from the git repository. Run `git status` for more details.") } // Get the build context @@ -174,6 +172,16 @@ func gitClone(ctx context.Context, workdir, remote string) (err error) { return } +func gitRemoteAdd(ctx context.Context, workdir, remoteName, remote string) (err error) { + args := []string{"-C", workdir, "remote", "add", remoteName, remote} + cmd := exec.CommandContext(ctx, "git", args...) + cmdErr := cmd.Run() + if cmdErr != nil { + err = fmt.Errorf("failed to add remote %q to repository %q: %v", remote, workdir, err) + } + return +} + func gitFetch(ctx context.Context, workdir, remote string) (err error) { args := []string{"-C", workdir, "fetch", remote} cmd := exec.CommandContext(ctx, "git", args...) From b07ca68c7cf91ef88b930b74c09332ddb652f337 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 13:27:49 -0700 Subject: [PATCH 18/20] route stderr and stdout of the git functions to the terminal Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 7c2821807..45bc5794f 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -165,6 +165,8 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str func gitClone(ctx context.Context, workdir, remote string) (err error) { args := []string{"clone", remote, workdir} cmd := exec.CommandContext(ctx, "git", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr cmdErr := cmd.Run() if cmdErr != nil { err = fmt.Errorf("failed to clone repository %q: %v", remote, err) @@ -175,6 +177,8 @@ func gitClone(ctx context.Context, workdir, remote string) (err error) { func gitRemoteAdd(ctx context.Context, workdir, remoteName, remote string) (err error) { args := []string{"-C", workdir, "remote", "add", remoteName, remote} cmd := exec.CommandContext(ctx, "git", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr cmdErr := cmd.Run() if cmdErr != nil { err = fmt.Errorf("failed to add remote %q to repository %q: %v", remote, workdir, err) @@ -185,6 +189,8 @@ func gitRemoteAdd(ctx context.Context, workdir, remoteName, remote string) (err func gitFetch(ctx context.Context, workdir, remote string) (err error) { args := []string{"-C", workdir, "fetch", remote} cmd := exec.CommandContext(ctx, "git", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr cmdErr := cmd.Run() if cmdErr != nil { err = fmt.Errorf("failed to fetch remote %q in repository %q: %v", remote, workdir, err) @@ -195,6 +201,8 @@ func gitFetch(ctx context.Context, workdir, remote string) (err error) { func gitCheckout(ctx context.Context, workdir, revision string) (err error) { args := []string{"-C", workdir, "checkout", revision} cmd := exec.CommandContext(ctx, "git", args...) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr cmdErr := cmd.Run() if cmdErr != nil { err = fmt.Errorf("failed to checkout revision %q: %v", revision, err) From 8477866b3049e4197bf982ebf5d5ad68b295feb3 Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 15:42:51 -0700 Subject: [PATCH 19/20] refactor the git operations into its own function to clean up logic Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 87 +++++++++++++++++++++++++++----------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index 45bc5794f..dcf8814ac 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -96,46 +96,9 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str workdir := filepath.Join(cloneDir, app.Name) - for i, remote := range vcs.Remotes { - // Check for the directory we want to use - f, err := os.Open(workdir) - if err == nil { - // Directory exists, check if empty - _, err = f.ReadDir(1) - if err != nil { - // Directory is empty, clone the repo - err = gitClone(ctx, workdir, remote) - if err != nil { - fmt.Printf("%v\n", err) - continue - } - } else { - // Directory is not empty so we assume it exists, add a new remote and try to fetch - remoteName := fmt.Sprintf("remote%d", i) - err = gitRemoteAdd(ctx, workdir, remoteName, remote) - if err != nil { - fmt.Printf("%v\n", err) - } - err = gitFetch(ctx, workdir, remoteName) - if err != nil { - fmt.Printf("%v\n", err) - continue - } - } - } else if os.IsNotExist(err) { - // Directory does not exist, just clone to create it - err = gitClone(ctx, workdir, remote) - if err != nil { - fmt.Printf("%v\n", err) - continue - } - } else { - fmt.Printf("failed to check for the existence of directory %q: %v", workdir, err) - continue - } - - // Try to checkout the revision - err = gitCheckout(ctx, workdir, vcs.Revision) + for i := range vcs.Remotes { + // Get the repository locally + err := getRemoteRepo(ctx, workdir, vcs, i) if err != nil { fmt.Printf("%v\n", err) continue @@ -162,6 +125,50 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str return "", "", fmt.Errorf("failed to resolve an acornfile from the app") } +func getRemoteRepo(ctx context.Context, workdir string, vcs v1.VCS, idx int) error { + remote := vcs.Remotes[idx] + remoteName := fmt.Sprintf("remote%d", idx) + + // Check for the directory we want to use + f, err := os.Open(workdir) + if err == nil { + // Directory exists, check if empty + _, err = f.ReadDir(1) + if err != nil { + // Directory is empty, clone the repo + err = gitClone(ctx, workdir, remote) + if err != nil { + return err + } + } else { + // Directory is not empty, we assume it already exists, add a new remote and try to fetch + err = gitRemoteAdd(ctx, workdir, remoteName, remote) + if err != nil { + return err + } + err = gitFetch(ctx, workdir, remoteName) + if err != nil { + return err + } + } + } else if os.IsNotExist(err) { + // Directory does not exist, just clone to create it + err = gitClone(ctx, workdir, remote) + if err != nil { + return err + } + } else { + return fmt.Errorf("failed to check for the existence of directory %q: %v", workdir, err) + } + + // Try to checkout the revision + err = gitCheckout(ctx, workdir, vcs.Revision) + if err != nil { + return err + } + return nil +} + func gitClone(ctx context.Context, workdir, remote string) (err error) { args := []string{"clone", remote, workdir} cmd := exec.CommandContext(ctx, "git", args...) From c0e3ba9c00ee4b571e36ac9784071a138b9f886f Mon Sep 17 00:00:00 2001 From: Oscar Ward Date: Fri, 13 Oct 2023 19:41:48 -0700 Subject: [PATCH 20/20] add missing newline Signed-off-by: Oscar Ward --- pkg/vcs/vcs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/vcs/vcs.go b/pkg/vcs/vcs.go index dcf8814ac..1a931c594 100644 --- a/pkg/vcs/vcs.go +++ b/pkg/vcs/vcs.go @@ -114,7 +114,7 @@ func ImageInfoFromApp(ctx context.Context, app *apiv1.App, cloneDir string) (str // Determine if the Acornfile is dirty or not if gitDirty(ctx, workdir) { - fmt.Printf("NOTE: The Acornfile used for this acorn differs from the git repository. Run `git status` for more details.") + fmt.Printf("NOTE: The Acornfile used for this acorn differs from the git repository. Run `git status` for more details.\n") } // Get the build context