[Feature] Create repository from template

Co-authored-by: Mislav Marohnić <mislav@github.com>
This commit is contained in:
Colin Shum 2020-08-27 13:00:34 -04:00
parent 727b726667
commit 58f62a4a15
3 changed files with 110 additions and 6 deletions

View file

@ -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
}

View file

@ -8,8 +8,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 +30,7 @@ type CreateOptions struct {
Description string
Homepage string
Team string
Template string
EnableIssues bool
EnableWiki bool
Public bool
@ -80,6 +83,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,11 +168,45 @@ func createRun(opts *CreateOptions) error {
}
}
// find template ID
if opts.Template != "" {
httpClient, err := opts.HttpClient()
if err != nil {
return err
}
var toView ghrepo.Interface
apiClient := api.NewClientFromHTTP(httpClient)
// var err errors
viewURL := opts.Template
if !strings.Contains(viewURL, "/") {
currentUser, err := api.CurrentLoginName(apiClient, ghinstance.Default())
if err != nil {
return err
}
viewURL = currentUser + "/" + viewURL
}
toView, err = ghrepo.FromFullName(viewURL)
if err != nil {
return fmt.Errorf("argument error: %w", err)
}
repo, err := api.GitHubRepo(apiClient, toView)
if err != nil {
return err
}
opts.Template = repo.ID
}
input := repoCreateInput{
Name: repoToCreate.RepoName(),
Visibility: visibility,
OwnerID: repoToCreate.RepoOwner(),
TeamID: opts.Team,
RepositoryID: opts.Template,
Description: opts.Description,
HomepageURL: opts.Homepage,
HasIssuesEnabled: opts.EnableIssues,

View file

@ -14,6 +14,8 @@ type repoCreateInput struct {
HomepageURL string `json:"homepageUrl,omitempty"`
Description string `json:"description,omitempty"`
RepositoryID string `json:"repositoryId,omitempty"`
OwnerID string `json:"ownerId,omitempty"`
TeamID string `json:"teamId,omitempty"`
@ -21,16 +23,18 @@ type repoCreateInput struct {
HasWikiEnabled bool `json:"hasWikiEnabled"`
}
type repoTemplateInput struct {
Name string `json:"name"`
Visibility string `json:"visibility"`
OwnerID string `json:"ownerId,omitempty"`
RepositoryID string `json:"repositoryId,omitempty"`
}
// repoCreate creates a new GitHub repository
func repoCreate(client *http.Client, hostname string, input repoCreateInput) (*api.Repository, error) {
apiClient := api.NewClientFromHTTP(client)
var response struct {
CreateRepository struct {
Repository api.Repository
}
}
if input.TeamID != "" {
orgID, teamID, err := resolveOrganizationTeam(apiClient, hostname, input.OwnerID, input.TeamID)
if err != nil {
@ -46,6 +50,57 @@ func repoCreate(client *http.Client, hostname string, input repoCreateInput) (*a
input.OwnerID = orgID
}
if input.RepositoryID != "" {
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: input.RepositoryID,
}
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,
}