Skip to content

Commit e7419ae

Browse files
Updates CLI to add group support for users
Signed-off-by: PuneetPunamiya <[email protected]>
1 parent 887bb0c commit e7419ae

File tree

7 files changed

+292
-29
lines changed

7 files changed

+292
-29
lines changed

pkg/actions/actions.go

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func Update(gr schema.GroupVersionResource, c *cli.Clients, opts *cli.Options) e
8888
return err
8989
}
9090

91-
if !containsUsername(at.Spec.Approvers, opts.Username) {
91+
if !containsUsername(at.Spec.Approvers, opts) {
9292
return fmt.Errorf("Approver: %s, is not present in the approvers list", opts.Username)
9393
}
9494

@@ -101,6 +101,46 @@ func Update(gr schema.GroupVersionResource, c *cli.Clients, opts *cli.Options) e
101101

102102
func update(gvr *schema.GroupVersionResource, dynamic dynamic.Interface, at *v1alpha1.ApprovalTask, opts *cli.Options) error {
103103
for i, approver := range at.Spec.Approvers {
104+
switch approver.Type {
105+
case "User":
106+
if approver.Name == opts.Username {
107+
// return true
108+
at.Spec.Approvers[i].Input = opts.Input
109+
if opts.Message != "" {
110+
at.Spec.Approvers[i].Message = opts.Message
111+
}
112+
}
113+
case "Group":
114+
for _, groupName := range opts.Groups {
115+
if approver.Name == groupName {
116+
// return true
117+
at.Spec.Approvers[i].Input = opts.Input
118+
if opts.Message != "" {
119+
at.Spec.Approvers[i].Message = opts.Message
120+
}
121+
122+
userExists := false
123+
124+
for j, existing := range at.Spec.Approvers[i].Users {
125+
if existing.Name == opts.Username {
126+
userExists = true
127+
if existing.Input != opts.Input {
128+
at.Spec.Approvers[i].Users[j].Input = opts.Input
129+
}
130+
break
131+
}
132+
}
133+
if !userExists {
134+
newUser := v1alpha1.UserDetails{
135+
Name: opts.Username,
136+
Input: opts.Input,
137+
}
138+
at.Spec.Approvers[i].Users = append(at.Spec.Approvers[i].Users, newUser)
139+
}
140+
}
141+
}
142+
}
143+
104144
if approver.Name == opts.Username {
105145
at.Spec.Approvers[i].Input = opts.Input
106146
if opts.Message != "" {
@@ -152,11 +192,26 @@ func InitializeAPIGroupRes(discovery discovery.DiscoveryInterface) error {
152192
return nil
153193
}
154194

155-
func containsUsername(approvers []v1alpha1.ApproverDetails, username string) bool {
195+
func containsUsername(approvers []v1alpha1.ApproverDetails, user *cli.Options) bool {
156196
for _, approver := range approvers {
157-
if approver.Name == username {
197+
if approver.Name == user.Username {
158198
return true
159199
}
160200
}
201+
202+
for _, approval := range approvers {
203+
switch approval.Type {
204+
case "User":
205+
if approval.Name == user.Username {
206+
return true
207+
}
208+
case "Group":
209+
for _, groupName := range user.Groups {
210+
if approval.Name == groupName {
211+
return true
212+
}
213+
}
214+
}
215+
}
161216
return false
162217
}

pkg/cli/cmd/approve/approve.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func Command(p cli.Params) *cobra.Command {
3737
ns = ""
3838
}
3939

40-
username, err := p.GetUserInfo()
40+
username, groups, err := p.GetUserInfo()
4141
if err != nil {
4242
return err
4343
}
@@ -50,6 +50,7 @@ func Command(p cli.Params) *cobra.Command {
5050
Input: "approve",
5151
Username: username,
5252
Message: message,
53+
Groups: groups,
5354
}
5455

5556
if err := actions.Update(taskGroupResource, cs, opts); err != nil {

pkg/cli/cmd/approve/approve_test.go

Lines changed: 104 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,67 @@ func TestApproveApprovalTask(t *testing.T) {
100100
State: "pending",
101101
},
102102
},
103+
// Test case with group approvers
104+
{
105+
ObjectMeta: metav1.ObjectMeta{
106+
Name: "at-group-1",
107+
Namespace: "foo",
108+
},
109+
Spec: v1alpha1.ApprovalTaskSpec{
110+
Approvers: []v1alpha1.ApproverDetails{
111+
{
112+
Name: "admin-group",
113+
Input: "pending",
114+
Type: "Group",
115+
Users: []v1alpha1.UserDetails{},
116+
},
117+
{
118+
Name: "dev-team",
119+
Input: "pending",
120+
Type: "Group",
121+
Users: []v1alpha1.UserDetails{},
122+
},
123+
},
124+
NumberOfApprovalsRequired: 2,
125+
},
126+
Status: v1alpha1.ApprovalTaskStatus{
127+
Approvers: []string{
128+
"admin-group",
129+
"dev-team",
130+
},
131+
State: "pending",
132+
},
133+
},
134+
// Test case with mixed user and group approvers
135+
{
136+
ObjectMeta: metav1.ObjectMeta{
137+
Name: "at-mixed-1",
138+
Namespace: "foo",
139+
},
140+
Spec: v1alpha1.ApprovalTaskSpec{
141+
Approvers: []v1alpha1.ApproverDetails{
142+
{
143+
Name: "alice",
144+
Input: "pending",
145+
Type: "User",
146+
},
147+
{
148+
Name: "admin-group",
149+
Input: "pending",
150+
Type: "Group",
151+
Users: []v1alpha1.UserDetails{},
152+
},
153+
},
154+
NumberOfApprovalsRequired: 2,
155+
},
156+
Status: v1alpha1.ApprovalTaskStatus{
157+
Approvers: []string{
158+
"alice",
159+
"admin-group",
160+
},
161+
State: "pending",
162+
},
163+
},
103164
}
104165

105166
ns := []*corev1.Namespace{
@@ -114,6 +175,8 @@ func TestApproveApprovalTask(t *testing.T) {
114175
cb.UnstructuredV1alpha1(approvaltasks[0], "v1alpha1"),
115176
cb.UnstructuredV1alpha1(approvaltasks[1], "v1alpha1"),
116177
cb.UnstructuredV1alpha1(approvaltasks[2], "v1alpha1"),
178+
cb.UnstructuredV1alpha1(approvaltasks[3], "v1alpha1"),
179+
cb.UnstructuredV1alpha1(approvaltasks[4], "v1alpha1"),
117180
)
118181
if err != nil {
119182
t.Errorf("unable to create dynamic client: %v", err)
@@ -128,25 +191,61 @@ func TestApproveApprovalTask(t *testing.T) {
128191
}{
129192
{
130193
name: "approve approval task",
131-
command: command(t, approvaltasks, ns, dc, "tekton"),
194+
command: command(t, approvaltasks, ns, dc, "tekton", []string{}),
132195
args: []string{"at-1", "-n", "foo"},
133196
expectedOutput: "ApprovalTask at-1 is approved in foo namespace\n",
134197
wantError: false,
135198
},
136199
{
137200
name: "invalid username",
138-
command: command(t, approvaltasks, ns, dc, "test-user"),
201+
command: command(t, approvaltasks, ns, dc, "test-user", []string{}),
139202
args: []string{"at-2", "-n", "foo"},
140203
expectedOutput: "Error: failed to approve approvalTask from namespace foo: Approver: test-user, is not present in the approvers list\n",
141204
wantError: true,
142205
},
143206
{
144207
name: "approvaltask not found",
145-
command: command(t, approvaltasks, ns, dc, "tekton"),
208+
command: command(t, approvaltasks, ns, dc, "tekton", []string{}),
146209
args: []string{"at-3", "-n", "test"},
147210
expectedOutput: fmt.Sprintf("Error: failed to approve approvalTask from namespace %s: approvaltasks.openshift-pipelines.org \"%s\" not found\n", "test", "at-3"),
148211
wantError: true,
149212
},
213+
// Group tests
214+
{
215+
name: "approve as group member",
216+
command: command(t, approvaltasks, ns, dc, "bob", []string{"admin-group"}),
217+
args: []string{"at-group-1", "-n", "foo"},
218+
expectedOutput: "ApprovalTask at-group-1 is approved in foo namespace\n",
219+
wantError: false,
220+
},
221+
{
222+
name: "user not in any required groups",
223+
command: command(t, approvaltasks, ns, dc, "charlie", []string{"other-group"}),
224+
args: []string{"at-group-1", "-n", "foo"},
225+
expectedOutput: "Error: failed to approve approvalTask from namespace foo: Approver: charlie, is not present in the approvers list\n",
226+
wantError: true,
227+
},
228+
{
229+
name: "approve mixed user and group - as group member",
230+
command: command(t, approvaltasks, ns, dc, "david", []string{"admin-group"}),
231+
args: []string{"at-mixed-1", "-n", "foo"},
232+
expectedOutput: "ApprovalTask at-mixed-1 is approved in foo namespace\n",
233+
wantError: false,
234+
},
235+
{
236+
name: "approve mixed user and group - as direct user",
237+
command: command(t, approvaltasks, ns, dc, "alice", []string{"other-group"}),
238+
args: []string{"at-mixed-1", "-n", "foo"},
239+
expectedOutput: "ApprovalTask at-mixed-1 is approved in foo namespace\n",
240+
wantError: false,
241+
},
242+
{
243+
name: "user in multiple groups but approves through one",
244+
command: command(t, approvaltasks, ns, dc, "eve", []string{"admin-group", "dev-team", "other-group"}),
245+
args: []string{"at-group-1", "-n", "foo"},
246+
expectedOutput: "ApprovalTask at-group-1 is approved in foo namespace\n",
247+
wantError: false,
248+
},
150249
}
151250

152251
for _, td := range tests {
@@ -163,9 +262,9 @@ func TestApproveApprovalTask(t *testing.T) {
163262
}
164263
}
165264

166-
func command(t *testing.T, approvaltasks []*v1alpha1.ApprovalTask, ns []*corev1.Namespace, dc dynamic.Interface, username string) *cobra.Command {
265+
func command(t *testing.T, approvaltasks []*v1alpha1.ApprovalTask, ns []*corev1.Namespace, dc dynamic.Interface, username string, groups []string) *cobra.Command {
167266
cs, _ := test.SeedTestData(t, test.Data{Approvaltasks: approvaltasks, Namespaces: ns})
168-
p := &test.Params{ApprovalTask: cs.ApprovalTask, Kube: cs.Kube, Dynamic: dc, Username: username}
267+
p := &test.Params{ApprovalTask: cs.ApprovalTask, Kube: cs.Kube, Dynamic: dc, Username: username, Groups: groups}
169268
cs.ApprovalTask.Resources = cb.APIResourceList("v1alpha1", []string{"approvaltask"})
170269

171270
return Command(p)

pkg/cli/cmd/reject/reject.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func Command(p cli.Params) *cobra.Command {
3737
ns = ""
3838
}
3939

40-
username, err := p.GetUserInfo()
40+
username, groups, err := p.GetUserInfo()
4141
if err != nil {
4242
return err
4343
}
@@ -50,6 +50,7 @@ func Command(p cli.Params) *cobra.Command {
5050
Input: "reject",
5151
Username: username,
5252
Message: message,
53+
Groups: groups,
5354
}
5455

5556
if err := actions.Update(taskGroupResource, cs, opts); err != nil {
@@ -64,7 +65,7 @@ func Command(p cli.Params) *cobra.Command {
6465
},
6566
}
6667

67-
c.Flags().StringVarP(&opts.Message, "message", "m", "", "message while approving the approvalTask")
68+
c.Flags().StringVarP(&opts.Message, "message", "m", "", "message while rejecting the approvalTask")
6869

6970
flags.AddOptions(c)
7071

0 commit comments

Comments
 (0)