From fb547863490f975c13b2a8d8316ce8870f936dec Mon Sep 17 00:00:00 2001 From: PuneetPunamiya Date: Thu, 9 May 2024 08:46:07 +0530 Subject: [PATCH] Adds implementation of reject ApprovalTask commmand This also adds e2e test for reject CLI command Signed-off-by: PuneetPunamiya --- pkg/cli/cmd/reject/reject.go | 72 +++++++++++++ pkg/cli/cmd/reject/reject_test.go | 166 +++++++++++++++++++++++++++++ pkg/cli/cmd/root.go | 2 + test/cli/reject/reject_test.go | 48 +++++++++ test/cli/reject/testdata/cr-1.yaml | 19 ++++ test/e2e-test.sh | 2 + 6 files changed, 309 insertions(+) create mode 100644 pkg/cli/cmd/reject/reject.go create mode 100644 pkg/cli/cmd/reject/reject_test.go create mode 100644 test/cli/reject/reject_test.go create mode 100644 test/cli/reject/testdata/cr-1.yaml diff --git a/pkg/cli/cmd/reject/reject.go b/pkg/cli/cmd/reject/reject.go new file mode 100644 index 00000000..8ebe6a4d --- /dev/null +++ b/pkg/cli/cmd/reject/reject.go @@ -0,0 +1,72 @@ +package reject + +import ( + "fmt" + "io" + + "github.com/openshift-pipelines/manual-approval-gate/pkg/actions" + cli "github.com/openshift-pipelines/manual-approval-gate/pkg/cli" + "github.com/openshift-pipelines/manual-approval-gate/pkg/cli/flags" + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var ( + taskGroupResource = schema.GroupVersionResource{Group: "openshift-pipelines.org", Resource: "approvaltasks"} +) + +func Command(p cli.Params) *cobra.Command { + opts := &cli.Options{} + c := &cobra.Command{ + Use: "reject", + Short: "Reject the approvaltask", + Long: `This command rejects the approvaltask.`, + Annotations: map[string]string{ + "commandType": "main", + }, + Args: cobra.ExactArgs(1), + PersistentPreRunE: flags.PersistentPreRunE(p), + RunE: func(cmd *cobra.Command, args []string) error { + cs, err := p.Clients() + if err != nil { + return err + } + + ns := p.Namespace() + if opts.AllNamespaces { + ns = "" + } + + username, err := p.GetUserInfo() + if err != nil { + return err + } + + message := opts.Message + + opts = &cli.Options{ + Name: args[0], + Namespace: ns, + Input: "reject", + Username: username, + Message: message, + } + + if err := actions.Update(taskGroupResource, cs, opts); err != nil { + return fmt.Errorf("failed to reject approvalTask from namespace %s: %v", ns, err) + } + + res := fmt.Sprintf("ApprovalTask %s is rejected in %s namespace\n", args[0], ns) + io.WriteString(cmd.OutOrStdout(), res) + + return nil + + }, + } + + c.Flags().StringVarP(&opts.Message, "message", "m", "", "message while approving the approvalTask") + + flags.AddOptions(c) + + return c +} diff --git a/pkg/cli/cmd/reject/reject_test.go b/pkg/cli/cmd/reject/reject_test.go new file mode 100644 index 00000000..725dbd48 --- /dev/null +++ b/pkg/cli/cmd/reject/reject_test.go @@ -0,0 +1,166 @@ +package reject + +import ( + "fmt" + "testing" + + "github.com/openshift-pipelines/manual-approval-gate/pkg/apis/approvaltask/v1alpha1" + "github.com/openshift-pipelines/manual-approval-gate/pkg/test" + cb "github.com/openshift-pipelines/manual-approval-gate/pkg/test/builder" + testDynamic "github.com/openshift-pipelines/manual-approval-gate/pkg/test/dynamic" + "github.com/spf13/cobra" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/dynamic" +) + +func TestRejectApprovalTask(t *testing.T) { + approvaltasks := []*v1alpha1.ApprovalTask{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "at-1", + Namespace: "foo", + }, + Spec: v1alpha1.ApprovalTaskSpec{ + Approvers: []v1alpha1.ApproverDetails{ + { + Name: "tekton", + Input: "pending", + }, + { + Name: "cli", + Input: "pending", + }, + }, + NumberOfApprovalsRequired: 2, + }, + Status: v1alpha1.ApprovalTaskStatus{ + Approvers: []string{ + "tekton", + "cli", + }, + State: "pending", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "at-2", + Namespace: "foo", + }, + Spec: v1alpha1.ApprovalTaskSpec{ + Approvers: []v1alpha1.ApproverDetails{ + { + Name: "tekton", + Input: "pending", + }, + { + Name: "cli", + Input: "pending", + }, + }, + NumberOfApprovalsRequired: 2, + }, + Status: v1alpha1.ApprovalTaskStatus{ + Approvers: []string{ + "tekton", + "cli", + }, + State: "pending", + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "at-3", + Namespace: "foo", + }, + Spec: v1alpha1.ApprovalTaskSpec{ + Approvers: []v1alpha1.ApproverDetails{ + { + Name: "tekton", + Input: "pending", + }, + { + Name: "cli", + Input: "pending", + }, + }, + NumberOfApprovalsRequired: 2, + }, + Status: v1alpha1.ApprovalTaskStatus{ + Approvers: []string{ + "tekton", + "cli", + }, + State: "pending", + }, + }, + } + + ns := []*corev1.Namespace{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "namespace", + }, + }, + } + + dc, err := testDynamic.Client( + cb.UnstructuredV1alpha1(approvaltasks[0], "v1alpha1"), + cb.UnstructuredV1alpha1(approvaltasks[1], "v1alpha1"), + cb.UnstructuredV1alpha1(approvaltasks[2], "v1alpha1"), + ) + if err != nil { + t.Errorf("unable to create dynamic client: %v", err) + } + + tests := []struct { + name string + command *cobra.Command + args []string + expectedOutput string + wantError bool + }{ + { + name: "reject approval task", + command: command(t, approvaltasks, ns, dc, "tekton"), + args: []string{"at-1", "-n", "foo"}, + expectedOutput: "ApprovalTask at-1 is rejected in foo namespace\n", + wantError: false, + }, + { + name: "invalid username", + command: command(t, approvaltasks, ns, dc, "test-user"), + args: []string{"at-2", "-n", "foo"}, + expectedOutput: "Error: failed to reject approvalTask from namespace foo: Approver: test-user, is not present in the approvers list\n", + wantError: true, + }, + { + name: "approvaltask not found", + command: command(t, approvaltasks, ns, dc, "tekton"), + args: []string{"at-3", "-n", "test"}, + expectedOutput: fmt.Sprintf("Error: failed to reject approvalTask from namespace %s: approvaltasks.openshift-pipelines.org \"%s\" not found\n", "test", "at-3"), + wantError: true, + }, + } + + for _, td := range tests { + t.Run(td.name, func(t *testing.T) { + output, err := test.ExecuteCommand(td.command, td.args...) + if err != nil && !td.wantError { + t.Errorf("Unexpected error: %v", err) + } + + if output != td.expectedOutput { + t.Errorf("Expected output to be %q, but got %q", td.expectedOutput, output) + } + }) + } +} + +func command(t *testing.T, approvaltasks []*v1alpha1.ApprovalTask, ns []*corev1.Namespace, dc dynamic.Interface, username string) *cobra.Command { + cs, _ := test.SeedTestData(t, test.Data{Approvaltasks: approvaltasks, Namespaces: ns}) + p := &test.Params{ApprovalTask: cs.ApprovalTask, Kube: cs.Kube, Dynamic: dc, Username: username} + cs.ApprovalTask.Resources = cb.APIResourceList("v1alpha1", []string{"approvaltask"}) + + return Command(p) +} diff --git a/pkg/cli/cmd/root.go b/pkg/cli/cmd/root.go index c1aacd3e..70a66329 100644 --- a/pkg/cli/cmd/root.go +++ b/pkg/cli/cmd/root.go @@ -5,6 +5,7 @@ import ( "github.com/openshift-pipelines/manual-approval-gate/pkg/cli/cmd/approve" "github.com/openshift-pipelines/manual-approval-gate/pkg/cli/cmd/describe" "github.com/openshift-pipelines/manual-approval-gate/pkg/cli/cmd/list" + "github.com/openshift-pipelines/manual-approval-gate/pkg/cli/cmd/reject" "github.com/openshift-pipelines/manual-approval-gate/pkg/cli/flags" "github.com/spf13/cobra" ) @@ -23,6 +24,7 @@ func Root(p cli.Params) *cobra.Command { c.AddCommand(list.Command(p)) c.AddCommand(approve.Command(p)) c.AddCommand(describe.Command(p)) + c.AddCommand(reject.Command(p)) return c } diff --git a/test/cli/reject/reject_test.go b/test/cli/reject/reject_test.go new file mode 100644 index 00000000..c6a1543c --- /dev/null +++ b/test/cli/reject/reject_test.go @@ -0,0 +1,48 @@ +//go:build e2e +// +build e2e + +package approve + +import ( + "context" + "testing" + + "github.com/openshift-pipelines/manual-approval-gate/test/cli" + "github.com/openshift-pipelines/manual-approval-gate/test/client" + "github.com/openshift-pipelines/manual-approval-gate/test/resources" + "github.com/stretchr/testify/assert" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +func TestApprovalTaskRejectCommand(t *testing.T) { + tknApprovaltask, err := cli.NewTknApprovalTaskRunner() + assert.Nil(t, err) + + clients := client.Setup(t, "default") + + t.Run("approve-approvaltask", func(t *testing.T) { + cr := resources.Create(t, clients, "./testdata/cr-1.yaml") + + _, err := resources.WaitForApprovalTaskCreation(clients.ApprovalTaskClient, cr.GetName(), cr.GetNamespace()) + if err != nil { + t.Fatal("Failed to get the approval task") + } + + res := tknApprovaltask.MustSucceed(t, "reject", cr.GetName(), "-n", "test-4") + + _, err = resources.WaitForApproverResponseUpdate(clients.ApprovalTaskClient, cr, "kubernetes-admin", "rejected") + if err != nil { + t.Fatal("Failed to get the approval task") + } + + approvalTask, err := clients.ApprovalTaskClient.ApprovalTasks(cr.GetNamespace()).Get(context.TODO(), cr.GetName(), metav1.GetOptions{}) + if err != nil { + t.Fatal("Failed to get the approval task") + } + + assert.Equal(t, 1, len(approvalTask.Status.ApproversResponse)) + assert.Equal(t, "ApprovalTask at-1 is rejected in test-4 namespace\n", res.Stdout()) + assert.Equal(t, "kubernetes-admin", approvalTask.Status.ApproversResponse[0].Name) + assert.Equal(t, "rejected", approvalTask.Status.ApproversResponse[0].Response) + }) +} diff --git a/test/cli/reject/testdata/cr-1.yaml b/test/cli/reject/testdata/cr-1.yaml new file mode 100644 index 00000000..30d6bdba --- /dev/null +++ b/test/cli/reject/testdata/cr-1.yaml @@ -0,0 +1,19 @@ +apiVersion: tekton.dev/v1beta1 +kind: CustomRun +metadata: + name: at-1 + namespace: test-4 +spec: + retries: 2 + customRef: + apiVersion: openshift-pipelines.org/v1alpha1 + kind: ApprovalTask + params: + - name: approvers + value: + - foo + - bar + - tekton + - kubernetes-admin + - name: numberOfApprovalsRequired + value: 2 diff --git a/test/e2e-test.sh b/test/e2e-test.sh index d5055489..43a82e66 100644 --- a/test/e2e-test.sh +++ b/test/e2e-test.sh @@ -124,6 +124,7 @@ main() { kubectl create ns test-1 kubectl create ns test-2 kubectl create ns test-3 + kubectl create ns test-4 kubectl create ns test-5 go build -o tkn-approvaltask github.com/openshift-pipelines/manual-approval-gate/cmd/tkn-approvaltask @@ -134,6 +135,7 @@ main() { kubectl delete ns test-1 kubectl delete ns test-2 kubectl delete ns test-3 + kubectl create ns test-4 kubectl create ns test-5 success