Skip to content

Commit 7e06933

Browse files
PuneetPunamiyambpavan
authored andcommitted
Updates describe CLI command to add support for Group of Users
Signed-off-by: PuneetPunamiya <[email protected]>
1 parent a74ecfb commit 7e06933

File tree

5 files changed

+226
-13
lines changed

5 files changed

+226
-13
lines changed

pkg/cli/cmd/describe/describe.go

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var taskTemplate = `📦 Name: {{ .ApprovalTask.Name }}
2424
2525
👥 Approvers
2626
{{- range .ApprovalTask.Spec.Approvers }}
27-
* {{ .Name }}
27+
* {{ .Name }}{{if eq .Type "Group"}} (Group){{end}}
2828
{{- end }}
2929
3030
@@ -33,10 +33,17 @@ var taskTemplate = `📦 Name: {{ .ApprovalTask.Name }}
3333
👨‍💻 ApproverResponse
3434
3535
Name ApproverResponse Message
36-
{{- range .ApprovalTask.Status.ApproversResponse }}
37-
{{ .Name }} {{response .Response }} {{message .Message }}
38-
{{- end }}
39-
{{- end }}
36+
{{- range .ApprovalTask.Status.ApproversResponse}}
37+
{{- if eq .Type "User"}}
38+
{{.Name}} {{response .Response}} {{message .Message}}
39+
{{- else if eq .Type "Group"}}
40+
{{- $groupName := .Name}}
41+
{{- range .GroupMembers}}
42+
{{$groupName}}: {{.Name}} {{response .Response}} {{message .Message}}
43+
{{- end}}
44+
{{- end}}
45+
{{- end}}
46+
{{- end}}
4047
4148
🌡️ Status
4249
@@ -49,7 +56,23 @@ var (
4956
)
5057

5158
func pendingApprovals(at *v1alpha1.ApprovalTask) int {
52-
return at.Spec.NumberOfApprovalsRequired - len(at.Status.ApproversResponse)
59+
// Count unique users who have responded (approved or rejected)
60+
respondedUsers := make(map[string]bool)
61+
62+
for _, approver := range at.Status.ApproversResponse {
63+
if approver.Type == "User" {
64+
respondedUsers[approver.Name] = true
65+
} else if approver.Type == "Group" {
66+
// Count individual group members who have responded
67+
for _, member := range approver.GroupMembers {
68+
if member.Response == "approved" || member.Response == "rejected" {
69+
respondedUsers[member.Name] = true
70+
}
71+
}
72+
}
73+
}
74+
75+
return at.Spec.NumberOfApprovalsRequired - len(respondedUsers)
5376
}
5477

5578
func pipelineRunRef(at *v1alpha1.ApprovalTask) string {
@@ -124,7 +147,7 @@ func Command(p cli.Params) *cobra.Command {
124147
ApprovalTask: at,
125148
}
126149

127-
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 5, 3, ' ', tabwriter.TabIndent)
150+
w := tabwriter.NewWriter(cmd.OutOrStdout(), 0, 8, 5, ' ', tabwriter.TabIndent)
128151
t := template.Must(template.New("Describe ApprovalTask").Funcs(funcMap).Parse(taskTemplate))
129152

