Skip to content
This repository was archived by the owner on Sep 6, 2025. It is now read-only.

Commit cc768db

Browse files
authored
Merge pull request #4 from hellofresh/feature/create-repo-improvements
Create repo improvements
2 parents c625d65 + 0f91b8b commit cc768db

File tree

6 files changed

+93
-56
lines changed

6 files changed

+93
-56
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Github CLI
22

3-
[![Build Status](https://travis-ci.org/hellofresh/github-cli.svg?branch=master)](https://travis-ci.org/hellofresh/phanes)
4-
[![Go Report Card](https://goreportcard.com/badge/github.com/hellofresh/github-cli)](https://goreportcard.com/report/github.com/hellofresh/phanes)
3+
[![Build Status](https://travis-ci.org/hellofresh/github-cli.svg?branch=master)](https://travis-ci.org/hellofresh/github-cli)
4+
[![Go Report Card](https://goreportcard.com/badge/github.com/hellofresh/github-cli)](https://goreportcard.com/report/github.com/hellofresh/github-cli)
55

66
> A CLI Tool to automate the creation of github repositories
77

build/build.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ echo "Building default binary"
1515
CGO_ENABLED=0 go build -ldflags "-s -w" -ldflags "-X cmd.version=${VERSION}" -o "dist/github-cli" $PKG_SRC
1616

1717
# Build 386 amd64 binaries
18-
OS_PLATFORM_ARG=(linux darwin windows freebsd openbsd)
18+
OS_PLATFORM_ARG=(linux darwin windows)
1919
OS_ARCH_ARG=(386 amd64)
2020
for OS in ${OS_PLATFORM_ARG[@]}; do
2121
for ARCH in ${OS_ARCH_ARG[@]}; do

cmd/create_repo.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -67,33 +67,35 @@ func RunCreateRepo(cmd *cobra.Command, args []string) {
6767
RemoveDefaultLabels: globalConfig.Github.RemoveDefaultLabels,
6868
Labels: globalConfig.Github.Labels,
6969
},
70-
Teams: &repo.TeamsOpts{
71-
Teams: globalConfig.Github.Teams,
72-
},
73-
Webhooks: &repo.WebhooksOpts{
74-
Webhooks: globalConfig.Github.Webhooks,
75-
},
76-
BranchProtections: &repo.BranchProtectionsOpts{
77-
Protections: globalConfig.Github.Protections,
78-
},
70+
Teams: globalConfig.Github.Teams,
71+
Webhooks: globalConfig.Github.Webhooks,
72+
BranchProtections: globalConfig.Github.Protections,
7973
}
8074

8175
creator := repo.NewGithub(githubClient)
8276

8377
color.White("Creating repository...")
8478
err = creator.CreateRepo(name, description, org, createRepoFlags.Private)
85-
checkEmpty(errors.Wrap(err, "could not create repository"), "")
79+
if errors.Cause(err) == repo.ErrRepositoryAlreadyExists {
80+
color.Cyan("Repository already exists. Trying to normalize it...")
81+
} else {
82+
checkEmpty(errors.Wrap(err, "could not create repository"), "")
83+
}
8684

8785
if createRepoFlags.HasPullApprove {
8886
color.White("Adding pull approve...")
8987
err = creator.AddPullApprove(name, org, opts.PullApprove)
90-
checkEmpty(errors.Wrap(err, "could not add pull approve"), "")
88+
if errors.Cause(err) == repo.ErrPullApproveFileAlreadyExists {
89+
color.Cyan("Pull approve already exists, moving on...")
90+
} else {
91+
checkEmpty(errors.Wrap(err, "could not add pull approve"), "")
92+
}
9193
}
9294

9395
if createRepoFlags.HasTeams {
9496
color.White("Adding teams to repository...")
9597
err = creator.AddTeamsToRepo(name, org, opts.Teams)
96-
checkEmpty(errors.Wrap(err, "could add teams to repository"), "")
98+
checkEmpty(errors.Wrap(err, "could not add teams to repository"), "")
9799
}
98100

99101
if createRepoFlags.HasCollaborators {
@@ -105,13 +107,21 @@ func RunCreateRepo(cmd *cobra.Command, args []string) {
105107
if createRepoFlags.HasLabels {
106108
color.White("Adding labels to repository...")
107109
err = creator.AddLabelsToRepo(name, org, opts.Labels)
108-
checkEmpty(errors.Wrap(err, "could add labels to repository"), "")
110+
if errors.Cause(err) == repo.ErrLabelNotFound {
111+
color.Cyan("Default labels does not exists, moving on...")
112+
} else {
113+
checkEmpty(errors.Wrap(err, "could not add labels to repository"), "")
114+
}
109115
}
110116

111117
if createRepoFlags.HasWebhooks {
112118
color.White("Adding webhooks to repository...")
113119
err = creator.AddWebhooksToRepo(name, org, opts.Webhooks)
114-
checkEmpty(errors.Wrap(err, "could add webhooks to repository"), "")
120+
if errors.Cause(err) == repo.ErrWebhookAlreadyExist {
121+
color.Cyan("Webhook already exists, moving on...")
122+
} else {
123+
checkEmpty(errors.Wrap(err, "could add webhooks to repository"), "")
124+
}
115125
}
116126

117127
if createRepoFlags.HasBranchProtections {

cmd/create_test_repo.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,10 @@ func RunCreateTestRepo(cmd *cobra.Command, args []string) {
6060
checkEmpty(err, "Could not create github repo for candidate")
6161

6262
color.White("Adding collaborators to repository...")
63-
opts := &repo.CollaboratorsOpts{
64-
Collaborators: []*config.Collaborator{
65-
&config.Collaborator{
66-
Username: candidate,
67-
Permission: "push",
68-
},
63+
opts := []*config.Collaborator{
64+
&config.Collaborator{
65+
Username: candidate,
66+
Permission: "push",
6967
},
7068
}
7169
err = creator.AddCollaborators(target, org, opts)

pkg/config/config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ type (
2929
Collaborators []*Collaborator
3030
Labels []*Label
3131
Webhooks []*Webhook
32-
Protections map[string][]string
32+
Protections BranchProtections
3333
// RemoveDefaultLabels Remove GitHub's default labels?
3434
RemoveDefaultLabels bool
3535
}
3636

37+
// BranchProtections represents github's branch protections
38+
BranchProtections map[string][]string
39+
3740
// Team represents a github team
3841
Team struct {
3942
ID int

pkg/repo/github.go

Lines changed: 58 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package repo
22

33
import (
44
"context"
5+
"net/http"
56

67
"github.com/google/go-github/github"
78
"github.com/hellofresh/github-cli/pkg/config"
@@ -18,42 +19,38 @@ type (
1819
// GithubRepoOpts represents the repo creation options
1920
GithubRepoOpts struct {
2021
PullApprove *PullApproveOpts
21-
Teams *TeamsOpts
22-
Collaborators *CollaboratorsOpts
22+
Teams []*config.Team
23+
Collaborators []*config.Collaborator
2324
Labels *LabelsOpts
24-
Webhooks *WebhooksOpts
25-
BranchProtections *BranchProtectionsOpts
25+
Webhooks []*config.Webhook
26+
BranchProtections config.BranchProtections
2627
}
2728

29+
// PullApproveOpts represents pull approve options
2830
PullApproveOpts struct {
2931
Client *pullapprove.Client
3032
Filename string
3133
ProtectedBranchName string
3234
}
3335

34-
TeamsOpts struct {
35-
Teams []*config.Team
36-
}
37-
38-
CollaboratorsOpts struct {
39-
Collaborators []*config.Collaborator
40-
}
41-
36+
// LabelsOpts represents label options
4237
LabelsOpts struct {
4338
RemoveDefaultLabels bool
4439
Labels []*config.Label
4540
}
46-
47-
WebhooksOpts struct {
48-
Webhooks []*config.Webhook
49-
}
50-
51-
BranchProtectionsOpts struct {
52-
Protections map[string][]string
53-
}
5441
)
5542

56-
var ctx = context.Background()
43+
var (
44+
ctx = context.Background()
45+
// ErrRepositoryAlreadyExists is used when the repository already exists
46+
ErrRepositoryAlreadyExists = errors.New("github repository already exists")
47+
// ErrPullApproveFileAlreadyExists is used when the pull approve file already exists
48+
ErrPullApproveFileAlreadyExists = errors.New("github pull approve file already exists")
49+
// ErrLabelNotFound is used when a label is not found
50+
ErrLabelNotFound = errors.New("github label does not exist")
51+
// ErrWebhookAlreadyExist is used when a webhook already exists
52+
ErrWebhookAlreadyExist = errors.New("github webhook already exists")
53+
)
5754

5855
// NewGithub creates a new instance of Client
5956
func NewGithub(githubClient *github.Client) *GithubRepo {
@@ -62,6 +59,7 @@ func NewGithub(githubClient *github.Client) *GithubRepo {
6259
}
6360
}
6461

62+
// CreateRepo creates a github repository
6563
func (c *GithubRepo) CreateRepo(name string, description string, org string, private bool) error {
6664
repo := &github.Repository{
6765
Name: github.String(name),
@@ -71,10 +69,18 @@ func (c *GithubRepo) CreateRepo(name string, description string, org string, pri
7169
}
7270

7371
_, _, err := c.GithubClient.Repositories.Create(ctx, org, repo)
72+
if githubError, ok := err.(*github.ErrorResponse); ok {
73+
if githubError.Response.StatusCode == http.StatusUnprocessableEntity {
74+
err = errors.Wrap(ErrRepositoryAlreadyExists, "repository already exists")
75+
}
76+
}
77+
7478
return err
7579
}
7680

81+
// AddPullApprove adds a file to the github repository and calls pull approve API to register the new repo
7782
func (c *GithubRepo) AddPullApprove(repo string, org string, opts *PullApproveOpts) error {
83+
var err error
7884
if opts.Client == nil {
7985
return errors.New("Cannot add pull approve, since the client is nil")
8086
}
@@ -84,8 +90,12 @@ func (c *GithubRepo) AddPullApprove(repo string, org string, opts *PullApproveOp
8490
Content: []byte("extends: hellofresh"),
8591
Branch: github.String(opts.ProtectedBranchName),
8692
}
87-
_, _, err := c.GithubClient.Repositories.CreateFile(ctx, org, repo, opts.Filename, fileOpt)
88-
if err != nil {
93+
_, _, err = c.GithubClient.Repositories.CreateFile(ctx, org, repo, opts.Filename, fileOpt)
94+
if githubError, ok := err.(*github.ErrorResponse); ok {
95+
if githubError.Response.StatusCode == http.StatusUnprocessableEntity {
96+
return errors.Wrap(ErrPullApproveFileAlreadyExists, "pull approve file already exists")
97+
}
98+
} else {
8999
return err
90100
}
91101

@@ -94,13 +104,14 @@ func (c *GithubRepo) AddPullApprove(repo string, org string, opts *PullApproveOp
94104
return err
95105
}
96106

97-
return nil
107+
return err
98108
}
99109

100-
func (c *GithubRepo) AddTeamsToRepo(repo string, org string, opts *TeamsOpts) error {
110+
// AddTeamsToRepo adds an slice of teams and their permissions to a repository
111+
func (c *GithubRepo) AddTeamsToRepo(repo string, org string, teams []*config.Team) error {
101112
var err error
102113

103-
for _, team := range opts.Teams {
114+
for _, team := range teams {
104115
opt := &github.OrganizationAddTeamRepoOptions{
105116
Permission: team.Permission,
106117
}
@@ -111,6 +122,8 @@ func (c *GithubRepo) AddTeamsToRepo(repo string, org string, opts *TeamsOpts) er
111122
return err
112123
}
113124

125+
// AddLabelsToRepo adds an slice of labels to the repository. Optionally this can also remove github's
126+
// default labels
114127
func (c *GithubRepo) AddLabelsToRepo(repo string, org string, opts *LabelsOpts) error {
115128
var err error
116129
defaultLabels := []string{"bug", "duplicate", "enhancement", "help wanted", "invalid", "question", "wontfix", "good first issue"}
@@ -127,30 +140,42 @@ func (c *GithubRepo) AddLabelsToRepo(repo string, org string, opts *LabelsOpts)
127140
if opts.RemoveDefaultLabels {
128141
for _, label := range defaultLabels {
129142
_, err = c.GithubClient.Issues.DeleteLabel(ctx, org, repo, label)
143+
if githubError, ok := err.(*github.ErrorResponse); ok {
144+
if githubError.Response.StatusCode == http.StatusNotFound {
145+
err = errors.Wrap(ErrLabelNotFound, "label not found")
146+
}
147+
}
130148
}
131149
}
132150

133151
return err
134152
}
135153

136-
func (c *GithubRepo) AddWebhooksToRepo(repo string, org string, opts *WebhooksOpts) error {
154+
// AddWebhooksToRepo adds an slice of webhooks to the repository
155+
func (c *GithubRepo) AddWebhooksToRepo(repo string, org string, webhooks []*config.Webhook) error {
137156
var err error
138157

139-
for _, webhook := range opts.Webhooks {
158+
for _, webhook := range webhooks {
140159
hook := &github.Hook{
141160
Name: github.String(webhook.Type),
142161
Config: webhook.Config,
143162
}
144163
_, _, err = c.GithubClient.Repositories.CreateHook(ctx, org, repo, hook)
164+
if githubError, ok := err.(*github.ErrorResponse); ok {
165+
if githubError.Response.StatusCode == http.StatusUnprocessableEntity {
166+
err = errors.Wrap(ErrWebhookAlreadyExist, "webhook already exists")
167+
}
168+
}
145169
}
146170

147171
return err
148172
}
149173

150-
func (c *GithubRepo) AddBranchProtections(repo string, org string, opts *BranchProtectionsOpts) error {
174+
// AddBranchProtections adds an slice of branch protections to the repository
175+
func (c *GithubRepo) AddBranchProtections(repo string, org string, protections config.BranchProtections) error {
151176
var err error
152177

153-
for branch, contexts := range opts.Protections {
178+
for branch, contexts := range protections {
154179
pr := &github.ProtectionRequest{
155180
RequiredStatusChecks: &github.RequiredStatusChecks{
156181
Contexts: contexts,
@@ -162,10 +187,11 @@ func (c *GithubRepo) AddBranchProtections(repo string, org string, opts *BranchP
162187
return err
163188
}
164189

165-
func (c *GithubRepo) AddCollaborators(repo string, org string, opts *CollaboratorsOpts) error {
190+
// AddCollaborators adds an slice of collaborators and their permissions to the repository
191+
func (c *GithubRepo) AddCollaborators(repo string, org string, collaborators []*config.Collaborator) error {
166192
var err error
167193

168-
for _, collaborator := range opts.Collaborators {
194+
for _, collaborator := range collaborators {
169195
opt := &github.RepositoryAddCollaboratorOptions{
170196
Permission: collaborator.Permission,
171197
}

0 commit comments

Comments
 (0)