Skip to content

Commit

Permalink
Merge pull request cli#3924 from cli/rest-org-repo-bug
Browse files Browse the repository at this point in the history
fix repo create in org with license/ignore
  • Loading branch information
Nate Smith authored Jun 30, 2021
2 parents 717c91c + 589b695 commit a6710ec
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 13 deletions.
1 change: 1 addition & 0 deletions pkg/cmd/factory/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ func NewHTTPClient(io *iostreams.IOStreams, cfg configGetter, appVersion string,
opts = append(opts,
api.AddHeaderFunc("Accept", func(req *http.Request) (string, error) {
accept := "application/vnd.github.merge-info-preview+json" // PullRequest.mergeStateStatus
accept += ", application/vnd.github.nebula-preview" // visibility when RESTing repos into an org
if ghinstance.IsEnterprise(getHost(req)) {
accept += ", application/vnd.github.antiope-preview" // Commit.statusCheckRollup
accept += ", application/vnd.github.shadow-cat-preview" // PullRequest.isDraft
Expand Down
10 changes: 5 additions & 5 deletions pkg/cmd/factory/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestNewHTTPClient(t *testing.T) {
wantHeader: map[string]string{
"authorization": "token MYTOKEN",
"user-agent": "GitHub CLI v1.2.3",
"accept": "application/vnd.github.merge-info-preview+json",
"accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview",
},
wantStderr: "",
},
Expand Down Expand Up @@ -69,7 +69,7 @@ func TestNewHTTPClient(t *testing.T) {
wantHeader: map[string]string{
"authorization": "",
"user-agent": "GitHub CLI v1.2.3",
"accept": "application/vnd.github.merge-info-preview+json",
"accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview",
},
wantStderr: "",
},
Expand All @@ -85,14 +85,14 @@ func TestNewHTTPClient(t *testing.T) {
wantHeader: map[string]string{
"authorization": "token MYTOKEN",
"user-agent": "GitHub CLI v1.2.3",
"accept": "application/vnd.github.merge-info-preview+json",
"accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview",
},
wantStderr: heredoc.Doc(`
* Request at <time>
* Request to http://<host>:<port>
> GET / HTTP/1.1
> Host: github.com
> Accept: application/vnd.github.merge-info-preview+json
> Accept: application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview
> Authorization: token ████████████████████
> User-Agent: GitHub CLI v1.2.3
Expand All @@ -113,7 +113,7 @@ func TestNewHTTPClient(t *testing.T) {
wantHeader: map[string]string{
"authorization": "token GHETOKEN",
"user-agent": "GitHub CLI v1.2.3",
"accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.antiope-preview, application/vnd.github.shadow-cat-preview",
"accept": "application/vnd.github.merge-info-preview+json, application/vnd.github.nebula-preview, application/vnd.github.antiope-preview, application/vnd.github.shadow-cat-preview",
},
wantStderr: "",
},
Expand Down
97 changes: 93 additions & 4 deletions pkg/cmd/repo/create/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,8 @@ func TestRepoCreate_WithGitIgnore(t *testing.T) {
if repoName := reqBody.Name; repoName != "REPO" {
t.Errorf("expected %q, got %q", "REPO", repoName)
}
if repoVisibility := reqBody.Visibility; repoVisibility != "PRIVATE" {
t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
if repoVisibility := reqBody.Visibility; repoVisibility != "private" {
t.Errorf("expected %q, got %q", "private", repoVisibility)
}
if ownerId := reqBody.OwnerId; ownerId != "OWNERID" {
t.Errorf("expected %q, got %q", "OWNERID", ownerId)
Expand Down Expand Up @@ -721,8 +721,97 @@ func TestRepoCreate_WithBothGitIgnoreLicense(t *testing.T) {
if repoName := reqBody.Name; repoName != "REPO" {
t.Errorf("expected %q, got %q", "REPO", repoName)
}
if repoVisibility := reqBody.Visibility; repoVisibility != "PRIVATE" {
t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
if repoVisibility := reqBody.Visibility; repoVisibility != "private" {
t.Errorf("expected %q, got %q", "private", repoVisibility)
}
if ownerId := reqBody.OwnerId; ownerId != "OWNERID" {
t.Errorf("expected %q, got %q", "OWNERID", ownerId)
}
}

func TestRepoCreate_WithGitIgnore_Org(t *testing.T) {
cs, cmdTeardown := run.Stub()
defer cmdTeardown(t)

cs.Register(`git remote add -f origin https://github\.com/OWNER/REPO\.git`, 0, "")
cs.Register(`git rev-parse --show-toplevel`, 0, "")

as, surveyTearDown := prompt.InitAskStubber()
defer surveyTearDown()

as.Stub([]*prompt.QuestionStub{
{
Name: "repoVisibility",
Value: "PRIVATE",
},
})

as.Stub([]*prompt.QuestionStub{
{
Name: "addGitIgnore",
Value: true,
},
})

as.Stub([]*prompt.QuestionStub{
{
Name: "chooseGitIgnore",
Value: "Go",
},
})

as.Stub([]*prompt.QuestionStub{
{
Name: "addLicense",
Value: false,
},
})

as.Stub([]*prompt.QuestionStub{
{
Name: "confirmSubmit",
Value: true,
},
})

reg := &httpmock.Registry{}
reg.Register(
httpmock.REST("GET", "users/OWNER"),
httpmock.StringResponse(`{ "node_id": "OWNERID", "type":"Organization" }`))
reg.Register(
httpmock.REST("GET", "gitignore/templates"),
httpmock.StringResponse(`["Actionscript","Android","AppceleratorTitanium","Autotools","Bancha","C","C++","Go"]`))
reg.Register(
httpmock.REST("POST", "orgs/OWNER/repos"),
httpmock.StringResponse(`{"name":"REPO", "owner":{"login": "OWNER"}, "html_url":"https://github.com/OWNER/REPO"}`))
httpClient := &http.Client{Transport: reg}

output, err := runCommand(httpClient, "OWNER/REPO", true)
if err != nil {
t.Errorf("error running command `repo create`: %v", err)
}

assert.Equal(t, "", output.String())
assert.Equal(t, "✓ Created repository OWNER/REPO on GitHub\n✓ Added remote https://github.com/OWNER/REPO.git\n", output.Stderr())

var reqBody struct {
Name string
Visibility string
OwnerId string
LicenseTemplate string
}

if len(reg.Requests) != 3 {
t.Fatalf("expected 3 HTTP request, got %d", len(reg.Requests))
}

bodyBytes, _ := ioutil.ReadAll(reg.Requests[2].Body)
_ = json.Unmarshal(bodyBytes, &reqBody)
if repoName := reqBody.Name; repoName != "REPO" {
t.Errorf("expected %q, got %q", "REPO", repoName)
}
if repoVisibility := reqBody.Visibility; repoVisibility != "private" {
t.Errorf("expected %q, got %q", "private", repoVisibility)
}
if ownerId := reqBody.OwnerId; ownerId != "OWNERID" {
t.Errorf("expected %q, got %q", "OWNERID", ownerId)
Expand Down
22 changes: 18 additions & 4 deletions pkg/cmd/repo/create/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"strings"

"github.com/cli/cli/api"
)
Expand Down Expand Up @@ -38,6 +39,9 @@ type repoTemplateInput struct {
func repoCreate(client *http.Client, hostname string, input repoCreateInput, templateRepositoryID string) (*api.Repository, error) {
apiClient := api.NewClientFromHTTP(client)

ownerName := input.OwnerID
isOrg := false

if input.TeamID != "" {
orgID, teamID, err := resolveOrganizationTeam(apiClient, hostname, input.OwnerID, input.TeamID)
if err != nil {
Expand All @@ -46,7 +50,9 @@ func repoCreate(client *http.Client, hostname string, input repoCreateInput, tem
input.TeamID = teamID
input.OwnerID = orgID
} else if input.OwnerID != "" {
orgID, err := resolveOrganization(apiClient, hostname, input.OwnerID)
var orgID string
var err error
orgID, isOrg, err = resolveOrganization(apiClient, hostname, input.OwnerID)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -109,12 +115,19 @@ func repoCreate(client *http.Client, hostname string, input repoCreateInput, tem
}

if input.GitIgnoreTemplate != "" || input.LicenseTemplate != "" {
input.Visibility = strings.ToLower(input.Visibility)
body := &bytes.Buffer{}
enc := json.NewEncoder(body)
if err := enc.Encode(input); err != nil {
return nil, err
}
repo, err := api.CreateRepoTransformToV4(apiClient, hostname, "POST", "user/repos", body)

path := "user/repos"
if isOrg {
path = fmt.Sprintf("orgs/%s/repos", ownerName)
}

repo, err := api.CreateRepoTransformToV4(apiClient, hostname, "POST", path, body)
if err != nil {
return nil, err
}
Expand All @@ -141,12 +154,13 @@ func repoCreate(client *http.Client, hostname string, input repoCreateInput, tem
}

// using API v3 here because the equivalent in GraphQL needs `read:org` scope
func resolveOrganization(client *api.Client, hostname, orgName string) (string, error) {
func resolveOrganization(client *api.Client, hostname, orgName string) (string, bool, error) {
var response struct {
NodeID string `json:"node_id"`
Type string
}
err := client.REST(hostname, "GET", fmt.Sprintf("users/%s", orgName), nil, &response)
return response.NodeID, err
return response.NodeID, response.Type == "Organization", err
}

// using API v3 here because the equivalent in GraphQL needs `read:org` scope
Expand Down

0 comments on commit a6710ec

Please sign in to comment.