Merge remote-tracking branch 'origin/trunk' into checks
This commit is contained in:
commit
eb132a1ae6
13 changed files with 276 additions and 49 deletions
3
.github/CONTRIBUTING.md
vendored
3
.github/CONTRIBUTING.md
vendored
|
|
@ -3,6 +3,8 @@
|
|||
[legal]: https://help.github.com/articles/github-terms-of-service/#6-contributions-under-repository-license
|
||||
[license]: ../LICENSE
|
||||
[code-of-conduct]: CODE-OF-CONDUCT.md
|
||||
[bug issues]: https://github.com/cli/cli/issues?q=is%3Aopen+is%3Aissue+label%3Abug
|
||||
[feature request issues]: https://github.com/cli/cli/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement
|
||||
|
||||
Hi! Thanks for your interest in contributing to the GitHub CLI!
|
||||
|
||||
|
|
@ -10,6 +12,7 @@ We accept pull requests for bug fixes and features where we've discussed the app
|
|||
|
||||
Please do:
|
||||
|
||||
* check existing issues to verify that the [bug][bug issues] or [feature request][feature request issues] has not already been submitted
|
||||
* open an issue if things aren't working as expected
|
||||
* open an issue to propose a significant change
|
||||
* open a pull request to fix a bug
|
||||
|
|
|
|||
23
README.md
23
README.md
|
|
@ -9,13 +9,9 @@ the terminal next to where you are already working with `git` and your code.
|
|||
|
||||
While in beta, GitHub CLI is available for repos hosted on GitHub.com only. It currently does not support repositories hosted on GitHub Enterprise Server or other hosting providers. We are planning on adding support for GitHub Enterprise Server after GitHub CLI is out of beta (likely towards the end of 2020), and we want to ensure that the API endpoints we use are more widely available for GHES versions that most GitHub customers are on.
|
||||
|
||||
## We need your feedback
|
||||
## We want your feedback
|
||||
|
||||
GitHub CLI is currently in its early development stages, and we're hoping to get feedback from people using it.
|
||||
|
||||
If you've installed and used `gh`, we'd love for you to take a short survey here (no more than five minutes): https://forms.gle/umxd3h31c7aMQFKG7
|
||||
|
||||
And if you spot bugs or have features that you'd really like to see in `gh`, please check out the [contributing page][]
|
||||
We'd love to hear your feedback about `gh`. If you spot bugs or have features that you'd really like to see in `gh`, please check out the [contributing page][].
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
@ -27,14 +23,14 @@ And if you spot bugs or have features that you'd really like to see in `gh`, ple
|
|||
|
||||
## Documentation
|
||||
|
||||
Read the [official docs](https://cli.github.com/manual/) for more information.
|
||||
Read the [official docs][] for more information.
|
||||
|
||||
## Comparison with hub
|
||||
|
||||
For many years, [hub][] was the unofficial GitHub CLI tool. `gh` is a new project that helps us explore
|
||||
what an official GitHub CLI tool can look like with a fundamentally different design. While both
|
||||
tools bring GitHub to the terminal, `hub` behaves as a proxy to `git`, and `gh` is a standalone
|
||||
tool. Check out our [more detailed explanation](/docs/gh-vs-hub.md) to learn more.
|
||||
tool. Check out our [more detailed explanation][gh-vs-hub] to learn more.
|
||||
|
||||
|
||||
<!-- this anchor is linked to from elsewhere, so avoid renaming it -->
|
||||
|
|
@ -128,7 +124,7 @@ Install and upgrade:
|
|||
Install and upgrade:
|
||||
|
||||
1. Download the `.rpm` file from the [releases page][];
|
||||
2. Install the downloaded file: `sudo yum localinstall gh_*_linux_amd64.rpm`
|
||||
2. Install the downloaded file: `sudo yum localinstall gh_*_linux_amd64.rpm`
|
||||
|
||||
### openSUSE/SUSE Linux
|
||||
|
||||
|
|
@ -139,7 +135,7 @@ Install and upgrade:
|
|||
|
||||
### Arch Linux
|
||||
|
||||
Arch Linux users can install from the [community repo](https://www.archlinux.org/packages/community/x86_64/github-cli/):
|
||||
Arch Linux users can install from the [community repo][arch linux repo]:
|
||||
|
||||
```bash
|
||||
pacman -S github-cli
|
||||
|
|
@ -159,11 +155,14 @@ Download packaged binaries from the [releases page][].
|
|||
|
||||
### Build from source
|
||||
|
||||
See here on how to [build GitHub CLI from source](/docs/source.md).
|
||||
See here on how to [build GitHub CLI from source][build from source].
|
||||
|
||||
[docs]: https://cli.github.com/manual
|
||||
[official docs]: https://cli.github.com/manual
|
||||
[scoop]: https://scoop.sh
|
||||
[Chocolatey]: https://chocolatey.org
|
||||
[releases page]: https://github.com/cli/cli/releases/latest
|
||||
[hub]: https://github.com/github/hub
|
||||
[contributing page]: https://github.com/cli/cli/blob/trunk/.github/CONTRIBUTING.md
|
||||
[gh-vs-hub]: /docs/gh-vs-hub.md
|
||||
[arch linux repo]: https://www.archlinux.org/packages/community/x86_64/github-cli
|
||||
[build from source]: /docs/source.md
|
||||
|
|
|
|||
|
|
@ -739,7 +739,7 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter
|
|||
}
|
||||
err := client.GraphQL(repo.RepoHost(), updateQuery, variables, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return pr, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -764,7 +764,7 @@ func CreatePullRequest(client *Client, repo *Repository, params map[string]inter
|
|||
}
|
||||
err := client.GraphQL(repo.RepoHost(), reviewQuery, variables, &result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return pr, err
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,3 +14,14 @@ func CurrentLoginName(client *Client, hostname string) (string, error) {
|
|||
err := gql.QueryNamed(context.Background(), "UserCurrent", &query, nil)
|
||||
return query.Viewer.Login, err
|
||||
}
|
||||
|
||||
func CurrentUserID(client *Client, hostname string) (string, error) {
|
||||
var query struct {
|
||||
Viewer struct {
|
||||
ID string
|
||||
}
|
||||
}
|
||||
gql := graphQLClient(client.http, hostname)
|
||||
err := gql.QueryNamed(context.Background(), "UserCurrent", &query, nil)
|
||||
return query.Viewer.ID, err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ func (oa *OAuthFlow) ObtainAccessToken() (accessToken string, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 ||
|
||||
if resp.StatusCode == 401 || resp.StatusCode == 403 || resp.StatusCode == 404 || resp.StatusCode == 422 ||
|
||||
(resp.StatusCode == 400 && values != nil && values.Get("error") == "unauthorized_client") {
|
||||
// OAuth Device Flow is not available; continue with OAuth browser flow with a
|
||||
// local server endpoint as callback target
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/cli/cli/auth"
|
||||
"github.com/cli/cli/pkg/browser"
|
||||
"github.com/cli/cli/utils"
|
||||
"github.com/mattn/go-colorable"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -29,7 +30,9 @@ func IsGitHubApp(id string) bool {
|
|||
}
|
||||
|
||||
func AuthFlowWithConfig(cfg Config, hostname, notice string, additionalScopes []string) (string, error) {
|
||||
token, userLogin, err := authFlow(hostname, notice, additionalScopes)
|
||||
stderr := colorable.NewColorableStderr()
|
||||
|
||||
token, userLogin, err := authFlow(hostname, stderr, notice, additionalScopes)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
@ -48,14 +51,17 @@ func AuthFlowWithConfig(cfg Config, hostname, notice string, additionalScopes []
|
|||
return "", err
|
||||
}
|
||||
|
||||
AuthFlowComplete()
|
||||
fmt.Fprintf(stderr, "%s Authentication complete. %s to continue...\n",
|
||||
utils.GreenCheck(), utils.Bold("Press Enter"))
|
||||
_ = waitForEnter(os.Stdin)
|
||||
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func authFlow(oauthHost, notice string, additionalScopes []string) (string, string, error) {
|
||||
func authFlow(oauthHost string, w io.Writer, notice string, additionalScopes []string) (string, string, error) {
|
||||
var verboseStream io.Writer
|
||||
if strings.Contains(os.Getenv("DEBUG"), "oauth") {
|
||||
verboseStream = os.Stderr
|
||||
verboseStream = w
|
||||
}
|
||||
|
||||
minimumScopes := []string{"repo", "read:org", "gist"}
|
||||
|
|
@ -73,9 +79,9 @@ func authFlow(oauthHost, notice string, additionalScopes []string) (string, stri
|
|||
HTTPClient: http.DefaultClient,
|
||||
OpenInBrowser: func(url, code string) error {
|
||||
if code != "" {
|
||||
fmt.Fprintf(os.Stderr, "%s First copy your one-time code: %s\n", utils.Yellow("!"), utils.Bold(code))
|
||||
fmt.Fprintf(w, "%s First copy your one-time code: %s\n", utils.Yellow("!"), utils.Bold(code))
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "- %s to open %s in your browser... ", utils.Bold("Press Enter"), oauthHost)
|
||||
fmt.Fprintf(w, "- %s to open %s in your browser... ", utils.Bold("Press Enter"), oauthHost)
|
||||
_ = waitForEnter(os.Stdin)
|
||||
|
||||
browseCmd, err := browser.Command(url)
|
||||
|
|
@ -84,15 +90,15 @@ func authFlow(oauthHost, notice string, additionalScopes []string) (string, stri
|
|||
}
|
||||
err = browseCmd.Run()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "%s Failed opening a web browser at %s\n", utils.Red("!"), url)
|
||||
fmt.Fprintf(os.Stderr, " %s\n", err)
|
||||
fmt.Fprint(os.Stderr, " Please try entering the URL in your browser manually\n")
|
||||
fmt.Fprintf(w, "%s Failed opening a web browser at %s\n", utils.Red("!"), url)
|
||||
fmt.Fprintf(w, " %s\n", err)
|
||||
fmt.Fprint(w, " Please try entering the URL in your browser manually\n")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Fprintln(os.Stderr, notice)
|
||||
fmt.Fprintln(w, notice)
|
||||
|
||||
token, err := flow.ObtainAccessToken()
|
||||
if err != nil {
|
||||
|
|
@ -107,12 +113,6 @@ func authFlow(oauthHost, notice string, additionalScopes []string) (string, stri
|
|||
return token, userLogin, nil
|
||||
}
|
||||
|
||||
func AuthFlowComplete() {
|
||||
fmt.Fprintf(os.Stderr, "%s Authentication complete. %s to continue...\n",
|
||||
utils.GreenCheck(), utils.Bold("Press Enter"))
|
||||
_ = waitForEnter(os.Stdin)
|
||||
}
|
||||
|
||||
func getViewer(hostname, token string) (string, error) {
|
||||
http := api.NewClient(api.AddHeader("Authorization", fmt.Sprintf("token %s", token)))
|
||||
return api.CurrentLoginName(http, hostname)
|
||||
|
|
|
|||
|
|
@ -87,6 +87,12 @@ func NewCmdLogin(f *cmdutil.Factory, runF func(*LoginOptions) error) *cobra.Comm
|
|||
}
|
||||
}
|
||||
|
||||
if cmd.Flags().Changed("hostname") {
|
||||
if err := hostnameValidator(opts.Hostname); err != nil {
|
||||
return &cmdutil.FlagError{Err: fmt.Errorf("error parsing --hostname: %w", err)}
|
||||
}
|
||||
}
|
||||
|
||||
if runF != nil {
|
||||
return runF(opts)
|
||||
}
|
||||
|
|
@ -156,7 +162,7 @@ func loginRun(opts *LoginOptions) error {
|
|||
if isEnterprise {
|
||||
err := prompt.SurveyAskOne(&survey.Input{
|
||||
Message: "GHE hostname:",
|
||||
}, &hostname, survey.WithValidator(survey.Required))
|
||||
}, &hostname, survey.WithValidator(hostnameValidator))
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not prompt: %w", err)
|
||||
}
|
||||
|
|
@ -256,7 +262,7 @@ func loginRun(opts *LoginOptions) error {
|
|||
|
||||
gitProtocol = strings.ToLower(gitProtocol)
|
||||
|
||||
fmt.Fprintf(opts.IO.ErrOut, "- gh config set -h%s git_protocol %s\n", hostname, gitProtocol)
|
||||
fmt.Fprintf(opts.IO.ErrOut, "- gh config set -h %s git_protocol %s\n", hostname, gitProtocol)
|
||||
err = cfg.Set(hostname, "git_protocol", gitProtocol)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
@ -288,3 +294,14 @@ func loginRun(opts *LoginOptions) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hostnameValidator(v interface{}) error {
|
||||
val := v.(string)
|
||||
if len(strings.TrimSpace(val)) < 1 {
|
||||
return errors.New("a value is required")
|
||||
}
|
||||
if strings.ContainsRune(val, '/') || strings.ContainsRune(val, ':') {
|
||||
return errors.New("invalid hostname")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,11 +366,15 @@ func createRun(opts *CreateOptions) error {
|
|||
}
|
||||
|
||||
pr, err := api.CreatePullRequest(client, baseRepo, params)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create pull request: %w", err)
|
||||
if pr != nil {
|
||||
fmt.Fprintln(opts.IO.Out, pr.URL)
|
||||
}
|
||||
if err != nil {
|
||||
if pr != nil {
|
||||
return fmt.Errorf("pull request update failed: %w", err)
|
||||
}
|
||||
return fmt.Errorf("pull request create failed: %w", err)
|
||||
}
|
||||
|
||||
fmt.Fprintln(opts.IO.Out, pr.URL)
|
||||
} else if action == shared.PreviewAction {
|
||||
openURL, err := generateCompareURL(baseRepo, baseBranch, headBranchLabel, title, body, tb.Assignees, tb.Labels, tb.Projects, tb.Milestones)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package create
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path"
|
||||
|
|
@ -8,8 +9,10 @@ import (
|
|||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/api"
|
||||
"github.com/cli/cli/git"
|
||||
"github.com/cli/cli/internal/config"
|
||||
"github.com/cli/cli/internal/ghinstance"
|
||||
"github.com/cli/cli/internal/ghrepo"
|
||||
"github.com/cli/cli/internal/run"
|
||||
"github.com/cli/cli/pkg/cmdutil"
|
||||
|
|
@ -28,6 +31,7 @@ type CreateOptions struct {
|
|||
Description string
|
||||
Homepage string
|
||||
Team string
|
||||
Template string
|
||||
EnableIssues bool
|
||||
EnableWiki bool
|
||||
Public bool
|
||||
|
|
@ -73,6 +77,10 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
|
|||
return runF(opts)
|
||||
}
|
||||
|
||||
if opts.Template != "" && (opts.Homepage != "" || opts.Team != "" || !opts.EnableIssues || !opts.EnableWiki) {
|
||||
return &cmdutil.FlagError{Err: errors.New(`The '--template' option is not supported with '--homepage, --team, --enable-issues or --enable-wiki'`)}
|
||||
}
|
||||
|
||||
return createRun(opts)
|
||||
},
|
||||
}
|
||||
|
|
@ -80,6 +88,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
|
|||
cmd.Flags().StringVarP(&opts.Description, "description", "d", "", "Description of repository")
|
||||
cmd.Flags().StringVarP(&opts.Homepage, "homepage", "h", "", "Repository home page URL")
|
||||
cmd.Flags().StringVarP(&opts.Team, "team", "t", "", "The name of the organization team to be granted access")
|
||||
cmd.Flags().StringVarP(&opts.Template, "template", "p", "", "Make the new repository based on a template repository")
|
||||
cmd.Flags().BoolVar(&opts.EnableIssues, "enable-issues", true, "Enable issues in the new repository")
|
||||
cmd.Flags().BoolVar(&opts.EnableWiki, "enable-wiki", true, "Enable wiki in the new repository")
|
||||
cmd.Flags().BoolVar(&opts.Public, "public", false, "Make the new repository public")
|
||||
|
|
@ -164,6 +173,37 @@ func createRun(opts *CreateOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
// Find template repo ID
|
||||
if opts.Template != "" {
|
||||
httpClient, err := opts.HttpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var toClone ghrepo.Interface
|
||||
apiClient := api.NewClientFromHTTP(httpClient)
|
||||
|
||||
cloneURL := opts.Template
|
||||
if !strings.Contains(cloneURL, "/") {
|
||||
currentUser, err := api.CurrentLoginName(apiClient, ghinstance.Default())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cloneURL = currentUser + "/" + cloneURL
|
||||
}
|
||||
toClone, err = ghrepo.FromFullName(cloneURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("argument error: %w", err)
|
||||
}
|
||||
|
||||
repo, err := api.GitHubRepo(apiClient, toClone)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts.Template = repo.ID
|
||||
}
|
||||
|
||||
input := repoCreateInput{
|
||||
Name: repoToCreate.RepoName(),
|
||||
Visibility: visibility,
|
||||
|
|
@ -189,7 +229,7 @@ func createRun(opts *CreateOptions) error {
|
|||
}
|
||||
|
||||
if opts.ConfirmSubmit {
|
||||
repo, err := repoCreate(httpClient, repoToCreate.RepoHost(), input)
|
||||
repo, err := repoCreate(httpClient, repoToCreate.RepoHost(), input, opts.Template)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
|
|
@ -303,3 +303,94 @@ func TestRepoCreate_orgWithTeam(t *testing.T) {
|
|||
t.Errorf("expected %q, got %q", "TEAMID", teamID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoCreate_template(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`mutation CloneTemplateRepository\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": { "cloneTemplateRepository": {
|
||||
"repository": {
|
||||
"id": "REPOID",
|
||||
"name": "REPO",
|
||||
"owner": {
|
||||
"login": "OWNER"
|
||||
},
|
||||
"url": "https://github.com/OWNER/REPO"
|
||||
}
|
||||
} } }`))
|
||||
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query RepositoryInfo\b`),
|
||||
httpmock.StringResponse(`
|
||||
{ "data": {
|
||||
"repository": {
|
||||
"id": "REPOID",
|
||||
"description": "DESCRIPTION"
|
||||
} } }`))
|
||||
|
||||
reg.Register(
|
||||
httpmock.GraphQL(`query UserCurrent\b`),
|
||||
httpmock.StringResponse(`{"data":{"viewer":{"ID":"OWNERID"}}}`))
|
||||
|
||||
httpClient := &http.Client{Transport: reg}
|
||||
|
||||
var seenCmd *exec.Cmd
|
||||
restoreCmd := run.SetPrepareCmd(func(cmd *exec.Cmd) run.Runnable {
|
||||
seenCmd = cmd
|
||||
return &test.OutputStub{}
|
||||
})
|
||||
defer restoreCmd()
|
||||
|
||||
as, surveyTearDown := prompt.InitAskStubber()
|
||||
defer surveyTearDown()
|
||||
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "repoVisibility",
|
||||
Value: "PRIVATE",
|
||||
},
|
||||
})
|
||||
as.Stub([]*prompt.QuestionStub{
|
||||
{
|
||||
Name: "confirmSubmit",
|
||||
Value: true,
|
||||
},
|
||||
})
|
||||
|
||||
output, err := runCommand(httpClient, "REPO --template='OWNER/REPO'")
|
||||
if err != nil {
|
||||
t.Errorf("error running command `repo create`: %v", err)
|
||||
}
|
||||
|
||||
assert.Equal(t, "https://github.com/OWNER/REPO\n", output.String())
|
||||
assert.Equal(t, "", output.Stderr())
|
||||
|
||||
if seenCmd == nil {
|
||||
t.Fatal("expected a command to run")
|
||||
}
|
||||
assert.Equal(t, "git remote add -f origin https://github.com/OWNER/REPO.git", strings.Join(seenCmd.Args, " "))
|
||||
|
||||
var reqBody struct {
|
||||
Query string
|
||||
Variables struct {
|
||||
Input map[string]interface{}
|
||||
}
|
||||
}
|
||||
|
||||
if len(reg.Requests) != 3 {
|
||||
t.Fatalf("expected 3 HTTP requests, got %d", len(reg.Requests))
|
||||
}
|
||||
|
||||
bodyBytes, _ := ioutil.ReadAll(reg.Requests[2].Body)
|
||||
_ = json.Unmarshal(bodyBytes, &reqBody)
|
||||
if repoName := reqBody.Variables.Input["name"].(string); repoName != "REPO" {
|
||||
t.Errorf("expected %q, got %q", "REPO", repoName)
|
||||
}
|
||||
if repoVisibility := reqBody.Variables.Input["visibility"].(string); repoVisibility != "PRIVATE" {
|
||||
t.Errorf("expected %q, got %q", "PRIVATE", repoVisibility)
|
||||
}
|
||||
if ownerId := reqBody.Variables.Input["ownerId"].(string); ownerId != "OWNERID" {
|
||||
t.Errorf("expected %q, got %q", "OWNERID", ownerId)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,15 +21,18 @@ type repoCreateInput struct {
|
|||
HasWikiEnabled bool `json:"hasWikiEnabled"`
|
||||
}
|
||||
|
||||
// repoCreate creates a new GitHub repository
|
||||
func repoCreate(client *http.Client, hostname string, input repoCreateInput) (*api.Repository, error) {
|
||||
apiClient := api.NewClientFromHTTP(client)
|
||||
type repoTemplateInput struct {
|
||||
Name string `json:"name"`
|
||||
Visibility string `json:"visibility"`
|
||||
OwnerID string `json:"ownerId,omitempty"`
|
||||
|
||||
var response struct {
|
||||
CreateRepository struct {
|
||||
Repository api.Repository
|
||||
}
|
||||
}
|
||||
RepositoryID string `json:"repositoryId,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
}
|
||||
|
||||
// repoCreate creates a new GitHub repository
|
||||
func repoCreate(client *http.Client, hostname string, input repoCreateInput, templateRepositoryID string) (*api.Repository, error) {
|
||||
apiClient := api.NewClientFromHTTP(client)
|
||||
|
||||
if input.TeamID != "" {
|
||||
orgID, teamID, err := resolveOrganizationTeam(apiClient, hostname, input.OwnerID, input.TeamID)
|
||||
|
|
@ -46,6 +49,57 @@ func repoCreate(client *http.Client, hostname string, input repoCreateInput) (*a
|
|||
input.OwnerID = orgID
|
||||
}
|
||||
|
||||
if templateRepositoryID != "" {
|
||||
var response struct {
|
||||
CloneTemplateRepository struct {
|
||||
Repository api.Repository
|
||||
}
|
||||
}
|
||||
|
||||
if input.OwnerID == "" {
|
||||
var err error
|
||||
input.OwnerID, err = api.CurrentUserID(apiClient, hostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
templateInput := repoTemplateInput{
|
||||
Name: input.Name,
|
||||
Visibility: input.Visibility,
|
||||
OwnerID: input.OwnerID,
|
||||
RepositoryID: templateRepositoryID,
|
||||
}
|
||||
|
||||
variables := map[string]interface{}{
|
||||
"input": templateInput,
|
||||
}
|
||||
|
||||
err := apiClient.GraphQL(hostname, `
|
||||
mutation CloneTemplateRepository($input: CloneTemplateRepositoryInput!) {
|
||||
cloneTemplateRepository(input: $input) {
|
||||
repository {
|
||||
id
|
||||
name
|
||||
owner { login }
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
`, variables, &response)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.InitRepoHostname(&response.CloneTemplateRepository.Repository, hostname), nil
|
||||
}
|
||||
|
||||
var response struct {
|
||||
CreateRepository struct {
|
||||
Repository api.Repository
|
||||
}
|
||||
}
|
||||
|
||||
variables := map[string]interface{}{
|
||||
"input": input,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ func Test_RepoCreate(t *testing.T) {
|
|||
HomepageURL: "http://example.com",
|
||||
}
|
||||
|
||||
_, err := repoCreate(httpClient, "github.com", input)
|
||||
_, err := repoCreate(httpClient, "github.com", input, "")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,12 +103,20 @@ func (s *IOStreams) TerminalWidth() int {
|
|||
}
|
||||
|
||||
func System() *IOStreams {
|
||||
return &IOStreams{
|
||||
stdoutIsTTY := isTerminal(os.Stdout)
|
||||
stderrIsTTY := isTerminal(os.Stderr)
|
||||
|
||||
io := &IOStreams{
|
||||
In: os.Stdin,
|
||||
Out: colorable.NewColorable(os.Stdout),
|
||||
ErrOut: colorable.NewColorable(os.Stderr),
|
||||
colorEnabled: os.Getenv("NO_COLOR") == "" && isTerminal(os.Stdout),
|
||||
colorEnabled: os.Getenv("NO_COLOR") == "" && stdoutIsTTY,
|
||||
}
|
||||
|
||||
// prevent duplicate isTerminal queries now that we know the answer
|
||||
io.SetStdoutTTY(stdoutIsTTY)
|
||||
io.SetStderrTTY(stderrIsTTY)
|
||||
return io
|
||||
}
|
||||
|
||||
func Test() (*IOStreams, *bytes.Buffer, *bytes.Buffer, *bytes.Buffer) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue