diff --git a/util/webhook/webhook.go b/util/webhook/webhook.go index 1348b295b9651..40c3eac5d8d9f 100644 --- a/util/webhook/webhook.go +++ b/util/webhook/webhook.go @@ -307,6 +307,22 @@ func (a *ArgoCDWebhookHandler) HandleEvent(payload interface{}) { continue } for _, app := range filteredApps { + if app.Spec.SourceHydrator != nil { + drySource := app.Spec.SourceHydrator.GetDrySource() + if sourceRevisionHasChanged(drySource, revision, touchedHead) && sourceUsesURL(drySource, webURL, repoRegexp) { + refreshPaths := path.GetAppRefreshPaths(&app) + if path.AppFilesHaveChanged(refreshPaths, changedFiles) { + namespacedAppInterface := a.appClientset.ArgoprojV1alpha1().Applications(app.ObjectMeta.Namespace) + log.Infof("webhook trigger refresh app to hydrate '%s'", app.ObjectMeta.Name) + _, err = argo.RefreshApp(namespacedAppInterface, app.ObjectMeta.Name, v1alpha1.RefreshTypeNormal, true) + if err != nil { + log.Warnf("Failed to hydrate app '%s' for controller reprocessing: %v", app.ObjectMeta.Name, err) + continue + } + } + } + } + for _, source := range app.Spec.GetSources() { if sourceRevisionHasChanged(source, revision, touchedHead) && sourceUsesURL(source, webURL, repoRegexp) { refreshPaths := path.GetAppRefreshPaths(&app) diff --git a/util/webhook/webhook_test.go b/util/webhook/webhook_test.go index 9f39ef4c1c24e..599b7dae000c6 100644 --- a/util/webhook/webhook_test.go +++ b/util/webhook/webhook_test.go @@ -276,6 +276,72 @@ func TestGitHubCommitEvent_AppsInOtherNamespaces(t *testing.T) { hook.Reset() } +// TestGitHubCommitEvent_Hydrate makes sure that a webhook will hydrate an app when dry source changed. +func TestGitHubCommitEvent_Hydrate(t *testing.T) { + hook := test.NewGlobal() + var patched bool + reaction := func(action kubetesting.Action) (handled bool, ret runtime.Object, err error) { + patchAction := action.(kubetesting.PatchAction) + assert.Equal(t, "app-to-hydrate", patchAction.GetName()) + patched = true + return true, nil, nil + } + h := NewMockHandler(&reactorDef{"patch", "applications", reaction}, []string{}, &v1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-to-hydrate", + Namespace: "argocd", + }, + Spec: v1alpha1.ApplicationSpec{ + SourceHydrator: &v1alpha1.SourceHydrator{ + DrySource: v1alpha1.DrySource{ + RepoURL: "https://github.com/jessesuen/test-repo", + TargetRevision: "HEAD", + Path: ".", + }, + SyncSource: v1alpha1.SyncSource{ + TargetBranch: "environments/dev", + Path: ".", + }, + HydrateTo: nil, + }, + }, + }, &v1alpha1.Application{ + ObjectMeta: metav1.ObjectMeta{ + Name: "app-to-ignore", + }, + Spec: v1alpha1.ApplicationSpec{ + Sources: v1alpha1.ApplicationSources{ + { + RepoURL: "https://github.com/some/unrelated-repo", + Path: ".", + }, + }, + }, + }, + ) + req := httptest.NewRequest(http.MethodPost, "/api/webhook", nil) + req.Header.Set("X-GitHub-Event", "push") + eventJSON, err := os.ReadFile("testdata/github-commit-event.json") + require.NoError(t, err) + req.Body = io.NopCloser(bytes.NewReader(eventJSON)) + w := httptest.NewRecorder() + h.Handler(w, req) + close(h.queue) + h.Wait() + assert.Equal(t, http.StatusOK, w.Code) + assert.True(t, patched) + + logMessages := make([]string, 0, len(hook.Entries)) + for _, entry := range hook.Entries { + logMessages = append(logMessages, entry.Message) + } + + assert.Contains(t, logMessages, "webhook trigger refresh app to hydrate 'app-to-hydrate'") + assert.NotContains(t, logMessages, "webhook trigger refresh app to hydrate 'app-to-ignore'") + + hook.Reset() +} + func TestGitHubTagEvent(t *testing.T) { hook := test.NewGlobal() h := NewMockHandler(nil, []string{})