-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds implementation of approvalTask describe CLI command
This patch also adds e2e tests for describe command CLI Signed-off-by: PuneetPunamiya <ppunamiy@redhat.com>
- Loading branch information
1 parent
e9cd2c9
commit 0d46326
Showing
9 changed files
with
380 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package describe | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"text/tabwriter" | ||
"text/template" | ||
|
||
"github.com/openshift-pipelines/manual-approval-gate/pkg/actions" | ||
"github.com/openshift-pipelines/manual-approval-gate/pkg/apis/approvaltask/v1alpha1" | ||
"github.com/openshift-pipelines/manual-approval-gate/pkg/cli" | ||
"github.com/openshift-pipelines/manual-approval-gate/pkg/cli/flags" | ||
"github.com/openshift-pipelines/manual-approval-gate/pkg/cli/formatter" | ||
"github.com/spf13/cobra" | ||
"k8s.io/apimachinery/pkg/runtime/schema" | ||
) | ||
|
||
var taskTemplate = `📦 Name: {{ .ApprovalTask.Name }} | ||
🗂 Namespace: {{ .ApprovalTask.Namespace }} | ||
{{- $pipelineRunRef := pipelineRunRef .ApprovalTask }} | ||
{{- if ne $pipelineRunRef "" }} | ||
🏷️ PipelineRunRef: {{ $pipelineRunRef }} | ||
{{- end }} | ||
👥 Approvers | ||
{{- range .ApprovalTask.Spec.Approvers }} | ||
* {{ .Name }} | ||
{{- end }} | ||
{{- if gt (len .ApprovalTask.Status.ApproversResponse) 0 }} | ||
👨💻 ApproverResponse | ||
Name ApproverResponse Message | ||
{{- range .ApprovalTask.Status.ApproversResponse }} | ||
{{ .Name }} {{response .Response }} {{message .Message }} | ||
{{- end }} | ||
{{- end }} | ||
🌡️ Status | ||
NumberOfApprovalsRequired PendingApprovals STATUS | ||
{{.ApprovalTask.Spec.NumberOfApprovalsRequired}} {{pendingApprovals .ApprovalTask}} {{state .ApprovalTask}} | ||
` | ||
|
||
var ( | ||
taskGroupResource = schema.GroupVersionResource{Group: "openshift-pipelines.org", Resource: "approvaltasks"} | ||
) | ||
|
||
func pendingApprovals(at *v1alpha1.ApprovalTask) int { | ||
return at.Spec.NumberOfApprovalsRequired - len(at.Status.ApproversResponse) | ||
} | ||
|
||
func pipelineRunRef(at *v1alpha1.ApprovalTask) string { | ||
var pipelineRunReference string | ||
for k, v := range at.Labels { | ||
if k == "tekton.dev/pipelineRun" { | ||
pipelineRunReference = v | ||
} | ||
} | ||
|
||
return pipelineRunReference | ||
} | ||
|
||
func message(msg string) string { | ||
if msg == "" { | ||
return "---" | ||
} | ||
return msg | ||
} | ||
|
||
func response(response string) string { | ||
if response == "approved" { | ||
return "✅" | ||
} | ||
return "❌" | ||
} | ||
|
||
func Command(p cli.Params) *cobra.Command { | ||
opts := &cli.Options{} | ||
|
||
funcMap := template.FuncMap{ | ||
"pipelineRunRef": pipelineRunRef, | ||
"pendingApprovals": pendingApprovals, | ||
"message": message, | ||
"response": response, | ||
"state": formatter.State, | ||
} | ||
|
||
c := &cobra.Command{ | ||
Use: "describe", | ||
Short: "Describe approval task", | ||
Long: `This command describe the approval task.`, | ||
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 = "" | ||
} | ||
|
||
opts = &cli.Options{ | ||
Namespace: ns, | ||
Name: args[0], | ||
} | ||
|
||
at, err := actions.Get(taskGroupResource, cs, opts) | ||
if err != nil { | ||
return fmt.Errorf("failed to Get ApprovalTasks %s from %s namespace", args[0], ns) | ||
} | ||
|
||
var data = struct { | ||
ApprovalTask *v1alpha1.ApprovalTask | ||
}{ | ||
ApprovalTask: at, | ||
} | ||
|
||
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 5, 3, ' ', tabwriter.TabIndent) | ||
t := template.Must(template.New("Describe ApprovalTask").Funcs(funcMap).Parse(taskTemplate)) | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
if err := t.Execute(w, data); err != nil { | ||
log.Fatal(err) | ||
return err | ||
} | ||
|
||
return w.Flush() | ||
}, | ||
} | ||
flags.AddOptions(c) | ||
|
||
return c | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package describe | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"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" | ||
"gotest.tools/v3/golden" | ||
corev1 "k8s.io/api/core/v1" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/client-go/dynamic" | ||
) | ||
|
||
func TestDescribeApprovalTask(t *testing.T) { | ||
approvaltasks := []*v1alpha1.ApprovalTask{ | ||
{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "at-1", | ||
Namespace: "foo", | ||
}, | ||
Spec: v1alpha1.ApprovalTaskSpec{ | ||
Approvers: []v1alpha1.ApproverDetails{ | ||
{ | ||
Name: "tekton", | ||
Input: "reject", | ||
}, | ||
{ | ||
Name: "cli", | ||
Input: "pending", | ||
}, | ||
}, | ||
NumberOfApprovalsRequired: 2, | ||
}, | ||
Status: v1alpha1.ApprovalTaskStatus{ | ||
Approvers: []string{ | ||
"tekton", | ||
"cli", | ||
}, | ||
ApproversResponse: []v1alpha1.ApproverState{ | ||
{ | ||
Name: "tekton", | ||
Response: "rejected", | ||
}, | ||
}, | ||
State: "rejected", | ||
}, | ||
}, | ||
} | ||
|
||
ns := []*corev1.Namespace{ | ||
{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "namespace", | ||
}, | ||
}, | ||
} | ||
|
||
dc, err := testDynamic.Client( | ||
cb.UnstructuredV1alpha1(approvaltasks[0], "v1alpha1"), | ||
) | ||
if err != nil { | ||
t.Errorf("unable to create dynamic client: %v", err) | ||
} | ||
|
||
c := command(t, approvaltasks, ns, dc) | ||
args := []string{"at-1", "-n", "foo"} | ||
|
||
output, err := test.ExecuteCommand(c, args...) | ||
golden.Assert(t, output, strings.ReplaceAll(fmt.Sprintf("%s.golden", t.Name()), "/", "-")) | ||
} | ||
|
||
func TestDescribeApprovalTaskNotFound(t *testing.T) { | ||
ns := []*corev1.Namespace{ | ||
{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: "namespace", | ||
}, | ||
}, | ||
} | ||
|
||
dc, err := testDynamic.Client() | ||
if err != nil { | ||
t.Errorf("unable to create dynamic client: %v", err) | ||
} | ||
|
||
c := command(t, []*v1alpha1.ApprovalTask{}, ns, dc) | ||
args := []string{"at-1", "-n", "foo"} | ||
|
||
output, err := test.ExecuteCommand(c, args...) | ||
|
||
expectedOutput := "Error: failed to Get ApprovalTasks at-1 from foo namespace\n" | ||
if output != expectedOutput { | ||
t.Errorf("Expected output to be %q, but got %q", expectedOutput, output) | ||
} | ||
} | ||
|
||
func command(t *testing.T, approvaltasks []*v1alpha1.ApprovalTask, ns []*corev1.Namespace, dc dynamic.Interface) *cobra.Command { | ||
cs, _ := test.SeedTestData(t, test.Data{Approvaltasks: approvaltasks, Namespaces: ns}) | ||
p := &test.Params{ApprovalTask: cs.ApprovalTask, Kube: cs.Kube, Dynamic: dc} | ||
cs.ApprovalTask.Resources = cb.APIResourceList("v1alpha1", []string{"approvaltask"}) | ||
|
||
return Command(p) | ||
} |
16 changes: 16 additions & 0 deletions
16
pkg/cli/cmd/describe/testdata/TestDescribeApprovalTask.golden
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
📦 Name: at-1 | ||
🗂 Namespace: foo | ||
|
||
👥 Approvers | ||
* tekton | ||
* cli | ||
|
||
👨💻 ApproverResponse | ||
|
||
Name ApproverResponse Message | ||
tekton ❌ --- | ||
|
||
🌡️ Status | ||
|
||
NumberOfApprovalsRequired PendingApprovals STATUS | ||
2 1 Rejected |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package formatter | ||
|
||
import ( | ||
"github.com/fatih/color" | ||
"github.com/openshift-pipelines/manual-approval-gate/pkg/apis/approvaltask/v1alpha1" | ||
) | ||
|
||
var ConditionColor = map[string]color.Attribute{ | ||
"Rejected": color.FgHiRed, | ||
"Approved": color.FgHiGreen, | ||
"Pending": color.FgHiBlue, | ||
} | ||
|
||
func ColorStatus(status string) string { | ||
return color.New(ConditionColor[status]).Sprint(status) | ||
} | ||
|
||
func State(at *v1alpha1.ApprovalTask) string { | ||
var state string | ||
|
||
switch at.Status.State { | ||
case "approved": | ||
state = "Approved" | ||
case "rejected": | ||
state = "Rejected" | ||
case "pending": | ||
state = "Pending" | ||
} | ||
return ColorStatus(state) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//go:build e2e | ||
// +build e2e | ||
|
||
package describe | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"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" | ||
"gotest.tools/v3/golden" | ||
) | ||
|
||
func TestApprovalTaskDescribeCommand(t *testing.T) { | ||
tknApprovaltask, err := cli.NewTknApprovalTaskRunner() | ||
assert.Nil(t, err) | ||
|
||
clients := client.Setup(t, "default") | ||
|
||
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, "describe", cr.GetName(), "-n", "test-3") | ||
golden.Assert(t, res.Stdout(), strings.ReplaceAll(fmt.Sprintf("%s.golden", t.Name()), "/", "-")) | ||
} |
13 changes: 13 additions & 0 deletions
13
test/cli/describe/testdata/TestApprovalTaskDescribeCommand.golden
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
📦 Name: at-1 | ||
🗂 Namespace: test-3 | ||
|
||
👥 Approvers | ||
* foo | ||
* bar | ||
* tekton | ||
* kubernetes-admin | ||
|
||
🌡️ Status | ||
|
||
NumberOfApprovalsRequired PendingApprovals STATUS | ||
2 2 Pending |
Oops, something went wrong.