1
1
mirror of https://github.com/cooperspencer/gickup synced 2024-10-18 13:48:07 +02:00
gickup/onedev/onedev.go
Andreas Wachter 67db501a30
added error counter for issues and stop after a 403 occurs (#256)
* added error counter for issues and stop after a 403 occurs

* added errorcounter to other hosters too
2024-08-20 14:13:42 +02:00

342 lines
8.2 KiB
Go

package onedev
import (
"fmt"
"net/http"
"strconv"
"strings"
"time"
"github.com/cooperspencer/gickup/logger"
"github.com/cooperspencer/gickup/types"
"github.com/cooperspencer/onedev"
"github.com/rs/zerolog"
)
var (
sub zerolog.Logger
)
func Get(conf *types.Conf) ([]types.Repo, bool) {
ran := false
repos := []types.Repo{}
for _, repo := range conf.Source.OneDev {
ran = true
if repo.URL == "" {
repo.URL = "https://code.onedev.io/"
}
sub = logger.CreateSubLogger("stage", "onedev", "url", repo.URL)
err := repo.Filter.ParseDuration()
if err != nil {
sub.Error().
Msg(err.Error())
}
include := types.GetMap(repo.Include)
exclude := types.GetMap(repo.Exclude)
excludeorgs := types.GetMap(repo.ExcludeOrgs)
if repo.Password == "" && repo.Token != "" {
repo.Password = repo.Token
}
client := &onedev.Client{}
if repo.Token != "" || repo.TokenFile != "" {
client = onedev.NewClient(repo.URL, onedev.SetToken(repo.GetToken()))
} else {
if repo.Password != "" {
client = onedev.NewClient(repo.URL, onedev.SetBasicAuth(repo.Username, repo.Password))
} else {
client = onedev.NewClient(repo.URL)
}
}
query := onedev.ProjectQueryOptions{
Query: "",
Offset: 0,
Count: 100,
}
user := onedev.User{}
if repo.User == "" {
u, _, err := client.GetMe()
if err != nil {
sub.Error().
Msg("can't find user")
break
}
user = u
repo.User = user.Name
}
sub.Info().
Msgf("grabbing repositories from %s", repo.User)
if repo.User != "" {
query.Query = fmt.Sprintf("owned by \"%s\"", repo.User)
}
userrepos, _, err := client.GetProjects(&query)
if err != nil {
sub.Error().
Msg(err.Error())
}
for _, r := range userrepos {
urls, _, err := client.GetCloneUrl(r.ID)
if err != nil {
sub.Error().
Msg("couldn't get clone urls")
continue
}
sub.Debug().Msg(urls.HTTP)
if repo.Filter.ExcludeForks {
if r.ForkedFromID != 0 {
continue
}
}
if len(repo.Include) > 0 {
if !include[r.Name] {
continue
}
if exclude[r.Name] {
continue
}
}
defaultbranch, _, err := client.GetDefaultBranch(r.ID)
if err != nil {
sub.Error().
Msgf("couldn't get default branch for %s", r.Name)
defaultbranch = "main"
}
if defaultbranch == "" {
continue
}
options := onedev.CommitQueryOptions{Query: fmt.Sprintf("branch(%s)", defaultbranch), Fields: []string{onedev.Committer, onedev.Parents, onedev.Author, onedev.CommitDate, onedev.Body, onedev.FileChanges, onedev.LineChanges, onedev.Subject}}
commits, _, err := client.GetCommits(r.ID, &options)
if err != nil {
if err != nil {
sub.Error().
Msgf("can't get latest commit for %s", defaultbranch)
} else {
if len(commits) > 0 {
lastactive := time.UnixMicro(commits[0].Author.When)
if time.Since(lastactive) > repo.Filter.LastActivityDuration && repo.Filter.LastActivityDuration != 0 {
continue
}
}
}
}
repos = append(repos, types.Repo{
Name: r.Name,
URL: urls.HTTP,
SSHURL: urls.SSH,
Token: repo.Token,
Defaultbranch: defaultbranch,
Origin: repo,
Owner: repo.User,
Hoster: types.GetHost(repo.URL),
Description: r.Description,
Issues: GetIssues(&r, client, repo, urls.HTTP),
})
}
if repo.Username != "" && repo.Password != "" && len(repo.IncludeOrgs) == 0 && user.Name != "" {
memberships, _, err := client.GetUserMemberships(user.ID)
if err != nil {
sub.Error().
Msgf("couldn't get memberships for %s", user.Name)
}
for _, membership := range memberships {
group, _, err := client.GetGroup(membership.GroupID)
if err != nil {
sub.Error().
Msgf("couldn't get group with id %d", membership.GroupID)
}
if !excludeorgs[group.Name] {
repo.IncludeOrgs = append(repo.IncludeOrgs, group.Name)
}
}
}
if len(repo.IncludeOrgs) > 0 {
for _, org := range repo.IncludeOrgs {
query.Query = fmt.Sprintf("children of \"%s\"", org)
orgrepos, _, err := client.GetProjects(&query)
if err != nil {
sub.Error().
Msg(err.Error())
}
for _, r := range orgrepos {
if repo.Filter.ExcludeForks {
if r.ForkedFromID != 0 {
continue
}
}
urls, _, err := client.GetCloneUrl(r.ID)
if err != nil {
sub.Error().
Msg("couldn't get clone urls")
continue
}
defaultbranch, _, err := client.GetDefaultBranch(r.ID)
if err != nil {
sub.Error().
Msgf("couldn't get default branch for %s", r.Name)
defaultbranch = "main"
}
repos = append(repos, types.Repo{
Name: r.Name,
URL: urls.HTTP,
SSHURL: urls.SSH,
Token: repo.Token,
Defaultbranch: defaultbranch,
Origin: repo,
Owner: org,
Hoster: types.GetHost(repo.URL),
Description: r.Description,
Issues: GetIssues(&r, client, repo, urls.HTTP),
})
}
}
}
}
return repos, ran
}
func GetOrCreate(destination types.GenRepo, repo types.Repo) (string, error) {
client := &onedev.Client{}
if destination.URL == "" {
destination.URL = "https://code.onedev.io/"
}
sub = logger.CreateSubLogger("stage", "onedev", "url", destination.URL)
if destination.Token != "" || destination.TokenFile != "" {
client = onedev.NewClient(destination.URL, onedev.SetToken(destination.GetToken()))
} else {
if destination.Password != "" {
client = onedev.NewClient(destination.URL, onedev.SetBasicAuth(destination.Username, destination.Password))
} else {
client = onedev.NewClient(destination.URL, "", "")
}
}
dest := ""
if destination.Organization == "" {
user, _, err := client.GetMe()
if err != nil {
return "", err
}
dest = user.Name
} else {
dest = destination.Organization
}
query := onedev.ProjectQueryOptions{
Query: fmt.Sprintf("\"Name\" is \"%s\" and children of \"%s\"", repo.Name, dest),
Offset: 0,
Count: 100,
}
projects, _, err := client.GetProjects(&query)
if err != nil {
return "", err
}
for _, project := range projects {
if project.Name == repo.Name {
cloneUrls, _, err := client.GetCloneUrl(project.ID)
if err != nil {
return "", err
}
return cloneUrls.HTTP, nil
}
}
query.Query = fmt.Sprintf("\"Name\" is \"%s\"", dest)
parentid := 0
parents, _, err := client.GetProjects(&query)
if err != nil {
return "", err
}
for _, parent := range parents {
if parent.Name == dest {
parentid = parent.ID
break
}
}
project, _, err := client.CreateProject(&onedev.CreateProjectOptions{Name: repo.Name, ParentID: parentid, CodeManagement: true})
if err != nil {
return "", err
}
cloneUrls, _, err := client.GetCloneUrl(project)
if err != nil {
return "", err
}
return cloneUrls.HTTP, nil
}
// GetIssues get issues
func GetIssues(repo *onedev.Project, client *onedev.Client, conf types.GenRepo, repourl string) map[string]interface{} {
issues := map[string]interface{}{}
if conf.Issues {
name := strings.TrimPrefix(repourl, conf.URL)
listOptions := &onedev.IssueQueryOptions{Count: 100, Offset: 0, Query: fmt.Sprintf("\"Project\" is \"%s\"", name)}
errorcount := 0
for {
i, returncode, err := client.GetIssues(listOptions)
if err != nil {
if returncode == http.StatusForbidden {
sub.Error().Err(err).Str("repo", repo.Name).Msg("can't fetch issues")
return issues
}
if errorcount < 5 {
sub.Error().Err(err).Str("repo", repo.Name).Msg("can't fetch issues")
time.Sleep(5 * time.Second)
errorcount++
} else {
return issues
}
} else {
if len(i) > 0 {
for _, issue := range i {
onedevissue := Issue{Issue: issue}
comments, _, err := client.GetIssueComments(onedevissue.ID)
if err != nil {
sub.Error().Err(err).Str("repo", repo.Name).Msg("can't fetch issues")
} else {
onedevissue.Comments = comments
}
issues[strconv.Itoa(int(issue.Number))] = onedevissue
}
} else {
break
}
listOptions.Offset += listOptions.Count
}
}
}
return issues
}
type Issue struct {
onedev.Issue
Comments []onedev.Comment
}