feat(hydrator): avoid unnecessary repo-server calls (#25150)

Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com>
Signed-off-by: pbhatnagar-oss <pbhatifiwork@gmail.com>
This commit is contained in:
pbhatnagar-oss
2025-12-03 20:29:44 -05:00
committed by GitHub
parent 8e91653f73
commit dea7ead9a3
4 changed files with 49 additions and 0 deletions

View File

@@ -366,6 +366,13 @@ func (h *Hydrator) hydrate(logCtx *log.Entry, apps []*appv1.Application, project
return "", "", errors, nil
}
paths := []*commitclient.PathDetails{pathDetails}
logCtx = logCtx.WithFields(log.Fields{"drySha": targetRevision})
// De-dupe, if the drySha was already hydrated log a debug and return using the data from the last successful hydration run.
// We only inspect one app. If apps have been added/removed, that will be handled on the next DRY commit.
if apps[0].Status.SourceHydrator.LastSuccessfulOperation != nil && targetRevision == apps[0].Status.SourceHydrator.LastSuccessfulOperation.DrySHA {
logCtx.Debug("Skipping hydration since the DRY commit was already hydrated")
return targetRevision, apps[0].Status.SourceHydrator.LastSuccessfulOperation.HydratedSHA, nil, nil
}
eg, ctx := errgroup.WithContext(context.Background())
var mu sync.Mutex

View File

@@ -1094,3 +1094,36 @@ func TestHydrator_getManifests_GetRepoObjsError(t *testing.T) {
assert.Empty(t, rev)
assert.Nil(t, pathDetails)
}
func TestHydrator_hydrate_DeDupe_Success(t *testing.T) {
t.Parallel()
d := mocks.NewDependencies(t)
h := &Hydrator{dependencies: d}
app1 := newTestApp("app1")
app2 := newTestApp("app2")
lastSuccessfulOperation := &v1alpha1.SuccessfulHydrateOperation{
DrySHA: "sha123",
HydratedSHA: "hydrated123",
}
app1.Status.SourceHydrator = v1alpha1.SourceHydratorStatus{
LastSuccessfulOperation: lastSuccessfulOperation,
}
apps := []*v1alpha1.Application{app1, app2}
proj := newTestProject()
projects := map[string]*v1alpha1.AppProject{app1.Spec.Project: proj}
// Asserting .Once() confirms that we only make one call to repo-server to get the last hydrated DRY
// sha, and then we quit early.
d.On("GetRepoObjs", mock.Anything, app1, app1.Spec.SourceHydrator.GetDrySource(), "main", proj).Return(nil, &repoclient.ManifestResponse{Revision: "sha123"}, nil).Once()
logCtx := log.NewEntry(log.StandardLogger())
sha, hydratedSha, errs, err := h.hydrate(logCtx, apps, projects)
require.NoError(t, err)
assert.Equal(t, "sha123", sha)
assert.Equal(t, "hydrated123", hydratedSha)
assert.Empty(t, errs)
}

View File

@@ -118,6 +118,11 @@ During each hydration run, Argo CD cleans the application's configured path befo
It is important to note that hydration only cleans the currently configured application path. If an applications path changes, the old directory is not removed automatically. Likewise, if an application is deleted, its output path remains in the repository and must be cleaned up manually by the repository owner if desired. This design is intentional: it prevents accidental deletion of files when applications are restructured or removed, and it protects critical files like CI pipelines that may coexist in the repository.
> [!NOTE]
> The hydrator triggers only when a new commit is detected in the dry source.
> Adding or removing Applications does not on its own cause hydration to run.
> If the set of Applications changes but the dry-source commit does not, hydration will wait until the next commit.
> [!IMPORTANT]
> **Project-Scoped Repositories**
>

View File

@@ -49,6 +49,8 @@ func TestHydrateTo(t *testing.T) {
When().
// Will now hydrate to the sync source branch.
AppSet("--hydrate-to-branch", "").
// a new git commit, that has a new revisionHistoryLimit.
PatchFile("guestbook/guestbook-ui-deployment.yaml", `[{"op": "replace", "path": "/spec/revisionHistoryLimit", "value": 10}]`).
Refresh(RefreshTypeNormal).
Wait("--hydrated").
Sync().
@@ -82,6 +84,8 @@ func TestAddingApp(t *testing.T) {
SyncSourceBranch("env/test").
When().
CreateApp().
// a new git commit, that has a new revisionHistoryLimit.
PatchFile("guestbook/guestbook-ui-deployment.yaml", `[{"op": "replace", "path": "/spec/revisionHistoryLimit", "value": 10}]`).
Refresh(RefreshTypeNormal).
Wait("--hydrated").
Sync().