Skip to content

Commit a4eb48f

Browse files
authored
Implement subPath filtering (#1936)
* Propagate feature flag struct SourceResolver and the git Resolver implementation. Signed-off-by: Erik Mogensen <erik@mogensoft.net> * Implement subPath filtering (behind feature flag) The new feature flag causes the git resolver of kpack to use shallow clones instead of the current "git ls-remote" technique of discovering revisions. A bare, shallow clone, is cloned into memory, mainly to receive the metadata. Subpaths are then exposed as "tree" in the status of the SourceResolver. The SourceResolver then avoids updating its status if the tree is unchanged. * The Status of the SourceResolver includes the "tree" of the detected source * The tree is only filled out if a subpath is requested * When the SourceResolver status is being updated, the "tree" is compared between the old status and the new status. If the tree didn't change, then the old status' commit is kept. The resolver does the equivalent of git clone --bare --depth=1 <repo> <ref> This downloads a copy of the repository, without checking it out, and with no history. If subPath is filled out, it performs the equivalent of git ls-tree <ref> -- <subpath> which provides a unique hash of the subpath at the commit in question. fixes #1068 Signed-off-by: Erik Mogensen <erik@mogensoft.net> * Move implementation to separate file Signed-off-by: Erik Mogensen <erik@mogensoft.net> * Filter blobs and specify a bare checkout Equivalent of --bare and --filter blob:none This now ensures that only metadata is downloaded, keeping memory overhead to an absolute minimum. Signed-off-by: Erik Mogensen <erik@mogensoft.net> --------- Signed-off-by: Erik Mogensen <erik@mogensoft.net>
1 parent 156854a commit a4eb48f

File tree

15 files changed

+320
-32
lines changed

15 files changed

+320
-32
lines changed

api/openapi-spec/swagger.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7537,6 +7537,9 @@
75377537
"subPath": {
75387538
"type": "string"
75397539
},
7540+
"tree": {
7541+
"type": "string"
7542+
},
75407543
"type": {
75417544
"type": "string",
75427545
"default": ""

cmd/controller/main.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ func main() {
9090

9191
flag.BoolVar(&featureFlags.InjectedSidecarSupport, "injected-sidecar-support", flaghelpers.GetEnvBool("INJECTED_SIDECAR_SUPPORT", false), "if set to true, all builds will execute in standard containers instead of init containers to support injected sidecars")
9292
flag.BoolVar(&featureFlags.GenerateSlsaAttestation, "experimental-generate-slsa-attestation", flaghelpers.GetEnvBool("EXPERIMENTAL_GENERATE_SLSA_ATTESTATION", false), "if set to true, SLSA attestations will be generated for each build")
93+
flag.BoolVar(&featureFlags.GitResolverUseShallowClone, "git-resolver-use-shallow-clone", flaghelpers.GetEnvBool("GIT_RESOLVER_USE_SHALLOW_CLONE", false), "if set to true, git source resolvers will use shallow clones instead of ls-remote")
9394

9495
flag.Parse()
9596

@@ -172,7 +173,7 @@ func main() {
172173
KpackClient: client,
173174
}
174175

175-
gitResolver := git.NewResolver(k8sClient, cfg.SshTrustUnknownHosts)
176+
gitResolver := git.NewResolver(k8sClient, cfg.SshTrustUnknownHosts, featureFlags)
176177
blobResolver := &blob.Resolver{}
177178
registryResolver := &registry.Resolver{}
178179

@@ -216,7 +217,7 @@ func main() {
216217

217218
buildController := build.NewController(ctx, options, k8sClient, buildInformer, podInformer, metadataRetriever, buildpodGenerator, podProgressLogger, keychainFactory, &slsaAttester, secretFetcher, featureFlags)
218219
imageController := image.NewController(ctx, options, k8sClient, imageInformer, buildInformer, duckBuilderInformer, sourceResolverInformer, pvcInformer, cfg.EnablePriorityClasses)
219-
sourceResolverController := sourceresolver.NewController(ctx, options, sourceResolverInformer, gitResolver, blobResolver, registryResolver)
220+
sourceResolverController := sourceresolver.NewController(ctx, options, sourceResolverInformer, gitResolver, blobResolver, registryResolver, featureFlags)
220221
builderController := builder.NewController(ctx, options, builderInformer, builderCreator, keychainFactory, clusterStoreInformer, buildpackInformer, clusterBuildpackInformer, clusterStackInformer, clusterLifecycleInformer, secretFetcher)
221222
buildpackController := buildpack.NewController(ctx, options, keychainFactory, buildpackInformer, remoteStoreReader)
222223
clusterBuilderController := clusterbuilder.NewController(ctx, options, clusterBuilderInformer, builderCreator, keychainFactory, clusterStoreInformer, clusterBuildpackInformer, clusterStackInformer, clusterLifecycleInformer, secretFetcher)

go.mod

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ require (
1616
github.com/buildpacks/lifecycle v0.20.12
1717
github.com/chainguard-dev/git-urls v1.0.2
1818
github.com/go-git/go-git/v5 v5.16.4
19+
github.com/go-git/go-git/v6 v6.0.0-20260127175347-b5117ad1603d
1920
github.com/google/go-cmp v0.7.0
2021
github.com/google/go-containerregistry v0.20.6
2122
github.com/google/go-containerregistry/pkg/authn/k8schain v0.0.0-20250613215107-59a4b8593039
@@ -141,7 +142,7 @@ require (
141142
github.com/containerd/typeurl/v2 v2.2.3 // indirect
142143
github.com/coreos/go-oidc/v3 v3.14.1 // indirect
143144
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 // indirect
144-
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
145+
github.com/cyphar/filepath-securejoin v0.6.1 // indirect
145146
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
146147
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
147148
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
@@ -168,7 +169,9 @@ require (
168169
github.com/globocom/go-buffer v1.2.2 // indirect
169170
github.com/go-chi/chi v4.1.2+incompatible // indirect
170171
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
172+
github.com/go-git/gcfg/v2 v2.0.2 // indirect
171173
github.com/go-git/go-billy/v5 v5.6.2 // indirect
174+
github.com/go-git/go-billy/v6 v6.0.0-20260114122816-19306b749ecc // indirect
172175
github.com/go-ini/ini v1.67.0 // indirect
173176
github.com/go-jose/go-jose/v3 v3.0.4 // indirect
174177
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
@@ -220,8 +223,9 @@ require (
220223
github.com/josharian/intern v1.0.0 // indirect
221224
github.com/json-iterator/go v1.1.12 // indirect
222225
github.com/kelseyhightower/envconfig v1.4.0 // indirect
223-
github.com/kevinburke/ssh_config v1.2.0 // indirect
226+
github.com/kevinburke/ssh_config v1.4.0 // indirect
224227
github.com/klauspost/compress v1.18.1 // indirect
228+
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
225229
github.com/kylelemons/godebug v1.1.0 // indirect
226230
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
227231
github.com/mailru/easyjson v0.9.0 // indirect
@@ -248,7 +252,7 @@ require (
248252
github.com/opentracing/opentracing-go v1.2.0 // indirect
249253
github.com/pborman/uuid v1.2.1 // indirect
250254
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
251-
github.com/pjbgf/sha1cd v0.3.2 // indirect
255+
github.com/pjbgf/sha1cd v0.5.0 // indirect
252256
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
253257
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
254258
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect

go.sum

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -984,8 +984,8 @@ github.com/creack/pty v1.1.19 h1:tUN6H7LWqNx4hQVxomd0CVsDwaDr9gaRQaI4GpSmrsA=
984984
github.com/creack/pty v1.1.19/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
985985
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467 h1:uX1JmpONuD549D73r6cgnxyUu18Zb7yHAy5AYU0Pm4Q=
986986
github.com/cyberphone/json-canonicalization v0.0.0-20241213102144-19d51d7fe467/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw=
987-
github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
988-
github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
987+
github.com/cyphar/filepath-securejoin v0.6.1 h1:5CeZ1jPXEiYt3+Z6zqprSAgSWiggmpVyciv8syjIpVE=
988+
github.com/cyphar/filepath-securejoin v0.6.1/go.mod h1:A8hd4EnAeyujCJRrICiOWqjS1AX0a9kM5XL+NwKoYSc=
989989
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
990990
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
991991
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -1120,12 +1120,20 @@ github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2H
11201120
github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY=
11211121
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
11221122
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
1123+
github.com/go-git/gcfg/v2 v2.0.2 h1:MY5SIIfTGGEMhdA7d7JePuVVxtKL7Hp+ApGDJAJ7dpo=
1124+
github.com/go-git/gcfg/v2 v2.0.2/go.mod h1:/lv2NsxvhepuMrldsFilrgct6pxzpGdSRC13ydTLSLs=
11231125
github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
11241126
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
1127+
github.com/go-git/go-billy/v6 v6.0.0-20260114122816-19306b749ecc h1:rhkjrnRkamkRC7woapp425E4CAH6RPcqsS9X8LA93IY=
1128+
github.com/go-git/go-billy/v6 v6.0.0-20260114122816-19306b749ecc/go.mod h1:X1oe0Z2qMsa9hkar3AAPuL9hu4Mi3ztXEjdqRhr6fcc=
11251129
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
11261130
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
1131+
github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67 h1:3hutPZF+/FBjR/9MdsLJ7e1mlt9pwHgwxMW7CrbmWII=
1132+
github.com/go-git/go-git-fixtures/v5 v5.1.2-0.20260122163445-0622d7459a67/go.mod h1:xKt0pNHST9tYHvbiLxSY27CQWFwgIxBJuDrOE0JvbZw=
11271133
github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y=
11281134
github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
1135+
github.com/go-git/go-git/v6 v6.0.0-20260127175347-b5117ad1603d h1:j/FU/xp07cA01tc4yiUjzmhlQsIFAxdhd17T8yXOIEo=
1136+
github.com/go-git/go-git/v6 v6.0.0-20260127175347-b5117ad1603d/go.mod h1:EWlxLBkiFCzXNCadvt05fT9PCAE2sUedgDsvUUIo18s=
11291137
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
11301138
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
11311139
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -1511,8 +1519,8 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E
15111519
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
15121520
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
15131521
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
1514-
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
1515-
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
1522+
github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ=
1523+
github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M=
15161524
github.com/keybase/go-keychain v0.0.1 h1:way+bWYa6lDppZoZcgMbYsvC7GxljxrskdNInRtuthU=
15171525
github.com/keybase/go-keychain v0.0.1/go.mod h1:PdEILRW3i9D8JcdM+FmY6RwkHGnhHxXwkPPMeUgOK1k=
15181526
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
@@ -1524,6 +1532,8 @@ github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
15241532
github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co=
15251533
github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0=
15261534
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
1535+
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
1536+
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
15271537
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
15281538
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
15291539
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -1688,8 +1698,8 @@ github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2
16881698
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
16891699
github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
16901700
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
1691-
github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
1692-
github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
1701+
github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0=
1702+
github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM=
16931703
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
16941704
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
16951705
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=

pkg/apis/core/v1alpha1/source_types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ type ResolvedGitSource struct {
186186
URL string `json:"url"`
187187
Revision string `json:"revision"`
188188
SubPath string `json:"subPath,omitempty"`
189+
Tree string `json:"tree,omitempty"`
189190
Type GitSourceKind `json:"type"`
190191
InitializeSubmodules bool `json:"initializeSubmodules,omitempty"`
191192
}

pkg/config/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ type Config struct {
1313
}
1414

1515
type FeatureFlags struct {
16-
InjectedSidecarSupport bool `json:"injectedSidecarSupport"`
17-
GenerateSlsaAttestation bool `json:"generateSlsaAttestation"`
16+
InjectedSidecarSupport bool `json:"injectedSidecarSupport"`
17+
GenerateSlsaAttestation bool `json:"generateSlsaAttestation"`
18+
GitResolverUseShallowClone bool `json:"gitResolverUseShallowClone"`
1819
}
1920

2021
type Images struct {

pkg/git/fetch_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ func testGitCheckout(t *testing.T, when spec.G, it spec.S) {
7979

8080
it("returns error on non-existent ref", func() {
8181
err := fetcher.Fetch(testDir, "https://github.com/git-fixtures/basic", "doesnotexist", metadataDir)
82-
require.EqualError(t, err, "unable to fetch references for repository: couldn't find remote ref \"doesnotexist\"")
82+
require.ErrorContains(t, err, "unable to fetch references for repository:")
83+
require.ErrorContains(t, err, "doesnotexist")
8384
})
8485

8586
it("preserves symbolic links", func() {

pkg/git/remote_git_resolver.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,31 @@ package git
22

33
import (
44
gogit "github.com/go-git/go-git/v5"
5-
"github.com/go-git/go-git/v5/config"
5+
gogitconfig "github.com/go-git/go-git/v5/config"
66
"github.com/go-git/go-git/v5/plumbing"
77
"github.com/go-git/go-git/v5/plumbing/transport"
88
"github.com/go-git/go-git/v5/storage/memory"
99

1010
corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1"
11+
"github.com/pivotal/kpack/pkg/config"
1112
)
1213

1314
const defaultRemote = "origin"
1415

15-
type remoteGitResolver struct{}
16+
type remoteGitResolver struct {
17+
featureFlags config.FeatureFlags
18+
}
19+
20+
func (r *remoteGitResolver) Resolve(auth transport.AuthMethod, sourceConfig corev1alpha1.SourceConfig) (corev1alpha1.ResolvedSourceConfig, error) {
21+
if r.featureFlags.GitResolverUseShallowClone {
22+
return r.ResolveByCloning(auth, sourceConfig)
23+
}
24+
25+
return r.ResolveByListingRemote(auth, sourceConfig)
26+
}
1627

17-
func (*remoteGitResolver) Resolve(auth transport.AuthMethod, sourceConfig corev1alpha1.SourceConfig) (corev1alpha1.ResolvedSourceConfig, error) {
18-
remote := gogit.NewRemote(memory.NewStorage(), &config.RemoteConfig{
28+
func (r *remoteGitResolver) ResolveByListingRemote(auth transport.AuthMethod, sourceConfig corev1alpha1.SourceConfig) (corev1alpha1.ResolvedSourceConfig, error) {
29+
remote := gogit.NewRemote(memory.NewStorage(), &gogitconfig.RemoteConfig{
1930
Name: defaultRemote,
2031
URLs: []string{sourceConfig.Git.URL},
2132
})
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package git
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"regexp"
7+
"strings"
8+
9+
gogit "github.com/go-git/go-git/v6"
10+
"github.com/go-git/go-git/v6/plumbing"
11+
"github.com/go-git/go-git/v6/plumbing/protocol/packp"
12+
"github.com/go-git/go-git/v6/plumbing/transport"
13+
"github.com/go-git/go-git/v6/storage/memory"
14+
15+
corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1"
16+
)
17+
18+
const commitSHARegex = `^[a-f0-9]{40}$`
19+
20+
var commitSHAValidator = regexp.MustCompile(commitSHARegex)
21+
22+
func (r *remoteGitResolver) ResolveByCloning(auth transport.AuthMethod, sourceConfig corev1alpha1.SourceConfig) (corev1alpha1.ResolvedSourceConfig, error) {
23+
// git clone
24+
repository, err := gogit.Clone(memory.NewStorage(), nil, &gogit.CloneOptions{
25+
URL: sourceConfig.Git.URL,
26+
Auth: auth,
27+
RemoteName: defaultRemote,
28+
ReferenceName: plumbing.ReferenceName(sourceConfig.Git.Revision),
29+
Depth: 1,
30+
Bare: true,
31+
Filter: packp.FilterBlobNone(),
32+
})
33+
34+
var resolvedRef *plumbing.Reference
35+
var hash plumbing.Hash
36+
var kind corev1alpha1.GitSourceKind
37+
errs := []error{}
38+
39+
for _, resolver := range resolvers {
40+
resolvedRef, hash, kind, err = resolver(repository, sourceConfig.Git.Revision)
41+
if err != nil {
42+
errs = append(errs, err)
43+
}
44+
if resolvedRef != nil {
45+
break
46+
}
47+
}
48+
49+
if resolvedRef == nil {
50+
return corev1alpha1.ResolvedSourceConfig{
51+
Git: &corev1alpha1.ResolvedGitSource{
52+
URL: sourceConfig.Git.URL,
53+
Revision: sourceConfig.Git.Revision,
54+
Type: corev1alpha1.Unknown,
55+
SubPath: sourceConfig.SubPath,
56+
InitializeSubmodules: sourceConfig.Git.InitializeSubmodules,
57+
},
58+
}, fmt.Errorf("revision \"%s\": unable to fetch references for repository: %w", sourceConfig.Git.Revision, errors.Join(errs...))
59+
}
60+
61+
return corev1alpha1.ResolvedSourceConfig{
62+
Git: &corev1alpha1.ResolvedGitSource{
63+
URL: sourceConfig.Git.URL,
64+
Revision: hash.String(),
65+
Tree: hashOfSubpath(sourceConfig.SubPath, hash, repository),
66+
Type: kind,
67+
SubPath: sourceConfig.SubPath,
68+
InitializeSubmodules: sourceConfig.Git.InitializeSubmodules,
69+
},
70+
}, nil
71+
}
72+
73+
func hashOfSubpath(subPath string, hash plumbing.Hash, repository *gogit.Repository) string {
74+
path := strings.Trim(subPath, "/")
75+
if path == "" {
76+
return ""
77+
}
78+
79+
commit, err := repository.CommitObject(hash)
80+
if err != nil {
81+
return ""
82+
}
83+
84+
treeObject, err := commit.Tree()
85+
if err != nil {
86+
return ""
87+
}
88+
89+
entry, err := treeObject.FindEntry(path)
90+
if err != nil {
91+
return ""
92+
}
93+
94+
return entry.Hash.String()
95+
96+
}
97+
98+
type resolverFunc func(repository *gogit.Repository, revision string) (*plumbing.Reference, plumbing.Hash, corev1alpha1.GitSourceKind, error)
99+
100+
var resolvers = []resolverFunc{resolveBranch, resolveTag, resolveRevision, looksLikeACommit}
101+
102+
func resolveBranch(repository *gogit.Repository, branch string) (*plumbing.Reference, plumbing.Hash, corev1alpha1.GitSourceKind, error) {
103+
resolvedBranch, err := repository.Branch(branch)
104+
if err != nil {
105+
return nil, plumbing.Hash{}, corev1alpha1.Unknown, err
106+
}
107+
108+
resolvedRef := plumbing.NewSymbolicReference(plumbing.ReferenceName(branch), plumbing.ReferenceName(resolvedBranch.Merge))
109+
h, err := repository.ResolveRevision(plumbing.Revision(resolvedBranch.Merge))
110+
if err != nil {
111+
return nil, plumbing.Hash{}, corev1alpha1.Unknown, err
112+
}
113+
114+
return resolvedRef, *h, corev1alpha1.Branch, nil
115+
}
116+
117+
func resolveTag(repository *gogit.Repository, tag string) (*plumbing.Reference, plumbing.Hash, corev1alpha1.GitSourceKind, error) {
118+
resolvedTag, err := repository.Tag(tag)
119+
if err != nil {
120+
return nil, plumbing.Hash{}, corev1alpha1.Unknown, err
121+
}
122+
123+
return resolvedTag, resolvedTag.Hash(), corev1alpha1.Tag, nil
124+
}
125+
126+
func resolveRevision(repository *gogit.Repository, revision string) (*plumbing.Reference, plumbing.Hash, corev1alpha1.GitSourceKind, error) {
127+
h := plumbing.NewHash(revision)
128+
_, err := repository.Object(plumbing.AnyObject, h)
129+
if err != nil {
130+
return nil, plumbing.Hash{}, corev1alpha1.Unknown, err
131+
}
132+
133+
return plumbing.NewHashReference(plumbing.ReferenceName(revision), h), h, corev1alpha1.Commit, nil
134+
}
135+
136+
func looksLikeACommit(_ *gogit.Repository, revision string) (*plumbing.Reference, plumbing.Hash, corev1alpha1.GitSourceKind, error) {
137+
if !commitSHAValidator.MatchString(revision) {
138+
return nil, plumbing.Hash{}, corev1alpha1.Unknown, nil
139+
}
140+
141+
hash := plumbing.NewHash(revision)
142+
143+
return plumbing.NewHashReference(plumbing.ReferenceName(revision), hash), hash, corev1alpha1.Commit, nil
144+
}

0 commit comments

Comments
 (0)