X Tutup
Skip to content

Commit be09717

Browse files
committed
Add ability to repo create within an org
1 parent 8deb0d8 commit be09717

File tree

4 files changed

+196
-2
lines changed

4 files changed

+196
-2
lines changed

api/queries_org.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package api
2+
3+
import "fmt"
4+
5+
// using API v3 here because the equivalent in GraphQL needs `read:org` scope
6+
func resolveOrganization(client *Client, orgName string) (string, error) {
7+
var response struct {
8+
NodeID string `json:"node_id"`
9+
}
10+
err := client.REST("GET", fmt.Sprintf("users/%s", orgName), nil, &response)
11+
return response.NodeID, err
12+
}
13+
14+
// using API v3 here because the equivalent in GraphQL needs `read:org` scope
15+
func resolveOrganizationTeam(client *Client, orgName, teamSlug string) (string, string, error) {
16+
var response struct {
17+
NodeID string `json:"node_id"`
18+
Organization struct {
19+
NodeID string `json:"node_id"`
20+
}
21+
}
22+
err := client.REST("GET", fmt.Sprintf("orgs/%s/teams/%s", orgName, teamSlug), nil, &response)
23+
return response.Organization.NodeID, response.NodeID, err
24+
}

api/queries_repo.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ type RepoCreateInput struct {
225225
Homepage string `json:"homepage,omitempty"`
226226
Description string `json:"description,omitempty"`
227227

228+
OwnerID string `json:"ownerId,omitempty"`
229+
TeamID string `json:"teamId,omitempty"`
230+
228231
HasIssuesEnabled bool `json:"hasIssuesEnabled"`
229232
HasWikiEnabled bool `json:"hasWikiEnabled"`
230233
}
@@ -237,6 +240,21 @@ func RepoCreate(client *Client, input RepoCreateInput) (*Repository, error) {
237240
}
238241
}
239242

243+
if input.TeamID != "" {
244+
orgID, teamID, err := resolveOrganizationTeam(client, input.OwnerID, input.TeamID)
245+
if err != nil {
246+
return nil, err
247+
}
248+
input.TeamID = teamID
249+
input.OwnerID = orgID
250+
} else if input.OwnerID != "" {
251+
orgID, err := resolveOrganization(client, input.OwnerID)
252+
if err != nil {
253+
return nil, err
254+
}
255+
input.OwnerID = orgID
256+
}
257+
240258
variables := map[string]interface{}{
241259
"input": input,
242260
}

command/repo.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ func init() {
2020
repoCmd.AddCommand(repoCreateCmd)
2121
repoCreateCmd.Flags().StringP("description", "d", "", "Description of repository")
2222
repoCreateCmd.Flags().StringP("homepage", "h", "", "Repository home page URL")
23+
repoCreateCmd.Flags().StringP("team", "t", "", "The name of the organization team to be granted access")
2324
repoCreateCmd.Flags().Bool("enable-issues", true, "Enable issues in the new repository")
2425
repoCreateCmd.Flags().Bool("enable-wiki", true, "Enable wiki in the new repository")
2526
repoCreateCmd.Flags().Bool("public", false, "Make the new repository public")
@@ -49,8 +50,10 @@ To pass 'git clone' options, separate them with '--'.`,
4950
var repoCreateCmd = &cobra.Command{
5051
Use: "create [<name>]",
5152
Short: "Create a new repository",
52-
Long: `Create a new GitHub repository.`,
53-
RunE: repoCreate,
53+
Long: `Create a new GitHub repository.
54+
55+
Use the "ORG/NAME" syntax to create a repository within your organization.`,
56+
RunE: repoCreate,
5457
}
5558

5659
var repoViewCmd = &cobra.Command{
@@ -82,9 +85,20 @@ func repoClone(cmd *cobra.Command, args []string) error {
8285
func repoCreate(cmd *cobra.Command, args []string) error {
8386
projectDir, projectDirErr := git.ToplevelDir()
8487

88+
orgName := ""
89+
teamSlug, err := cmd.Flags().GetString("team")
90+
if err != nil {
91+
return err
92+
}
93+
8594
var name string
8695
if len(args) > 0 {
8796
name = args[0]
97+
if strings.Contains(name, "/") {
98+
newRepo := ghrepo.FromFullName(name)
99+
orgName = newRepo.RepoOwner()
100+
name = newRepo.RepoName()
101+
}
88102
} else {
89103
if projectDirErr != nil {
90104
return projectDirErr
@@ -122,6 +136,8 @@ func repoCreate(cmd *cobra.Command, args []string) error {
122136
input := api.RepoCreateInput{
123137
Name: name,
124138
Visibility: visibility,
139+
OwnerID: orgName,
140+
TeamID: teamSlug,
125141
Description: description,
126142
Homepage: homepage,
127143
HasIssuesEnabled: hasIssuesEnabled,

command/repo_test.go

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ func TestRepoCreate(t *testing.T) {
108108
}
109109
}
110110

111+
if len(http.Requests) != 1 {
112+
t.Fatalf("expected 1 HTTP request, got %d", len(http.Requests))
113+
}
114+
111115
bodyBytes, _ := ioutil.ReadAll(http.Requests[0].Body)
112116
json.Unmarshal(bodyBytes, &reqBody)
113117
if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
@@ -116,6 +120,138 @@ func TestRepoCreate(t *testing.T) {
116120
if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
117121
t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
118122
}
123+
if _, ownerSet := reqBody.Variables.Input["ownerId"]; ownerSet {
124+
t.Error("expected ownerId not to be set")
125+
}
126+
}
127+
128+
func TestRepoCreate_org(t *testing.T) {
129+
ctx := context.NewBlank()
130+
ctx.SetBranch("master")
131+
initContext = func() context.Context {
132+
return ctx
133+
}
134+
135+
http := initFakeHTTP()
136+
http.StubResponse(200, bytes.NewBufferString(`
137+
{ "node_id": "ORGID"
138+
}
139+
`))
140+
http.StubResponse(200, bytes.NewBufferString(`
141+
{ "data": { "createRepository": {
142+
"repository": {
143+
"id": "REPOID",
144+
"url": "https://github.com/ORG/REPO"
145+
}
146+
} } }
147+
`))
148+
149+
var seenCmd *exec.Cmd
150+
restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
151+
seenCmd = cmd
152+
return &outputStub{}
153+
})
154+
defer restoreCmd()
155+
156+
output, err := RunCommand(repoCreateCmd, "repo create ORG/REPO")
157+
if err != nil {
158+
t.Errorf("error running command `repo create`: %v", err)
159+
}
160+
161+
eq(t, output.String(), "https://github.com/ORG/REPO\n")
162+
eq(t, output.Stderr(), "")
163+
164+
if seenCmd == nil {
165+
t.Fatal("expected a command to run")
166+
}
167+
eq(t, strings.Join(seenCmd.Args, " "), "git remote add origin https://github.com/ORG/REPO.git")
168+
169+
var reqBody struct {
170+
Query string
171+
Variables struct {
172+
Input map[string]interface{}
173+
}
174+
}
175+
176+
if len(http.Requests) != 2 {
177+
t.Fatalf("expected 2 HTTP requests, got %d", len(http.Requests))
178+
}
179+
180+
eq(t, http.Requests[0].URL.Path, "/users/ORG")
181+
182+
bodyBytes, _ := ioutil.ReadAll(http.Requests[1].Body)
183+
json.Unmarshal(bodyBytes, &reqBody)
184+
if orgID := reqBody.Variables.Input["ownerId"].(string); orgID != "ORGID" {
185+
t.Errorf("expected %q, got %q", "ORGID", orgID)
186+
}
187+
if _, teamSet := reqBody.Variables.Input["teamId"]; teamSet {
188+
t.Error("expected teamId not to be set")
189+
}
190+
}
191+
192+
func TestRepoCreate_orgWithTeam(t *testing.T) {
193+
ctx := context.NewBlank()
194+
ctx.SetBranch("master")
195+
initContext = func() context.Context {
196+
return ctx
197+
}
198+
199+
http := initFakeHTTP()
200+
http.StubResponse(200, bytes.NewBufferString(`
201+
{ "node_id": "TEAMID",
202+
"organization": { "node_id": "ORGID" }
203+
}
204+
`))
205+
http.StubResponse(200, bytes.NewBufferString(`
206+
{ "data": { "createRepository": {
207+
"repository": {
208+
"id": "REPOID",
209+
"url": "https://github.com/ORG/REPO"
210+
}
211+
} } }
212+
`))
213+
214+
var seenCmd *exec.Cmd
215+
restoreCmd := utils.SetPrepareCmd(func(cmd *exec.Cmd) utils.Runnable {
216+
seenCmd = cmd
217+
return &outputStub{}
218+
})
219+
defer restoreCmd()
220+
221+
output, err := RunCommand(repoCreateCmd, "repo create ORG/REPO --team monkeys")
222+
if err != nil {
223+
t.Errorf("error running command `repo create`: %v", err)
224+
}
225+
226+
eq(t, output.String(), "https://github.com/ORG/REPO\n")
227+
eq(t, output.Stderr(), "")
228+
229+
if seenCmd == nil {
230+
t.Fatal("expected a command to run")
231+
}
232+
eq(t, strings.Join(seenCmd.Args, " "), "git remote add origin https://github.com/ORG/REPO.git")
233+
234+
var reqBody struct {
235+
Query string
236+
Variables struct {
237+
Input map[string]interface{}
238+
}
239+
}
240+
241+
if len(http.Requests) != 2 {
242+
t.Fatalf("expected 2 HTTP requests, got %d", len(http.Requests))
243+
}
244+
245+
eq(t, http.Requests[0].URL.Path, "/orgs/ORG/teams/monkeys")
246+
247+
bodyBytes, _ := ioutil.ReadAll(http.Requests[1].Body)
248+
json.Unmarshal(bodyBytes, &reqBody)
249+
if orgID := reqBody.Variables.Input["ownerId"].(string); orgID != "ORGID" {
250+
t.Errorf("expected %q, got %q", "ORGID", orgID)
251+
}
252+
if teamID := reqBody.Variables.Input["teamId"].(string); teamID != "TEAMID" {
253+
t.Errorf("expected %q, got %q", "TEAMID", teamID)
254+
}
119255
}
120256

121257
func TestRepoView(t *testing.T) {

0 commit comments

Comments
 (0)
X Tutup