Skip to content
This repository has been archived by the owner on Feb 27, 2023. It is now read-only.

Commit

Permalink
Merge 1847fc8 into 753477d
Browse files Browse the repository at this point in the history
  • Loading branch information
duck8823 committed Sep 23, 2018
2 parents 753477d + 1847fc8 commit 7bbc854
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 46 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ If you have already set $GOPATH, you can install it with the following command.
$ go get -u github.com/duck8823/duci
```

### Setting SSH
This server clone from github.com with **SSH** protocol
using private key `$HOME/.ssh/id_rsa` (default).
### Setting SSH (optional)
If target repository is private, You can use SSH key to clone repository from github.com.
Please set the public key of the pair at https://github.com/settings/keys.

### Add Webhooks to Your GitHub repository
Expand All @@ -79,12 +78,13 @@ server:
port: 8080
database_path: '$HOME/.duci/db'
github:
ssh_key_path: '$HOME/.ssh/id_rsa'
# (optional) You can use SSH key to clone. ex. '${HOME}/.ssh/id_rsa'
ssh_key_path: ''
# For create commit status. You can also use environment variable
api_token: ${GITHUB_API_TOKEN}
job:
timeout: 600
concurrency: `number of cpu`
concurrency: 4 # default is number of cpu
```

You can check the default value.
Expand Down
2 changes: 1 addition & 1 deletion application/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func init() {
DatabasePath: path.Join(os.Getenv("HOME"), ".duci/db"),
},
GitHub: &GitHub{
SSHKeyPath: path.Join(os.Getenv("HOME"), ".ssh/id_rsa"),
SSHKeyPath: "",
APIToken: maskString(os.Getenv("GITHUB_API_TOKEN")),
},
Job: &Job{
Expand Down
43 changes: 37 additions & 6 deletions application/service/git/git.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package git

import (
"github.com/duck8823/duci/application"
"github.com/duck8823/duci/application/context"
"github.com/pkg/errors"
"gopkg.in/src-d/go-git.v4"
Expand All @@ -25,9 +26,14 @@ type sshGitService struct {
auth transport.AuthMethod
}

// New returns the Service with ssh key path.
func New(sshKeyPath string) (Service, error) {
auth, err := ssh.NewPublicKeysFromFile("git", sshKeyPath, "")
type httpGitService struct{}

// New returns the Service.
func New() (Service, error) {
if application.Config.GitHub.SSHKeyPath == "" {
return &httpGitService{}, nil
}
auth, err := ssh.NewPublicKeysFromFile("git", application.Config.GitHub.SSHKeyPath, "")
if err != nil {
return nil, err
}
Expand All @@ -47,14 +53,39 @@ func (s *sshGitService) Clone(ctx context.Context, dir string, src TargetSource)
return errors.WithStack(err)
}

wt, err := gitRepository.Worktree()
if err := checkout(gitRepository, src.SHA); err != nil {
return errors.WithStack(err)
}
return nil
}

// Clone a repository into the path with target source.
func (s *httpGitService) Clone(ctx context.Context, dir string, src TargetSource) error {
gitRepository, err := git.PlainClone(dir, false, &git.CloneOptions{
URL: src.URL,
Progress: &ProgressLogger{ctx.UUID()},
ReferenceName: plumbing.ReferenceName(src.Ref),
Depth: 1,
})
if err != nil {
return errors.WithStack(err)
}

if err := checkout(gitRepository, src.SHA); err != nil {
return errors.WithStack(err)
}
return nil
}

func checkout(repo *git.Repository, sha plumbing.Hash) error {
wt, err := repo.Worktree()
if err != nil {
return errors.WithStack(err)
}

if err := wt.Checkout(&git.CheckoutOptions{
Hash: src.SHA,
Branch: plumbing.ReferenceName(src.SHA.String()),
Hash: sha,
Branch: plumbing.ReferenceName(sha.String()),
Create: true,
}); err != nil {
return errors.WithStack(err)
Expand Down
134 changes: 131 additions & 3 deletions application/service/git/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package git_test

import (
"fmt"
"github.com/duck8823/duci/application"
"github.com/duck8823/duci/application/context"
"github.com/duck8823/duci/application/service/git"
"github.com/google/uuid"
Expand All @@ -14,18 +15,31 @@ import (
)

func TestNew(t *testing.T) {
t.Run("when missing ssh key", func(t *testing.T) {
t.Run("when without ssh key path", func(t *testing.T) {
// expect
if _, err := git.New("/path/to/wrong/"); err == nil {
if _, err := git.New(); err != nil {
t.Error("error must not occur")
}
})

t.Run("when missing ssh key path", func(t *testing.T) {
// given
application.Config.GitHub.SSHKeyPath = "/path/to/wrong"

// expect
if _, err := git.New(); err == nil {
t.Error("error must occur")
}
})
}

func TestSshGitService_Clone(t *testing.T) {
// setup
application.Config.GitHub.SSHKeyPath = path.Join(os.Getenv("HOME"), ".ssh/id_rsa")

t.Run("with correct key", func(t *testing.T) {
// setup
client, err := git.New(path.Join(os.Getenv("HOME"), ".ssh/id_rsa"))
client, err := git.New()
if err != nil {
t.Fatalf("error occurred. %+v", err)
}
Expand Down Expand Up @@ -82,5 +96,119 @@ func TestSshGitService_Clone(t *testing.T) {
t.Error("erro must occur")
}
})

t.Run("with wrong sha", func(t *testing.T) {
// setup
tempDir := path.Join(os.TempDir(), fmt.Sprintf("duci_test_%v", time.Now().Unix()))
if err := os.MkdirAll(path.Join(tempDir, "dir"), 0700); err != nil {
t.Fatalf("%+v", err)
}

// when
err := client.Clone(
context.New("test/task", uuid.New(), &url.URL{}),
tempDir,
git.TargetSource{
URL: "git@github.com:duck8823/duci.git",
Ref: "refs/heads/master",
SHA: plumbing.NewHash(uuid.New().String()),
},
)

// then
if err == nil {
t.Error("error must occur")
}
})
})
}

func TestHttpGitService_Clone(t *testing.T) {
// setup
application.Config.GitHub.SSHKeyPath = ""

t.Run("with correct key", func(t *testing.T) {
// setup
client, err := git.New()
if err != nil {
t.Fatalf("error occurred. %+v", err)
}

t.Run("when target directory exists", func(t *testing.T) {
// setup
tempDir := path.Join(os.TempDir(), fmt.Sprintf("duci_test_%v", time.Now().Unix()))
if err := os.MkdirAll(path.Join(tempDir, "dir"), 0700); err != nil {
t.Fatalf("%+v", err)
}

// when
err := client.Clone(
context.New("test/task", uuid.New(), &url.URL{}),
tempDir,
git.TargetSource{
URL: "https://github.com/duck8823/duci.git",
Ref: "refs/heads/master",
SHA: plumbing.ZeroHash,
},
)

// then
if err != nil {
t.Errorf("must not error. %+v", err)
}

if _, err := os.Stat(path.Join(tempDir, ".git")); err != nil {
t.Errorf("must create dir: %s", path.Join(tempDir, ".git"))
}
})

t.Run("when target directory not exists", func(t *testing.T) {
if os.Getuid() == 0 {
t.Skip("skip if root user")
}

// given
wrongPath := "/path/to/not/exists"

// when
err := client.Clone(
context.New("test/task", uuid.New(), &url.URL{}),
wrongPath,
git.TargetSource{
URL: "https://github.com/duck8823/duci.git",
Ref: "refs/heads/master",
SHA: plumbing.ZeroHash,
},
)

// then
if err == nil {
t.Error("erro must occur")
}
})

t.Run("with wrong sha", func(t *testing.T) {
// setup
tempDir := path.Join(os.TempDir(), fmt.Sprintf("duci_test_%v", time.Now().Unix()))
if err := os.MkdirAll(path.Join(tempDir, "dir"), 0700); err != nil {
t.Fatalf("%+v", err)
}

// when
err := client.Clone(
context.New("test/task", uuid.New(), &url.URL{}),
tempDir,
git.TargetSource{
URL: "git@github.com:duck8823/duci.git",
Ref: "refs/heads/master",
SHA: plumbing.NewHash(uuid.New().String()),
},
)

// then
if err == nil {
t.Error("error must occur")
}
})
})
}
1 change: 1 addition & 0 deletions application/service/github/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import "github.com/google/go-github/github"
type Repository interface {
GetFullName() string
GetSSHURL() string
GetCloneURL() string
}

// PullRequest is a type alias of github.PullRequest
Expand Down
5 changes: 5 additions & 0 deletions application/service/github/github_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
type MockRepo struct {
FullName string
SSHURL string
CloneURL string
}

func (r *MockRepo) GetFullName() string {
Expand All @@ -25,6 +26,10 @@ func (r *MockRepo) GetSSHURL() string {
return r.SSHURL
}

func (r *MockRepo) GetCloneURL() string {
return r.CloneURL
}

func TestService_GetPullRequest(t *testing.T) {
// setup
s, err := github.New()
Expand Down
9 changes: 8 additions & 1 deletion application/service/github/target_source.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package github

import (
"github.com/duck8823/duci/application"
"github.com/duck8823/duci/application/service/git"
"gopkg.in/src-d/go-git.v4/plumbing"
)
Expand All @@ -14,8 +15,14 @@ type TargetSource struct {

// ToGitTargetSource returns a git.TargetSource.
func (s TargetSource) ToGitTargetSource() git.TargetSource {
var url string
if application.Config.GitHub.SSHKeyPath != "" {
url = s.Repo.GetSSHURL()
} else {
url = s.Repo.GetCloneURL()
}
return git.TargetSource{
URL: s.Repo.GetSSHURL(),
URL: url,
Ref: s.Ref,
SHA: s.SHA,
}
Expand Down

0 comments on commit 7bbc854

Please sign in to comment.