feat: replace error message in webhook handler with metrics (#27215)

Signed-off-by: Alexander Matyushentsev <alexander@akuity.io>
This commit is contained in:
Alexander Matyushentsev 2026-04-08 13:59:58 -07:00 committed by GitHub
parent 6743cdf9cc
commit ad310c2452
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 1051 additions and 820 deletions

4
assets/swagger.json generated
View file

@ -9727,6 +9727,10 @@
"username": {
"type": "string",
"title": "Username contains the user name used for authenticating at the remote repository"
},
"webhookManifestCacheWarmDisabled": {
"description": "WebhookManifestCacheWarmDisabled disables manifest cache warming during webhook processing for this repository.\nWhen set, webhook handlers will only trigger reconciliation for affected applications and skip Redis cache\noperations for unaffected ones. Recommended for large monorepos with plain YAML manifests.",
"type": "boolean"
}
}
},

View file

@ -149,6 +149,7 @@ func NewGenRepoSpecCommand() *cobra.Command {
repoOpts.Repo.EnableOCI = repoOpts.EnableOci
repoOpts.Repo.UseAzureWorkloadIdentity = repoOpts.UseAzureWorkloadIdentity
repoOpts.Repo.InsecureOCIForceHttp = repoOpts.InsecureOCIForceHTTP
repoOpts.Repo.WebhookManifestCacheWarmDisabled = repoOpts.WebhookManifestCacheWarmDisabled
if repoOpts.Repo.Type == "helm" && repoOpts.Repo.Name == "" {
errors.CheckError(stderrors.New("must specify --name for repos of type 'helm'"))

View file

@ -192,6 +192,7 @@ func NewRepoAddCommand(clientOpts *argocdclient.ClientOptions) *cobra.Command {
repoOpts.Repo.ForceHttpBasicAuth = repoOpts.ForceHttpBasicAuth
repoOpts.Repo.UseAzureWorkloadIdentity = repoOpts.UseAzureWorkloadIdentity
repoOpts.Repo.Depth = repoOpts.Depth
repoOpts.Repo.WebhookManifestCacheWarmDisabled = repoOpts.WebhookManifestCacheWarmDisabled
if repoOpts.Repo.Type == "helm" && repoOpts.Repo.Name == "" {
errors.Fatal(errors.ErrorGeneric, "Must specify --name for repos of type 'helm'")

View file

@ -8,26 +8,27 @@ import (
)
type RepoOptions struct {
Repo appsv1.Repository
Upsert bool
SshPrivateKeyPath string //nolint:revive //FIXME(var-naming)
InsecureOCIForceHTTP bool
InsecureIgnoreHostKey bool
InsecureSkipServerVerification bool
TlsClientCertPath string //nolint:revive //FIXME(var-naming)
TlsClientCertKeyPath string //nolint:revive //FIXME(var-naming)
EnableLfs bool
EnableOci bool
GithubAppId int64
GithubAppInstallationId int64
GithubAppPrivateKeyPath string
GitHubAppEnterpriseBaseURL string
Proxy string
NoProxy string
GCPServiceAccountKeyPath string
ForceHttpBasicAuth bool //nolint:revive //FIXME(var-naming)
UseAzureWorkloadIdentity bool
Depth int64
Repo appsv1.Repository
Upsert bool
SshPrivateKeyPath string //nolint:revive //FIXME(var-naming)
InsecureOCIForceHTTP bool
InsecureIgnoreHostKey bool
InsecureSkipServerVerification bool
TlsClientCertPath string //nolint:revive //FIXME(var-naming)
TlsClientCertKeyPath string //nolint:revive //FIXME(var-naming)
EnableLfs bool
EnableOci bool
GithubAppId int64
GithubAppInstallationId int64
GithubAppPrivateKeyPath string
GitHubAppEnterpriseBaseURL string
Proxy string
NoProxy string
GCPServiceAccountKeyPath string
ForceHttpBasicAuth bool //nolint:revive //FIXME(var-naming)
UseAzureWorkloadIdentity bool
Depth int64
WebhookManifestCacheWarmDisabled bool
}
func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
@ -55,4 +56,5 @@ func AddRepoFlags(command *cobra.Command, opts *RepoOptions) {
command.Flags().BoolVar(&opts.UseAzureWorkloadIdentity, "use-azure-workload-identity", false, "whether to use azure workload identity for authentication")
command.Flags().BoolVar(&opts.InsecureOCIForceHTTP, "insecure-oci-force-http", false, "Use http when accessing an OCI repository")
command.Flags().Int64Var(&opts.Depth, "depth", 0, "Specify a custom depth for git clone operations. Unless specified, a full clone is performed using the depth of 0")
command.Flags().BoolVar(&opts.WebhookManifestCacheWarmDisabled, "webhook-manifest-cache-warm-disabled", false, "disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)")
}

View file

@ -438,6 +438,55 @@ spec:
> paths
> provided in the annotation. The application path serves as the deepest path that can be selected as the root.
#### Measuring Annotation Efficiency
You can use the following metrics to evaluate how effectively the `argocd.argoproj.io/manifest-generate-paths`
annotation is reducing unnecessary manifest regeneration:
- **`argocd_webhook_requests_total`** (label: `repo`) — counts incoming webhook events per repository. Use this as the
baseline for how many push events Argo CD is receiving.
- **`argocd_webhook_store_cache_attempts_total`** (labels: `repo`, `successful`) — counts attempts to reuse the previously
cached manifests for the new commit SHA when an application's refresh paths have _not_ changed. A `successful=true`
result means the cache was warmed for the new revision without re-generating manifests, which is the desired outcome.
To assess efficiency, compare the rate of `successful=true` attempts against the total webhook rate. A high ratio
indicates the annotation is working well and preventing unnecessary manifest regeneration.
Note that some `successful=false` results are expected and not a cause for concern — they occur when Argo CD has not
yet cached manifests for an application (e.g. after a restart or first sync), so there is nothing to carry forward to
the new revision.
#### Disabling Manifest Cache Warming in Webhooks
In some cases, the manifest cache warming done by the webhook handler can hurt performance rather than help it:
- **Plain YAML repositories**: if applications use plain YAML manifests (no Helm or Kustomize rendering), manifest
generation is fast and caching provides little benefit. Attempting to warm the cache for thousands of unaffected
applications on every commit adds significant overhead.
- **Large monorepos**: with many applications sharing a single repository, each webhook event triggers a cache warm
attempt for every application whose paths did not change. With thousands of applications, this can cause the webhook
handler to spend significant time on Redis operations, delaying the actual reconciliation trigger for the affected
application.
When disabled, the webhook handler will only trigger reconciliation for applications whose files have changed and
will skip all Redis cache operations for unaffected applications. This is the recommended setting for large monorepos
with plain YAML manifests.
**Per-repository setting (recommended)**: set `webhookManifestCacheWarmDisabled: true` on the repository via the
ArgoCD CLI or UI:
```bash
argocd repo edit https://github.com/org/repo.git --webhook-manifest-cache-warm-disabled
```
**Global setting**: to disable cache warming for all repositories, set the following environment variable on
`argocd-server`:
```
ARGOCD_WEBHOOK_MANIFEST_CACHE_WARM_DISABLED=true
```
### Application Sync Timeout & Jitter
Argo CD has a timeout for application syncs. It will trigger a refresh for each application periodically when the

View file

@ -85,6 +85,7 @@ argocd admin repo generate-spec REPOURL [flags]
--type string type of the repository, "git", "oci" or "helm" (default "git")
--use-azure-workload-identity whether to use azure workload identity for authentication
--username string username to the repository
--webhook-manifest-cache-warm-disabled disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)
```
### Options inherited from parent commands

View file

@ -87,6 +87,7 @@ argocd repo add REPOURL [flags]
--upsert Override an existing repository with the same name even if the spec differs
--use-azure-workload-identity whether to use azure workload identity for authentication
--username string username to the repository
--webhook-manifest-cache-warm-disabled disable manifest cache warming during webhook processing for this repository (recommended for large monorepos with plain YAML manifests)
```
### Options inherited from parent commands

File diff suppressed because it is too large Load diff

View file

@ -1968,6 +1968,11 @@ message Repository {
// Depth specifies the depth for shallow clones. A value of 0 or omitting the field indicates a full clone.
optional int64 depth = 27;
// WebhookManifestCacheWarmDisabled disables manifest cache warming during webhook processing for this repository.
// When set, webhook handlers will only trigger reconciliation for affected applications and skip Redis cache
// operations for unaffected ones. Recommended for large monorepos with plain YAML manifests.
optional bool webhookManifestCacheWarmDisabled = 28;
}
// A RepositoryCertificate is either SSH known hosts entry or TLS certificate

View file

@ -116,6 +116,10 @@ type Repository struct {
InsecureOCIForceHttp bool `json:"insecureOCIForceHttp,omitempty" protobuf:"bytes,26,opt,name=insecureOCIForceHttp"` //nolint:revive //FIXME(var-naming)
// Depth specifies the depth for shallow clones. A value of 0 or omitting the field indicates a full clone.
Depth int64 `json:"depth,omitempty" protobuf:"bytes,27,opt,name=depth"`
// WebhookManifestCacheWarmDisabled disables manifest cache warming during webhook processing for this repository.
// When set, webhook handlers will only trigger reconciliation for affected applications and skip Redis cache
// operations for unaffected ones. Recommended for large monorepos with plain YAML manifests.
WebhookManifestCacheWarmDisabled bool `json:"webhookManifestCacheWarmDisabled,omitempty" protobuf:"varint,28,opt,name=webhookManifestCacheWarmDisabled"`
}
// IsInsecure returns true if the repository has been configured to skip server verification or set to HTTP only

View file

@ -407,6 +407,12 @@ func secretToRepository(secret *corev1.Secret) (*appsv1.Repository, error) {
}
repository.Depth = depth
webhookManifestCacheWarmDisabled, err := boolOrFalse(secret, "webhookManifestCacheWarmDisabled")
if err != nil {
return repository, err
}
repository.WebhookManifestCacheWarmDisabled = webhookManifestCacheWarmDisabled
return repository, nil
}
@ -444,6 +450,7 @@ func (s *secretsRepositoryBackend) repositoryToSecret(repository *appsv1.Reposit
updateSecretBool(secretCopy, "forceHttpBasicAuth", repository.ForceHttpBasicAuth)
updateSecretBool(secretCopy, "useAzureWorkloadIdentity", repository.UseAzureWorkloadIdentity)
updateSecretInt(secretCopy, "depth", repository.Depth)
updateSecretBool(secretCopy, "webhookManifestCacheWarmDisabled", repository.WebhookManifestCacheWarmDisabled)
addSecretMetadata(secretCopy, s.getSecretType())
return secretCopy

View file

@ -1205,6 +1205,71 @@ func TestCreateReadAndWriteSecretForSameURL(t *testing.T) {
assert.Equal(t, common.LabelValueSecretTypeRepositoryWrite, writeSecret.Labels[common.LabelKeySecretType])
}
func TestRepositoryToSecret(t *testing.T) {
clientset := getClientset()
testee := &secretsRepositoryBackend{db: &db{
ns: testNamespace,
kubeclientset: clientset,
settingsMgr: settings.NewSettingsManager(t.Context(), clientset, testNamespace),
}}
s := &corev1.Secret{}
repo := &appsv1.Repository{
Name: "Name",
Repo: "git@github.com:argoproj/argo-cd.git",
Username: "Username",
Password: "Password",
SSHPrivateKey: "SSHPrivateKey",
InsecureIgnoreHostKey: true,
Insecure: true,
EnableLFS: true,
EnableOCI: true,
InsecureOCIForceHttp: true,
TLSClientCertData: "TLSClientCertData",
TLSClientCertKey: "TLSClientCertKey",
Type: "Type",
GithubAppPrivateKey: "GithubAppPrivateKey",
GithubAppId: 123,
GithubAppInstallationId: 456,
GitHubAppEnterpriseBaseURL: "GitHubAppEnterpriseBaseURL",
Proxy: "Proxy",
NoProxy: "NoProxy",
Project: "Project",
GCPServiceAccountKey: "GCPServiceAccountKey",
ForceHttpBasicAuth: true,
UseAzureWorkloadIdentity: true,
Depth: 1,
WebhookManifestCacheWarmDisabled: true,
}
s = testee.repositoryToSecret(repo, s)
assert.Equal(t, []byte(repo.Name), s.Data["name"])
assert.Equal(t, []byte(repo.Repo), s.Data["url"])
assert.Equal(t, []byte(repo.Username), s.Data["username"])
assert.Equal(t, []byte(repo.Password), s.Data["password"])
assert.Equal(t, []byte(repo.SSHPrivateKey), s.Data["sshPrivateKey"])
assert.Equal(t, []byte(strconv.FormatBool(repo.InsecureIgnoreHostKey)), s.Data["insecureIgnoreHostKey"])
assert.Equal(t, []byte(strconv.FormatBool(repo.Insecure)), s.Data["insecure"])
assert.Equal(t, []byte(strconv.FormatBool(repo.EnableLFS)), s.Data["enableLfs"])
assert.Equal(t, []byte(strconv.FormatBool(repo.EnableOCI)), s.Data["enableOCI"])
assert.Equal(t, []byte(strconv.FormatBool(repo.InsecureOCIForceHttp)), s.Data["insecureOCIForceHttp"])
assert.Equal(t, []byte(repo.TLSClientCertData), s.Data["tlsClientCertData"])
assert.Equal(t, []byte(repo.TLSClientCertKey), s.Data["tlsClientCertKey"])
assert.Equal(t, []byte(repo.Type), s.Data["type"])
assert.Equal(t, []byte(repo.GithubAppPrivateKey), s.Data["githubAppPrivateKey"])
assert.Equal(t, []byte(strconv.FormatInt(repo.GithubAppId, 10)), s.Data["githubAppID"])
assert.Equal(t, []byte(strconv.FormatInt(repo.GithubAppInstallationId, 10)), s.Data["githubAppInstallationID"])
assert.Equal(t, []byte(repo.GitHubAppEnterpriseBaseURL), s.Data["githubAppEnterpriseBaseUrl"])
assert.Equal(t, []byte(repo.Proxy), s.Data["proxy"])
assert.Equal(t, []byte(repo.NoProxy), s.Data["noProxy"])
assert.Equal(t, []byte(repo.Project), s.Data["project"])
assert.Equal(t, []byte(repo.GCPServiceAccountKey), s.Data["gcpServiceAccountKey"])
assert.Equal(t, []byte(strconv.FormatBool(repo.ForceHttpBasicAuth)), s.Data["forceHttpBasicAuth"])
assert.Equal(t, []byte(strconv.FormatBool(repo.UseAzureWorkloadIdentity)), s.Data["useAzureWorkloadIdentity"])
assert.Equal(t, []byte(strconv.FormatInt(repo.Depth, 10)), s.Data["depth"])
assert.Equal(t, []byte(strconv.FormatBool(repo.WebhookManifestCacheWarmDisabled)), s.Data["webhookManifestCacheWarmDisabled"])
assert.Equal(t, map[string]string{common.AnnotationKeyManagedBy: common.AnnotationValueManagedByArgoCD}, s.Annotations)
assert.Equal(t, map[string]string{common.LabelKeySecretType: common.LabelValueSecretTypeRepository}, s.Labels)
}
func TestCreateReadAndWriteRepoCredsSecretForSameURL(t *testing.T) {
clientset := getClientset()
settingsMgr := settings.NewSettingsManager(t.Context(), clientset, testNamespace)

View file

@ -7,6 +7,7 @@ import (
"html"
"net/http"
"net/url"
"os"
"regexp"
"strings"
"sync"
@ -25,6 +26,8 @@ import (
"github.com/go-playground/webhooks/v6/gitlab"
"github.com/go-playground/webhooks/v6/gogs"
gogsclient "github.com/gogits/go-gogs-client"
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"
log "github.com/sirupsen/logrus"
"github.com/argoproj/argo-cd/v3/common"
@ -55,6 +58,24 @@ const payloadQueueSize = 50000
const panicMsgServer = "panic while processing api-server webhook event"
var (
webhookManifestCacheWarmDisabled = os.Getenv("ARGOCD_WEBHOOK_MANIFEST_CACHE_WARM_DISABLED") == "true"
webhookRequestsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "argocd_webhook_requests_total",
Help: "Number of webhook requests received by repo.",
}, []string{"repo"})
webhookStoreCacheAttemptsTotal = promauto.NewCounterVec(prometheus.CounterOpts{
Name: "argocd_webhook_store_cache_attempts_total",
Help: "Number of attempts to store previously cached manifests triggered by a webhook event.",
}, []string{"repo", "successful"})
webhookHandlersInFlight = promauto.NewGauge(prometheus.GaugeOpts{
Name: "argocd_webhook_handlers_in_flight",
Help: "Number of webhook HandleEvent calls currently in progress.",
})
)
var _ settingsSource = &settings.SettingsManager{}
type ArgoCDWebhookHandler struct {
@ -313,6 +334,15 @@ type changeInfo struct {
// HandleEvent handles webhook events for repo push events
func (a *ArgoCDWebhookHandler) HandleEvent(payload any) {
webhookHandlersInFlight.Inc()
defer webhookHandlersInFlight.Dec()
start := time.Now()
log.Info("Webhook handler started")
defer func() {
log.Infof("Webhook handler completed in %v", time.Since(start))
}()
webURLs, revision, change, touchedHead, changedFiles := a.affectedRevisionInfo(payload)
// NOTE: the webURL does not include the .git extension
if len(webURLs) == 0 {
@ -321,6 +351,7 @@ func (a *ArgoCDWebhookHandler) HandleEvent(payload any) {
}
for _, webURL := range webURLs {
log.Infof("Received push event repo: %s, revision: %s, touchedHead: %v", webURL, revision, touchedHead)
webhookRequestsTotal.WithLabelValues(git.NormalizeGitURL(webURL)).Inc()
}
nsFilter := a.ns
@ -368,6 +399,16 @@ func (a *ArgoCDWebhookHandler) HandleEvent(payload any) {
continue
}
cacheWarmDisabled := webhookManifestCacheWarmDisabled
if !cacheWarmDisabled {
repo, err := a.lookupRepository(context.Background(), webURL)
if err != nil {
log.Debugf("Failed to look up repository for %s: %v", webURL, err)
} else if repo != nil && repo.WebhookManifestCacheWarmDisabled {
cacheWarmDisabled = true
}
}
// iterate over apps and check if any files specified in their sources have changed
for _, app := range filteredApps {
// get all sources, including sync source and dry source if source hydrator is configured
@ -401,10 +442,13 @@ func (a *ArgoCDWebhookHandler) HandleEvent(payload any) {
log.Errorf("Failed to refresh app '%s': %v", app.Name, err)
}
break // we don't need to check other sources
} else if change.shaBefore != "" && change.shaAfter != "" {
} else if change.shaBefore != "" && change.shaAfter != "" && !cacheWarmDisabled {
// update the cached manifests with the new revision cache key
if err := a.storePreviouslyCachedManifests(&app, change, trackingMethod, appInstanceLabelKey, installationID, source); err != nil {
log.Errorf("Failed to store cached manifests of previous revision for app '%s': %v", app.Name, err)
log.Debugf("Failed to store cached manifests of previous revision for app '%s': %v", app.Name, err)
webhookStoreCacheAttemptsTotal.WithLabelValues(git.NormalizeGitURL(webURL), "false").Inc()
} else {
webhookStoreCacheAttemptsTotal.WithLabelValues(git.NormalizeGitURL(webURL), "true").Inc()
}
}
}

View file

@ -70,13 +70,25 @@ type reactorDef struct {
reaction kubetesting.ReactionFunc
}
func assertLogContains(t *testing.T, hook *test.Hook, msg string) {
t.Helper()
for _, entry := range hook.Entries {
if entry.Message == msg {
return
}
}
t.Errorf("log hook did not contain message: %q", msg)
}
func NewMockHandler(reactor *reactorDef, applicationNamespaces []string, objects ...runtime.Object) *ArgoCDWebhookHandler {
defaultMaxPayloadSize := int64(50) * 1024 * 1024
return NewMockHandlerWithPayloadLimit(reactor, applicationNamespaces, defaultMaxPayloadSize, objects...)
}
func NewMockHandlerWithPayloadLimit(reactor *reactorDef, applicationNamespaces []string, maxPayloadSize int64, objects ...runtime.Object) *ArgoCDWebhookHandler {
return newMockHandler(reactor, applicationNamespaces, maxPayloadSize, &mocks.ArgoDB{}, &settings.ArgoCDSettings{}, objects...)
mockDB := &mocks.ArgoDB{}
mockDB.EXPECT().ListRepositories(mock.Anything).Return([]*v1alpha1.Repository{}, nil).Maybe()
return newMockHandler(reactor, applicationNamespaces, maxPayloadSize, mockDB, &settings.ArgoCDSettings{}, objects...)
}
func NewMockHandlerForBitbucketCallback(reactor *reactorDef, applicationNamespaces []string, objects ...runtime.Object) *ArgoCDWebhookHandler {
@ -161,7 +173,7 @@ func TestGitHubCommitEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Received push event repo: https://github.com/jessesuen/test-repo, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -179,7 +191,7 @@ func TestAzureDevOpsCommitEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Received push event repo: https://dev.azure.com/alexander0053/alex-test/_git/alex-test, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -295,7 +307,7 @@ func TestGitHubTagEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Received push event repo: https://github.com/jessesuen/test-repo, revision: v1.0, touchedHead: false"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -313,7 +325,7 @@ func TestGitHubPingEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Ignoring webhook event"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -331,9 +343,9 @@ func TestBitbucketServerRepositoryReferenceChangedEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResultSSH := "Received push event repo: ssh://git@bitbucketserver:7999/myproject/test-repo.git, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResultSSH, hook.AllEntries()[len(hook.AllEntries())-2].Message)
assertLogContains(t, hook, expectedLogResultSSH)
expectedLogResultHTTPS := "Received push event repo: https://bitbucketserver/scm/myproject/test-repo.git, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResultHTTPS, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResultHTTPS)
hook.Reset()
}
@ -349,7 +361,7 @@ func TestBitbucketServerRepositoryDiagnosticPingEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Ignoring webhook event"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -367,7 +379,7 @@ func TestGogsPushEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Received push event repo: http://gogs-server/john/repo-test, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -385,7 +397,7 @@ func TestGitLabPushEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Received push event repo: https://gitlab.com/group/name, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -403,7 +415,7 @@ func TestGitLabSystemEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusOK, w.Code)
expectedLogResult := "Received push event repo: https://gitlab.com/group/name, revision: master, touchedHead: true"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -418,7 +430,7 @@ func TestInvalidMethod(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusMethodNotAllowed, w.Code)
expectedLogResult := "Webhook processing failed: invalid HTTP Method"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
assert.Equal(t, expectedLogResult+"\n", w.Body.String())
hook.Reset()
}
@ -434,7 +446,7 @@ func TestInvalidEvent(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusBadRequest, w.Code)
expectedLogResult := "Webhook processing failed: The payload is either too large or corrupted. Please check the payload size (must be under 50 MB) and ensure it is valid JSON"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
assert.Equal(t, expectedLogResult+"\n", w.Body.String())
hook.Reset()
}
@ -752,7 +764,7 @@ func TestGitHubCommitEventMaxPayloadSize(t *testing.T) {
h.Wait()
assert.Equal(t, http.StatusBadRequest, w.Code)
expectedLogResult := "Webhook processing failed: The payload is either too large or corrupted. Please check the payload size (must be under 0 MB) and ensure it is valid JSON"
assert.Equal(t, expectedLogResult, hook.LastEntry().Message)
assertLogContains(t, hook, expectedLogResult)
hook.Reset()
}
@ -1119,6 +1131,7 @@ func TestHandleEvent(t *testing.T) {
APIVersions: []string{},
},
}, nil).Maybe()
mockDB.EXPECT().ListRepositories(mock.Anything).Return([]*v1alpha1.Repository{}, nil).Maybe()
err := serverCache.SetClusterInfo(testClusterURL, &v1alpha1.ClusterInfo{
ServerVersion: "1.28.0",