Skip to content

Commit 60582d8

Browse files
committed
fix(SourceHydrator): implement new api param for dry hydrated source and reverted to orig protobuff order and used struct as map key (#3)
Signed-off-by: Elias Rami <[email protected]>
1 parent 87b1b75 commit 60582d8

File tree

14 files changed

+1852
-1746
lines changed

14 files changed

+1852
-1746
lines changed

assets/swagger.json

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

controller/hydrator/hydrator.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,18 @@ func (h *Hydrator) getAppsForHydrationKey(hydrationKey types.HydrationQueueKey)
296296
return relevantApps, nil
297297
}
298298

299+
// hydrationDestKey is a struct key for tracking unique hydration destinations.
300+
// Using a struct instead of string formatting better communicates intent and guarantees no collisions.
301+
type hydrationDestKey struct {
302+
repoURL string
303+
path string
304+
}
305+
299306
// validateApplications checks that all applications are valid for hydration.
300307
func (h *Hydrator) validateApplications(apps []*appv1.Application) (map[string]*appv1.AppProject, map[string]error) {
301308
projects := make(map[string]*appv1.AppProject)
302309
errors := make(map[string]error)
303-
uniquePaths := make(map[string]string, len(apps))
310+
uniquePaths := make(map[hydrationDestKey]string, len(apps))
304311

305312
for _, app := range apps {
306313
// Get the project for the app and validate if the app is allowed to use the source.
@@ -338,11 +345,11 @@ func (h *Hydrator) validateApplications(apps []*appv1.Application) (map[string]*
338345

339346
// TODO: test the dupe detection
340347
// TODO: normalize the path to avoid "path/.." from being treated as different from "."
341-
// Use a combination of repo URL and path for uniqueness since apps can hydrate to different repos
342-
destKey := fmt.Sprintf("%s:%s", hydrateToSource.RepoURL, destPath)
348+
// Use a struct key for uniqueness since apps can hydrate to different repos
349+
destKey := hydrationDestKey{repoURL: hydrateToSource.RepoURL, path: destPath}
343350
if appName, ok := uniquePaths[destKey]; ok {
344-
errors[app.QualifiedName()] = fmt.Errorf("app %s hydrator use the same destination: %v", appName, destKey)
345-
errors[appName] = fmt.Errorf("app %s hydrator use the same destination: %v", app.QualifiedName(), destKey)
351+
errors[app.QualifiedName()] = fmt.Errorf("app %s hydrator uses the same destination: repo=%s, path=%s", appName, destKey.repoURL, destKey.path)
352+
errors[appName] = fmt.Errorf("app %s hydrator uses the same destination: repo=%s, path=%s", app.QualifiedName(), destKey.repoURL, destKey.path)
346353
continue
347354
}
348355
uniquePaths[destKey] = app.QualifiedName()

controller/hydrator/hydrator_test.go

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -780,8 +780,8 @@ func TestValidateApplications_DuplicateDestination(t *testing.T) {
780780
projects, errs := h.validateApplications([]*v1alpha1.Application{app1, app2})
781781
require.Nil(t, projects)
782782
require.Len(t, errs, 2)
783-
require.ErrorContains(t, errs[app1.QualifiedName()], "app default/app2 hydrator use the same destination")
784-
require.ErrorContains(t, errs[app2.QualifiedName()], "app default/app1 hydrator use the same destination")
783+
require.ErrorContains(t, errs[app1.QualifiedName()], "app default/app2 hydrator uses the same destination")
784+
require.ErrorContains(t, errs[app2.QualifiedName()], "app default/app1 hydrator uses the same destination")
785785
}
786786

787787
func TestValidateApplications_Success(t *testing.T) {
@@ -1224,3 +1224,97 @@ func TestGetSyncSource_FallsBackToDrySourceRepo(t *testing.T) {
12241224
assert.Equal(t, "app", source.Path)
12251225
assert.Equal(t, "hydrated", source.TargetRevision)
12261226
}
1227+
1228+
// TestGetSyncSource_FallsBackToDrySourceRepoAndPath tests that when both RepoURL and Path
1229+
// are empty in SyncSource, it falls back to both DrySource.RepoURL and DrySource.Path.
1230+
func TestGetSyncSource_FallsBackToDrySourceRepoAndPath(t *testing.T) {
1231+
hydrator := &v1alpha1.SourceHydrator{
1232+
DrySource: v1alpha1.DrySource{
1233+
RepoURL: "https://example.com/dry-repo",
1234+
TargetRevision: "main",
1235+
Path: "base",
1236+
},
1237+
SyncSource: v1alpha1.SyncSource{
1238+
TargetBranch: "hydrated",
1239+
// RepoURL and Path are empty, should fall back to DrySource
1240+
},
1241+
}
1242+
1243+
source := hydrator.GetSyncSource()
1244+
assert.Equal(t, "https://example.com/dry-repo", source.RepoURL)
1245+
assert.Equal(t, "base", source.Path)
1246+
assert.Equal(t, "hydrated", source.TargetRevision)
1247+
}
1248+
1249+
// TestGetHydrateToSource_FallsBackToDrySourceRepo tests that when only RepoURL is empty
1250+
// in SyncSource but Path is set, it only falls back to DrySource.RepoURL (not Path).
1251+
func TestGetHydrateToSource_FallsBackToDrySourceRepo(t *testing.T) {
1252+
spec := &v1alpha1.ApplicationSpec{
1253+
SourceHydrator: &v1alpha1.SourceHydrator{
1254+
DrySource: v1alpha1.DrySource{
1255+
RepoURL: "https://example.com/dry-repo",
1256+
TargetRevision: "main",
1257+
Path: "base",
1258+
},
1259+
SyncSource: v1alpha1.SyncSource{
1260+
TargetBranch: "hydrated",
1261+
Path: "app",
1262+
// RepoURL is empty, should fall back to DrySource.RepoURL
1263+
},
1264+
},
1265+
}
1266+
1267+
source := spec.GetHydrateToSource()
1268+
assert.Equal(t, "https://example.com/dry-repo", source.RepoURL)
1269+
assert.Equal(t, "app", source.Path) // Path should NOT fall back since it's set
1270+
assert.Equal(t, "hydrated", source.TargetRevision)
1271+
}
1272+
1273+
// TestGetHydrateToSource_FallsBackToDrySourceRepoAndPath tests that when both RepoURL
1274+
// and Path are empty in SyncSource, it falls back to both DrySource values.
1275+
func TestGetHydrateToSource_FallsBackToDrySourceRepoAndPath(t *testing.T) {
1276+
spec := &v1alpha1.ApplicationSpec{
1277+
SourceHydrator: &v1alpha1.SourceHydrator{
1278+
DrySource: v1alpha1.DrySource{
1279+
RepoURL: "https://example.com/dry-repo",
1280+
TargetRevision: "main",
1281+
Path: "base",
1282+
},
1283+
SyncSource: v1alpha1.SyncSource{
1284+
TargetBranch: "hydrated",
1285+
// RepoURL and Path are empty, should fall back to DrySource
1286+
},
1287+
},
1288+
}
1289+
1290+
source := spec.GetHydrateToSource()
1291+
assert.Equal(t, "https://example.com/dry-repo", source.RepoURL)
1292+
assert.Equal(t, "base", source.Path)
1293+
assert.Equal(t, "hydrated", source.TargetRevision)
1294+
}
1295+
1296+
// TestGetHydrateToSource_UsesHydrateToTargetBranch tests that when HydrateTo is set,
1297+
// its TargetBranch is used instead of SyncSource.TargetBranch.
1298+
func TestGetHydrateToSource_UsesHydrateToTargetBranch(t *testing.T) {
1299+
spec := &v1alpha1.ApplicationSpec{
1300+
SourceHydrator: &v1alpha1.SourceHydrator{
1301+
DrySource: v1alpha1.DrySource{
1302+
RepoURL: "https://example.com/dry-repo",
1303+
TargetRevision: "main",
1304+
Path: "base",
1305+
},
1306+
SyncSource: v1alpha1.SyncSource{
1307+
TargetBranch: "hydrated",
1308+
// RepoURL and Path are empty
1309+
},
1310+
HydrateTo: &v1alpha1.HydrateTo{
1311+
TargetBranch: "staging",
1312+
},
1313+
},
1314+
}
1315+
1316+
source := spec.GetHydrateToSource()
1317+
assert.Equal(t, "https://example.com/dry-repo", source.RepoURL)
1318+
assert.Equal(t, "base", source.Path)
1319+
assert.Equal(t, "staging", source.TargetRevision) // Uses HydrateTo.TargetBranch
1320+
}

0 commit comments

Comments
 (0)