mirror of
https://github.com/cooperspencer/gickup.git
synced 2025-05-11 17:55:34 +02:00
switched cvs functions to modules
This commit is contained in:
parent
0ea1ba5036
commit
5015f4fb73
10 changed files with 629 additions and 612 deletions
41
bitbucket/bitbucket.go
Normal file
41
bitbucket/bitbucket.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package bitbucket
|
||||
|
||||
import (
|
||||
"gickup/types"
|
||||
"net/url"
|
||||
|
||||
"github.com/ktrysmt/go-bitbucket"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func Get(conf *types.Conf) []types.Repo {
|
||||
repos := []types.Repo{}
|
||||
for _, repo := range conf.Source.BitBucket {
|
||||
client := bitbucket.NewBasicAuth(repo.Username, repo.Password)
|
||||
if repo.Url == "" {
|
||||
repo.Url = bitbucket.DEFAULT_BITBUCKET_API_BASE_URL
|
||||
} else {
|
||||
bitbucketUrl, err := url.Parse(repo.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "bitbucket").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
client.SetApiBaseURL(*bitbucketUrl)
|
||||
}
|
||||
log.Info().Str("stage", "bitbucket").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
|
||||
repositories, err := client.Repositories.ListForAccount(&bitbucket.RepositoriesOptions{Owner: repo.User})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "bitbucket").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
exclude := types.GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range repositories.Items {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, types.Repo{Name: r.Name, Url: r.Links["clone"].([]interface{})[0].(map[string]interface{})["href"].(string), SshUrl: r.Links["clone"].([]interface{})[1].(map[string]interface{})["href"].(string), Token: "", Defaultbranch: r.Mainbranch.Name, Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
90
gitea/gitea.go
Normal file
90
gitea/gitea.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package gitea
|
||||
|
||||
import (
|
||||
"gickup/types"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func Backup(r types.Repo, d types.GenRepo, dry bool) {
|
||||
if d.Url == "" {
|
||||
d.Url = "https://gitea.com/"
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("mirroring %s to %s", types.Blue(r.Name), d.Url)
|
||||
giteaclient, err := gitea.NewClient(d.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
giteaclient.SetBasicAuth(d.Token, "")
|
||||
user, _, err := giteaclient.GetMyUserInfo()
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
if !dry {
|
||||
repo, _, err := giteaclient.GetRepo(user.UserName, r.Name)
|
||||
if err != nil {
|
||||
opts := gitea.MigrateRepoOption{RepoName: r.Name, RepoOwner: user.UserName, Mirror: true, CloneAddr: r.Url, AuthToken: r.Token}
|
||||
if r.Token == "" {
|
||||
opts = gitea.MigrateRepoOption{RepoName: r.Name, RepoOwner: user.UserName, Mirror: true, CloneAddr: r.Url, AuthUsername: r.Origin.User, AuthPassword: r.Origin.Password}
|
||||
}
|
||||
_, _, err := giteaclient.MigrateRepo(opts)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("mirrored %s to %s", types.Blue(r.Name), d.Url)
|
||||
} else {
|
||||
if repo.Mirror {
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("mirror of %s already exists, syncing instead", types.Blue(r.Name))
|
||||
_, err := giteaclient.MirrorSync(user.UserName, repo.Name)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("successfully synced %s.", types.Blue(r.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Get(conf *types.Conf) []types.Repo {
|
||||
repos := []types.Repo{}
|
||||
for _, repo := range conf.Source.Gitea {
|
||||
if repo.Url == "" {
|
||||
repo.Url = "https://gitea.com"
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
opt := gitea.ListReposOptions{}
|
||||
opt.PageSize = 50
|
||||
i := 0
|
||||
gitearepos := []*gitea.Repository{}
|
||||
for {
|
||||
opt.Page = i
|
||||
client, err := gitea.NewClient(repo.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if repo.Token != "" {
|
||||
client.SetBasicAuth(repo.Token, "")
|
||||
}
|
||||
repos, _, err := client.ListUserRepos(repo.User, opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if len(repos) == 0 {
|
||||
break
|
||||
}
|
||||
gitearepos = append(gitearepos, repos...)
|
||||
i++
|
||||
}
|
||||
|
||||
exclude := types.GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range gitearepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, types.Repo{Name: r.Name, Url: r.CloneURL, SshUrl: r.SSHURL, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
57
github/github.go
Normal file
57
github/github.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"gickup/types"
|
||||
|
||||
"github.com/google/go-github/v41/github"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
func Get(conf *types.Conf) []types.Repo {
|
||||
repos := []types.Repo{}
|
||||
for _, repo := range conf.Source.Github {
|
||||
log.Info().Str("stage", "github").Str("url", "https://github.com").Msgf("grabbing the repositories from %s", repo.User)
|
||||
client := &github.Client{}
|
||||
opt := &github.RepositoryListOptions{ListOptions: github.ListOptions{PerPage: 50}}
|
||||
i := 1
|
||||
githubrepos := []*github.Repository{}
|
||||
if repo.Token == "" {
|
||||
client = github.NewClient(nil)
|
||||
} else {
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: repo.Token},
|
||||
)
|
||||
tc := oauth2.NewClient(context.TODO(), ts)
|
||||
client = github.NewClient(tc)
|
||||
}
|
||||
for {
|
||||
opt.Page = i
|
||||
repos, _, err := client.Repositories.List(context.TODO(), repo.User, opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "github").Str("url", "https://github.com").Msg(err.Error())
|
||||
}
|
||||
if len(repos) == 0 {
|
||||
break
|
||||
}
|
||||
githubrepos = append(githubrepos, repos...)
|
||||
i++
|
||||
}
|
||||
|
||||
exclude := types.GetExcludedMap(repo.Exclude)
|
||||
excludeorgs := types.GetExcludedMap(repo.ExcludeOrgs)
|
||||
|
||||
for _, r := range githubrepos {
|
||||
if exclude[*r.Name] {
|
||||
continue
|
||||
}
|
||||
if excludeorgs[r.GetOwner().GetLogin()] {
|
||||
continue
|
||||
}
|
||||
|
||||
repos = append(repos, types.Repo{Name: r.GetName(), Url: r.GetCloneURL(), SshUrl: r.GetSSHURL(), Token: repo.Token, Defaultbranch: r.GetDefaultBranch(), Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
138
gitlab/gitlab.go
Normal file
138
gitlab/gitlab.go
Normal file
|
@ -0,0 +1,138 @@
|
|||
package gitlab
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"gickup/types"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
)
|
||||
|
||||
func Backup(r types.Repo, d types.GenRepo, dry bool) {
|
||||
gitlabclient := &gitlab.Client{}
|
||||
var err error
|
||||
if d.Url == "" {
|
||||
d.Url = "https://gitlab.com"
|
||||
gitlabclient, err = gitlab.NewClient(d.Token)
|
||||
} else {
|
||||
gitlabclient, err = gitlab.NewClient(d.Token, gitlab.WithBaseURL(d.Url))
|
||||
}
|
||||
log.Info().Str("stage", "gitlab").Str("url", d.Url).Msgf("mirroring %s to %s", types.Blue(r.Name), d.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
True := true
|
||||
opt := gitlab.ListProjectsOptions{Search: &r.Name, Owned: &True}
|
||||
projects, _, err := gitlabclient.Projects.ListProjects(&opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, p := range projects {
|
||||
if p.Name == r.Name {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !dry {
|
||||
if !found {
|
||||
if r.Token != "" {
|
||||
splittedurl := strings.Split(r.Url, "//")
|
||||
r.Url = fmt.Sprintf("%s//%s@%s", splittedurl[0], r.Token, splittedurl[1])
|
||||
if r.Token == "" {
|
||||
r.Url = fmt.Sprintf("%s//%s:%s@%s", splittedurl[0], r.Origin.User, r.Origin.Password, splittedurl[1])
|
||||
}
|
||||
}
|
||||
opts := &gitlab.CreateProjectOptions{Mirror: &True, ImportURL: &r.Url, Name: &r.Name}
|
||||
_, _, err := gitlabclient.Projects.CreateProject(opts)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Get(conf *types.Conf) []types.Repo {
|
||||
repos := []types.Repo{}
|
||||
for _, repo := range conf.Source.Gitlab {
|
||||
if repo.Url == "" {
|
||||
repo.Url = "https://gitlab.com"
|
||||
}
|
||||
log.Info().Str("stage", "gitlab").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
gitlabrepos := []*gitlab.Project{}
|
||||
gitlabgrouprepos := []*gitlab.Project{}
|
||||
client, err := gitlab.NewClient(repo.Token, gitlab.WithBaseURL(repo.Url))
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
opt := &gitlab.ListProjectsOptions{}
|
||||
users, _, err := client.Users.ListUsers(&gitlab.ListUsersOptions{Username: &repo.User})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
opt.PerPage = 50
|
||||
i := 0
|
||||
for _, user := range users {
|
||||
if user.Username == repo.User {
|
||||
for {
|
||||
projects, _, err := client.Projects.ListUserProjects(user.ID, opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if len(projects) == 0 {
|
||||
break
|
||||
}
|
||||
gitlabrepos = append(gitlabrepos, projects...)
|
||||
i++
|
||||
opt.Page = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exclude := types.GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range gitlabrepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, types.Repo{Name: r.Name, Url: r.HTTPURLToRepo, SshUrl: r.SSHURLToRepo, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
groups, _, err := client.Groups.ListGroups(&gitlab.ListGroupsOptions{})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
visibilities := []gitlab.VisibilityValue{gitlab.PrivateVisibility, gitlab.PublicVisibility, gitlab.InternalVisibility}
|
||||
|
||||
for _, visibility := range visibilities {
|
||||
gopt := &gitlab.ListGroupProjectsOptions{Visibility: gitlab.Visibility(visibility)}
|
||||
gopt.PerPage = 50
|
||||
i = 0
|
||||
for _, group := range groups {
|
||||
for {
|
||||
projects, _, err := client.Groups.ListGroupProjects(group.ID, gopt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if len(projects) == 0 {
|
||||
break
|
||||
}
|
||||
gitlabgrouprepos = append(gitlabgrouprepos, projects...)
|
||||
i++
|
||||
gopt.Page = i
|
||||
}
|
||||
}
|
||||
for _, r := range gitlabgrouprepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, types.Repo{Name: r.Name, Url: r.HTTPURLToRepo, SshUrl: r.SSHURLToRepo, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
6
go.mod
6
go.mod
|
@ -10,16 +10,13 @@ require (
|
|||
github.com/go-git/go-git/v5 v5.4.2
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/google/go-github/v41 v41.0.0 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/go-github/v41 v41.0.0
|
||||
github.com/gookit/color v1.5.0
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/go-version v1.3.0 // indirect
|
||||
github.com/k0kubun/pp v3.0.1+incompatible // indirect
|
||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||
github.com/ktrysmt/go-bitbucket v0.9.32
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/melbahja/goph v1.3.0
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/rs/zerolog v1.26.0
|
||||
|
@ -31,7 +28,6 @@ require (
|
|||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 // indirect
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
|
44
go.sum
44
go.sum
|
@ -38,19 +38,14 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
|
||||
github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
|
||||
github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU=
|
||||
github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
|
||||
github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210920160938-87db9fbc61c7 h1:DSqTh6nEes/uO8BlNcGk8PzZsxY2sN9ZL//veWBdTRI=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210920160938-87db9fbc61c7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3 h1:XcF0cTDJeiuZ5NU8w7WUDge0HRwwNRmxj/GGk6KSA6g=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20211112122917-428f8eabeeb3/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
|
||||
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
|
||||
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/alecthomas/kong v0.2.17 h1:URDISCI96MIgcIlQyoCAlhOmrSw6pZScBNkctg8r0W0=
|
||||
github.com/alecthomas/kong v0.2.17/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ=
|
||||
github.com/alecthomas/kong v0.2.19 h1:qBDfByO5XgWUXyNB4D6OOhGh5Z1eNOwWayDPQJFNWdc=
|
||||
github.com/alecthomas/kong v0.2.19/go.mod h1:ka3VZ8GZNPXv9Ov+j4YNLkI8mTuhXyr/0ktSlqIydQQ=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
|
@ -130,7 +125,6 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
|
@ -151,8 +145,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/gookit/color v1.4.2 h1:tXy44JFSFkKnELV6WaMo/lLfu/meqITX3iAV52do7lk=
|
||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||
github.com/gookit/color v1.5.0 h1:1Opow3+BWDwqor78DcJkJCIwnkviFi+rrOANki9BUFw=
|
||||
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
|
@ -176,11 +168,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i
|
|||
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||
github.com/k0kubun/pp v2.3.0+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
|
||||
github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40=
|
||||
github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg=
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kevinburke/ssh_config v1.1.0 h1:pH/t1WS9NzT8go394IqZeJTMHVm6Cr6ZJ6AQ+mdNo/o=
|
||||
github.com/kevinburke/ssh_config v1.1.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
|
@ -195,27 +184,17 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/ktrysmt/go-bitbucket v0.9.27 h1:1VGdeRHpZZyiIIIBjLr62ATbtOOZCJyyaFZeEWHzmOU=
|
||||
github.com/ktrysmt/go-bitbucket v0.9.27/go.mod h1:FWxy2UK7GlK5b0NSJGc5hPqnssVlkNnsChvyuOf/Xno=
|
||||
github.com/ktrysmt/go-bitbucket v0.9.32 h1:IVk0m0gdB4OzRRLgxFnqNsfWKPXNdrcvgdpp9BojTpI=
|
||||
github.com/ktrysmt/go-bitbucket v0.9.32/go.mod h1:FWxy2UK7GlK5b0NSJGc5hPqnssVlkNnsChvyuOf/Xno=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/melbahja/goph v1.3.0 h1:RAIS7eL2tew/UrNmBpY2NZMxw6fWtOxki9nkrzw8mZY=
|
||||
github.com/melbahja/goph v1.3.0/go.mod h1:04M6J+mKmwzAOWhO0ABTweHGU3cizOp90WdCoxrn9gQ=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20180220230111-00c29f56e238/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.2 h1:6h7AQ0yhTcIsmFmnAwQls75jp2Gzs4iB8W7pjMO+rqo=
|
||||
github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
|
@ -229,8 +208,6 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
|||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
|
||||
github.com/rs/zerolog v1.25.0 h1:Rj7XygbUHKUlDPcVdoLyR91fJBsduXj5fRxyqIQj/II=
|
||||
github.com/rs/zerolog v1.25.0/go.mod h1:7KHcEGe0QZPOm2IE4Kpb5rTh6n1h2hIgS5OOnu1rUaI=
|
||||
github.com/rs/zerolog v1.26.0 h1:ORM4ibhEZeTeQlCojCK2kPz1ogAY4bGs4tD+SaAdGaE=
|
||||
github.com/rs/zerolog v1.26.0/go.mod h1:yBiM87lvSqX8h0Ww4sdzNSkVYZ8dL2xjZJG1lAuGZEo=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
|
@ -245,8 +222,6 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
|
|||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/xanzy/go-gitlab v0.51.1 h1:wWKLalwx4omxFoHh3PLs9zDgAD4GXDP/uoxwMRCSiWM=
|
||||
github.com/xanzy/go-gitlab v0.51.1/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
|
||||
github.com/xanzy/go-gitlab v0.52.2 h1:gkgg1z4ON70sphibtD86Bfmt1qV3mZ0pU0CBBCFAEvQ=
|
||||
github.com/xanzy/go-gitlab v0.52.2/go.mod h1:Q+hQhV508bDPoBijv7YjK/Lvlb4PhVhJdKqXVQrUoAE=
|
||||
github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
|
||||
|
@ -257,7 +232,6 @@ github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1z
|
|||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
|
@ -274,10 +248,7 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
|
|||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e h1:MUP6MR3rJ7Gk9LEia0LP2ytiH6MuCfs7qYz+47jGdD8=
|
||||
golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
@ -341,11 +312,7 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw=
|
||||
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c h1:WtYZ93XtWSO5KlOMgPZu7hXY9WhMZpprvlm5VwvAl8c=
|
||||
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
@ -356,8 +323,6 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
|
|||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 h1:B333XXssMuKQeBwiNODx4TupZy7bf4sxFZnN2ZOcvUE=
|
||||
golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -408,18 +373,12 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac h1:oN6lz7iLW/YC7un8pq+9bOLyXrprv2+DKfkJY+2LJJw=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps=
|
||||
golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881 h1:TyHqChC80pFkXWraUUf6RuB5IqFdQieMLwwCJokV2pc=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
|
@ -433,8 +392,6 @@ golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11 h1:GZokNIeuVkl3aZHJchRrr13WCsols02MLUcz1U9is6M=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
@ -478,7 +435,6 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
|
62
gogs/gogs.go
Normal file
62
gogs/gogs.go
Normal file
|
@ -0,0 +1,62 @@
|
|||
package gogs
|
||||
|
||||
import (
|
||||
"gickup/types"
|
||||
|
||||
"github.com/gogs/go-gogs-client"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func Backup(r types.Repo, d types.GenRepo, dry bool) {
|
||||
log.Info().Str("stage", "gogs").Str("url", d.Url).Msgf("mirroring %s to %s", types.Blue(r.Name), d.Url)
|
||||
gogsclient := gogs.NewClient(d.Url, d.Token)
|
||||
|
||||
user, err := gogsclient.GetSelfInfo()
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
if !dry {
|
||||
repo, err := gogsclient.GetRepo(user.UserName, r.Name)
|
||||
if err != nil {
|
||||
opts := gogs.MigrateRepoOption{RepoName: r.Name, UID: int(user.ID), Mirror: true, CloneAddr: r.Url, AuthUsername: r.Token}
|
||||
if r.Token == "" {
|
||||
opts = gogs.MigrateRepoOption{RepoName: r.Name, UID: int(user.ID), Mirror: true, CloneAddr: r.Url, AuthUsername: r.Origin.User, AuthPassword: r.Origin.Password}
|
||||
}
|
||||
_, err := gogsclient.MigrateRepo(opts)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
} else {
|
||||
if repo.Mirror {
|
||||
log.Info().Str("stage", "gogs").Str("url", d.Url).Msgf("mirror of %s already exists, syncing instead", types.Blue(r.Name))
|
||||
err := gogsclient.MirrorSync(user.UserName, repo.Name)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
log.Info().Str("stage", "gogs").Str("url", d.Url).Msgf("successfully synced %s.", types.Blue(r.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Get(conf *types.Conf) []types.Repo {
|
||||
repos := []types.Repo{}
|
||||
for _, repo := range conf.Source.Gogs {
|
||||
log.Info().Str("stage", "gogs").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
client := gogs.NewClient(repo.Url, repo.Token)
|
||||
gogsrepos, err := client.ListUserRepos(repo.User)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
exclude := types.GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range gogsrepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, types.Repo{Name: r.Name, Url: r.CloneURL, SshUrl: r.SSHURL, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
170
local/local.go
Normal file
170
local/local.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
package local
|
||||
|
||||
import (
|
||||
"gickup/types"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
|
||||
"github.com/melbahja/goph"
|
||||
"github.com/rs/zerolog/log"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
func Locally(repo types.Repo, l types.Local, dry bool) {
|
||||
stat, err := os.Stat(l.Path)
|
||||
if os.IsNotExist(err) && !dry {
|
||||
err := os.MkdirAll(l.Path, 0777)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
}
|
||||
stat, _ = os.Stat(l.Path)
|
||||
}
|
||||
if stat != nil {
|
||||
if stat.IsDir() {
|
||||
os.Chdir(l.Path)
|
||||
}
|
||||
}
|
||||
|
||||
tries := 5
|
||||
var auth transport.AuthMethod
|
||||
if repo.Origin.SSH {
|
||||
if repo.Origin.SSHKey == "" {
|
||||
home := os.Getenv("HOME")
|
||||
repo.Origin.SSHKey = path.Join(home, ".ssh", "id_rsa")
|
||||
}
|
||||
auth, err = ssh.NewPublicKeysFromFile("git", repo.Origin.SSHKey, "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if repo.Token != "" {
|
||||
auth = &http.BasicAuth{
|
||||
Username: "xyz",
|
||||
Password: repo.Token,
|
||||
}
|
||||
} else if repo.Origin.Username != "" && repo.Origin.Password != "" {
|
||||
auth = &http.BasicAuth{
|
||||
Username: repo.Origin.Username,
|
||||
Password: repo.Origin.Password,
|
||||
}
|
||||
}
|
||||
for x := 1; x <= tries; x++ {
|
||||
stat, err := os.Stat(repo.Name)
|
||||
if os.IsNotExist(err) {
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msgf("cloning %s", types.Green(repo.Name))
|
||||
|
||||
if !dry {
|
||||
url := repo.Url
|
||||
if repo.Origin.SSH {
|
||||
url = repo.SshUrl
|
||||
site := types.Site{}
|
||||
err := site.GetValues(url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Msg(err.Error())
|
||||
}
|
||||
auth, err := goph.Key(repo.Origin.SSHKey, "")
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Msg(err.Error())
|
||||
}
|
||||
_, err = goph.NewConn(&goph.Config{
|
||||
User: site.User,
|
||||
Addr: site.Url,
|
||||
Port: uint(site.Port),
|
||||
Auth: auth,
|
||||
Callback: VerifyHost,
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Msg(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
_, err = git.PlainClone(repo.Name, false, &git.CloneOptions{
|
||||
URL: url,
|
||||
Auth: auth,
|
||||
SingleBranch: false,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if x == tries {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
} else {
|
||||
if strings.Contains(err.Error(), "remote repository is empty") {
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
break
|
||||
}
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msgf("retry %s from %s", types.Red(x), types.Red(tries))
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if stat.IsDir() {
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msgf("opening %s locally", types.Green(repo.Name))
|
||||
r, err := git.PlainOpen(repo.Name)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
}
|
||||
w, err := r.Worktree()
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
}
|
||||
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msgf("pulling %s", types.Green(repo.Name))
|
||||
if !dry {
|
||||
err = w.Pull(&git.PullOptions{Auth: auth, RemoteName: "origin", SingleBranch: false})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already up-to-date") {
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
} else {
|
||||
if x == tries {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
} else {
|
||||
os.RemoveAll(repo.Name)
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msgf("retry %s from %s", types.Red(x), types.Red(tries))
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msgf("%s is a file", types.Red(repo.Name))
|
||||
}
|
||||
}
|
||||
x = 5
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyHost(host string, remote net.Addr, key gossh.PublicKey) error {
|
||||
// Got from the example from https://github.com/melbahja/goph/blob/master/examples/goph/main.go
|
||||
//
|
||||
// If you want to connect to new hosts.
|
||||
// here your should check new connections public keys
|
||||
// if the key not trusted you shuld return an error
|
||||
//
|
||||
|
||||
// hostFound: is host in known hosts file.
|
||||
// err: error if key not in known hosts file OR host in known hosts file but key changed!
|
||||
hostFound, err := goph.CheckKnownHost(host, remote, key, "")
|
||||
// Host in known hosts but key mismatch!
|
||||
// Maybe because of MAN IN THE MIDDLE ATTACK!
|
||||
/*
|
||||
if hostFound && err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
// handshake because public key already exists.
|
||||
if hostFound && err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add the new host to known hosts file.
|
||||
return goph.AddKnownHost(host, remote, key, "")
|
||||
}
|
587
main.go
587
main.go
|
@ -1,34 +1,22 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/sdk/gitea"
|
||||
"gickup/bitbucket"
|
||||
"gickup/gitea"
|
||||
"gickup/github"
|
||||
"gickup/gitlab"
|
||||
"gickup/gogs"
|
||||
"gickup/local"
|
||||
"gickup/types"
|
||||
|
||||
"github.com/alecthomas/kong"
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/http"
|
||||
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
|
||||
"github.com/gogs/go-gogs-client"
|
||||
"github.com/google/go-github/v41/github"
|
||||
"github.com/gookit/color"
|
||||
"github.com/ktrysmt/go-bitbucket"
|
||||
"github.com/melbahja/goph"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
"golang.org/x/oauth2"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
|
@ -48,75 +36,23 @@ func (v dryrunFlag) BeforeApply() error {
|
|||
}
|
||||
|
||||
var cli struct {
|
||||
Configfile string `arg required name:"conf" help:"path to the configfile." type:"existingfile"`
|
||||
Configfile string `arg requitypes.Red name:"conf" help:"path to the configfile." type:"existingfile"`
|
||||
Version versionFlag
|
||||
Dry dryrunFlag `flag name:"dryrun" help:"make a dry-run."`
|
||||
}
|
||||
|
||||
var (
|
||||
red = color.FgRed.Render
|
||||
green = color.FgGreen.Render
|
||||
blue = color.FgBlue.Render
|
||||
dry = false
|
||||
dry = false
|
||||
)
|
||||
|
||||
func (s *Site) GetValues(url string) {
|
||||
if strings.HasPrefix(url, "ssh://") {
|
||||
url = strings.Split(url, "ssh://")[1]
|
||||
userurl := strings.Split(url, "@")
|
||||
s.User = userurl[0]
|
||||
urlport := strings.Split(userurl[1], ":")
|
||||
s.Url = urlport[0]
|
||||
portstring := strings.Split(urlport[1], "/")[0]
|
||||
port, err := strconv.Atoi(portstring)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "GetValus").Msg(err.Error())
|
||||
}
|
||||
s.Port = port
|
||||
} else {
|
||||
userurl := strings.Split(url, "@")
|
||||
s.User = userurl[0]
|
||||
urlport := strings.Split(userurl[1], ":")
|
||||
s.Url = urlport[0]
|
||||
s.Port = 22
|
||||
}
|
||||
}
|
||||
|
||||
func VerifyHost(host string, remote net.Addr, key gossh.PublicKey) error {
|
||||
// Got from the example from https://github.com/melbahja/goph/blob/master/examples/goph/main.go
|
||||
//
|
||||
// If you want to connect to new hosts.
|
||||
// here your should check new connections public keys
|
||||
// if the key not trusted you shuld return an error
|
||||
//
|
||||
|
||||
// hostFound: is host in known hosts file.
|
||||
// err: error if key not in known hosts file OR host in known hosts file but key changed!
|
||||
hostFound, err := goph.CheckKnownHost(host, remote, key, "")
|
||||
// Host in known hosts but key mismatch!
|
||||
// Maybe because of MAN IN THE MIDDLE ATTACK!
|
||||
/*
|
||||
if hostFound && err != nil {
|
||||
return err
|
||||
}
|
||||
*/
|
||||
// handshake because public key already exists.
|
||||
if hostFound && err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Add the new host to known hosts file.
|
||||
return goph.AddKnownHost(host, remote, key, "")
|
||||
}
|
||||
|
||||
func ReadConfigfile(configfile string) *Conf {
|
||||
func ReadConfigfile(configfile string) *types.Conf {
|
||||
cfgdata, err := ioutil.ReadFile(configfile)
|
||||
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "readconfig").Str("file", configfile).Msgf("Cannot open config file from %s", red(configfile))
|
||||
log.Panic().Str("stage", "readconfig").Str("file", configfile).Msgf("Cannot open config file from %s", types.Red(configfile))
|
||||
}
|
||||
|
||||
t := Conf{}
|
||||
t := types.Conf{}
|
||||
|
||||
err = yaml.Unmarshal([]byte(cfgdata), &t)
|
||||
|
||||
|
@ -127,254 +63,7 @@ func ReadConfigfile(configfile string) *Conf {
|
|||
return &t
|
||||
}
|
||||
|
||||
func GetExcludedMap(excludes []string) map[string]bool {
|
||||
excludemap := make(map[string]bool)
|
||||
for _, exclude := range excludes {
|
||||
excludemap[exclude] = true
|
||||
}
|
||||
return excludemap
|
||||
}
|
||||
|
||||
func Locally(repo Repo, l Local) {
|
||||
stat, err := os.Stat(l.Path)
|
||||
if os.IsNotExist(err) && !dry {
|
||||
err := os.MkdirAll(l.Path, 0777)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
}
|
||||
stat, _ = os.Stat(l.Path)
|
||||
}
|
||||
if stat != nil {
|
||||
if stat.IsDir() {
|
||||
os.Chdir(l.Path)
|
||||
}
|
||||
}
|
||||
|
||||
tries := 5
|
||||
var auth transport.AuthMethod
|
||||
if repo.Origin.SSH {
|
||||
if repo.Origin.SSHKey == "" {
|
||||
home := os.Getenv("HOME")
|
||||
repo.Origin.SSHKey = path.Join(home, ".ssh", "id_rsa")
|
||||
}
|
||||
auth, err = ssh.NewPublicKeysFromFile("git", repo.Origin.SSHKey, "")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else if repo.Token != "" {
|
||||
auth = &http.BasicAuth{
|
||||
Username: "xyz",
|
||||
Password: repo.Token,
|
||||
}
|
||||
} else if repo.Origin.Username != "" && repo.Origin.Password != "" {
|
||||
auth = &http.BasicAuth{
|
||||
Username: repo.Origin.Username,
|
||||
Password: repo.Origin.Password,
|
||||
}
|
||||
}
|
||||
for x := 1; x <= tries; x++ {
|
||||
stat, err := os.Stat(repo.Name)
|
||||
if os.IsNotExist(err) {
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msgf("cloning %s", green(repo.Name))
|
||||
|
||||
if !dry {
|
||||
url := repo.Url
|
||||
if repo.Origin.SSH {
|
||||
url = repo.SshUrl
|
||||
site := Site{}
|
||||
site.GetValues(url)
|
||||
auth, err := goph.Key(repo.Origin.SSHKey, "")
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Msg(err.Error())
|
||||
}
|
||||
_, err = goph.NewConn(&goph.Config{
|
||||
User: site.User,
|
||||
Addr: site.Url,
|
||||
Port: uint(site.Port),
|
||||
Auth: auth,
|
||||
Callback: VerifyHost,
|
||||
})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Msg(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
_, err = git.PlainClone(repo.Name, false, &git.CloneOptions{
|
||||
URL: url,
|
||||
Auth: auth,
|
||||
SingleBranch: false,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if x == tries {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
} else {
|
||||
if strings.Contains(err.Error(), "remote repository is empty") {
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
break
|
||||
}
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msgf("retry %s from %s", red(x), red(tries))
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if stat.IsDir() {
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msgf("opening %s locally", green(repo.Name))
|
||||
r, err := git.PlainOpen(repo.Name)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
}
|
||||
w, err := r.Worktree()
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
}
|
||||
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msgf("pulling %s", green(repo.Name))
|
||||
if !dry {
|
||||
err = w.Pull(&git.PullOptions{Auth: auth, RemoteName: "origin", SingleBranch: false})
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "already up-to-date") {
|
||||
log.Info().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
} else {
|
||||
if x == tries {
|
||||
log.Panic().Str("stage", "locally").Str("path", l.Path).Msg(err.Error())
|
||||
} else {
|
||||
os.RemoveAll(repo.Name)
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msgf("retry %s from %s", red(x), red(tries))
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.Warn().Str("stage", "locally").Str("path", l.Path).Msgf("%s is a file", red(repo.Name))
|
||||
}
|
||||
}
|
||||
x = 5
|
||||
}
|
||||
}
|
||||
|
||||
func BackupGitea(r Repo, d GenRepo) {
|
||||
if d.Url == "" {
|
||||
d.Url = "https://gitea.com/"
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("mirroring %s to %s", blue(r.Name), d.Url)
|
||||
giteaclient, err := gitea.NewClient(d.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
giteaclient.SetBasicAuth(d.Token, "")
|
||||
user, _, err := giteaclient.GetMyUserInfo()
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
if !dry {
|
||||
repo, _, err := giteaclient.GetRepo(user.UserName, r.Name)
|
||||
if err != nil {
|
||||
opts := gitea.MigrateRepoOption{RepoName: r.Name, RepoOwner: user.UserName, Mirror: true, CloneAddr: r.Url, AuthToken: r.Token}
|
||||
if r.Token == "" {
|
||||
opts = gitea.MigrateRepoOption{RepoName: r.Name, RepoOwner: user.UserName, Mirror: true, CloneAddr: r.Url, AuthUsername: r.Origin.User, AuthPassword: r.Origin.Password}
|
||||
}
|
||||
_, _, err := giteaclient.MigrateRepo(opts)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("mirrored %s to %s", blue(r.Name), d.Url)
|
||||
} else {
|
||||
if repo.Mirror {
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("mirror of %s already exists, syncing instead", blue(r.Name))
|
||||
_, err := giteaclient.MirrorSync(user.UserName, repo.Name)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", d.Url).Msgf("successfully synced %s.", blue(r.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BackupGogs(r Repo, d GenRepo) {
|
||||
log.Info().Str("stage", "gogs").Str("url", d.Url).Msgf("mirroring %s to %s", blue(r.Name), d.Url)
|
||||
gogsclient := gogs.NewClient(d.Url, d.Token)
|
||||
|
||||
user, err := gogsclient.GetSelfInfo()
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
if !dry {
|
||||
repo, err := gogsclient.GetRepo(user.UserName, r.Name)
|
||||
if err != nil {
|
||||
opts := gogs.MigrateRepoOption{RepoName: r.Name, UID: int(user.ID), Mirror: true, CloneAddr: r.Url, AuthUsername: r.Token}
|
||||
if r.Token == "" {
|
||||
opts = gogs.MigrateRepoOption{RepoName: r.Name, UID: int(user.ID), Mirror: true, CloneAddr: r.Url, AuthUsername: r.Origin.User, AuthPassword: r.Origin.Password}
|
||||
}
|
||||
_, err := gogsclient.MigrateRepo(opts)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
} else {
|
||||
if repo.Mirror {
|
||||
log.Info().Str("stage", "gogs").Str("url", d.Url).Msgf("mirror of %s already exists, syncing instead", blue(r.Name))
|
||||
err := gogsclient.MirrorSync(user.UserName, repo.Name)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
log.Info().Str("stage", "gogs").Str("url", d.Url).Msgf("successfully synced %s.", blue(r.Name))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BackupGitlab(r Repo, d GenRepo) {
|
||||
gitlabclient := &gitlab.Client{}
|
||||
var err error
|
||||
if d.Url == "" {
|
||||
d.Url = "https://gitlab.com"
|
||||
gitlabclient, err = gitlab.NewClient(d.Token)
|
||||
} else {
|
||||
gitlabclient, err = gitlab.NewClient(d.Token, gitlab.WithBaseURL(d.Url))
|
||||
}
|
||||
log.Info().Str("stage", "gitlab").Str("url", d.Url).Msgf("mirroring %s to %s", blue(r.Name), d.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
True := true
|
||||
opt := gitlab.ListProjectsOptions{Search: &r.Name, Owned: &True}
|
||||
projects, _, err := gitlabclient.Projects.ListProjects(&opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, p := range projects {
|
||||
if p.Name == r.Name {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !dry {
|
||||
if !found {
|
||||
if r.Token != "" {
|
||||
splittedurl := strings.Split(r.Url, "//")
|
||||
r.Url = fmt.Sprintf("%s//%s@%s", splittedurl[0], r.Token, splittedurl[1])
|
||||
if r.Token == "" {
|
||||
r.Url = fmt.Sprintf("%s//%s:%s@%s", splittedurl[0], r.Origin.User, r.Origin.Password, splittedurl[1])
|
||||
}
|
||||
}
|
||||
opts := &gitlab.CreateProjectOptions{Mirror: &True, ImportURL: &r.Url, Name: &r.Name}
|
||||
_, _, err := gitlabclient.Projects.CreateProject(opts)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", d.Url).Msg(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Backup(repos []Repo, conf *Conf) {
|
||||
func Backup(repos []types.Repo, conf *types.Conf) {
|
||||
checkedpath := false
|
||||
for _, r := range repos {
|
||||
log.Info().Str("stage", "backup").Msgf("starting backup for %s", r.Url)
|
||||
|
@ -387,246 +76,20 @@ func Backup(repos []Repo, conf *Conf) {
|
|||
conf.Destination.Local[i].Path = path
|
||||
checkedpath = true
|
||||
}
|
||||
Locally(r, d)
|
||||
local.Locally(r, d, dry)
|
||||
}
|
||||
for _, d := range conf.Destination.Gitea {
|
||||
BackupGitea(r, d)
|
||||
gitea.Backup(r, d, dry)
|
||||
}
|
||||
for _, d := range conf.Destination.Gogs {
|
||||
BackupGogs(r, d)
|
||||
gogs.Backup(r, d, dry)
|
||||
}
|
||||
for _, d := range conf.Destination.Gitlab {
|
||||
BackupGitlab(r, d)
|
||||
gitlab.Backup(r, d, dry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getGithub(conf *Conf) []Repo {
|
||||
repos := []Repo{}
|
||||
for _, repo := range conf.Source.Github {
|
||||
log.Info().Str("stage", "github").Str("url", "https://github.com").Msgf("grabbing the repositories from %s", repo.User)
|
||||
client := &github.Client{}
|
||||
opt := &github.RepositoryListOptions{ListOptions: github.ListOptions{PerPage: 50}}
|
||||
i := 1
|
||||
githubrepos := []*github.Repository{}
|
||||
if repo.Token == "" {
|
||||
client = github.NewClient(nil)
|
||||
} else {
|
||||
ts := oauth2.StaticTokenSource(
|
||||
&oauth2.Token{AccessToken: repo.Token},
|
||||
)
|
||||
tc := oauth2.NewClient(context.TODO(), ts)
|
||||
client = github.NewClient(tc)
|
||||
}
|
||||
for {
|
||||
opt.Page = i
|
||||
repos, _, err := client.Repositories.List(context.TODO(), repo.User, opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "github").Str("url", "https://github.com").Msg(err.Error())
|
||||
}
|
||||
if len(repos) == 0 {
|
||||
break
|
||||
}
|
||||
githubrepos = append(githubrepos, repos...)
|
||||
i++
|
||||
}
|
||||
|
||||
exclude := GetExcludedMap(repo.Exclude)
|
||||
excludeorgs := GetExcludedMap(repo.ExcludeOrgs)
|
||||
|
||||
for _, r := range githubrepos {
|
||||
if exclude[*r.Name] {
|
||||
continue
|
||||
}
|
||||
if excludeorgs[r.GetOwner().GetLogin()] {
|
||||
continue
|
||||
}
|
||||
|
||||
repos = append(repos, Repo{Name: r.GetName(), Url: r.GetCloneURL(), SshUrl: r.GetSSHURL(), Token: repo.Token, Defaultbranch: r.GetDefaultBranch(), Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
||||
|
||||
func getGitea(conf *Conf) []Repo {
|
||||
repos := []Repo{}
|
||||
for _, repo := range conf.Source.Gitea {
|
||||
if repo.Url == "" {
|
||||
repo.Url = "https://gitea.com"
|
||||
}
|
||||
log.Info().Str("stage", "gitea").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
opt := gitea.ListReposOptions{}
|
||||
opt.PageSize = 50
|
||||
i := 0
|
||||
gitearepos := []*gitea.Repository{}
|
||||
for {
|
||||
opt.Page = i
|
||||
client, err := gitea.NewClient(repo.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if repo.Token != "" {
|
||||
client.SetBasicAuth(repo.Token, "")
|
||||
}
|
||||
repos, _, err := client.ListUserRepos(repo.User, opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitea").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if len(repos) == 0 {
|
||||
break
|
||||
}
|
||||
gitearepos = append(gitearepos, repos...)
|
||||
i++
|
||||
}
|
||||
|
||||
exclude := GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range gitearepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, Repo{Name: r.Name, Url: r.CloneURL, SshUrl: r.SSHURL, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
||||
|
||||
func getGogs(conf *Conf) []Repo {
|
||||
repos := []Repo{}
|
||||
for _, repo := range conf.Source.Gogs {
|
||||
log.Info().Str("stage", "gogs").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
client := gogs.NewClient(repo.Url, repo.Token)
|
||||
gogsrepos, err := client.ListUserRepos(repo.User)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gogs").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
exclude := GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range gogsrepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, Repo{Name: r.Name, Url: r.CloneURL, SshUrl: r.SSHURL, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
||||
|
||||
func getGitlab(conf *Conf) []Repo {
|
||||
repos := []Repo{}
|
||||
for _, repo := range conf.Source.Gitlab {
|
||||
if repo.Url == "" {
|
||||
repo.Url = "https://gitlab.com"
|
||||
}
|
||||
log.Info().Str("stage", "gitlab").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
gitlabrepos := []*gitlab.Project{}
|
||||
gitlabgrouprepos := []*gitlab.Project{}
|
||||
client, err := gitlab.NewClient(repo.Token, gitlab.WithBaseURL(repo.Url))
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
opt := &gitlab.ListProjectsOptions{}
|
||||
users, _, err := client.Users.ListUsers(&gitlab.ListUsersOptions{Username: &repo.User})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
opt.PerPage = 50
|
||||
i := 0
|
||||
for _, user := range users {
|
||||
if user.Username == repo.User {
|
||||
for {
|
||||
projects, _, err := client.Projects.ListUserProjects(user.ID, opt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if len(projects) == 0 {
|
||||
break
|
||||
}
|
||||
gitlabrepos = append(gitlabrepos, projects...)
|
||||
i++
|
||||
opt.Page = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exclude := GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range gitlabrepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, Repo{Name: r.Name, Url: r.HTTPURLToRepo, SshUrl: r.SSHURLToRepo, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
groups, _, err := client.Groups.ListGroups(&gitlab.ListGroupsOptions{})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
visibilities := []gitlab.VisibilityValue{gitlab.PrivateVisibility, gitlab.PublicVisibility, gitlab.InternalVisibility}
|
||||
|
||||
for _, visibility := range visibilities {
|
||||
gopt := &gitlab.ListGroupProjectsOptions{Visibility: gitlab.Visibility(visibility)}
|
||||
gopt.PerPage = 50
|
||||
i = 0
|
||||
for _, group := range groups {
|
||||
for {
|
||||
projects, _, err := client.Groups.ListGroupProjects(group.ID, gopt)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "gitlab").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
if len(projects) == 0 {
|
||||
break
|
||||
}
|
||||
gitlabgrouprepos = append(gitlabgrouprepos, projects...)
|
||||
i++
|
||||
gopt.Page = i
|
||||
}
|
||||
}
|
||||
for _, r := range gitlabgrouprepos {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, Repo{Name: r.Name, Url: r.HTTPURLToRepo, SshUrl: r.SSHURLToRepo, Token: repo.Token, Defaultbranch: r.DefaultBranch, Origin: repo})
|
||||
}
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
||||
|
||||
func getBitbucket(conf *Conf) []Repo {
|
||||
repos := []Repo{}
|
||||
for _, repo := range conf.Source.BitBucket {
|
||||
client := bitbucket.NewBasicAuth(repo.Username, repo.Password)
|
||||
if repo.Url == "" {
|
||||
repo.Url = bitbucket.DEFAULT_BITBUCKET_API_BASE_URL
|
||||
} else {
|
||||
bitbucketUrl, err := url.Parse(repo.Url)
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "bitbucket").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
client.SetApiBaseURL(*bitbucketUrl)
|
||||
}
|
||||
log.Info().Str("stage", "bitbucket").Str("url", repo.Url).Msgf("grabbing repositories from %s", repo.User)
|
||||
|
||||
repositories, err := client.Repositories.ListForAccount(&bitbucket.RepositoriesOptions{Owner: repo.User})
|
||||
if err != nil {
|
||||
log.Panic().Str("stage", "bitbucket").Str("url", repo.Url).Msg(err.Error())
|
||||
}
|
||||
|
||||
exclude := GetExcludedMap(repo.Exclude)
|
||||
|
||||
for _, r := range repositories.Items {
|
||||
if exclude[r.Name] {
|
||||
continue
|
||||
}
|
||||
repos = append(repos, Repo{Name: r.Name, Url: r.Links["clone"].([]interface{})[0].(map[string]interface{})["href"].(string), SshUrl: r.Links["clone"].([]interface{})[1].(map[string]interface{})["href"].(string), Token: "", Defaultbranch: r.Mainbranch.Name, Origin: repo})
|
||||
}
|
||||
}
|
||||
return repos
|
||||
}
|
||||
|
||||
func main() {
|
||||
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
@ -634,29 +97,29 @@ func main() {
|
|||
kong.Parse(&cli, kong.Name("gickup"), kong.Description("a tool to backup all your favorite repos"))
|
||||
|
||||
if dry {
|
||||
log.Info().Str("dry", "true").Msgf("this is a %s", blue("dry run"))
|
||||
log.Info().Str("dry", "true").Msgf("this is a %s", types.Blue("dry run"))
|
||||
}
|
||||
|
||||
log.Info().Str("file", cli.Configfile).Msgf("Reading %s", green(cli.Configfile))
|
||||
log.Info().Str("file", cli.Configfile).Msgf("Reading %s", types.Green(cli.Configfile))
|
||||
conf := ReadConfigfile(cli.Configfile)
|
||||
|
||||
// Github
|
||||
repos := getGithub(conf)
|
||||
repos := github.Get(conf)
|
||||
Backup(repos, conf)
|
||||
|
||||
// Gitea
|
||||
repos = getGitea(conf)
|
||||
repos = gitea.Get(conf)
|
||||
Backup(repos, conf)
|
||||
|
||||
// Gogs
|
||||
repos = getGogs(conf)
|
||||
repos = gogs.Get(conf)
|
||||
Backup(repos, conf)
|
||||
|
||||
// Gitlab
|
||||
repos = getGitlab(conf)
|
||||
repos = gitlab.Get(conf)
|
||||
Backup(repos, conf)
|
||||
|
||||
//Bitbucket
|
||||
repos = getBitbucket(conf)
|
||||
repos = bitbucket.Get(conf)
|
||||
Backup(repos, conf)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,11 @@
|
|||
package main
|
||||
package types
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gookit/color"
|
||||
)
|
||||
|
||||
// Destination
|
||||
type Destination struct {
|
||||
|
@ -58,3 +65,40 @@ type Site struct {
|
|||
User string
|
||||
Port int
|
||||
}
|
||||
|
||||
func (s *Site) GetValues(url string) error {
|
||||
if strings.HasPrefix(url, "ssh://") {
|
||||
url = strings.Split(url, "ssh://")[1]
|
||||
userurl := strings.Split(url, "@")
|
||||
s.User = userurl[0]
|
||||
urlport := strings.Split(userurl[1], ":")
|
||||
s.Url = urlport[0]
|
||||
portstring := strings.Split(urlport[1], "/")[0]
|
||||
port, err := strconv.Atoi(portstring)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Port = port
|
||||
} else {
|
||||
userurl := strings.Split(url, "@")
|
||||
s.User = userurl[0]
|
||||
urlport := strings.Split(userurl[1], ":")
|
||||
s.Url = urlport[0]
|
||||
s.Port = 22
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
Red = color.FgRed.Render
|
||||
Green = color.FgGreen.Render
|
||||
Blue = color.FgBlue.Render
|
||||
)
|
||||
|
||||
func GetExcludedMap(excludes []string) map[string]bool {
|
||||
excludemap := make(map[string]bool)
|
||||
for _, exclude := range excludes {
|
||||
excludemap[exclude] = true
|
||||
}
|
||||
return excludemap
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue