github.com/secman-team/gh-api@v1.8.2/pkg/cmd/repo/create/create_test.go (about)

     1  package create
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"testing"
     9  
    10  	"github.com/MakeNowJust/heredoc"
    11  	"github.com/secman-team/gh-api/core/config"
    12  	"github.com/secman-team/gh-api/core/run"
    13  	"github.com/secman-team/gh-api/pkg/cmdutil"
    14  	"github.com/secman-team/gh-api/pkg/httpmock"
    15  	"github.com/secman-team/gh-api/pkg/iostreams"
    16  	"github.com/secman-team/gh-api/pkg/prompt"
    17  	"github.com/secman-team/gh-api/test"
    18  	"github.com/google/shlex"
    19  	"github.com/stretchr/testify/assert"
    20  )
    21  
    22  func runCommand(httpClient *http.Client, cli string, isTTY bool) (*test.CmdOut, error) {
    23  	io, _, stdout, stderr := iostreams.Test()
    24  	io.SetStdoutTTY(isTTY)
    25  	io.SetStdinTTY(isTTY)
    26  	fac := &cmdutil.Factory{
    27  		IOStreams: io,
    28  		HttpClient: func() (*http.Client, error) {
    29  			return httpClient, nil
    30  		},
    31  		Config: func() (config.Config, error) {
    32  			return config.NewBlankConfig(), nil
    33  		},
    34  	}
    35  
    36  	cmd := NewCmdCreate(fac, nil)
    37  
    38  	// TODO STUPID HACK
    39  	// cobra aggressively adds help to all commands. since we're not running through the root command
    40  	// (which manages help when running for real) and since create has a '-h' flag (for homepage),
    41  	// cobra blows up when it tried to add a help flag and -h is already in use. This hack adds a
    42  	// dummy help flag with a random shorthand to get around this.
    43  	cmd.Flags().BoolP("help", "x", false, "")
    44  
    45  	argv, err := shlex.Split(cli)
    46  	cmd.SetArgs(argv)
    47  
    48  	cmd.SetIn(&bytes.Buffer{})
    49  	cmd.SetOut(&bytes.Buffer{})
    50  	cmd.SetErr(&bytes.Buffer{})
    51  
    52  	if err != nil {
    53  		panic(err)
    54  	}
    55  
    56  	_, err = cmd.ExecuteC()
    57  
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	return &test.CmdOut{
    63  		OutBuf: stdout,
    64  		ErrBuf: stderr}, nil
    65  }
    66  
    67  func TestRepoCreate(t *testing.T) {
    68  	reg := &httpmock.Registry{}
    69  	reg.Register(
    70  		httpmock.GraphQL(`mutation RepositoryCreate\b`),
    71  		httpmock.StringResponse(`
    72  		{ "data": { "createRepository": {
    73  			"repository": {
    74  				"id": "REPOID",
    75  				"url": "https://github.com/OWNER/REPO",
    76  				"name": "REPO",
    77  				"owner": {
    78  					"login": "OWNER"
    79  				}
    80  			}
    81  		} } }`))
    82  
    83  	httpClient := &http.Client{Transport: reg}
    84  
    85  	cs, cmdTeardown := run.Stub()
    86  	defer cmdTeardown(t)
    87  
    88  	cs.Register(`git remote add -f origin https://github\.com/OWNER/REPO\.git`, 0, "")
    89  	cs.Register(`git rev-parse --show-toplevel`, 0, "")
    90  
    91  	as, surveyTearDown := prompt.InitAskStubber()
    92  	defer surveyTearDown()
    93  
    94  	as.Stub([]*prompt.QuestionStub{
    95  		{
    96  			Name:  "repoVisibility",
    97  			Value: "PRIVATE",
    98  		},
    99  	})
   100  	as.Stub([]*prompt.QuestionStub{
   101  		{
   102  			Name:  "confirmSubmit",
   103  			Value: true,
   104  		},
   105  	})
   106  
   107  	output, err := runCommand(httpClient, "REPO", true)
   108  	if err != nil {
   109  		t.Errorf("error running command `repo create`: %v", err)
   110  	}
   111  
   112  	assert.Equal(t, "", output.String())
   113  	assert.Equal(t, "✓ Created repository OWNER/REPO on GitHub\n✓ Added remote https://github.com/OWNER/REPO.git\n", output.Stderr())
   114  
   115  	var reqBody struct {
   116  		Query     string
   117  		Variables struct {
   118  			Input map[string]interface{}
   119  		}
   120  	}
   121  
   122  	if len(reg.Requests) != 1 {
   123  		t.Fatalf("expected 1 HTTP request, got %d", len(reg.Requests))
   124  	}
   125  
   126  	bodyBytes, _ := ioutil.ReadAll(reg.Requests[0].Body)
   127  	_ = json.Unmarshal(bodyBytes, &reqBody)
   128  	if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
   129  		t.Errorf("expected %q, got %q", "REPO", repoName)
   130  	}
   131  	if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
   132  		t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
   133  	}
   134  	if _, ownerSet := reqBody.Variables.Input["ownerId"]; ownerSet {
   135  		t.Error("expected ownerId not to be set")
   136  	}
   137  }
   138  
   139  func TestRepoCreate_outsideGitWorkDir(t *testing.T) {
   140  	reg := &httpmock.Registry{}
   141  	reg.Register(
   142  		httpmock.GraphQL(`mutation RepositoryCreate\b`),
   143  		httpmock.StringResponse(`
   144  		{ "data": { "createRepository": {
   145  			"repository": {
   146  				"id": "REPOID",
   147  				"url": "https://github.com/OWNER/REPO",
   148  				"name": "REPO",
   149  				"owner": {
   150  					"login": "OWNER"
   151  				}
   152  			}
   153  		} } }`))
   154  
   155  	httpClient := &http.Client{Transport: reg}
   156  
   157  	cs, cmdTeardown := run.Stub()
   158  	defer cmdTeardown(t)
   159  
   160  	cs.Register(`git rev-parse --show-toplevel`, 1, "")
   161  	cs.Register(`git init REPO`, 0, "")
   162  	cs.Register(`git -C REPO remote add origin https://github\.com/OWNER/REPO\.git`, 0, "")
   163  
   164  	output, err := runCommand(httpClient, "REPO --private --confirm", false)
   165  	if err != nil {
   166  		t.Errorf("error running command `repo create`: %v", err)
   167  	}
   168  
   169  	assert.Equal(t, "https://github.com/OWNER/REPO\n", output.String())
   170  	assert.Equal(t, "", output.Stderr())
   171  
   172  	var reqBody struct {
   173  		Query     string
   174  		Variables struct {
   175  			Input map[string]interface{}
   176  		}
   177  	}
   178  
   179  	if len(reg.Requests) != 1 {
   180  		t.Fatalf("expected 1 HTTP request, got %d", len(reg.Requests))
   181  	}
   182  
   183  	bodyBytes, _ := ioutil.ReadAll(reg.Requests[0].Body)
   184  	_ = json.Unmarshal(bodyBytes, &reqBody)
   185  	if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
   186  		t.Errorf("expected %q, got %q", "REPO", repoName)
   187  	}
   188  	if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
   189  		t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
   190  	}
   191  	if _, ownerSet := reqBody.Variables.Input["ownerId"]; ownerSet {
   192  		t.Error("expected ownerId not to be set")
   193  	}
   194  }
   195  
   196  func TestRepoCreate_org(t *testing.T) {
   197  	reg := &httpmock.Registry{}
   198  	reg.Register(
   199  		httpmock.REST("GET", "users/ORG"),
   200  		httpmock.StringResponse(`
   201  		{ "node_id": "ORGID"
   202  		}`))
   203  	reg.Register(
   204  		httpmock.GraphQL(`mutation RepositoryCreate\b`),
   205  		httpmock.StringResponse(`
   206  		{ "data": { "createRepository": {
   207  			"repository": {
   208  				"id": "REPOID",
   209  				"url": "https://github.com/ORG/REPO",
   210  				"name": "REPO",
   211  				"owner": {
   212  					"login": "ORG"
   213  				}
   214  			}
   215  		} } }`))
   216  	httpClient := &http.Client{Transport: reg}
   217  
   218  	cs, cmdTeardown := run.Stub()
   219  	defer cmdTeardown(t)
   220  
   221  	cs.Register(`git remote add -f origin https://github\.com/ORG/REPO\.git`, 0, "")
   222  	cs.Register(`git rev-parse --show-toplevel`, 0, "")
   223  
   224  	as, surveyTearDown := prompt.InitAskStubber()
   225  	defer surveyTearDown()
   226  
   227  	as.Stub([]*prompt.QuestionStub{
   228  		{
   229  			Name:  "repoVisibility",
   230  			Value: "PRIVATE",
   231  		},
   232  	})
   233  	as.Stub([]*prompt.QuestionStub{
   234  		{
   235  			Name:  "confirmSubmit",
   236  			Value: true,
   237  		},
   238  	})
   239  
   240  	output, err := runCommand(httpClient, "ORG/REPO", true)
   241  	if err != nil {
   242  		t.Errorf("error running command `repo create`: %v", err)
   243  	}
   244  
   245  	assert.Equal(t, "", output.String())
   246  	assert.Equal(t, "✓ Created repository ORG/REPO on GitHub\n✓ Added remote https://github.com/ORG/REPO.git\n", output.Stderr())
   247  
   248  	var reqBody struct {
   249  		Query     string
   250  		Variables struct {
   251  			Input map[string]interface{}
   252  		}
   253  	}
   254  
   255  	if len(reg.Requests) != 2 {
   256  		t.Fatalf("expected 2 HTTP requests, got %d", len(reg.Requests))
   257  	}
   258  
   259  	assert.Equal(t, "/users/ORG", reg.Requests[0].URL.Path)
   260  
   261  	bodyBytes, _ := ioutil.ReadAll(reg.Requests[1].Body)
   262  	_ = json.Unmarshal(bodyBytes, &reqBody)
   263  	if orgID := reqBody.Variables.Input["ownerId"].(string); orgID != "ORGID" {
   264  		t.Errorf("expected %q, got %q", "ORGID", orgID)
   265  	}
   266  	if _, teamSet := reqBody.Variables.Input["teamId"]; teamSet {
   267  		t.Error("expected teamId not to be set")
   268  	}
   269  }
   270  
   271  func TestRepoCreate_orgWithTeam(t *testing.T) {
   272  	reg := &httpmock.Registry{}
   273  	reg.Register(
   274  		httpmock.REST("GET", "orgs/ORG/teams/monkeys"),
   275  		httpmock.StringResponse(`
   276  		{ "node_id": "TEAMID",
   277  			"organization": { "node_id": "ORGID" }
   278  		}`))
   279  	reg.Register(
   280  		httpmock.GraphQL(`mutation RepositoryCreate\b`),
   281  		httpmock.StringResponse(`
   282  		{ "data": { "createRepository": {
   283  			"repository": {
   284  				"id": "REPOID",
   285  				"url": "https://github.com/ORG/REPO",
   286  				"name": "REPO",
   287  				"owner": {
   288  					"login": "ORG"
   289  				}
   290  			}
   291  		} } }`))
   292  	httpClient := &http.Client{Transport: reg}
   293  
   294  	cs, cmdTeardown := run.Stub()
   295  	defer cmdTeardown(t)
   296  
   297  	cs.Register(`git remote add -f origin https://github\.com/ORG/REPO\.git`, 0, "")
   298  	cs.Register(`git rev-parse --show-toplevel`, 0, "")
   299  
   300  	as, surveyTearDown := prompt.InitAskStubber()
   301  	defer surveyTearDown()
   302  
   303  	as.Stub([]*prompt.QuestionStub{
   304  		{
   305  			Name:  "repoVisibility",
   306  			Value: "PRIVATE",
   307  		},
   308  	})
   309  	as.Stub([]*prompt.QuestionStub{
   310  		{
   311  			Name:  "confirmSubmit",
   312  			Value: true,
   313  		},
   314  	})
   315  
   316  	output, err := runCommand(httpClient, "ORG/REPO --team monkeys", true)
   317  	if err != nil {
   318  		t.Errorf("error running command `repo create`: %v", err)
   319  	}
   320  
   321  	assert.Equal(t, "", output.String())
   322  	assert.Equal(t, "✓ Created repository ORG/REPO on GitHub\n✓ Added remote https://github.com/ORG/REPO.git\n", output.Stderr())
   323  
   324  	var reqBody struct {
   325  		Query     string
   326  		Variables struct {
   327  			Input map[string]interface{}
   328  		}
   329  	}
   330  
   331  	if len(reg.Requests) != 2 {
   332  		t.Fatalf("expected 2 HTTP requests, got %d", len(reg.Requests))
   333  	}
   334  
   335  	assert.Equal(t, "/orgs/ORG/teams/monkeys", reg.Requests[0].URL.Path)
   336  
   337  	bodyBytes, _ := ioutil.ReadAll(reg.Requests[1].Body)
   338  	_ = json.Unmarshal(bodyBytes, &reqBody)
   339  	if orgID := reqBody.Variables.Input["ownerId"].(string); orgID != "ORGID" {
   340  		t.Errorf("expected %q, got %q", "ORGID", orgID)
   341  	}
   342  	if teamID := reqBody.Variables.Input["teamId"].(string); teamID != "TEAMID" {
   343  		t.Errorf("expected %q, got %q", "TEAMID", teamID)
   344  	}
   345  }
   346  
   347  func TestRepoCreate_template(t *testing.T) {
   348  	reg := &httpmock.Registry{}
   349  	defer reg.Verify(t)
   350  	reg.Register(
   351  		httpmock.GraphQL(`mutation CloneTemplateRepository\b`),
   352  		httpmock.StringResponse(`
   353  		{ "data": { "cloneTemplateRepository": {
   354  			"repository": {
   355  				"id": "REPOID",
   356  				"name": "REPO",
   357  				"owner": {
   358  					"login": "OWNER"
   359  				},
   360  				"url": "https://github.com/OWNER/REPO"
   361  			}
   362  		} } }`))
   363  
   364  	reg.StubRepoInfoResponse("OWNER", "REPO", "main")
   365  
   366  	reg.Register(
   367  		httpmock.GraphQL(`query UserCurrent\b`),
   368  		httpmock.StringResponse(`{"data":{"viewer":{"ID":"OWNERID"}}}`))
   369  
   370  	httpClient := &http.Client{Transport: reg}
   371  
   372  	cs, cmdTeardown := run.Stub()
   373  	defer cmdTeardown(t)
   374  
   375  	cs.Register(`git rev-parse --show-toplevel`, 1, "")
   376  	cs.Register(`git init REPO`, 0, "")
   377  	cs.Register(`git -C REPO remote add`, 0, "")
   378  	cs.Register(`git -C REPO fetch origin \+refs/heads/main:refs/remotes/origin/main`, 0, "")
   379  	cs.Register(`git -C REPO checkout main`, 0, "")
   380  
   381  	_, surveyTearDown := prompt.InitAskStubber()
   382  	defer surveyTearDown()
   383  
   384  	output, err := runCommand(httpClient, "REPO -y --private --template='OWNER/REPO'", true)
   385  	if err != nil {
   386  		t.Errorf("error running command `repo create`: %v", err)
   387  		return
   388  	}
   389  
   390  	assert.Equal(t, "", output.String())
   391  	assert.Equal(t, heredoc.Doc(`
   392  		✓ Created repository OWNER/REPO on GitHub
   393  		✓ Initialized repository in "REPO"
   394  	`), output.Stderr())
   395  
   396  	var reqBody struct {
   397  		Query     string
   398  		Variables struct {
   399  			Input map[string]interface{}
   400  		}
   401  	}
   402  
   403  	bodyBytes, _ := ioutil.ReadAll(reg.Requests[2].Body)
   404  	_ = json.Unmarshal(bodyBytes, &reqBody)
   405  	if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
   406  		t.Errorf("expected %q, got %q", "REPO", repoName)
   407  	}
   408  	if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
   409  		t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
   410  	}
   411  	if ownerId := reqBody.Variables.Input["ownerId"].(string); ownerId != "OWNERID" {
   412  		t.Errorf("expected %q, got %q", "OWNERID", ownerId)
   413  	}
   414  }
   415  
   416  func TestRepoCreate_withoutNameArg(t *testing.T) {
   417  	reg := &httpmock.Registry{}
   418  	reg.Register(
   419  		httpmock.REST("GET", "users/OWNER"),
   420  		httpmock.StringResponse(`{ "node_id": "OWNERID" }`))
   421  	reg.Register(
   422  		httpmock.GraphQL(`mutation RepositoryCreate\b`),
   423  		httpmock.StringResponse(`
   424  		{ "data": { "createRepository": {
   425  			"repository": {
   426  				"id": "REPOID",
   427  				"url": "https://github.com/OWNER/REPO",
   428  				"name": "REPO",
   429  				"owner": {
   430  					"login": "OWNER"
   431  				}
   432  			}
   433  		} } }`))
   434  	httpClient := &http.Client{Transport: reg}
   435  
   436  	cs, cmdTeardown := run.Stub()
   437  	defer cmdTeardown(t)
   438  
   439  	cs.Register(`git remote add -f origin https://github\.com/OWNER/REPO\.git`, 0, "")
   440  	cs.Register(`git rev-parse --show-toplevel`, 0, "")
   441  
   442  	as, surveyTearDown := prompt.InitAskStubber()
   443  	defer surveyTearDown()
   444  
   445  	as.Stub([]*prompt.QuestionStub{
   446  		{
   447  			Name:  "repoName",
   448  			Value: "OWNER/REPO",
   449  		},
   450  		{
   451  			Name:  "repoDescription",
   452  			Value: "DESCRIPTION",
   453  		},
   454  		{
   455  			Name:  "repoVisibility",
   456  			Value: "PRIVATE",
   457  		},
   458  	})
   459  	as.Stub([]*prompt.QuestionStub{
   460  		{
   461  			Name:  "confirmSubmit",
   462  			Value: true,
   463  		},
   464  	})
   465  
   466  	output, err := runCommand(httpClient, "", true)
   467  	if err != nil {
   468  		t.Errorf("error running command `repo create`: %v", err)
   469  	}
   470  
   471  	assert.Equal(t, "", output.String())
   472  	assert.Equal(t, "✓ Created repository OWNER/REPO on GitHub\n✓ Added remote https://github.com/OWNER/REPO.git\n", output.Stderr())
   473  
   474  	var reqBody struct {
   475  		Query     string
   476  		Variables struct {
   477  			Input map[string]interface{}
   478  		}
   479  	}
   480  
   481  	if len(reg.Requests) != 2 {
   482  		t.Fatalf("expected 2 HTTP request, got %d", len(reg.Requests))
   483  	}
   484  
   485  	bodyBytes, _ := ioutil.ReadAll(reg.Requests[1].Body)
   486  	_ = json.Unmarshal(bodyBytes, &reqBody)
   487  	if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
   488  		t.Errorf("expected %q, got %q", "REPO", repoName)
   489  	}
   490  	if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
   491  		t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
   492  	}
   493  	if ownerId := reqBody.Variables.Input["ownerId"].(string); ownerId != "OWNERID" {
   494  		t.Errorf("expected %q, got %q", "OWNERID", ownerId)
   495  	}
   496  }