@@ -590,6 +590,16 @@ func (r *GitRepositoryReconciler) reconcileSource(ctx context.Context, sp *patch
590
590
ctrl .LoggerFrom (ctx ).V (logger .DebugLevel ).Info ("git repository checked out" , "url" , obj .Spec .URL , "revision" , commitReference (obj , commit ))
591
591
conditions .Delete (obj , sourcev1 .FetchFailedCondition )
592
592
593
+ // Validate sparse checkout paths after successful checkout.
594
+ if err := r .validateSparseCheckoutPaths (ctx , obj , dir ); err != nil {
595
+ e := serror .NewStalling (
596
+ fmt .Errorf ("failed to sparse checkout directories : %w" , err ),
597
+ sourcev1 .GitOperationFailedReason ,
598
+ )
599
+ conditions .MarkTrue (obj , sourcev1 .FetchFailedCondition , e .Reason , "%s" , e )
600
+ return sreconcile .ResultEmpty , e
601
+ }
602
+
593
603
// Verify commit signature
594
604
if result , err := r .verifySignature (ctx , obj , * commit ); err != nil || result == sreconcile .ResultEmpty {
595
605
return result , err
@@ -812,6 +822,7 @@ func (r *GitRepositoryReconciler) reconcileArtifact(ctx context.Context, sp *pat
812
822
obj .Status .ObservedIgnore = obj .Spec .Ignore
813
823
obj .Status .ObservedRecurseSubmodules = obj .Spec .RecurseSubmodules
814
824
obj .Status .ObservedInclude = obj .Spec .Include
825
+ obj .Status .ObservedSparseCheckout = obj .Spec .SparseCheckout
815
826
816
827
// Remove the deprecated symlink.
817
828
// TODO(hidde): remove 2 minor versions from introduction of v1.
@@ -884,6 +895,7 @@ func (r *GitRepositoryReconciler) reconcileInclude(ctx context.Context, sp *patc
884
895
// performs a git checkout.
885
896
func (r * GitRepositoryReconciler ) gitCheckout (ctx context.Context , obj * sourcev1.GitRepository ,
886
897
authOpts * git.AuthOptions , proxyOpts * transport.ProxyOptions , dir string , optimized bool ) (* git.Commit , error ) {
898
+
887
899
// Configure checkout strategy.
888
900
cloneOpts := repository.CloneConfig {
889
901
RecurseSubmodules : obj .Spec .RecurseSubmodules ,
@@ -896,7 +908,14 @@ func (r *GitRepositoryReconciler) gitCheckout(ctx context.Context, obj *sourcev1
896
908
cloneOpts .SemVer = ref .SemVer
897
909
cloneOpts .RefName = ref .Name
898
910
}
899
-
911
+ if obj .Spec .SparseCheckout != nil {
912
+ // Trim any leading "./" in the directory paths since underlying go-git API does not honor them.
913
+ sparseCheckoutDirs := make ([]string , len (obj .Spec .SparseCheckout ))
914
+ for i , path := range obj .Spec .SparseCheckout {
915
+ sparseCheckoutDirs [i ] = strings .TrimPrefix (path , "./" )
916
+ }
917
+ cloneOpts .SparseCheckoutDirectories = sparseCheckoutDirs
918
+ }
900
919
// Only if the object has an existing artifact in storage, attempt to
901
920
// short-circuit clone operation. reconcileStorage has already verified
902
921
// that the artifact exists.
@@ -1172,6 +1191,14 @@ func gitContentConfigChanged(obj *sourcev1.GitRepository, includes *artifactSet)
1172
1191
if requiresVerification (obj ) {
1173
1192
return true
1174
1193
}
1194
+ if len (obj .Spec .SparseCheckout ) != len (obj .Status .ObservedSparseCheckout ) {
1195
+ return true
1196
+ }
1197
+ for index , dir := range obj .Spec .SparseCheckout {
1198
+ if dir != obj .Status .ObservedSparseCheckout [index ] {
1199
+ return true
1200
+ }
1201
+ }
1175
1202
1176
1203
// Convert artifactSet to index addressable artifacts and ensure that it and
1177
1204
// the included artifacts include all the include from the spec.
@@ -1206,6 +1233,19 @@ func gitContentConfigChanged(obj *sourcev1.GitRepository, includes *artifactSet)
1206
1233
return false
1207
1234
}
1208
1235
1236
+ // validateSparseCheckoutPaths checks if the sparse checkout paths exist in the cloned repository.
1237
+ func (r * GitRepositoryReconciler ) validateSparseCheckoutPaths (ctx context.Context , obj * sourcev1.GitRepository , dir string ) error {
1238
+ if obj .Spec .SparseCheckout != nil {
1239
+ for _ , path := range obj .Spec .SparseCheckout {
1240
+ fullPath := filepath .Join (dir , path )
1241
+ if _ , err := os .Lstat (fullPath ); err != nil {
1242
+ return fmt .Errorf ("sparse checkout dir '%s' does not exist in repository: %w" , path , err )
1243
+ }
1244
+ }
1245
+ }
1246
+ return nil
1247
+ }
1248
+
1209
1249
// Returns true if both GitRepositoryIncludes are equal.
1210
1250
func gitRepositoryIncludeEqual (a , b sourcev1.GitRepositoryInclude ) bool {
1211
1251
if a .GitRepositoryRef != b .GitRepositoryRef {
0 commit comments