Cleanup Code (#348)

* Fix "Empty slice declaration using a literal"
* Fix "collides with imported package name"
* Remove unused code in pipeline
* Remove unused oauth2.providerAuthHeaderWorks()
* Add TODOs
* Format Code
* Cleanup doublestar import
* Migrate deprecated functions

Co-authored-by: Anbraten <anton@ju60.de>
This commit is contained in:
6543 2021-09-24 16:29:26 +02:00 committed by GitHub
parent e8db6b8c04
commit 0bd10fa507
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 144 additions and 187 deletions

View file

@ -319,7 +319,7 @@ func execWithAxis(c *cli.Context, axis matrix.Axis) error {
metadata := metadataFromContext(c, axis) metadata := metadataFromContext(c, axis)
environ := metadata.Environ() environ := metadata.Environ()
secrets := []compiler.Secret{} var secrets []compiler.Secret
for k, v := range metadata.EnvironDrone() { for k, v := range metadata.EnvironDrone() {
environ[k] = v environ[k] = v
} }

View file

@ -279,7 +279,7 @@ func (a *authorizer) authorize(ctx context.Context) error {
} }
func redirect(w http.ResponseWriter, req *http.Request) { func redirect(w http.ResponseWriter, req *http.Request) {
var serverHost string = server.Config.Server.Host serverHost := server.Config.Server.Host
serverHost = strings.TrimPrefix(serverHost, "http://") serverHost = strings.TrimPrefix(serverHost, "http://")
serverHost = strings.TrimPrefix(serverHost, "https://") serverHost = strings.TrimPrefix(serverHost, "https://")
req.URL.Scheme = "https" req.URL.Scheme = "https"

2
go.mod
View file

@ -7,7 +7,7 @@ require (
docker.io/go-docker v1.0.0 docker.io/go-docker v1.0.0
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 // indirect github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5 // indirect
github.com/bmatcuk/doublestar v1.3.4 github.com/bmatcuk/doublestar v1.3.4 // indirect
github.com/bmatcuk/doublestar/v4 v4.0.2 github.com/bmatcuk/doublestar/v4 v4.0.2
github.com/bradrydzewski/togo v0.0.0-20180401185031-50a0e4726e74 // indirect github.com/bradrydzewski/togo v0.0.0-20180401185031-50a0e4726e74 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect

View file

@ -41,7 +41,7 @@ type TaskStore interface {
// ensures the task Queue can be restored when the system starts. // ensures the task Queue can be restored when the system starts.
func WithTaskStore(q queue.Queue, s TaskStore) queue.Queue { func WithTaskStore(q queue.Queue, s TaskStore) queue.Queue {
tasks, _ := s.TaskList() tasks, _ := s.TaskList()
toEnqueue := []*queue.Task{} var toEnqueue []*queue.Task
for _, task := range tasks { for _, task := range tasks {
toEnqueue = append(toEnqueue, &queue.Task{ toEnqueue = append(toEnqueue, &queue.Task{
ID: task.ID, ID: task.ID,

View file

@ -165,7 +165,7 @@ func splitVolumeParts(volumeParts string) ([]string, error) {
} }
if r.MatchString(volumeParts) { if r.MatchString(volumeParts) {
results := r.FindStringSubmatch(volumeParts)[1:] results := r.FindStringSubmatch(volumeParts)[1:]
cleanResults := []string{} var cleanResults []string
for _, item := range results { for _, item := range results {
if item != "" { if item != "" {
cleanResults = append(cleanResults, item) cleanResults = append(cleanResults, item)

View file

@ -2,9 +2,6 @@ package docker
import ( import (
"context" "context"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/term"
"io" "io"
"os" "os"
@ -14,6 +11,9 @@ import (
"docker.io/go-docker/api/types" "docker.io/go-docker/api/types"
"docker.io/go-docker/api/types/network" "docker.io/go-docker/api/types/network"
"docker.io/go-docker/api/types/volume" "docker.io/go-docker/api/types/volume"
"github.com/docker/docker/pkg/jsonmessage"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/term"
) )
type engine struct { type engine struct {
@ -49,10 +49,10 @@ func (e *engine) Setup(_ context.Context, conf *backend.Config) error {
return err return err
} }
} }
for _, network := range conf.Networks { for _, n := range conf.Networks {
_, err := e.client.NetworkCreate(noContext, network.Name, types.NetworkCreate{ _, err := e.client.NetworkCreate(noContext, n.Name, types.NetworkCreate{
Driver: network.Driver, Driver: n.Driver,
Options: network.DriverOpts, Options: n.DriverOpts,
// Labels: defaultLabels, // Labels: defaultLabels,
}) })
if err != nil { if err != nil {
@ -89,7 +89,7 @@ func (e *engine) Exec(ctx context.Context, proc *backend.Step) error {
} }
_, err := e.client.ContainerCreate(ctx, config, hostConfig, nil, proc.Name) _, err := e.client.ContainerCreate(ctx, config, hostConfig, nil, proc.Name)
if docker.IsErrImageNotFound(err) { if docker.IsErrNotFound(err) {
// automatically pull and try to re-create the image if the // automatically pull and try to re-create the image if the
// failure is caused because the image does not exist. // failure is caused because the image does not exist.
responseBody, perr := e.client.ImagePull(ctx, config.Image, pullopts) responseBody, perr := e.client.ImagePull(ctx, config.Image, pullopts)
@ -178,11 +178,11 @@ func (e *engine) Destroy(_ context.Context, conf *backend.Config) error {
e.client.ContainerRemove(noContext, step.Name, removeOpts) e.client.ContainerRemove(noContext, step.Name, removeOpts)
} }
} }
for _, volume := range conf.Volumes { for _, v := range conf.Volumes {
e.client.VolumeRemove(noContext, volume.Name, true) e.client.VolumeRemove(noContext, v.Name, true)
} }
for _, network := range conf.Networks { for _, n := range conf.Networks {
e.client.NetworkRemove(noContext, network.Name) e.client.NetworkRemove(noContext, n.Name)
} }
return nil return nil
} }

View file

@ -1 +0,0 @@
package pipeline

View file

@ -47,7 +47,7 @@ func paramsToEnv(from map[string]interface{}, to map[string]string) error {
return err return err
} }
in := []string{} var in []string
err = yaml.Unmarshal(out, &in) err = yaml.Unmarshal(out, &in)
if err == nil { if err == nil {
to[k] = strings.Join(in, ",") to[k] = strings.Join(in, ",")

View file

@ -5,7 +5,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
doublestar "github.com/bmatcuk/doublestar/v4" "github.com/bmatcuk/doublestar/v4"
libcompose "github.com/docker/libcompose/yaml" libcompose "github.com/docker/libcompose/yaml"
"github.com/woodpecker-ci/woodpecker/pipeline/frontend" "github.com/woodpecker-ci/woodpecker/pipeline/frontend"
"github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/types" "github.com/woodpecker-ci/woodpecker/pipeline/frontend/yaml/types"

View file

@ -66,7 +66,7 @@ func calc(matrix Matrix) []Axis {
} }
// structure to hold the transformed result set // structure to hold the transformed result set
axisList := []Axis{} var axisList []Axis
// for each axis calculate the uniqe set of values that should be used. // for each axis calculate the uniqe set of values that should be used.
for p := 0; p < perm; p++ { for p := 0; p < perm; p++ {

View file

@ -11,6 +11,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
// generate protobuffs // generate protobuffs
@ -48,9 +49,9 @@ func (c *client) Next(ctx context.Context, f Filter) (*Pipeline, error) {
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: done(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: done(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -88,9 +89,9 @@ func (c *client) Wait(ctx context.Context, id string) (err error) {
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: wait(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: wait(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -122,9 +123,9 @@ func (c *client) Init(ctx context.Context, id string, state State) (err error) {
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: init(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: init(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -156,9 +157,9 @@ func (c *client) Done(ctx context.Context, id string, state State) (err error) {
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: done(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: done(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -183,9 +184,9 @@ func (c *client) Extend(ctx context.Context, id string) (err error) {
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: extend(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: extend(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -217,9 +218,9 @@ func (c *client) Update(ctx context.Context, id string, state State) (err error)
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: update(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: update(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -252,9 +253,9 @@ func (c *client) Upload(ctx context.Context, id string, file *File) (err error)
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: upload(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: upload(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,
@ -284,9 +285,9 @@ func (c *client) Log(ctx context.Context, id string, line *Line) (err error) {
if err == nil { if err == nil {
break break
} else { } else {
log.Printf("grpc error: log(): code: %v: %s", grpc.Code(err), err) log.Printf("grpc error: log(): code: %v: %s", status.Code(err), err)
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,

View file

@ -10,6 +10,7 @@ import (
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
// generate protobuffs // generate protobuffs
@ -45,7 +46,7 @@ func (c *healthClient) Check(ctx context.Context) (bool, error) {
} }
return false, nil return false, nil
} }
switch grpc.Code(err) { switch status.Code(err) {
case case
codes.Aborted, codes.Aborted,
codes.DataLoss, codes.DataLoss,

View file

@ -1,17 +0,0 @@
package version
import "fmt"
var (
// major is for an API incompatible changes
major = 1
// minor is for functionality in a backwards-compatible manner
minor = 0
// patch is for backwards-compatible bug fixes
patch = 0
)
// String returns the supporeted specification versions in string format.
func String() string {
return fmt.Sprintf("%d.%d.%d", major, minor, patch)
}

View file

@ -167,13 +167,13 @@ func DeleteBuild(c *gin.Context) {
build, err := store.GetBuildNumber(c, repo, num) build, err := store.GetBuildNumber(c, repo, num)
if err != nil { if err != nil {
c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
procs, err := store.FromContext(c).ProcList(build) procs, err := store.FromContext(c).ProcList(build)
if err != nil { if err != nil {
c.AbortWithError(404, err) _ = c.AbortWithError(404, err)
return return
} }
@ -183,8 +183,10 @@ func DeleteBuild(c *gin.Context) {
} }
// First cancel/evict procs in the queue in one go // First cancel/evict procs in the queue in one go
procToCancel := []string{} var (
procToEvict := []string{} procToCancel []string
procToEvict []string
)
for _, proc := range procs { for _, proc := range procs {
if proc.PPID != 0 { if proc.PPID != 0 {
continue continue

View file

@ -404,8 +404,7 @@ func queueBuild(build *model.Build, repo *model.Repo, buildItems []*shared.Build
server.Config.Services.Queue.PushAtOnce(context.Background(), tasks) server.Config.Services.Queue.PushAtOnce(context.Background(), tasks)
} }
func taskIds(dependsOn []string, buildItems []*shared.BuildItem) []string { func taskIds(dependsOn []string, buildItems []*shared.BuildItem) (taskIds []string) {
taskIds := []string{}
for _, dep := range dependsOn { for _, dep := range dependsOn {
for _, buildItem := range buildItems { for _, buildItem := range buildItems {
if buildItem.Proc.Name == dep { if buildItem.Proc.Name == dep {
@ -413,7 +412,7 @@ func taskIds(dependsOn []string, buildItems []*shared.BuildItem) []string {
} }
} }
} }
return taskIds return
} }
func shasum(raw []byte) string { func shasum(raw []byte) string {

View file

@ -133,15 +133,14 @@ func HandleAuth(c *gin.Context) {
} }
exp := time.Now().Add(server.Config.Server.SessionExpires).Unix() exp := time.Now().Add(server.Config.Server.SessionExpires).Unix()
token := token.New(token.SessToken, u.Login) tokenString, err := token.New(token.SessToken, u.Login).SignExpires(u.Hash, exp)
tokenstr, err := token.SignExpires(u.Hash, exp)
if err != nil { if err != nil {
logrus.Errorf("cannot create token for %s. %s", u.Login, err) logrus.Errorf("cannot create token for %s. %s", u.Login, err)
c.Redirect(303, "/login?error=internal_error") c.Redirect(303, "/login?error=internal_error")
return return
} }
httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenstr) httputil.SetCookie(c.Writer, c.Request, "user_sess", tokenString)
intendedURL := c.Request.URL.Query()["url"] intendedURL := c.Request.URL.Query()["url"]
if len(intendedURL) > 0 { if len(intendedURL) > 0 {

View file

@ -32,7 +32,7 @@ import (
) )
func PostRepo(c *gin.Context) { func PostRepo(c *gin.Context) {
remote := remote.FromContext(c) r := remote.FromContext(c)
user := session.User(c) user := session.User(c)
repo := session.Repo(c) repo := session.Repo(c)
@ -75,13 +75,13 @@ func PostRepo(c *gin.Context) {
sig, sig,
) )
err = remote.Activate(user, repo, link) err = r.Activate(user, repo, link)
if err != nil { if err != nil {
c.String(500, err.Error()) c.String(500, err.Error())
return return
} }
from, err := remote.Repo(user, repo.Owner, repo.Name) from, err := r.Repo(user, repo.Owner, repo.Name)
if err == nil { if err == nil {
repo.Update(from) repo.Update(from)
} }
@ -166,7 +166,7 @@ func GetRepo(c *gin.Context) {
func DeleteRepo(c *gin.Context) { func DeleteRepo(c *gin.Context) {
remove, _ := strconv.ParseBool(c.Query("remove")) remove, _ := strconv.ParseBool(c.Query("remove"))
remote := remote.FromContext(c) r := remote.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -187,12 +187,12 @@ func DeleteRepo(c *gin.Context) {
} }
} }
remote.Deactivate(user, repo, server.Config.Server.Host) r.Deactivate(user, repo, server.Config.Server.Host)
c.JSON(200, repo) c.JSON(200, repo)
} }
func RepairRepo(c *gin.Context) { func RepairRepo(c *gin.Context) {
remote := remote.FromContext(c) r := remote.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -212,14 +212,14 @@ func RepairRepo(c *gin.Context) {
sig, sig,
) )
remote.Deactivate(user, repo, host) r.Deactivate(user, repo, host)
err = remote.Activate(user, repo, link) err = r.Activate(user, repo, link)
if err != nil { if err != nil {
c.String(500, err.Error()) c.String(500, err.Error())
return return
} }
from, err := remote.Repo(user, repo.Owner, repo.Name) from, err := r.Repo(user, repo.Owner, repo.Name)
if err == nil { if err == nil {
repo.Name = from.Name repo.Name = from.Name
repo.Owner = from.Owner repo.Owner = from.Owner
@ -238,7 +238,7 @@ func RepairRepo(c *gin.Context) {
} }
func MoveRepo(c *gin.Context) { func MoveRepo(c *gin.Context) {
remote := remote.FromContext(c) r := remote.FromContext(c)
repo := session.Repo(c) repo := session.Repo(c)
user := session.User(c) user := session.User(c)
@ -255,7 +255,7 @@ func MoveRepo(c *gin.Context) {
return return
} }
from, err := remote.Repo(user, owner, name) from, err := r.Repo(user, owner, name)
if err != nil { if err != nil {
c.AbortWithError(http.StatusInternalServerError, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
@ -298,8 +298,8 @@ func MoveRepo(c *gin.Context) {
sig, sig,
) )
remote.Deactivate(user, repo, host) r.Deactivate(user, repo, host)
err = remote.Activate(user, repo, link) err = r.Activate(user, repo, link)
if err != nil { if err != nil {
c.String(500, err.Error()) c.String(500, err.Error())
return return

View file

@ -118,7 +118,7 @@ func GetRepos(c *gin.Context) {
return return
} }
active := []*model.Repo{} var active []*model.Repo
for _, repo := range repos { for _, repo := range repos {
if repo.IsActive { if repo.IsActive {
active = append(active, repo) active = append(active, repo)
@ -129,14 +129,12 @@ func GetRepos(c *gin.Context) {
func PostToken(c *gin.Context) { func PostToken(c *gin.Context) {
user := session.User(c) user := session.User(c)
tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
token := token.New(token.UserToken, user.Login)
tokenstr, err := token.Sign(user.Hash)
if err != nil { if err != nil {
c.AbortWithError(http.StatusInternalServerError, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
c.String(http.StatusOK, tokenstr) c.String(http.StatusOK, tokenString)
} }
func DeleteToken(c *gin.Context) { func DeleteToken(c *gin.Context) {
@ -149,11 +147,10 @@ func DeleteToken(c *gin.Context) {
return return
} }
token := token.New(token.UserToken, user.Login) tokenString, err := token.New(token.UserToken, user.Login).Sign(user.Hash)
tokenstr, err := token.Sign(user.Hash)
if err != nil { if err != nil {
c.AbortWithError(http.StatusInternalServerError, err) c.AbortWithError(http.StatusInternalServerError, err)
return return
} }
c.String(http.StatusOK, tokenstr) c.String(http.StatusOK, tokenString)
} }

View file

@ -50,8 +50,7 @@ func parseDockerConfig(path string) ([]*model.Registry, error) {
} }
} }
auths := []*model.Registry{} var auths []*model.Registry
for key, auth := range configFile.AuthConfigs { for key, auth := range configFile.AuthConfigs {
auths = append(auths, &model.Registry{ auths = append(auths, &model.Registry{
Address: key, Address: key,

View file

@ -44,9 +44,8 @@ func (p *plugin) SenderDelete(repo *model.Repo, login string) error {
return internal.Send("DELETE", path, nil, nil) return internal.Send("DELETE", path, nil, nil)
} }
func (p *plugin) SenderList(repo *model.Repo) ([]*model.Sender, error) { func (p *plugin) SenderList(repo *model.Repo) (out []*model.Sender, err error) {
path := fmt.Sprintf("%s/senders/%s/%s", p.endpoint, repo.Owner, repo.Name) path := fmt.Sprintf("%s/senders/%s/%s", p.endpoint, repo.Owner, repo.Name)
out := []*model.Sender{} err = internal.Send("GET", path, nil, out)
err := internal.Send("GET", path, nil, out)
return out, err return out, err
} }

View file

@ -267,7 +267,7 @@ func (q *fifo) filterWaiting() {
// rebuild waitingDeps // rebuild waitingDeps
q.waitingOnDeps = list.New() q.waitingOnDeps = list.New()
filtered := []*list.Element{} var filtered []*list.Element
var nextPending *list.Element var nextPending *list.Element
for e := q.pending.Front(); e != nil; e = nextPending { for e := q.pending.Front(); e != nil; e = nextPending {
nextPending = e.Next() nextPending = e.Next()

View file

@ -104,13 +104,13 @@ func New(opts Opts) (remote.Remote, error) {
} }
func (c *Config) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) { func (c *Config) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) {
requestToken, url, err := c.Consumer.GetRequestTokenAndUrl("oob") requestToken, u, err := c.Consumer.GetRequestTokenAndUrl("oob")
if err != nil { if err != nil {
return nil, err return nil, err
} }
var code = req.FormValue("oauth_verifier") var code = req.FormValue("oauth_verifier")
if len(code) == 0 { if len(code) == 0 {
http.Redirect(res, req, url, http.StatusSeeOther) http.Redirect(res, req, u, http.StatusSeeOther)
return nil, nil return nil, nil
} }
requestToken.Token = req.FormValue("oauth_token") requestToken.Token = req.FormValue("oauth_token")

View file

@ -48,7 +48,7 @@ type Opts struct {
// New returns a Remote implementation that integrates with a Coding Platform or // New returns a Remote implementation that integrates with a Coding Platform or
// Coding Enterprise version control hosting provider. // Coding Enterprise version control hosting provider.
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
remote := &Coding{ r := &Coding{
URL: defaultURL, URL: defaultURL,
Client: opts.Client, Client: opts.Client,
Secret: opts.Secret, Secret: opts.Secret,
@ -59,10 +59,10 @@ func New(opts Opts) (remote.Remote, error) {
SkipVerify: opts.SkipVerify, SkipVerify: opts.SkipVerify,
} }
if opts.URL != defaultURL { if opts.URL != defaultURL {
remote.URL = strings.TrimSuffix(opts.URL, "/") r.URL = strings.TrimSuffix(opts.URL, "/")
} }
return remote, nil return r, nil
} }
type Coding struct { type Coding struct {

View file

@ -48,17 +48,17 @@ type client struct {
// New returns a Remote implementation that integrates with Getter, an open // New returns a Remote implementation that integrates with Getter, an open
// source Git hosting service and code review system. // source Git hosting service and code review system.
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
return &client{ return &client{
URL: opts.URL, URL: opts.URL,
Machine: url.Host, Machine: u.Host,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
PrivateMode: opts.PrivateMode, PrivateMode: opts.PrivateMode,

View file

@ -110,18 +110,18 @@ func getDesc(status string) string {
// New returns a Remote implementation that integrates with Gitea, an open // New returns a Remote implementation that integrates with Gitea, an open
// source Git service written in Go. See https://gitea.io/ // source Git service written in Go. See https://gitea.io/
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
return &client{ return &client{
URL: opts.URL, URL: opts.URL,
Context: opts.Context, Context: opts.Context,
Machine: url.Host, Machine: u.Host,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
PrivateMode: opts.PrivateMode, PrivateMode: opts.PrivateMode,
@ -129,6 +129,8 @@ func New(opts Opts) (remote.Remote, error) {
}, nil }, nil
} }
// TODO: dont create a new client for each func
// Login authenticates an account with Gitea using basic authentication. The // Login authenticates an account with Gitea using basic authentication. The
// Gitea account details are returned when the user is successfully authenticated. // Gitea account details are returned when the user is successfully authenticated.
func (c *client) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) { func (c *client) Login(res http.ResponseWriter, req *http.Request) (*model.User, error) {
@ -228,16 +230,14 @@ func (c *client) Repo(u *model.User, owner, name string) (*model.Repo, error) {
// Repos returns a list of all repositories for the Gitea account, including // Repos returns a list of all repositories for the Gitea account, including
// organization repositories. // organization repositories.
func (c *client) Repos(u *model.User) ([]*model.Repo, error) { func (c *client) Repos(u *model.User) (repos []*model.Repo, err error) {
repos := []*model.Repo{}
client, err := c.newClientToken(u.Token) client, err := c.newClientToken(u.Token)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Gitea SDK forces us to read repo list paginated. // Gitea SDK forces us to read repo list paginated.
var page int = 1 var page = 1
for { for {
all, _, err := client.ListMyRepos( all, _, err := client.ListMyRepos(
gitea.ListReposOptions{ gitea.ListReposOptions{

View file

@ -51,21 +51,23 @@ type oauthclient struct {
SkipVerify bool SkipVerify bool
} }
// New returns a Remote implementation that integrates with Gitea, an open // TODO: merge with gitea.go (or drop basic auth)
// NewOauth returns a Remote implementation that integrates with Gitea, an open
// source Git service written in Go. See https://gitea.io/ // source Git service written in Go. See https://gitea.io/
func NewOauth(opts Opts) (remote.Remote, error) { func NewOauth(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
return &oauthclient{ return &oauthclient{
URL: opts.URL, URL: opts.URL,
Context: opts.Context, Context: opts.Context,
Machine: url.Host, Machine: u.Host,
Client: opts.Client, Client: opts.Client,
Secret: opts.Secret, Secret: opts.Secret,
Username: opts.Username, Username: opts.Username,
@ -219,7 +221,7 @@ func (c *oauthclient) Repos(u *model.User) ([]*model.Repo, error) {
} }
// Gitea SDK forces us to read repo list paginated. // Gitea SDK forces us to read repo list paginated.
var page int = 1 var page = 1
for { for {
all, _, err := client.ListMyRepos( all, _, err := client.ListMyRepos(
gitea.ListReposOptions{ gitea.ListReposOptions{

View file

@ -55,15 +55,15 @@ type Opts struct {
// New returns a Remote implementation that integrates with a GitHub Cloud or // New returns a Remote implementation that integrates with a GitHub Cloud or
// GitHub Enterprise version control hosting provider. // GitHub Enterprise version control hosting provider.
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
remote := &client{ r := &client{
API: defaultAPI, API: defaultAPI,
URL: defaultURL, URL: defaultURL,
Context: opts.Context, Context: opts.Context,
@ -73,18 +73,19 @@ func New(opts Opts) (remote.Remote, error) {
PrivateMode: opts.PrivateMode, PrivateMode: opts.PrivateMode,
SkipVerify: opts.SkipVerify, SkipVerify: opts.SkipVerify,
MergeRef: opts.MergeRef, MergeRef: opts.MergeRef,
Machine: url.Host, Machine: u.Host,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
} }
if opts.URL != defaultURL { if opts.URL != defaultURL {
remote.URL = strings.TrimSuffix(opts.URL, "/") r.URL = strings.TrimSuffix(opts.URL, "/")
remote.API = remote.URL + "/api/v3/" r.API = r.URL + "/api/v3/"
} }
// Hack to enable oauth2 access in older GHE // Hack to enable oauth2 access in older GHE
oauth2.RegisterBrokenAuthHeaderProvider(remote.URL) // TODO: dont use deprecated func
return remote, nil oauth2.RegisterBrokenAuthHeaderProvider(r.URL)
return r, nil
} }
type client struct { type client struct {
@ -371,9 +372,9 @@ func (c *client) newClientToken(token string) *github.Client {
}, },
} }
} }
github := github.NewClient(tc) client := github.NewClient(tc)
github.BaseURL, _ = url.Parse(c.API) client.BaseURL, _ = url.Parse(c.API)
return github return client
} }
// helper function to return matching user email. // helper function to return matching user email.
@ -437,13 +438,12 @@ func (c *client) Status(u *model.User, r *model.Repo, b *model.Build, link strin
} }
func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link, ctx string, proc *model.Proc) error { func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link, ctx string, proc *model.Proc) error {
context := ctx
switch b.Event { switch b.Event {
case model.EventPull: case model.EventPull:
context += "/pr" ctx += "/pr"
default: default:
if len(b.Event) > 0 { if len(b.Event) > 0 {
context += "/" + b.Event ctx += "/" + b.Event
} }
} }
@ -451,13 +451,13 @@ func repoStatus(client *github.Client, r *model.Repo, b *model.Build, link, ctx
desc := github.String(convertDesc(b.Status)) desc := github.String(convertDesc(b.Status))
if proc != nil { if proc != nil {
context += "/" + proc.Name ctx += "/" + proc.Name
status = github.String(convertStatus(proc.State)) status = github.String(convertStatus(proc.State))
desc = github.String(convertDesc(proc.State)) desc = github.String(convertDesc(proc.State))
} }
data := github.RepoStatus{ data := github.RepoStatus{
Context: github.String(context), Context: github.String(ctx),
State: status, State: status,
Description: desc, Description: desc,
TargetURL: github.String(link), TargetURL: github.String(link),

View file

@ -48,19 +48,19 @@ type Opts struct {
// New returns a Remote implementation that integrates with Gitlab, an open // New returns a Remote implementation that integrates with Gitlab, an open
// source Git service. See https://gitlab.com // source Git service. See https://gitlab.com
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
return &Gitlab{ return &Gitlab{
URL: opts.URL, URL: opts.URL,
Client: opts.Client, Client: opts.Client,
Secret: opts.Secret, Secret: opts.Secret,
Machine: url.Host, Machine: u.Host,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
PrivateMode: opts.PrivateMode, PrivateMode: opts.PrivateMode,

View file

@ -48,19 +48,19 @@ type Opts struct {
// New returns a Remote implementation that integrates with Gitlab, an open // New returns a Remote implementation that integrates with Gitlab, an open
// source Git service. See https://gitlab.com // source Git service. See https://gitlab.com
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
return &Gitlab{ return &Gitlab{
URL: opts.URL, URL: opts.URL,
Client: opts.Client, Client: opts.Client,
Secret: opts.Secret, Secret: opts.Secret,
Machine: url.Host, Machine: u.Host,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
PrivateMode: opts.PrivateMode, PrivateMode: opts.PrivateMode,

View file

@ -48,17 +48,17 @@ type client struct {
// New returns a Remote implementation that integrates with Gogs, an open // New returns a Remote implementation that integrates with Gogs, an open
// source Git service written in Go. See https://gogs.io/ // source Git service written in Go. See https://gogs.io/
func New(opts Opts) (remote.Remote, error) { func New(opts Opts) (remote.Remote, error) {
url, err := url.Parse(opts.URL) u, err := url.Parse(opts.URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
host, _, err := net.SplitHostPort(url.Host) host, _, err := net.SplitHostPort(u.Host)
if err == nil { if err == nil {
url.Host = host u.Host = host
} }
return &client{ return &client{
URL: opts.URL, URL: opts.URL,
Machine: url.Host, Machine: u.Host,
Username: opts.Username, Username: opts.Username,
Password: opts.Password, Password: opts.Password,
PrivateMode: opts.PrivateMode, PrivateMode: opts.PrivateMode,

View file

@ -202,7 +202,7 @@ func TestFetch(t *testing.T) {
} }
if matchingFiles != len(tt.expectedFileNames) { if matchingFiles != len(tt.expectedFileNames) {
receivedFileNames := []string{} var receivedFileNames []string
for _, file := range files { for _, file := range files {
receivedFileNames = append(receivedFileNames, file.Name) receivedFileNames = append(receivedFileNames, file.Name)
} }

View file

@ -37,7 +37,7 @@ func TestUpdateProcStatusNotExited(t *testing.T) {
Exited: false, Exited: false,
// Dummy data // Dummy data
Finished: int64(1), Finished: int64(1),
ExitCode: int(137), ExitCode: 137,
Error: "not an error", Error: "not an error",
} }
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(1)) proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(1))
@ -48,7 +48,7 @@ func TestUpdateProcStatusNotExited(t *testing.T) {
t.Errorf("Proc started not equals 42 != %d", proc.Started) t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(0) { } else if proc.Stopped != int64(0) {
t.Errorf("Proc stopped not equals 0 != %d", proc.Stopped) t.Errorf("Proc stopped not equals 0 != %d", proc.Stopped)
} else if proc.ExitCode != int(0) { } else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} else if proc.Error != "" { } else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error) t.Errorf("Proc error not equals '' != '%s'", proc.Error)
@ -64,7 +64,7 @@ func TestUpdateProcStatusNotExitedButStopped(t *testing.T) {
Exited: false, Exited: false,
// Dummy data // Dummy data
Finished: int64(1), Finished: int64(1),
ExitCode: int(137), ExitCode: 137,
Error: "not an error", Error: "not an error",
} }
proc, _ = UpdateProcStatus(&mockUpdateProcStore{}, *proc, state, int64(42)) proc, _ = UpdateProcStatus(&mockUpdateProcStore{}, *proc, state, int64(42))
@ -75,7 +75,7 @@ func TestUpdateProcStatusNotExitedButStopped(t *testing.T) {
t.Errorf("Proc started not equals 42 != %d", proc.Started) t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(64) { } else if proc.Stopped != int64(64) {
t.Errorf("Proc stopped not equals 64 != %d", proc.Stopped) t.Errorf("Proc stopped not equals 64 != %d", proc.Stopped)
} else if proc.ExitCode != int(0) { } else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} else if proc.Error != "" { } else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error) t.Errorf("Proc error not equals '' != '%s'", proc.Error)
@ -89,7 +89,7 @@ func TestUpdateProcStatusExited(t *testing.T) {
Started: int64(42), Started: int64(42),
Exited: true, Exited: true,
Finished: int64(34), Finished: int64(34),
ExitCode: int(137), ExitCode: 137,
Error: "an error", Error: "an error",
} }
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42)) proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42))
@ -100,7 +100,7 @@ func TestUpdateProcStatusExited(t *testing.T) {
t.Errorf("Proc started not equals 42 != %d", proc.Started) t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(34) { } else if proc.Stopped != int64(34) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped) t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.ExitCode != int(137) { } else if proc.ExitCode != 137 {
t.Errorf("Proc exit code not equals 137 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 137 != %d", proc.ExitCode)
} else if proc.Error != "an error" { } else if proc.Error != "an error" {
t.Errorf("Proc error not equals 'an error' != '%s'", proc.Error) t.Errorf("Proc error not equals 'an error' != '%s'", proc.Error)
@ -124,7 +124,7 @@ func TestUpdateProcStatusExitedButNot137(t *testing.T) {
t.Errorf("Proc started not equals 42 != %d", proc.Started) t.Errorf("Proc started not equals 42 != %d", proc.Started)
} else if proc.Stopped != int64(34) { } else if proc.Stopped != int64(34) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped) t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.ExitCode != int(0) { } else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} else if proc.Error != "an error" { } else if proc.Error != "an error" {
t.Errorf("Proc error not equals 'an error' != '%s'", proc.Error) t.Errorf("Proc error not equals 'an error' != '%s'", proc.Error)
@ -138,14 +138,14 @@ func TestUpdateProcStatusExitedWithCode(t *testing.T) {
Started: int64(42), Started: int64(42),
Exited: true, Exited: true,
Finished: int64(34), Finished: int64(34),
ExitCode: int(1), ExitCode: 1,
Error: "an error", Error: "an error",
} }
proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42)) proc, _ := UpdateProcStatus(&mockUpdateProcStore{}, model.Proc{}, state, int64(42))
if proc.State != model.StatusFailure { if proc.State != model.StatusFailure {
t.Errorf("Proc status not equals '%s' != '%s'", model.StatusFailure, proc.State) t.Errorf("Proc status not equals '%s' != '%s'", model.StatusFailure, proc.State)
} else if proc.ExitCode != int(1) { } else if proc.ExitCode != 1 {
t.Errorf("Proc exit code not equals 1 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 1 != %d", proc.ExitCode)
} }
} }
@ -206,7 +206,7 @@ func TestUpdateProcStatusToDoneSkipped(t *testing.T) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped) t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.Error != "" { } else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error) t.Errorf("Proc error not equals '' != '%s'", proc.Error)
} else if proc.ExitCode != int(0) { } else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} }
} }
@ -227,7 +227,7 @@ func TestUpdateProcStatusToDoneSuccess(t *testing.T) {
t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped) t.Errorf("Proc stopped not equals 34 != %d", proc.Stopped)
} else if proc.Error != "" { } else if proc.Error != "" {
t.Errorf("Proc error not equals '' != '%s'", proc.Error) t.Errorf("Proc error not equals '' != '%s'", proc.Error)
} else if proc.ExitCode != int(0) { } else if proc.ExitCode != 0 {
t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 0 != %d", proc.ExitCode)
} }
} }
@ -247,7 +247,7 @@ func TestUpdateProcStatusToDoneFailureWithError(t *testing.T) {
func TestUpdateProcStatusToDoneFailureWithExitCode(t *testing.T) { func TestUpdateProcStatusToDoneFailureWithExitCode(t *testing.T) {
t.Parallel() t.Parallel()
state := rpc.State{ExitCode: int(43)} state := rpc.State{ExitCode: 43}
proc, _ := UpdateProcStatusToDone(&mockUpdateProcStore{}, model.Proc{}, state) proc, _ := UpdateProcStatusToDone(&mockUpdateProcStore{}, model.Proc{}, state)
@ -269,7 +269,7 @@ func TestUpdateProcToStatusKilledStarted(t *testing.T) {
t.Errorf("Proc stopped not equals %d < %d", now, proc.Stopped) t.Errorf("Proc stopped not equals %d < %d", now, proc.Stopped)
} else if proc.Started != proc.Stopped { } else if proc.Started != proc.Stopped {
t.Errorf("Proc started not equals %d != %d", proc.Stopped, proc.Started) t.Errorf("Proc started not equals %d != %d", proc.Stopped, proc.Started)
} else if proc.ExitCode != int(137) { } else if proc.ExitCode != 137 {
t.Errorf("Proc exit code not equals 137 != %d", proc.ExitCode) t.Errorf("Proc exit code not equals 137 != %d", proc.ExitCode)
} }
} }

View file

@ -69,12 +69,12 @@ func (s *Syncer) Sync(user *model.User) error {
return err return err
} }
var remote []*model.Repo var remoteRepos []*model.Repo
var perms []*model.Perm var perms []*model.Perm
for _, repo := range repos { for _, repo := range repos {
if s.Match(repo) { if s.Match(repo) {
remote = append(remote, repo) remoteRepos = append(remoteRepos, repo)
perm := model.Perm{ perm := model.Perm{
UserID: user.ID, UserID: user.ID,
Repo: repo.FullName, Repo: repo.FullName,
@ -89,7 +89,7 @@ func (s *Syncer) Sync(user *model.User) error {
} }
} }
err = s.Store.RepoBatch(remote) err = s.Store.RepoBatch(remoteRepos)
if err != nil { if err != nil {
return err return err
} }

View file

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build !cgo
// +build !cgo // +build !cgo
package datastore package datastore

View file

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
//go:build cgo
// +build cgo // +build cgo
package datastore package datastore

View file

@ -380,29 +380,6 @@ func (t *Transport) AuthenticateClient() error {
return t.updateToken(t.Token, url.Values{"grant_type": {"client_credentials"}}) return t.updateToken(t.Token, url.Values{"grant_type": {"client_credentials"}})
} }
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
// implements the OAuth2 spec correctly
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
// In summary:
// - Reddit only accepts client secret in the Authorization header
// - Dropbox accepts either it in URL param or Auth header, but not both.
// - Google only accepts URL param (not spec compliant?), not Auth header
func providerAuthHeaderWorks(tokenURL string) bool {
if strings.HasPrefix(tokenURL, "https://accounts.google.com/") ||
strings.HasPrefix(tokenURL, "https://github.com/") ||
strings.HasPrefix(tokenURL, "https://api.instagram.com/") ||
strings.HasPrefix(tokenURL, "https://www.douban.com/") {
// Some sites fail to implement the OAuth2 spec fully.
return false
}
// Assume the provider implements the spec properly
// otherwise. We can add more exceptions as they're
// discovered. We will _not_ be adding configurable hooks
// to this package to let users select server bugs.
return true
}
// updateToken mutates both tok and v. // updateToken mutates both tok and v.
func (t *Transport) updateToken(tok *Token, v url.Values) error { func (t *Transport) updateToken(tok *Token, v url.Values) error {
v.Set("client_id", t.ClientId) v.Set("client_id", t.ClientId)

View file

@ -5,6 +5,5 @@
package tools package tools
import ( import (
_ "github.com/bmatcuk/doublestar"
_ "github.com/woodpecker-ci/togo" _ "github.com/woodpecker-ci/togo"
) )

2
vendor/modules.txt vendored
View file

@ -174,8 +174,6 @@ github.com/mattn/go-isatty
# github.com/mattn/go-sqlite3 v2.0.3+incompatible # github.com/mattn/go-sqlite3 v2.0.3+incompatible
## explicit ## explicit
github.com/mattn/go-sqlite3 github.com/mattn/go-sqlite3
# github.com/mattn/go-zglob v0.0.3
## explicit
# github.com/matttproud/golang_protobuf_extensions v1.0.1 # github.com/matttproud/golang_protobuf_extensions v1.0.1
github.com/matttproud/golang_protobuf_extensions/pbutil github.com/matttproud/golang_protobuf_extensions/pbutil
# github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd