Diff
1diff --git a/server/cmd/admin.go b/server/cmd/admin.go
2new file mode 100644
3index 0000000000000000000000000000000000000000..687117edfcb27e81555c87c100a795d3eb6f67a5
4--- /dev/null
5+++ b/server/cmd/admin.go
6@@ -0,0 +1,88 @@
7+package cmd
8+
9+import (
10+ "strings"
11+
12+ "github.com/charmbracelet/soft-serve/server/backend"
13+ "github.com/spf13/cobra"
14+)
15+
16+func adminCommand() *cobra.Command {
17+ cmd := &cobra.Command{
18+ Use: "admin",
19+ Aliases: []string{"admins"},
20+ Short: "Manage admins",
21+ }
22+
23+ cmd.AddCommand(
24+ adminAddCommand(),
25+ adminRemoveCommand(),
26+ adminListCommand(),
27+ )
28+
29+ return cmd
30+}
31+
32+func adminAddCommand() *cobra.Command {
33+ cmd := &cobra.Command{
34+ Use: "add AUTHORIZED_KEY",
35+ Short: "Add an admin",
36+ Args: cobra.MinimumNArgs(1),
37+ PersistentPreRunE: checkIfAdmin,
38+ RunE: func(cmd *cobra.Command, args []string) error {
39+ cfg, _ := fromContext(cmd)
40+ pk, c, err := backend.ParseAuthorizedKey(strings.Join(args, " "))
41+ if err != nil {
42+ return err
43+ }
44+
45+ return cfg.Backend.AddAdmin(pk, c)
46+ },
47+ }
48+
49+ return cmd
50+}
51+
52+func adminRemoveCommand() *cobra.Command {
53+ cmd := &cobra.Command{
54+ Use: "remove AUTHORIZED_KEY",
55+ Args: cobra.MinimumNArgs(1),
56+ Short: "Remove an admin",
57+ PersistentPreRunE: checkIfAdmin,
58+ RunE: func(cmd *cobra.Command, args []string) error {
59+ cfg, _ := fromContext(cmd)
60+ pk, _, err := backend.ParseAuthorizedKey(strings.Join(args, " "))
61+ if err != nil {
62+ return err
63+ }
64+
65+ return cfg.Backend.RemoveAdmin(pk)
66+ },
67+ }
68+
69+ return cmd
70+}
71+
72+func adminListCommand() *cobra.Command {
73+ cmd := &cobra.Command{
74+ Use: "list",
75+ Args: cobra.NoArgs,
76+ Short: "List admins",
77+ PersistentPreRunE: checkIfAdmin,
78+ RunE: func(cmd *cobra.Command, _ []string) error {
79+ cfg, _ := fromContext(cmd)
80+ admins, err := cfg.Backend.Admins()
81+ if err != nil {
82+ return err
83+ }
84+
85+ for _, admin := range admins {
86+ cmd.Println(admin)
87+ }
88+
89+ return nil
90+ },
91+ }
92+
93+ return cmd
94+}
95diff --git a/server/cmd/cmd.go b/server/cmd/cmd.go
96index 60b0ab1cb2d8ec7c7b34d4629d98d90b28c5ce85..4f474c97261ddd4e5be5ce030ecd165d9f869b4c 100644
97--- a/server/cmd/cmd.go
98+++ b/server/cmd/cmd.go
99@@ -46,7 +46,9 @@ func rootCommand() *cobra.Command {
100 // TODO: use command usage template to include hostname and port
101 rootCmd.CompletionOptions.DisableDefaultCmd = true
102 rootCmd.AddCommand(
103+ adminCommand(),
104 branchCommand(),
105+ collabCommand(),
106 createCommand(),
107 deleteCommand(),
108 descriptionCommand(),
109diff --git a/server/cmd/collab.go b/server/cmd/collab.go
110new file mode 100644
111index 0000000000000000000000000000000000000000..15cdd0b1792d7e3942a78d97b8758dd82e966963
112--- /dev/null
113+++ b/server/cmd/collab.go
114@@ -0,0 +1,91 @@
115+package cmd
116+
117+import (
118+ "strings"
119+
120+ "github.com/charmbracelet/soft-serve/server/backend"
121+ "github.com/spf13/cobra"
122+)
123+
124+func collabCommand() *cobra.Command {
125+ cmd := &cobra.Command{
126+ Use: "collab",
127+ Aliases: []string{"collaborator", "collaborators"},
128+ Short: "Manage collaborators",
129+ }
130+
131+ cmd.AddCommand(
132+ collabAddCommand(),
133+ collabRemoveCommand(),
134+ collabListCommand(),
135+ )
136+
137+ return cmd
138+}
139+
140+func collabAddCommand() *cobra.Command {
141+ cmd := &cobra.Command{
142+ Use: "add REPOSITORY AUTHORIZED_KEY",
143+ Short: "Add a collaborator to a repo",
144+ Args: cobra.MinimumNArgs(2),
145+ PersistentPreRunE: checkIfAdmin,
146+ RunE: func(cmd *cobra.Command, args []string) error {
147+ cfg, _ := fromContext(cmd)
148+ repo := args[0]
149+ pk, c, err := backend.ParseAuthorizedKey(strings.Join(args[1:], " "))
150+ if err != nil {
151+ return err
152+ }
153+
154+ return cfg.Backend.AddCollaborator(pk, c, repo)
155+ },
156+ }
157+
158+ return cmd
159+}
160+
161+func collabRemoveCommand() *cobra.Command {
162+ cmd := &cobra.Command{
163+ Use: "remove REPOSITORY AUTHORIZED_KEY",
164+ Args: cobra.MinimumNArgs(2),
165+ Short: "Remove a collaborator from a repo",
166+ PersistentPreRunE: checkIfAdmin,
167+ RunE: func(cmd *cobra.Command, args []string) error {
168+ cfg, _ := fromContext(cmd)
169+ repo := args[0]
170+ pk, _, err := backend.ParseAuthorizedKey(strings.Join(args[1:], " "))
171+ if err != nil {
172+ return err
173+ }
174+
175+ return cfg.Backend.RemoveCollaborator(pk, repo)
176+ },
177+ }
178+
179+ return cmd
180+}
181+
182+func collabListCommand() *cobra.Command {
183+ cmd := &cobra.Command{
184+ Use: "list REPOSITORY",
185+ Short: "List collaborators for a repo",
186+ Args: cobra.ExactArgs(1),
187+ PersistentPreRunE: checkIfCollab,
188+ RunE: func(cmd *cobra.Command, args []string) error {
189+ cfg, _ := fromContext(cmd)
190+ repo := args[0]
191+ collabs, err := cfg.Backend.Collaborators(repo)
192+ if err != nil {
193+ return err
194+ }
195+
196+ for _, c := range collabs {
197+ cmd.Println(c)
198+ }
199+
200+ return nil
201+ },
202+ }
203+
204+ return cmd
205+}