Skip to content

Commit

Permalink
Switch to go-git for a pure golang implementation (#5)
Browse files Browse the repository at this point in the history
* Switch to go-git for a pure golang implementation

After src-d/go-git#1081 was merged,
the performance seems to be significantly better (usable).

Even if a slight bit slower, this means theres no more CGO dependency
making it much more portable.

* Format cmd/brew.go

Co-Authored-By: fixmie[bot] <44270338+fixmie[bot]@users.noreply.github.com>
  • Loading branch information
Adam Kunicki and fixmie[bot] authored Jul 10, 2019
1 parent 8a2b0a1 commit e83d900
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 149 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,7 @@ beer

# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736
.glide/
vendor/

# ignore release binaries
dist/
58 changes: 10 additions & 48 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,54 +1,16 @@
image: golang:1.11

variables:
GOFLAGS: -mod=readonly
GOPATH: ${CI_PROJECT_DIR}/vendor/go
PKG_CONFIG_PATH: ${CI_PROJECT_DIR}/libgit2/lib/pkgconfig

.modcache: &modcache
key: modcache
paths:
- vendor/go/pkg/mod/
- libgit2

before_script:
- apt-get -qq update
- apt-get install -y libssh2-1-dev cmake libssl-dev zlib1g-dev libcurl4-openssl-dev
image: docker:stable
services:
- docker:dind

stages:
- dependencies
- test
- build
- build

dependencies:
stage: dependencies
before_script:
- apt-get -qq update
- apt-get install -y libssh2-1-dev cmake libssl-dev zlib1g-dev libcurl4-openssl-dev
- wget https://github.com/libgit2/libgit2/archive/v0.27.8.tar.gz
- tar xf v0.27.8.tar.gz
- mkdir -p ${CI_PROJECT_DIR}/libgit2
- pushd libgit2-0.27.8 && mkdir -p build && cd build && cmake .. -DCMAKE_INSTALL_PREFIX=${CI_PROJECT_DIR}/libgit2 && cmake --build . --target install && popd

script: go mod download
cache: *modcache

test:
stage: test
image: golang:1.11
cache:
<<: *modcache
policy: pull
script: go test ./...
variables:
GORELEASER_IMAGE: goreleaser/goreleaser:latest
DOCKER_REGISTRY: https://index.docker.io/v1/

build:
stage: build
cache:
<<: *modcache
policy: pull
script: go build
artifacts:
paths:
- beer
expire_in: 1 week

script:
- docker pull $GORELEASER_IMAGE
- docker run --rm --privileged -v $PWD:/go/src/github.com/kunickiaj/beer -v /var/run/docker.sock:/var/run/docker.sock -w /go/src/github.com/kunickiaj/beer -e GITHUB_TOKEN -e DOCKER_USERNAME -e DOCKER_PASSWORD -e DOCKER_REGISTRY $GORELEASER_IMAGE release --rm-dist
31 changes: 31 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
before:
hooks:
builds:
- env:
- CGO_ENABLED=0
archives:
- id: dist
replacements:
darwin: Darwin
linux: Linux
windows: Windows
amd64: x86_64
dockers:
-
goos: linux
goarch: amd64
binaries:
- beer
image_templates:
- 'kunickiaj/beer:{{ .Tag }}'
- 'kunickiaj/beer:latest'
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
6 changes: 6 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
FROM scratch

ADD beer /beer

ENTRYPOINT [ "/beer" ]
CMD [ "--help" ]
105 changes: 47 additions & 58 deletions cmd/brew.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,20 @@ import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path"
"regexp"
"time"

"gopkg.in/src-d/go-git.v4/plumbing/object"

jira "github.com/andygrunwald/go-jira"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/viper"
git "gopkg.in/libgit2/git2go.v27"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/plumbing"
"gopkg.in/src-d/go-git.v4/plumbing/format/config"
)

