Skip to content

Commit a4d1c25

Browse files
Miguel Tanadabzon
authored andcommitted
Add delete all members command
1 parent 0ff2dbe commit a4d1c25

File tree

6 files changed

+235
-2
lines changed

6 files changed

+235
-2
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,5 @@ Contributors are welcomed with love! Please read [CONTRIBUTING.md](./CONTRIBUTIN
248248
* [x] `delete member [username] --from-project`
249249
* [x] `edit member [username] --from-group [flags]`
250250
* [x] `edit member [username] --from-project [flags]`
251-
* [ ] `remove all-members --from-group`
252-
* [ ] `remove all-members --from-project`
251+
* [x] `delete all-members --from-project`
253252

cmd/delete_all_members.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Copyright © 2018 github.com/devopsctl authors
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package cmd
22+
23+
import (
24+
"strconv"
25+
26+
"github.com/spf13/cobra"
27+
)
28+
29+
var deleteAllMembersCmd = &cobra.Command{
30+
Use: "all-members",
31+
SuggestFor: []string{"all", "all-member"},
32+
Short: "Delete all members of a project",
33+
Example: `gitlabctl delete all-members --from-project Group1/Project1`,
34+
Args: cobra.ExactArgs(0),
35+
SilenceErrors: true,
36+
SilenceUsage: true,
37+
DisableAutoGenTag: true,
38+
PreRunE: func(cmd *cobra.Command, args []string) error {
39+
return validateFromProjectFlag(cmd)
40+
},
41+
RunE: func(cmd *cobra.Command, args []string) error {
42+
return deleteAllProjectMembers(getFlagString(cmd, "from-project"))
43+
},
44+
}
45+
46+
func init() {
47+
deleteCmd.AddCommand(deleteAllMembersCmd)
48+
addFromProjectFlag(deleteAllMembersCmd)
49+
}
50+
51+
func deleteAllProjectMembers(project string) error {
52+
git, err := newGitlabClient()
53+
if err != nil {
54+
return err
55+
}
56+
57+
members, _, err := git.ProjectMembers.ListProjectMembers(project, nil)
58+
if err != nil {
59+
return err
60+
}
61+
62+
p, _ := descProject(project)
63+
64+
for _, member := range members {
65+
if member.ID != p.CreatorID {
66+
if err := deleteProjectMember(project, strconv.Itoa(member.ID)); err != nil {
67+
return err
68+
}
69+
}
70+
}
71+
return nil
72+
}

cmd/delete_all_members_test.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright © 2018 github.com/devopsctl authors
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package cmd
22+
23+
import (
24+
"fmt"
25+
"testing"
26+
27+
gitlab "github.com/xanzy/go-gitlab"
28+
)
29+
30+
func TestDeleteAllMembers(t *testing.T) {
31+
tg := []struct {
32+
name string
33+
args []string
34+
flagsMap map[string]string
35+
expect testResult
36+
}{
37+
{
38+
name: "delete all from a project",
39+
flagsMap: map[string]string{
40+
"from-project": "TestDeleteAllMembersProject",
41+
},
42+
expect: pass,
43+
},
44+
}
45+
t.Run(tg[0].name, func(t *testing.T) {
46+
// SETUP:
47+
// create the test project
48+
gid, _ := getNamespaceID("Group1")
49+
if _, err := newProject(&gitlab.CreateProjectOptions{
50+
Path: gitlab.String(tg[0].flagsMap["from-project"]),
51+
Name: gitlab.String(tg[0].flagsMap["from-project"]),
52+
NamespaceID: gitlab.Int(gid),
53+
}); err != nil {
54+
tInfo(err)
55+
}
56+
57+
tg[0].flagsMap["from-project"] = "Group1/" + tg[0].flagsMap["from-project"]
58+
// add project members
59+
if _, err := newProjectMember(tg[0].flagsMap["from-project"],
60+
"john.smith",
61+
&gitlab.AddProjectMemberOptions{
62+
AccessLevel: gitlab.AccessLevel(40),
63+
}); err != nil {
64+
tInfo(err)
65+
}
66+
67+
if _, err := newProjectMember(tg[0].flagsMap["from-project"],
68+
"john.doe",
69+
&gitlab.AddProjectMemberOptions{
70+
AccessLevel: gitlab.AccessLevel(40),
71+
}); err != nil {
72+
tInfo(err)
73+
}
74+
75+
execT := execTestCmdFlags{
76+
t: t,
77+
cmd: deleteAllMembersCmd,
78+
flagsMap: tg[0].flagsMap,
79+
}
80+
stdout, execResult := execT.executeCommand()
81+
assertEqualResult(t, tg[0].expect, execResult, stdout)
82+
83+
// delete test project
84+
if err := deleteProject(tg[0].flagsMap["from-project"]); err != nil {
85+
tInfo("Removal of test data failure for delete all-members test")
86+
}
87+
88+
})
89+
90+
// negative tests
91+
tt := []struct {
92+
name string
93+
flagsMap map[string]string
94+
expect testResult
95+
expectOut string
96+
}{
97+
{
98+
name: "fails when no flag is used",
99+
flagsMap: map[string]string{
100+
"from-project": "",
101+
},
102+
expect: fail,
103+
expectOut: fmt.Sprint(setAtLeastOneFlagError),
104+
},
105+
}
106+
107+
for _, tc := range tt {
108+
t.Run(tc.name, func(t *testing.T) {
109+
execT := execTestCmdFlags{
110+
t: t,
111+
cmd: deleteAllMembersCmd,
112+
flagsMap: tc.flagsMap,
113+
}
114+
stdout, _ := execT.executeCommand()
115+
assertOutContains(t, stdout, tc.expectOut)
116+
})
117+
}
118+
}

cmd/flags_definers.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,13 @@ func validateFromGroupAndProjectFlags(cmd *cobra.Command) error {
267267
return nil
268268
}
269269

270+
func validateFromProjectFlag(cmd *cobra.Command) error {
271+
if getFlagString(cmd, "from-project") == "" {
272+
return newSetAtLeastOneFlagError("from-project")
273+
}
274+
return nil
275+
}
276+
270277
func validateAccessLevelFlag(cmd *cobra.Command) error {
271278
return validateFlagIntValue([]int{10, 20, 30, 40, 50},
272279
cmd, "access-level")

docs/gitlabctl_delete.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Delete a Gitlab resource
2121
### SEE ALSO
2222

2323
* [gitlabctl](gitlabctl.md) - Gitlab command-line interface
24+
* [gitlabctl delete all-members](gitlabctl_delete_all-members.md) - Delete all members(except creator) of a project
2425
* [gitlabctl delete branch](gitlabctl_delete_branch.md) - Delete a project branch
2526
* [gitlabctl delete group](gitlabctl_delete_group.md) - Delete a Gitlab group by specifying the id or group path
2627
* [gitlabctl delete member](gitlabctl_delete_member.md) - Delete a member by specifying the member name as the first argument
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
## gitlabctl delete all-members
2+
3+
Delete all members(except creator) of a project
4+
5+
### Synopsis
6+
7+
Delete all members(except creator) of a project
8+
9+
```
10+
gitlabctl delete all-members [flags]
11+
```
12+
13+
### Examples
14+
15+
```
16+
# remove all members(except creator) from a project
17+
gitlabctl delete all-members --from-project Group1/Project1
18+
```
19+
20+
### Options
21+
22+
```
23+
-P, --from-project string Use a project as the target namespace when performing the command
24+
-h, --help help for all-members
25+
```
26+
27+
### Options inherited from parent commands
28+
29+
```
30+
--config string config file (default is $HOME/.gitlabctl.yaml)
31+
```
32+
33+
### SEE ALSO
34+
35+
* [gitlabctl delete](gitlabctl_delete.md) - Delete a Gitlab resource
36+

0 commit comments

Comments
 (0)