130153
if err != nil {

pkg/cli/cmd/describe/describe_test.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@ func TestDescribeApprovalTask(t *testing.T) {
2828
{
2929
Name: "tekton",
3030
Input: "reject",
31+
Type: "User",
3132
},
3233
{
3334
Name: "cli",
3435
Input: "pending",
36+
Type: "User",
3537
},
3638
},
3739
NumberOfApprovalsRequired: 2,
@@ -44,6 +46,7 @@ func TestDescribeApprovalTask(t *testing.T) {
4446
ApproversResponse: []v1alpha1.ApproverState{
4547
{
4648
Name: "tekton",
49+
Type: "User",
4750
Response: "rejected",
4851
},
4952
},
@@ -99,6 +102,174 @@ func TestDescribeApprovalTaskNotFound(t *testing.T) {
99102
}
100103
}
101104

105+
func TestDescribeApprovalTaskWithGroups(t *testing.T) {
106+
approvaltasks := []*v1alpha1.ApprovalTask{
107+
{
108+
ObjectMeta: metav1.ObjectMeta{
109+
Name: "at-group",
110+
Namespace: "foo",
111+
},
112+
Spec: v1alpha1.ApprovalTaskSpec{
113+
Approvers: []v1alpha1.ApproverDetails{
114+
{
115+
Name: "admin-group",
116+
Input: "approve",
117+
Type: "Group",
118+
},
119+
{
120+
Name: "dev-team",
121+
Input: "reject",
122+
Type: "Group",
123+
},
124+
{
125+
Name: "alice",
126+
Input: "pending",
127+
Type: "User",
128+
},
129+
},
130+
NumberOfApprovalsRequired: 3,
131+
},
132+
Status: v1alpha1.ApprovalTaskStatus{
133+
Approvers: []string{
134+
"admin-group",
135+
"dev-team",
136+
"alice",
137+
},
138+
ApproversResponse: []v1alpha1.ApproverState{
139+
{
140+
Name: "admin-group",
141+
Type: "Group",
142+
Response: "approved",
143+
GroupMembers: []v1alpha1.GroupMemberState{
144+
{
145+
Name: "bob",
146+
Response: "approved",
147+
Message: "LGTM",
148+
},
149+
{
150+
Name: "charlie",
151+
Response: "approved",
152+
},
153+
},
154+
},
155+
{
156+
Name: "dev-team",
157+
Type: "Group",
158+
Response: "rejected",
159+
GroupMembers: []v1alpha1.GroupMemberState{
160+
{
161+
Name: "david",
162+
Response: "rejected",
163+
Message: "Needs more testing",
164+
},
165+
},
166+
},
167+
},
168+
State: "approved",
169+
},
170+
},
171+
}
172+
173+
ns := []*corev1.Namespace{
174+
{
175+
ObjectMeta: metav1.ObjectMeta{
176+
Name: "namespace",
177+
},
178+
},
179+
}
180+
181+
dc, err := testDynamic.Client(
182+
cb.UnstructuredV1alpha1(approvaltasks[0], "v1alpha1"),
183+
)
184+
if err != nil {
185+
t.Errorf("unable to create dynamic client: %v", err)
186+
}
187+
188+
c := command(t, approvaltasks, ns, dc)
189+
args := []string{"at-group", "-n", "foo"}
190+
191+
output, err := test.ExecuteCommand(c, args...)
192+
golden.Assert(t, output, strings.ReplaceAll(fmt.Sprintf("%s.golden", t.Name()), "/", "-"))
193+
}
194+
195+
// Test individual functions for group functionality
196+
func TestPendingApprovalsWithGroups(t *testing.T) {
197+
tests := []struct {
198+
name string
199+
at *v1alpha1.ApprovalTask
200+
expected int
201+
}{
202+
{
203+
name: "group with multiple members responded",
204+
at: &v1alpha1.ApprovalTask{
205+
Spec: v1alpha1.ApprovalTaskSpec{
206+
NumberOfApprovalsRequired: 3,
207+
},
208+
Status: v1alpha1.ApprovalTaskStatus{
209+
ApproversResponse: []v1alpha1.ApproverState{
210+
{
211+
Name: "admin-group",
212+
Type: "Group",
213+
GroupMembers: []v1alpha1.GroupMemberState{
214+
{Name: "alice", Response: "approved"},
215+
{Name: "bob", Response: "rejected"},
216+
},
217+
},
218+
},
219+
},
220+
},
221+
expected: 1, // 3 required - 2 responded = 1 pending
222+
},
223+
{
224+
name: "mixed user and group responses",
225+
at: &v1alpha1.ApprovalTask{
226+
Spec: v1alpha1.ApprovalTaskSpec{
227+
NumberOfApprovalsRequired: 4,
228+
},
229+
Status: v1alpha1.ApprovalTaskStatus{
230+
ApproversResponse: []v1alpha1.ApproverState{
231+
{
232+
Name: "direct-user",
233+
Type: "User",
234+
Response: "approved",
235+
},
236+
{
237+
Name: "dev-team",
238+
Type: "Group",
239+
GroupMembers: []v1alpha1.GroupMemberState{
240+
{Name: "charlie", Response: "approved"},
241+
{Name: "david", Response: "approved"},
242+
},
243+
},
244+
},
245+
},
246+
},
247+
expected: 1, // 4 required - 3 responded = 1 pending
248+
},
249+
{
250+
name: "no responses",
251+
at: &v1alpha1.ApprovalTask{
252+
Spec: v1alpha1.ApprovalTaskSpec{
253+
NumberOfApprovalsRequired: 2,
254+
},
255+
Status: v1alpha1.ApprovalTaskStatus{
256+
ApproversResponse: []v1alpha1.ApproverState{},
257+
},
258+
},
259+
expected: 2, // 2 required - 0 responded = 2 pending
260+
},
261+
}
262+
263+
for _, tt := range tests {
264+
t.Run(tt.name, func(t *testing.T) {
265+
result := pendingApprovals(tt.at)
266+
if result != tt.expected {
267+
t.Errorf("pendingApprovals() = %d, expected %d", result, tt.expected)
268+
}
269+
})
270+
}
271+
}
272+
102273
func command(t *testing.T, approvaltasks []*v1alpha1.ApprovalTask, ns []*corev1.Namespace, dc dynamic.Interface) *cobra.Command {
103274
cs, _ := test.SeedTestData(t, test.Data{Approvaltasks: approvaltasks, Namespaces: ns})
104275
p := &test.Params{ApprovalTask: cs.ApprovalTask, Kube: cs.Kube, Dynamic: dc}

pkg/cli/cmd/describe/testdata/TestDescribeApprovalTask.golden

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77

88
👨‍💻 ApproverResponse
99

10-
Name ApproverResponse Message
11-
tekton ---
10+
Name ApproverResponse Message
11+
tekton ---
1212

1313
🌡️ Status
1414

15-
NumberOfApprovalsRequired PendingApprovals STATUS
16-
2 1 Rejected
15+
NumberOfApprovalsRequired PendingApprovals STATUS
16+
2 1 Rejected
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
📦 Name: at-group
2+
🗂 Namespace: foo
3+
4+
👥 Approvers
5+
* admin-group (Group)
6+
* dev-team (Group)
7+
* alice
8+
9+
👨‍💻 ApproverResponse
10+
11+
Name ApproverResponse Message
12+
admin-group: bob ✅ LGTM
13+
admin-group: charlie ✅ ---
14+
dev-team: david ❌ Needs more testing
15+
16+
🌡️ Status
17+
18+
NumberOfApprovalsRequired PendingApprovals STATUS
19+
3 0 Approved

test/cli/describe/testdata/TestApprovalTaskDescribeCommand.golden

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@
99

1010
🌡️ Status
1111

12-
NumberOfApprovalsRequired PendingApprovals STATUS
13-
2 2 Pending
12+
NumberOfApprovalsRequired PendingApprovals STATUS
13+
2 2 Pending

0 commit comments

Comments
 (0)