diff --git a/api/v1/testkube.yaml b/api/v1/testkube.yaml index a2592f16301..b25b3803299 100644 --- a/api/v1/testkube.yaml +++ b/api/v1/testkube.yaml @@ -2309,7 +2309,7 @@ paths: description: "Create new webhook based on variables passed in request" operationId: createWebhook requestBody: - description: executor request body data + description: webhook request body data required: true content: application/json: @@ -2332,7 +2332,7 @@ paths: schema: $ref: "#/components/schemas/Webhook" 400: - description: "problem with executor definition - probably some bad input occurs (invalid JSON body or similar)" + description: "problem with webhook definition - probably some bad input occurs (invalid JSON body or similar)" content: application/problem+json: schema: @@ -2449,6 +2449,56 @@ paths: type: array items: $ref: "#/components/schemas/Problem" + patch: + parameters: + - $ref: "#/components/parameters/ID" + tags: + - webhook + - api + summary: "Update new webhook" + description: "Update new webhook based on variables passed in request" + operationId: updateWebhook + requestBody: + description: webhook request body data + required: true + content: + application/json: + schema: + $ref: "#/components/schemas/WebhookUpdateRequest" + text/yaml: + schema: + type: string + responses: + 200: + description: "successful operation" + content: + application/json: + schema: + $ref: "#/components/schemas/Webhook" + 400: + description: "problem with webhook definition - probably some bad input occurs (invalid JSON body or similar)" + content: + application/problem+json: + schema: + type: array + items: + $ref: "#/components/schemas/Problem" + 404: + description: "webhook not found" + content: + application/problem+json: + schema: + type: array + items: + $ref: "#/components/schemas/Problem" + 502: + description: "problem with communicating with kubernetes cluster" + content: + application/problem+json: + schema: + type: array + items: + $ref: "#/components/schemas/Problem" /config: patch: @@ -4618,6 +4668,13 @@ components: allOf: - $ref: "#/components/schemas/Webhook" + WebhookUpdateRequest: + description: webhook update request body + type: object + nullable: true + allOf: + - $ref: "#/components/schemas/Webhook" + # Copied from CRD spec # https://github.com/kubeshop/testkube-operator/blob/main/config/crd/bases/executor.testkube.io_executors.yaml # TODO we need to sync those in some nice way diff --git a/cmd/kubectl-testkube/commands/executors/common.go b/cmd/kubectl-testkube/commands/executors/common.go index cccba5aa3f2..37d084097fd 100644 --- a/cmd/kubectl-testkube/commands/executors/common.go +++ b/cmd/kubectl-testkube/commands/executors/common.go @@ -11,7 +11,7 @@ import ( "github.com/kubeshop/testkube/pkg/ui" ) -// NewUpsertExecutorOptionsFromFlags creates upsert executor options fom command flags +// NewUpsertExecutorOptionsFromFlags creates upsert executor options from command flags func NewUpsertExecutorOptionsFromFlags(cmd *cobra.Command) (options apiClient.UpsertExecutorOptions, err error) { name := cmd.Flag("name").Value.String() types, err := cmd.Flags().GetStringArray("types") diff --git a/cmd/kubectl-testkube/commands/update.go b/cmd/kubectl-testkube/commands/update.go index 73ad55f3fe0..157a5eb0f38 100644 --- a/cmd/kubectl-testkube/commands/update.go +++ b/cmd/kubectl-testkube/commands/update.go @@ -9,6 +9,7 @@ import ( "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/tests" "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsources" "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/testsuites" + "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/webhooks" "github.com/kubeshop/testkube/cmd/kubectl-testkube/config" "github.com/kubeshop/testkube/pkg/ui" ) @@ -35,6 +36,7 @@ func NewUpdateCmd() *cobra.Command { cmd.AddCommand(testsuites.UpdateTestSuitesCmd()) cmd.AddCommand(testsources.UpdateTestSourceCmd()) cmd.AddCommand(executors.UpdateExecutorCmd()) + cmd.AddCommand(webhooks.UpdateWebhookCmd()) return cmd } diff --git a/cmd/kubectl-testkube/commands/webhooks/common.go b/cmd/kubectl-testkube/commands/webhooks/common.go new file mode 100644 index 00000000000..fbff807dd63 --- /dev/null +++ b/cmd/kubectl-testkube/commands/webhooks/common.go @@ -0,0 +1,135 @@ +package webhooks + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + + apiv1 "github.com/kubeshop/testkube/pkg/api/v1/client" + "github.com/kubeshop/testkube/pkg/api/v1/testkube" + webhooksmapper "github.com/kubeshop/testkube/pkg/mapper/webhooks" + "github.com/kubeshop/testkube/pkg/ui" +) + +// NewCreateWebhookOptionsFromFlags creates create webhook options from command flags +func NewCreateWebhookOptionsFromFlags(cmd *cobra.Command) (options apiv1.CreateWebhookOptions, err error) { + name := cmd.Flag("name").Value.String() + namespace := cmd.Flag("namespace").Value.String() + events, err := cmd.Flags().GetStringArray("events") + if err != nil { + return options, err + } + + payloadObjectField := cmd.Flag("payload-field").Value.String() + payloadTemplate := cmd.Flag("payload-template").Value.String() + payloadTemplateContent := "" + if payloadTemplate != "" { + b, err := os.ReadFile(payloadTemplate) + ui.ExitOnError("reading payload template", err) + payloadTemplateContent = string(b) + } + + uri := cmd.Flag("uri").Value.String() + selector := cmd.Flag("selector").Value.String() + labels, err := cmd.Flags().GetStringToString("label") + if err != nil { + return options, err + } + + headers, err := cmd.Flags().GetStringToString("header") + if err != nil { + return options, err + } + + options = apiv1.CreateWebhookOptions{ + Name: name, + Namespace: namespace, + Events: webhooksmapper.MapStringArrayToCRDEvents(events), + Uri: uri, + Selector: selector, + Labels: labels, + PayloadObjectField: payloadObjectField, + PayloadTemplate: payloadTemplateContent, + Headers: headers, + } + + return options, nil +} + +// NewUpdateWebhookOptionsFromFlags creates update webhook options from command flags +func NewUpdateWebhookOptionsFromFlags(cmd *cobra.Command) (options apiv1.UpdateWebhookOptions, err error) { + var fields = []struct { + name string + destination **string + }{ + { + "name", + &options.Name, + }, + { + "uri", + &options.Uri, + }, + { + "selector", + &options.Selector, + }, + { + "payload-field", + &options.PayloadObjectField, + }, + } + + for _, field := range fields { + if cmd.Flag(field.name).Changed { + value := cmd.Flag(field.name).Value.String() + *field.destination = &value + } + } + + if cmd.Flag("payload-template").Changed { + payloadTemplate := cmd.Flag("payload-template").Value.String() + b, err := os.ReadFile(payloadTemplate) + if err != nil { + return options, fmt.Errorf("reading payload template %w", err) + } + + value := string(b) + options.PayloadTemplate = &value + } + + if cmd.Flag("events").Changed { + events, err := cmd.Flags().GetStringArray("events") + if err != nil { + return options, err + } + + var eventTypes []testkube.EventType + for _, event := range events { + eventTypes = append(eventTypes, testkube.EventType(event)) + } + + options.Events = &eventTypes + } + + if cmd.Flag("label").Changed { + labels, err := cmd.Flags().GetStringToString("label") + if err != nil { + return options, err + } + + options.Labels = &labels + } + + if cmd.Flag("header").Changed { + headers, err := cmd.Flags().GetStringToString("header") + if err != nil { + return options, err + } + + options.Headers = &headers + } + + return options, nil +} diff --git a/cmd/kubectl-testkube/commands/webhooks/create.go b/cmd/kubectl-testkube/commands/webhooks/create.go index 81d91c35756..b615e33eab5 100644 --- a/cmd/kubectl-testkube/commands/webhooks/create.go +++ b/cmd/kubectl-testkube/commands/webhooks/create.go @@ -2,7 +2,6 @@ package webhooks import ( "fmt" - "os" "strconv" "github.com/spf13/cobra" @@ -10,7 +9,6 @@ import ( "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" apiv1 "github.com/kubeshop/testkube/pkg/api/v1/client" "github.com/kubeshop/testkube/pkg/crd" - webhooksmapper "github.com/kubeshop/testkube/pkg/mapper/webhooks" "github.com/kubeshop/testkube/pkg/ui" ) @@ -39,14 +37,6 @@ func NewCreateWebhookCmd() *cobra.Command { } namespace := cmd.Flag("namespace").Value.String() - payloadTemplate = cmd.Flag("payload-template").Value.String() - payloadTemplateContent := "" - if payloadTemplate != "" { - b, err := os.ReadFile(payloadTemplate) - ui.ExitOnError("reading job template", err) - payloadTemplateContent = string(b) - } - var client apiv1.Client if !crdOnly { client, namespace, err = common.GetClient(cmd) @@ -58,17 +48,8 @@ func NewCreateWebhookCmd() *cobra.Command { } } - options := apiv1.CreateWebhookOptions{ - Name: name, - Namespace: namespace, - Events: webhooksmapper.MapStringArrayToCRDEvents(events), - Uri: uri, - Selector: selector, - Labels: labels, - PayloadObjectField: payloadObjectField, - PayloadTemplate: payloadTemplateContent, - Headers: headers, - } + options, err := NewCreateWebhookOptionsFromFlags(cmd) + ui.ExitOnError("getting webhook options", err) if !crdOnly { _, err := client.CreateWebhook(options) @@ -89,7 +70,7 @@ func NewCreateWebhookCmd() *cobra.Command { } cmd.Flags().StringVarP(&name, "name", "n", "", "unique webhook name - mandatory") - cmd.Flags().StringArrayVarP(&events, "events", "e", []string{}, "event types handled by executor e.g. start-test|end-test") + cmd.Flags().StringArrayVarP(&events, "events", "e", []string{}, "event types handled by webhook e.g. start-test|end-test") cmd.Flags().StringVarP(&uri, "uri", "u", "", "URI which should be called when given event occurs") cmd.Flags().StringVarP(&selector, "selector", "", "", "expression to select tests and test suites for webhook events: --selector app=backend") cmd.Flags().StringToStringVarP(&labels, "label", "l", nil, "label key value pair: --label key1=value1") diff --git a/cmd/kubectl-testkube/commands/webhooks/update.go b/cmd/kubectl-testkube/commands/webhooks/update.go new file mode 100644 index 00000000000..81d2a469a33 --- /dev/null +++ b/cmd/kubectl-testkube/commands/webhooks/update.go @@ -0,0 +1,59 @@ +package webhooks + +import ( + "github.com/spf13/cobra" + + "github.com/kubeshop/testkube/cmd/kubectl-testkube/commands/common" + "github.com/kubeshop/testkube/pkg/ui" +) + +func UpdateWebhookCmd() *cobra.Command { + var ( + events []string + name, uri string + selector string + labels map[string]string + payloadObjectField string + payloadTemplate string + headers map[string]string + ) + + cmd := &cobra.Command{ + Use: "webhook", + Aliases: []string{"webhooks", "wh"}, + Short: "Update Webhook", + Long: `Update Webhook Custom Resource`, + Run: func(cmd *cobra.Command, args []string) { + if name == "" { + ui.Failf("pass valid name (in '--name' flag)") + } + + client, namespace, err := common.GetClient(cmd) + ui.ExitOnError("getting client", err) + + webhook, _ := client.GetWebhook(name) + if name != webhook.Name { + ui.Failf("Webhook with name '%s' not exists in namespace %s", name, namespace) + } + + options, err := NewUpdateWebhookOptionsFromFlags(cmd) + ui.ExitOnError("getting webhook options", err) + + _, err = client.UpdateWebhook(options) + ui.ExitOnError("updating webhook "+name+" in namespace "+namespace, err) + + ui.Success("Webhook updated", name) + }, + } + + cmd.Flags().StringVarP(&name, "name", "n", "", "unique webhook name - mandatory") + cmd.Flags().StringArrayVarP(&events, "events", "e", []string{}, "event types handled by webhook e.g. start-test|end-test") + cmd.Flags().StringVarP(&uri, "uri", "u", "", "URI which should be called when given event occurs") + cmd.Flags().StringVarP(&selector, "selector", "", "", "expression to select tests and test suites for webhook events: --selector app=backend") + cmd.Flags().StringToStringVarP(&labels, "label", "l", nil, "label key value pair: --label key1=value1") + cmd.Flags().StringVarP(&payloadObjectField, "payload-field", "", "", "field to use for notification object payload") + cmd.Flags().StringVarP(&payloadTemplate, "payload-template", "", "", "if webhook needs to send a custom notification, then a path to template file should be provided") + cmd.Flags().StringToStringVarP(&headers, "header", "", nil, "webhook header value pair: --header Content-Type=application/xml") + + return cmd +} diff --git a/docs/docs/cli/testkube_create_webhook.md b/docs/docs/cli/testkube_create_webhook.md index a97b3a4f577..ae50d764a27 100644 --- a/docs/docs/cli/testkube_create_webhook.md +++ b/docs/docs/cli/testkube_create_webhook.md @@ -13,7 +13,7 @@ testkube create webhook [flags] ### Options ``` - -e, --events stringArray event types handled by executor e.g. start-test|end-test + -e, --events stringArray event types handled by webhook e.g. start-test|end-test --header stringToString webhook header value pair: --header Content-Type=application/xml (default []) -h, --help help for webhook -l, --label stringToString label key value pair: --label key1=value1 (default []) diff --git a/docs/docs/cli/testkube_update.md b/docs/docs/cli/testkube_update.md index 40ef4975e3c..7a3de7cc45b 100644 --- a/docs/docs/cli/testkube_update.md +++ b/docs/docs/cli/testkube_update.md @@ -29,4 +29,5 @@ testkube update [flags] * [testkube update test](testkube_update_test.md) - Update test * [testkube update testsource](testkube_update_testsource.md) - Update TestSource * [testkube update testsuite](testkube_update_testsuite.md) - Update Test Suite +* [testkube update webhook](testkube_update_webhook.md) - Update Webhook diff --git a/docs/docs/cli/testkube_update_webhook.md b/docs/docs/cli/testkube_update_webhook.md new file mode 100644 index 00000000000..08772132bf6 --- /dev/null +++ b/docs/docs/cli/testkube_update_webhook.md @@ -0,0 +1,40 @@ +## testkube update webhook + +Update Webhook + +### Synopsis + +Update Webhook Custom Resource + +``` +testkube update webhook [flags] +``` + +### Options + +``` + -e, --events stringArray event types handled by webhook e.g. start-test|end-test + --header stringToString webhook header value pair: --header Content-Type=application/xml (default []) + -h, --help help for webhook + -l, --label stringToString label key value pair: --label key1=value1 (default []) + -n, --name string unique webhook name - mandatory + --payload-field string field to use for notification object payload + --payload-template string if webhook needs to send a custom notification, then a path to template file should be provided + --selector string expression to select tests and test suites for webhook events: --selector app=backend + -u, --uri string URI which should be called when given event occurs +``` + +### Options inherited from parent commands + +``` + -a, --api-uri string api uri, default value read from config if set (default "https://demo.testkube.io/results/v1") + -c, --client string client used for connecting to Testkube API one of proxy|direct (default "proxy") + --namespace string Kubernetes namespace, default value read from config if set (default "testkube") + --oauth-enabled enable oauth + --verbose show additional debug messages +``` + +### SEE ALSO + +* [testkube update](testkube_update.md) - Update resource + diff --git a/internal/app/api/v1/executor.go b/internal/app/api/v1/executor.go index e68e51bfa83..b0220202688 100644 --- a/internal/app/api/v1/executor.go +++ b/internal/app/api/v1/executor.go @@ -102,7 +102,7 @@ func (s TestkubeAPI) UpdateExecutorHandler() fiber.Handler { } s.Events.Notify(testkube.NewEvent( - testkube.EventCreated, + testkube.EventUpdated, testkube.EventResourceExecutor, updatedExecutor.Name, )) diff --git a/internal/app/api/v1/server.go b/internal/app/api/v1/server.go index c56cfbf4eed..6c535c2773f 100644 --- a/internal/app/api/v1/server.go +++ b/internal/app/api/v1/server.go @@ -250,6 +250,7 @@ func (s *TestkubeAPI) InitRoutes() { webhooks := s.Routes.Group("/webhooks") webhooks.Post("/", s.CreateWebhookHandler()) + webhooks.Patch("/:name", s.UpdateWebhookHandler()) webhooks.Get("/", s.ListWebhooksHandler()) webhooks.Get("/:name", s.GetWebhookHandler()) webhooks.Delete("/:name", s.DeleteWebhookHandler()) diff --git a/internal/app/api/v1/webhook.go b/internal/app/api/v1/webhook.go index 9a9135b9930..1c51bfdb0f0 100644 --- a/internal/app/api/v1/webhook.go +++ b/internal/app/api/v1/webhook.go @@ -55,6 +55,53 @@ func (s TestkubeAPI) CreateWebhookHandler() fiber.Handler { } } +func (s TestkubeAPI) UpdateWebhookHandler() fiber.Handler { + return func(c *fiber.Ctx) error { + errPrefix := "failed to update webhook" + var request testkube.WebhookUpdateRequest + if string(c.Request().Header.ContentType()) == mediaTypeYAML { + var webhook executorv1.Webhook + webhookSpec := string(c.Body()) + decoder := yaml.NewYAMLOrJSONDecoder(bytes.NewBufferString(webhookSpec), len(webhookSpec)) + if err := decoder.Decode(&webhook); err != nil { + return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse yaml request: %w", errPrefix, err)) + } + + request = webhooksmapper.MapSpecToUpdate(&webhook) + } else { + err := c.BodyParser(&request) + if err != nil { + return s.Error(c, http.StatusBadRequest, fmt.Errorf("%s: could not parse json request: %w", errPrefix, err)) + } + } + + var name string + if request.Name != nil { + name = *request.Name + } + errPrefix = errPrefix + " " + name + // we need to get resource first and load its metadata.ResourceVersion + webhook, err := s.WebhooksClient.Get(name) + if err != nil { + if errors.IsNotFound(err) { + return s.Error(c, http.StatusNotFound, fmt.Errorf("%s: client found no webhook: %w", errPrefix, err)) + } + + return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not get webhook: %w", errPrefix, err)) + } + + // map update webhook but load spec only to not override metadata.ResourceVersion + webhookSpec := webhooksmapper.MapUpdateToSpec(request, webhook) + + updatedWebhook, err := s.WebhooksClient.Update(webhookSpec) + if err != nil { + return s.Error(c, http.StatusBadGateway, fmt.Errorf("%s: client could not update webhook: %w", errPrefix, err)) + } + + return c.JSON(updatedWebhook) + } +} + func (s TestkubeAPI) ListWebhooksHandler() fiber.Handler { return func(c *fiber.Ctx) error { errPrefix := "failed to list webhooks" diff --git a/pkg/api/v1/client/interface.go b/pkg/api/v1/client/interface.go index 9a318af2a65..3ca1ba414ba 100644 --- a/pkg/api/v1/client/interface.go +++ b/pkg/api/v1/client/interface.go @@ -84,6 +84,7 @@ type ExecutorAPI interface { // WebhookAPI describes webhook api methods type WebhookAPI interface { CreateWebhook(options CreateWebhookOptions) (webhook testkube.Webhook, err error) + UpdateWebhook(options UpdateWebhookOptions) (webhook testkube.Webhook, err error) GetWebhook(name string) (webhook testkube.Webhook, err error) ListWebhooks(selector string) (webhooks testkube.Webhooks, err error) DeleteWebhook(name string) (err error) @@ -142,6 +143,9 @@ type UpdateExecutorOptions testkube.ExecutorUpdateRequest // CreateWebhookOptions - is mapping for now to OpenAPI schema for creating/changing webhook type CreateWebhookOptions testkube.WebhookCreateRequest +// UpdateWebhookOptions - is mapping for now to OpenAPI schema for changing webhook request +type UpdateWebhookOptions testkube.WebhookUpdateRequest + // UpsertTestSourceOptions - is mapping for now to OpenAPI schema for creating test source // if needed can be extended to custom struct type UpsertTestSourceOptions testkube.TestSourceUpsertRequest diff --git a/pkg/api/v1/client/webhook.go b/pkg/api/v1/client/webhook.go index 380cfe1d500..399fda08f1c 100644 --- a/pkg/api/v1/client/webhook.go +++ b/pkg/api/v1/client/webhook.go @@ -48,6 +48,19 @@ func (c WebhookClient) CreateWebhook(options CreateWebhookOptions) (webhook test return c.webhookTransport.Execute(http.MethodPost, uri, body, nil) } +// UpdateWebhook updates Webhook Custom Resource +func (c WebhookClient) UpdateWebhook(options UpdateWebhookOptions) (webhook testkube.Webhook, err error) { + uri := c.webhookTransport.GetURI("/webhooks/%s", options.Name) + request := testkube.WebhookUpdateRequest(options) + + body, err := json.Marshal(request) + if err != nil { + return webhook, err + } + + return c.webhookTransport.Execute(http.MethodPatch, uri, body, nil) +} + // DeleteWebhooks deletes all webhooks func (c WebhookClient) DeleteWebhooks(selector string) (err error) { uri := c.webhookTransport.GetURI("/webhooks") diff --git a/pkg/api/v1/testkube/model_webhook_update_request.go b/pkg/api/v1/testkube/model_webhook_update_request.go new file mode 100644 index 00000000000..dc65e7c4a4f --- /dev/null +++ b/pkg/api/v1/testkube/model_webhook_update_request.go @@ -0,0 +1,28 @@ +/* + * Testkube API + * + * Testkube provides a Kubernetes-native framework for test definition, execution and results + * + * API version: 1.0.0 + * Contact: testkube@kubeshop.io + * Generated by: Swagger Codegen (https://github.com/swagger-api/swagger-codegen.git) + */ +package testkube + +// webhook update request body +type WebhookUpdateRequest struct { + Name *string `json:"name,omitempty"` + Namespace *string `json:"namespace,omitempty"` + Uri *string `json:"uri"` + Events *[]EventType `json:"events"` + // Labels to filter for tests and test suites + Selector *string `json:"selector,omitempty"` + // will load the generated payload for notification inside the object + PayloadObjectField *string `json:"payloadObjectField,omitempty"` + // golang based template for notification payload + PayloadTemplate *string `json:"payloadTemplate,omitempty"` + // webhook headers + Headers *map[string]string `json:"headers,omitempty"` + // webhook labels + Labels *map[string]string `json:"labels,omitempty"` +} diff --git a/pkg/mapper/webhooks/mapper.go b/pkg/mapper/webhooks/mapper.go index dad2489e065..63e23755196 100644 --- a/pkg/mapper/webhooks/mapper.go +++ b/pkg/mapper/webhooks/mapper.go @@ -64,3 +64,101 @@ func MapEventTypesToStringArray(eventTypes []testkube.EventType) (arr []executor } return } + +// MapUpdateToSpec maps WebhookUpdateRequest to Wehook CRD spec +func MapUpdateToSpec(request testkube.WebhookUpdateRequest, webhook *executorv1.Webhook) *executorv1.Webhook { + var fields = []struct { + source *string + destination *string + }{ + { + request.Name, + &webhook.Name, + }, + { + request.Namespace, + &webhook.Namespace, + }, + { + request.Uri, + &webhook.Spec.Uri, + }, + { + request.Selector, + &webhook.Spec.Selector, + }, + { + request.PayloadObjectField, + &webhook.Spec.PayloadObjectField, + }, + { + request.PayloadTemplate, + &webhook.Spec.PayloadTemplate, + }, + } + + for _, field := range fields { + if field.source != nil { + *field.destination = *field.source + } + } + + if request.Events != nil { + webhook.Spec.Events = MapEventTypesToStringArray(*request.Events) + } + + if request.Labels != nil { + webhook.Labels = *request.Labels + } + + if request.Headers != nil { + webhook.Spec.Headers = *request.Headers + } + + return webhook +} + +// MapSpecToUpdate maps Webhook CRD to WebhookUpdate Request to spec +func MapSpecToUpdate(webhook *executorv1.Webhook) (request testkube.WebhookUpdateRequest) { + var fields = []struct { + source *string + destination **string + }{ + { + &webhook.Name, + &request.Name, + }, + { + &webhook.Namespace, + &request.Namespace, + }, + { + &webhook.Spec.Uri, + &request.Uri, + }, + { + &webhook.Spec.Selector, + &request.Selector, + }, + { + &webhook.Spec.PayloadObjectField, + &request.PayloadObjectField, + }, + { + &webhook.Spec.PayloadTemplate, + &request.PayloadTemplate, + }, + } + + for _, field := range fields { + *field.destination = field.source + } + + events := MapEventArrayToCRDEvents(webhook.Spec.Events) + request.Events = &events + + request.Labels = &webhook.Labels + request.Headers = &webhook.Spec.Headers + + return request +}