X Tutup
Skip to content

Commit 58f62a4

Browse files
colinshummislav
andcommitted
[Feature] Create repository from template
Co-authored-by: Mislav Marohnić <mislav@github.com>
1 parent 727b726 commit 58f62a4

File tree

3 files changed

+110
-6
lines changed

3 files changed

+110
-6
lines changed

api/queries_user.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,14 @@ func CurrentLoginName(client *Client, hostname string) (string, error) {
1414
err := gql.QueryNamed(context.Background(), "UserCurrent", &query, nil)
1515
return query.Viewer.Login, err
1616
}
17+
18+
func CurrentUserID(client *Client, hostname string) (string, error) {
19+
var query struct {
20+
Viewer struct {
21+
ID string
22+
}
23+
}
24+
gql := graphQLClient(client.http, hostname)
25+
err := gql.QueryNamed(context.Background(), "UserCurrent", &query, nil)
26+
return query.Viewer.ID, err
27+
}

pkg/cmd/repo/create/create.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,10 @@ import (
88

99
"github.com/AlecAivazis/survey/v2"
1010
"github.com/MakeNowJust/heredoc"
11+
"github.com/cli/cli/api"
1112
"github.com/cli/cli/git"
1213
"github.com/cli/cli/internal/config"
14+
"github.com/cli/cli/internal/ghinstance"
1315
"github.com/cli/cli/internal/ghrepo"
1416
"github.com/cli/cli/internal/run"
1517
"github.com/cli/cli/pkg/cmdutil"
@@ -28,6 +30,7 @@ type CreateOptions struct {
2830
Description string
2931
Homepage string
3032
Team string
33+
Template string
3134
EnableIssues bool
3235
EnableWiki bool
3336
Public bool
@@ -80,6 +83,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
8083
cmd.Flags().StringVarP(&opts.Description, "description", "d", "", "Description of repository")
8184
cmd.Flags().StringVarP(&opts.Homepage, "homepage", "h", "", "Repository home page URL")
8285
cmd.Flags().StringVarP(&opts.Team, "team", "t", "", "The name of the organization team to be granted access")
86+
cmd.Flags().StringVarP(&opts.Template, "template", "p", "", "Make the new repository based on a template repository")
8387
cmd.Flags().BoolVar(&opts.EnableIssues, "enable-issues", true, "Enable issues in the new repository")
8488
cmd.Flags().BoolVar(&opts.EnableWiki, "enable-wiki", true, "Enable wiki in the new repository")
8589
cmd.Flags().BoolVar(&opts.Public, "public", false, "Make the new repository public")
@@ -164,11 +168,45 @@ func createRun(opts *CreateOptions) error {
164168
}
165169
}
166170

171+
// find template ID
172+
173+
if opts.Template != "" {
174+
httpClient, err := opts.HttpClient()
175+
if err != nil {
176+
return err
177+
}
178+
179+
var toView ghrepo.Interface
180+
apiClient := api.NewClientFromHTTP(httpClient)
181+
182+
// var err errors
183+
viewURL := opts.Template
184+
if !strings.Contains(viewURL, "/") {
185+
currentUser, err := api.CurrentLoginName(apiClient, ghinstance.Default())
186+
if err != nil {
187+
return err
188+
}
189+
viewURL = currentUser + "/" + viewURL
190+
}
191+
toView, err = ghrepo.FromFullName(viewURL)
192+
if err != nil {
193+
return fmt.Errorf("argument error: %w", err)
194+
}
195+
196+
repo, err := api.GitHubRepo(apiClient, toView)
197+
if err != nil {
198+
return err
199+
}
200+
201+
opts.Template = repo.ID
202+
}
203+
167204
input := repoCreateInput{
168205
Name: repoToCreate.RepoName(),
169206
Visibility: visibility,
170207
OwnerID: repoToCreate.RepoOwner(),
171208
TeamID: opts.Team,
209+
RepositoryID: opts.Template,
172210
Description: opts.Description,
173211
HomepageURL: opts.Homepage,
174212
HasIssuesEnabled: opts.EnableIssues,

pkg/cmd/repo/create/http.go

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,27 @@ type repoCreateInput struct {
1414
HomepageURL string `json:"homepageUrl,omitempty"`
1515
Description string `json:"description,omitempty"`
1616

17+
RepositoryID string `json:"repositoryId,omitempty"`
18+
1719
OwnerID string `json:"ownerId,omitempty"`
1820
TeamID string `json:"teamId,omitempty"`
1921

2022
HasIssuesEnabled bool `json:"hasIssuesEnabled"`
2123
HasWikiEnabled bool `json:"hasWikiEnabled"`
2224
}
2325

26+
type repoTemplateInput struct {
27+
Name string `json:"name"`
28+
Visibility string `json:"visibility"`
29+
OwnerID string `json:"ownerId,omitempty"`
30+
31+
RepositoryID string `json:"repositoryId,omitempty"`
32+
}
33+
2434
// repoCreate creates a new GitHub repository
2535
func repoCreate(client *http.Client, hostname string, input repoCreateInput) (*api.Repository, error) {
2636
apiClient := api.NewClientFromHTTP(client)
2737

28-
var response struct {
29-
CreateRepository struct {
30-
Repository api.Repository
31-
}
32-
}
33-
3438
if input.TeamID != "" {
3539
orgID, teamID, err := resolveOrganizationTeam(apiClient, hostname, input.OwnerID, input.TeamID)
3640
if err != nil {
@@ -46,6 +50,57 @@ func repoCreate(client *http.Client, hostname string, input repoCreateInput) (*a
4650
input.OwnerID = orgID
4751
}
4852

53+
if input.RepositoryID != "" {
54+
var response struct {
55+
CloneTemplateRepository struct {
56+
Repository api.Repository
57+
}
58+
}
59+
60+
if input.OwnerID == "" {
61+
var err error
62+
input.OwnerID, err = api.CurrentUserID(apiClient, hostname)
63+
if err != nil {
64+
return nil, err
65+
}
66+
}
67+
68+
templateInput := repoTemplateInput{
69+
Name: input.Name,
70+
Visibility: input.Visibility,
71+
OwnerID: input.OwnerID,
72+
RepositoryID: input.RepositoryID,
73+
}
74+
75+
variables := map[string]interface{}{
76+
"input": templateInput,
77+
}
78+
79+
err := apiClient.GraphQL(hostname, `
80+
mutation CloneTemplateRepository($input: CloneTemplateRepositoryInput!) {
81+
cloneTemplateRepository(input: $input) {
82+
repository {
83+
id
84+
name
85+
owner { login }
86+
url
87+
}
88+
}
89+
}
90+
`, variables, &response)
91+
if err != nil {
92+
return nil, err
93+
}
94+
95+
return api.InitRepoHostname(&response.CloneTemplateRepository.Repository, hostname), nil
96+
}
97+
98+
var response struct {
99+
CreateRepository struct {
100+
Repository api.Repository
101+
}
102+
}
103+
49104
variables := map[string]interface{}{
50105
"input": input,
51106
}

0 commit comments

Comments
 (0)
X Tutup