var brewCmd = &cobra.Command{
Expand Down Expand Up @@ -77,13 +84,11 @@ func brew(cmd *cobra.Command, args []string) {
panic(err)
}

repo, err := git.OpenRepositoryExtended(cwd, git.RepositoryOpenFromEnv, "")
repo, err := git.PlainOpenWithOptions(cwd, &git.PlainOpenOptions{DetectDotGit: true})
if err != nil {
panic(err)
}

defer repo.Free()

// Get user struct for logged in user
jiraUser, _, err := jiraClient.User.Get(username)
if err != nil {
Expand Down Expand Up @@ -231,100 +236,84 @@ func bodyToString(res *jira.Response) string {
}

func checkout(repo *git.Repository, issue *jira.Issue) error {
checkoutOpts := &git.CheckoutOpts{
Strategy: git.CheckoutSafe | git.CheckoutRecreateMissing | git.CheckoutAllowConflicts | git.CheckoutUseTheirs,
workTree, err := repo.Worktree()
if err != nil {
return err
}

// Check only for local branches
branch, err := repo.LookupBranch(issue.Key, git.BranchLocal)
branch := fmt.Sprintf("refs/heads/%s", issue.Key)
b := plumbing.ReferenceName(branch)

// First try to checkout branch
newBranch := false
// If it doesn't exist then create it
if branch == nil || err != nil {
err = workTree.Checkout(&git.CheckoutOptions{Create: false, Force: false, Keep: true, Branch: b})
if err != nil {
// didn't exist so try to create it
newBranch = true
err = workTree.Checkout(&git.CheckoutOptions{Create: true, Force: false, Keep: true, Branch: b})
}

if err != nil {
return err
}

head, err := repo.Head()
if newBranch {
commitMessage := fmt.Sprintf("%s. %s", issue.Key, issue.Fields.Summary)
usr, err := user.Current()
if err != nil {
return err
}

headCommit, err := repo.LookupCommit(head.Target())
gitConfig, err := os.Open(path.Join(usr.HomeDir, ".gitconfig"))
if err != nil {
return err
}
decoder := config.NewDecoder(gitConfig)
decodedConfig := config.New()
err = decoder.Decode(decodedConfig)

branch, err = repo.CreateBranch(issue.Key, headCommit, false)
if err != nil {
return err
}
}

defer branch.Free()

// Get tree for the branch
commit, err := repo.LookupCommit(branch.Target())
if err != nil {
userSection := decodedConfig.Section("user")
_, err = workTree.Commit(commitMessage, &git.CommitOptions{
Author: &object.Signature{
Name: userSection.Option("name"),
Email: userSection.Option("email"),
When: time.Now(),
},
})
return err
}

defer commit.Free()

tree, err := repo.LookupTree(commit.TreeId())
if err != nil {
return err
}

// Checkout the tree
err = repo.CheckoutTree(tree, checkoutOpts)
if err != nil {
return err
}

// Set the head to point to the new branch
repo.SetHead("refs/heads/" + issue.Key)

headCommit, err := repo.LookupCommit(branch.Target())
if err != nil {
return err
}

signature, err := repo.DefaultSignature()
if err != nil {
return err
}

if newBranch {
commitMessage := fmt.Sprintf("%s. %s", issue.Key, issue.Fields.Summary)
_, err = repo.CreateCommit("refs/heads/"+issue.Key, signature, signature, commitMessage, tree, headCommit)
}
return nil
}

func getProjectKey(repo *git.Repository) (string, error) {
head, err := repo.Head()
ref, err := repo.Head()
if err != nil {
return "", err
}

commit, err := repo.LookupCommit(head.Target())
cIter, err := repo.Log(&git.LogOptions{From: ref.Hash()})
if err != nil {
return "", err
}

var depth uint
for depth < 5 {
commit, err := cIter.Next()
for depth < 5 && err != nil {
re := regexp.MustCompile("^([a-zA-Z]{3,})(-[0-9]+)")
message := commit.Message()
message := commit.Message
match := re.FindStringSubmatch(message)
if len(match) == 3 && len(match[1]) > 0 {
log.WithField("project_key", match[1]).Info("Inferred project key; override with --project if incorrect")
return match[1], nil
}
depth++
commit = commit.Parent(0)
commit, err = cIter.Next()
}

defer commit.Free()
return "", errors.New("Wasn't able to infer a project key")
return "", errors.New("wasn't able to infer a project key")
}

func createMetaProject(jira *jira.Client, projectKey string) (*jira.MetaProject, error) {
Expand Down
40 changes: 7 additions & 33 deletions cmd/taste.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import (

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
git "gopkg.in/libgit2/git2go.v27"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/config"
)

var tasteCmd = &cobra.Command{
Expand Down Expand Up @@ -57,13 +58,11 @@ func taste(cmd *cobra.Command, args []string) {
panic(err)
}

repo, err := git.OpenRepository(cwd)
repo, err := git.PlainOpenWithOptions(cwd, &git.PlainOpenOptions{DetectDotGit: true})
if err != nil {
panic(err)
}

defer repo.Free()

var ref string
if isWIP {
ref = "master%wip"
Expand All @@ -77,38 +76,13 @@ func taste(cmd *cobra.Command, args []string) {
}
log.WithField("refspec", refspec).Debug("Using refspec")

remote, err := repo.Remotes.Lookup("origin")
if err != nil {
panic(err)
}
log.WithField("remote", remote).Debug("Discovered remote")

pushOpts := &git.PushOptions{
RemoteCallbacks: git.RemoteCallbacks{
CredentialsCallback: credentialsCallback,
CertificateCheckCallback: certificateCheckCallback,
SidebandProgressCallback: transportMessageCallback,
},
}
refspecs := []string{refspec}
err = remote.Push(refspecs, pushOpts)
err = repo.Push(&git.PushOptions{
RemoteName: "origin",
RefSpecs: []config.RefSpec{config.RefSpec(refspec)},
})
if err != nil {
log.WithError(err).Error("Error pushing review")
os.Exit(1)
}
log.Info("Pushed review")
}

func credentialsCallback(url string, username string, allowedTypes git.CredType) (git.ErrorCode, *git.Cred) {
ret, cred := git.NewCredSshKeyFromAgent(username)
return git.ErrorCode(ret), &cred
}

func certificateCheckCallback(cert *git.Certificate, valid bool, hostname string) git.ErrorCode {
return 0
}

func transportMessageCallback(str string) git.ErrorCode {
fmt.Printf(str)
return 0
}
6 changes: 2 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,11 @@ require (
github.com/google/go-querystring v1.0.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/pkg/errors v0.8.1 // indirect
github.com/sirupsen/logrus v1.3.0
github.com/spf13/afero v1.2.0 // indirect
github.com/spf13/cobra v0.0.3
github.com/spf13/viper v1.3.1
github.com/trivago/tgo v1.0.5 // indirect
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b // indirect
golang.org/x/sys v0.0.0-20190124100055-b90733256f2e // indirect
gopkg.in/libgit2/git2go.v27 v27.0.0-20190104134018-ecaeb7a21d47
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529 // indirect
gopkg.in/src-d/go-git.v4 v4.12.0
)
Loading

0 comments on commit e83d900

Please sign in to comment.