aboutsummaryrefslogtreecommitdiffstats
path: root/bridge/github
diff options
context:
space:
mode:
Diffstat (limited to 'bridge/github')
-rw-r--r--bridge/github/config.go50
-rw-r--r--bridge/github/config_test.go146
2 files changed, 180 insertions, 16 deletions
diff --git a/bridge/github/config.go b/bridge/github/config.go
index f44be472..c48c11f6 100644
--- a/bridge/github/config.go
+++ b/bridge/github/config.go
@@ -16,6 +16,8 @@ import (
"syscall"
"time"
+ "github.com/pkg/errors"
+
"golang.org/x/crypto/ssh/terminal"
"github.com/MichaelMure/git-bug/bridge/core"
@@ -32,7 +34,7 @@ const (
)
var (
- rxGithubURL = regexp.MustCompile(`github\.com[\/:]([a-zA-Z0-9\-\_]+)\/([a-zA-Z0-9\-\_\.]+)`)
+ ErrBadProjectURL = errors.New("bad project url")
)
func (*Github) Configure(repo repository.RepoCommon, params core.BridgeParams) (core.Configuration, error) {
@@ -50,7 +52,7 @@ func (*Github) Configure(repo repository.RepoCommon, params core.BridgeParams) (
} else if params.URL != "" {
// try to parse params URL and extract owner and project
- _, owner, project, err = splitURL(params.URL)
+ owner, project, err = splitURL(params.URL)
if err != nil {
return nil, err
}
@@ -227,9 +229,9 @@ func promptToken() (string, error) {
fmt.Println()
fmt.Println("The access scope depend on the type of repository.")
fmt.Println("Public:")
- fmt.Println(" - 'repo:public_repo': to be able to read public repositories")
+ fmt.Println(" - 'public_repo': to be able to read public repositories")
fmt.Println("Private:")
- fmt.Println(" - 'repo' : to be able to read private repositories")
+ fmt.Println(" - 'repo' : to be able to read private repositories")
fmt.Println()
for {
@@ -255,9 +257,9 @@ func loginAndRequestToken(owner, project string) (string, error) {
fmt.Println()
fmt.Println("The access scope depend on the type of repository.")
fmt.Println("Public:")
- fmt.Println(" - 'repo:public_repo': to be able to read public repositories")
+ fmt.Println(" - 'public_repo': to be able to read public repositories")
fmt.Println("Private:")
- fmt.Println(" - 'repo' : to be able to read private repositories")
+ fmt.Println(" - 'repo' : to be able to read private repositories")
fmt.Println()
// prompt project visibility to know the token scope needed for the repository
@@ -278,8 +280,8 @@ func loginAndRequestToken(owner, project string) (string, error) {
var scope string
if isPublic {
- // repo:public_repo is requested to be able to read public repositories
- scope = "repo:public_repo"
+ // public_repo is requested to be able to read public repositories
+ scope = "public_repo"
} else {
// 'repo' is request to be able to read private repositories
// /!\ token will have read/write rights on every private repository you have access to
@@ -377,7 +379,7 @@ func promptURL(remotes map[string]string) (string, string, error) {
}
// get owner and project with index
- _, owner, project, _ := splitURL(validRemotes[index-1])
+ owner, project, _ := splitURL(validRemotes[index-1])
return owner, project, nil
}
}
@@ -398,7 +400,7 @@ func promptURL(remotes map[string]string) (string, string, error) {
}
// get owner and project from url
- _, owner, project, err := splitURL(line)
+ owner, project, err := splitURL(line)
if err != nil {
fmt.Println(err)
continue
@@ -408,22 +410,34 @@ func promptURL(remotes map[string]string) (string, string, error) {
}
}
-func splitURL(url string) (shortURL string, owner string, project string, err error) {
+// splitURL extract the owner and project from a github repository URL. It will remove the
+// '.git' extension from the URL before parsing it.
+// Note that Github removes the '.git' extension from projects names at their creation
+func splitURL(url string) (owner string, project string, err error) {
cleanURL := strings.TrimSuffix(url, ".git")
- res := rxGithubURL.FindStringSubmatch(cleanURL)
+
+ re, err := regexp.Compile(`github\.com[/:]([a-zA-Z0-9\-_]+)/([a-zA-Z0-9\-_.]+)`)
+ if err != nil {
+ return "", "", err
+ }
+
+ res := re.FindStringSubmatch(cleanURL)
if res == nil {
- return "", "", "", fmt.Errorf("bad github project url")
+ return "", "", ErrBadProjectURL
}
- return res[0], res[1], res[2], nil
+ owner = res[1]
+ project = res[2]
+ return owner, project, nil
}
func getValidGithubRemoteURLs(remotes map[string]string) []string {
urls := make([]string, 0, len(remotes))
for _, url := range remotes {
// split url can work again with shortURL
- shortURL, _, _, err := splitURL(url)
+ owner, project, err := splitURL(url)
if err == nil {
+ shortURL := fmt.Sprintf("%s/%s/%s", "github.com", owner, project)
urls = append(urls, shortURL)
}
}
@@ -434,7 +448,11 @@ func getValidGithubRemoteURLs(remotes map[string]string) []string {
func validateUsername(username string) (bool, error) {
url := fmt.Sprintf("%s/users/%s", githubV3Url, username)
- resp, err := http.Get(url)
+ client := &http.Client{
+ Timeout: defaultTimeout,
+ }
+
+ resp, err := client.Get(url)
if err != nil {
return false, err
}
diff --git a/bridge/github/config_test.go b/bridge/github/config_test.go
new file mode 100644
index 00000000..6c84046a
--- /dev/null
+++ b/bridge/github/config_test.go
@@ -0,0 +1,146 @@
+package github
+
+import (
+ "os"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSplitURL(t *testing.T) {
+ type args struct {
+ url string
+ }
+ type want struct {
+ owner string
+ project string
+ err error
+ }
+ tests := []struct {
+ name string
+ args args
+ want want
+ }{
+ {
+ name: "default url",
+ args: args{
+ url: "https://github.com/MichaelMure/git-bug",
+ },
+ want: want{
+ owner: "MichaelMure",
+ project: "git-bug",
+ err: nil,
+ },
+ },
+
+ {
+ name: "default url with git extension",
+ args: args{
+ url: "https://github.com/MichaelMure/git-bug.git",
+ },
+ want: want{
+ owner: "MichaelMure",
+ project: "git-bug",
+ err: nil,
+ },
+ },
+ {
+ name: "url with git protocol",
+ args: args{
+ url: "git://github.com/MichaelMure/git-bug.git",
+ },
+ want: want{
+ owner: "MichaelMure",
+ project: "git-bug",
+ err: nil,
+ },
+ },
+ {
+ name: "ssh url",
+ args: args{
+ url: "git@github.com:MichaelMure/git-bug.git",
+ },
+ want: want{
+ owner: "MichaelMure",
+ project: "git-bug",
+ err: nil,
+ },
+ },
+ {
+ name: "bad url",
+ args: args{
+ url: "https://githb.com/MichaelMure/git-bug.git",
+ },
+ want: want{
+ err: ErrBadProjectURL,
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ owner, project, err := splitURL(tt.args.url)
+ assert.Equal(t, tt.want.err, err)
+ assert.Equal(t, tt.want.owner, owner)
+ assert.Equal(t, tt.want.project, project)
+ })
+ }
+}
+
+func TestValidateProject(t *testing.T) {
+ tokenPrivateScope := os.Getenv("GITHUB_TOKEN_PRIVATE")
+ if tokenPrivateScope == "" {
+ t.Skip("Env var GITHUB_TOKEN_PRIVATE missing")
+ }
+
+ tokenPublicScope := os.Getenv("GITHUB_TOKEN_PUBLIC")
+ if tokenPublicScope == "" {
+ t.Skip("Env var GITHUB_TOKEN_PUBLIC missing")
+ }
+
+ type args struct {
+ owner string
+ project string
+ token string
+ }
+ tests := []struct {
+ name string
+ args args
+ want bool
+ }{
+ {
+ name: "public repository and token with scope 'public_repo",
+ args: args{
+ project: "git-bug",
+ owner: "MichaelMure",
+ token: tokenPublicScope,
+ },
+ want: true,
+ },
+ {
+ name: "private repository and token with scope 'repo",
+ args: args{
+ project: "git-bug-test-github-bridge",
+ owner: "MichaelMure",
+ token: tokenPrivateScope,
+ },
+ want: true,
+ },
+ {
+ name: "private repository and token with scope 'public_repo'",
+ args: args{
+ project: "git-bug-test-github-bridge",
+ owner: "MichaelMure",
+ token: tokenPublicScope,
+ },
+ want: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ ok, _ := validateProject(tt.args.owner, tt.args.project, tt.args.token)
+ assert.Equal(t, tt.want, ok)
+ })
+ }
+}