123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545 |
- package gitlab
- import (
- "net/url"
- "strings"
- "go-common/app/tool/saga/model"
- "go-common/library/log"
- "github.com/pkg/errors"
- "github.com/xanzy/go-gitlab"
- )
- // Gitlab def
- type Gitlab struct {
- url string
- token string
- client *gitlab.Client
- }
- // New new gitlab structure
- func New(url string, token string) (g *Gitlab) {
- g = &Gitlab{
- url: url,
- token: token,
- client: gitlab.NewClient(nil, token),
- }
- g.client.SetBaseURL(url)
- return
- }
- // HostToken ...
- func (g *Gitlab) HostToken() (host string, token string, err error) {
- var u *url.URL
- if u, err = url.Parse(g.url); err != nil {
- return
- }
- host = u.Host
- token = g.token
- return
- }
- // LastGreenCommit get last green pipeline commit
- func (g *Gitlab) LastGreenCommit(ciProjectID string, ciCommitRefName string) (commit string, err error) {
- var (
- status = gitlab.Success
- pipelines gitlab.PipelineList
- )
- opt := &gitlab.ListProjectPipelinesOptions{
- Status: &status,
- Ref: gitlab.String(ciCommitRefName),
- }
- if pipelines, _, err = g.client.Pipelines.ListProjectPipelines(ciProjectID, opt); err != nil {
- return
- }
- if len(pipelines) == 0 {
- return
- }
- commit = pipelines[0].Sha
- return
- }
- // AcceptMR accept Merge request
- func (g *Gitlab) AcceptMR(projID int, mrIID int, msg string) (state string, err error) {
- var (
- opt = &gitlab.AcceptMergeRequestOptions{
- ShouldRemoveSourceBranch: gitlab.Bool(true),
- MergeCommitMessage: gitlab.String(msg),
- }
- mergeRequest *gitlab.MergeRequest
- )
- if mergeRequest, _, err = g.client.MergeRequests.AcceptMergeRequest(projID, mrIID, opt); err != nil {
- err = errors.Wrapf(err, "AcceptMergeRequest(%d,%d)", projID, mrIID)
- return
- }
- state = mergeRequest.State
- return
- }
- // CloseMR close merge request
- func (g *Gitlab) CloseMR(projID int, mrIID int) (err error) {
- var (
- opt = &gitlab.UpdateMergeRequestOptions{
- StateEvent: gitlab.String("close"),
- }
- )
- if _, _, err = g.client.MergeRequests.UpdateMergeRequest(projID, mrIID, opt); err != nil {
- err = errors.Wrapf(err, "CloseMR(%d,%d)", projID, mrIID)
- }
- return
- }
- // CreateMRNote create note to merge request
- func (g *Gitlab) CreateMRNote(projID int, mrIID int, content string) (noteID int, err error) {
- var (
- opt = &gitlab.CreateMergeRequestNoteOptions{
- Body: gitlab.String(content),
- }
- note *gitlab.Note
- )
- if note, _, err = g.client.Notes.CreateMergeRequestNote(projID, mrIID, opt); err != nil {
- err = errors.Wrapf(err, "CreateMergeRequestNote(%d,%d)", projID, mrIID)
- return
- }
- noteID = note.ID
- return
- }
- // UpdateMRNote update the specified merge request note
- func (g *Gitlab) UpdateMRNote(projID int, mrIID int, noteID int, content string) (err error) {
- var (
- opt = &gitlab.UpdateMergeRequestNoteOptions{
- Body: gitlab.String(content),
- }
- )
- if _, _, err = g.client.Notes.UpdateMergeRequestNote(projID, mrIID, noteID, opt); err != nil {
- err = errors.Wrapf(err, "UpdateMergeRequestNote(%d,%d,%d)", projID, mrIID, noteID)
- return
- }
- return
- }
- // DeleteMRNote delete the specified note for merge request
- func (g *Gitlab) DeleteMRNote(projID int, mrIID int, noteID int) (err error) {
- if _, err = g.client.Notes.DeleteMergeRequestNote(projID, mrIID, noteID); err != nil {
- err = errors.Wrapf(err, "DeleteMergeRequestNote(%d,%d,%d)", projID, mrIID, noteID)
- }
- return
- }
- // UserName get user name for user id
- func (g *Gitlab) UserName(userID int) (userName string, err error) {
- var (
- user *gitlab.User
- )
- if user, _, err = g.client.Users.GetUser(userID); err != nil {
- err = errors.WithStack(err)
- return
- }
- userName = user.Username
- return
- }
- // Triggers get pipeline triggers
- func (g *Gitlab) Triggers(projectID int) (triggers []*gitlab.PipelineTrigger, err error) {
- var (
- opt = &gitlab.ListPipelineTriggersOptions{}
- )
- if triggers, _, err = g.client.PipelineTriggers.ListPipelineTriggers(projectID, opt); err != nil {
- err = errors.Wrapf(err, "ListPipelineTriggers (projectID: %d)", projectID)
- return nil, err
- }
- return triggers, nil
- }
- // CreateTrigger create the trigger to trigger pipeline
- func (g *Gitlab) CreateTrigger(projectID int) (trigger *gitlab.PipelineTrigger, err error) {
- var (
- opt = &gitlab.AddPipelineTriggerOptions{
- Description: gitlab.String("gitlab-ci-build-on-merge-request"),
- }
- )
- if trigger, _, err = g.client.PipelineTriggers.AddPipelineTrigger(projectID, opt); err != nil {
- err = errors.Wrapf(err, "CreateTrigger (projectID: %d)", projectID)
- return nil, err
- }
- return trigger, nil
- }
- // TakeOwnership take ownership of the trigger
- func (g *Gitlab) TakeOwnership(projectID int, triggerID int) (trigger *gitlab.PipelineTrigger, err error) {
- if trigger, _, err = g.client.PipelineTriggers.TakeOwnershipOfPipelineTrigger(projectID, triggerID); err != nil {
- err = errors.Wrapf(err, "TakeOwnershipOfPipelineTrigger (projectID: %d, triggerID: %d)", projectID, triggerID)
- return nil, err
- }
- return trigger, nil
- }
- // TriggerPipeline trigger the pipeline
- func (g *Gitlab) TriggerPipeline(projectID int, ref string, token string) (pipeline *gitlab.Pipeline, err error) {
- var (
- opt = &gitlab.RunPipelineTriggerOptions{
- Ref: gitlab.String(ref),
- Token: gitlab.String(token),
- }
- )
- if pipeline, _, err = g.client.PipelineTriggers.RunPipelineTrigger(projectID, opt); err != nil {
- err = errors.Wrapf(err, "RunPipelineTrigger (projectID: %d, ref: %s, token: %s)", projectID, ref, token)
- return nil, err
- }
- return pipeline, nil
- }
- // AwardEmojiUsernames get the username who gave the emoji
- func (g *Gitlab) AwardEmojiUsernames(projID int, mrIID int) (usernames []string, err error) {
- var (
- opt = &gitlab.ListAwardEmojiOptions{
- Page: 1,
- PerPage: 100,
- }
- awards []*gitlab.AwardEmoji
- )
- if awards, _, err = g.client.AwardEmoji.ListMergeRequestAwardEmoji(projID, mrIID, opt); err != nil {
- return
- }
- for _, a := range awards {
- if a.Name == "thumbsup" {
- usernames = append(usernames, a.User.Username)
- }
- }
- return
- }
- // AuditProjects audit all the given projects
- func (g *Gitlab) AuditProjects(repos []*model.Repo, hooks []*model.WebHook) (err error) {
- var (
- repo *model.Repo
- projID int
- )
- log.Info("AuditProjects start")
- for _, repo = range repos {
- log.Info("AuditProjects project [%s]", repo.Config.URL)
- if projID, err = g.ProjectID(repo.Config.URL); err != nil {
- log.Error("Failed to get project ID [%s], err: %+v", repo.Config.URL, err)
- continue
- }
- if err = g.AuditProjectHooks(projID, hooks); err != nil {
- log.Error("Failed to get hooks [%s], err: %+v", repo.Config.URL, err)
- continue
- }
- log.Info("AuditProjects project [%s]", repo.Config.URL)
- }
- log.Info("AuditProjects end")
- return
- }
- // AuditProjectHooks check and add or edit the project webhooks
- func (g *Gitlab) AuditProjectHooks(projID int, hooks []*model.WebHook) (err error) {
- var (
- webHooks []*gitlab.ProjectHook
- h *model.WebHook
- )
- if webHooks, err = g.ListProjectHook(projID); err != nil {
- return
- }
- // 配置文件中的webhook是否配置在项目中
- inWebHooks := func(h *model.WebHook) (in bool, ph *gitlab.ProjectHook) {
- for _, ph = range webHooks {
- if h.URL == ph.URL {
- in = true
- return
- }
- }
- in = false
- return
- }
- // 找到的webhook是否和配置文件中webhook配置相等
- equalHook := func(h *model.WebHook, ph *gitlab.ProjectHook) (equal bool) {
- if h.PushEvents == ph.PushEvents && h.IssuesEvents == ph.IssuesEvents &&
- h.ConfidentialIssuesEvents == ph.ConfidentialIssuesEvents && h.MergeRequestsEvents == ph.MergeRequestsEvents &&
- h.TagPushEvents == ph.TagPushEvents && h.NoteEvents == ph.NoteEvents &&
- h.JobEvents == ph.JobEvents && h.PipelineEvents == ph.PipelineEvents &&
- h.WikiPageEvents == ph.WikiPageEvents && !ph.EnableSSLVerification {
- return true
- }
- return false
- }
- // 配置的webhook与查询出来的对比,如果存在,则比较属性,属性不同,则修改;不存在,则创建
- for _, h = range hooks {
- if in, ph := inWebHooks(h); in {
- if !equalHook(h, ph) {
- if err = g.EditProjectHook(projID, ph.ID, h); err != nil {
- return
- }
- }
- } else {
- if err = g.AddProjectHook(projID, h); err != nil {
- return
- }
- }
- }
- return
- }
- // AddProjectHook add project hook for the project
- func (g *Gitlab) AddProjectHook(projID int, hook *model.WebHook) (err error) {
- var (
- opt = &gitlab.AddProjectHookOptions{
- URL: &hook.URL,
- PushEvents: &hook.PushEvents,
- IssuesEvents: &hook.IssuesEvents,
- ConfidentialIssuesEvents: &hook.ConfidentialIssuesEvents,
- MergeRequestsEvents: &hook.MergeRequestsEvents,
- TagPushEvents: &hook.TagPushEvents,
- NoteEvents: &hook.NoteEvents,
- JobEvents: &hook.JobEvents,
- PipelineEvents: &hook.PipelineEvents,
- WikiPageEvents: &hook.WikiPageEvents,
- EnableSSLVerification: gitlab.Bool(false),
- }
- )
- if _, _, err = g.client.Projects.AddProjectHook(projID, opt); err != nil {
- return
- }
- return
- }
- // ListProjectHook list all the webhook for the project
- func (g *Gitlab) ListProjectHook(projID int) (hooks []*gitlab.ProjectHook, err error) {
- var (
- opt = &gitlab.ListProjectHooksOptions{
- Page: 1,
- PerPage: 100,
- }
- )
- if hooks, _, err = g.client.Projects.ListProjectHooks(projID, opt); err != nil {
- return
- }
- return
- }
- // EditProjectHook edit the specified webhook for the project
- func (g *Gitlab) EditProjectHook(projID int, hookID int, hook *model.WebHook) (err error) {
- var (
- opt = &gitlab.EditProjectHookOptions{
- URL: &hook.URL,
- PushEvents: &hook.PushEvents,
- IssuesEvents: &hook.IssuesEvents,
- ConfidentialIssuesEvents: &hook.ConfidentialIssuesEvents,
- MergeRequestsEvents: &hook.MergeRequestsEvents,
- TagPushEvents: &hook.TagPushEvents,
- NoteEvents: &hook.NoteEvents,
- JobEvents: &hook.JobEvents,
- PipelineEvents: &hook.PipelineEvents,
- WikiPageEvents: &hook.WikiPageEvents,
- EnableSSLVerification: gitlab.Bool(false),
- }
- )
- if _, _, err = g.client.Projects.EditProjectHook(projID, hookID, opt); err != nil {
- return
- }
- return
- }
- // DeletePojectHook delete the specified hook for the project
- func (g *Gitlab) DeletePojectHook(projID int, hookID int) (err error) {
- if _, err = g.client.Projects.DeleteProjectHook(projID, hookID); err != nil {
- return
- }
- return
- }
- // ProjectID get project id by project URL-encoded name
- func (g *Gitlab) ProjectID(url string) (projID int, err error) {
- var (
- projectName = url[strings.LastIndex(url, ":")+1 : strings.LastIndex(url, ".git")]
- project *gitlab.Project
- )
- if project, _, err = g.client.Projects.GetProject(projectName); err != nil {
- return
- }
- projID = project.ID
- return
- }
- // MRPipelineStatus query PipelineState for mr
- func (g *Gitlab) MRPipelineStatus(projID int, mrIID int) (id int, status string, err error) {
- var pipelineList gitlab.PipelineList
- if pipelineList, _, err = g.client.MergeRequests.ListMergeRequestPipelines(projID, mrIID); err != nil {
- return
- }
- if len(pipelineList) == 0 {
- status = model.PipelineSuccess
- return
- }
- id = pipelineList[0].ID
- status = pipelineList[0].Status
- return
- }
- // LastPipeLineState query Last PipeLineState
- func (g *Gitlab) LastPipeLineState(projID int, ciCommitRefName string) (state bool, err error) {
- var pipelines gitlab.PipelineList
- opt := &gitlab.ListProjectPipelinesOptions{
- Ref: gitlab.String(ciCommitRefName),
- }
- state = true
- if pipelines, _, err = g.client.Pipelines.ListProjectPipelines(projID, opt); err != nil {
- return
- }
- if len(pipelines) < 2 {
- return
- }
- state = pipelines[1].Status == model.PipelineSuccess
- return
- }
- // MergeStatus query MergeStatus
- func (g *Gitlab) MergeStatus(projID int, mrIID int) (wip bool, state string, status string, err error) {
- var mergerequest *gitlab.MergeRequest
- if mergerequest, _, err = g.client.MergeRequests.GetMergeRequest(projID, mrIID); err != nil {
- return
- }
- state = mergerequest.State
- status = mergerequest.MergeStatus
- wip = mergerequest.WorkInProgress
- return
- }
- // MergeLabels get Merge request labels
- func (g *Gitlab) MergeLabels(projID int, mrIID int) (labels []string, err error) {
- var mergerequest *gitlab.MergeRequest
- if mergerequest, _, err = g.client.MergeRequests.GetMergeRequest(projID, mrIID); err != nil {
- return
- }
- labels = mergerequest.Labels
- return
- }
- // PlusUsernames get the username who +1
- func (g *Gitlab) PlusUsernames(projID int, mrIID int) (usernames []string, err error) {
- var (
- opt = &gitlab.ListMergeRequestNotesOptions{
- Page: 1,
- PerPage: 100,
- }
- notes []*gitlab.Note
- exist bool
- )
- if notes, _, err = g.client.Notes.ListMergeRequestNotes(projID, mrIID, opt); err != nil {
- return
- }
- for _, note := range notes {
- if (strings.TrimSpace(note.Body) == model.SagaCommandPlusOne) || (strings.TrimSpace(note.Body) == model.SagaCommandPlusOne1) {
- exist = false
- for _, user := range usernames {
- if user == note.Author.Username {
- exist = true
- break
- }
- }
- if !exist {
- usernames = append(usernames, note.Author.Username)
- }
- }
- }
- return
- }
- // CompareDiff ...
- func (g *Gitlab) CompareDiff(projID int, from string, to string) (files []string, err error) {
- var (
- opt = &gitlab.CompareOptions{
- From: &from,
- To: &to,
- }
- compare *gitlab.Compare
- )
- if compare, _, err = g.client.Repositories.Compare(projID, opt); err != nil {
- return
- }
- for _, diff := range compare.Diffs {
- if diff.NewFile {
- files = append(files, diff.NewPath)
- } else {
- files = append(files, diff.OldPath)
- }
- }
- return
- }
- // CommitDiff ...
- func (g *Gitlab) CommitDiff(projID int, sha string) (files []string, err error) {
- var (
- diffs []*gitlab.Diff
- opt = &gitlab.GetCommitDiffOptions{
- Page: 1,
- PerPage: 100,
- }
- )
- if diffs, _, err = g.client.Commits.GetCommitDiff(projID, sha, opt); err != nil {
- return
- }
- for _, diff := range diffs {
- if diff.NewFile {
- files = append(files, diff.NewPath)
- } else {
- files = append(files, diff.OldPath)
- }
- }
- return
- }
- // MRChanges ...
- func (g *Gitlab) MRChanges(projID, mrIID int) (changeFiles []string, deleteFiles []string, err error) {
- var (
- mr *gitlab.MergeRequest
- )
- if mr, _, err = g.client.MergeRequests.GetMergeRequestChanges(projID, mrIID); err != nil {
- return
- }
- for _, c := range mr.Changes {
- if c.RenamedFile {
- deleteFiles = append(deleteFiles, c.OldPath)
- changeFiles = append(changeFiles, c.NewPath)
- } else if c.DeletedFile {
- deleteFiles = append(deleteFiles, c.OldPath)
- } else if c.NewFile {
- changeFiles = append(changeFiles, c.NewPath)
- } else {
- changeFiles = append(changeFiles, c.OldPath)
- }
- }
- return
- }
- // RepoRawFile ...
- func (g *Gitlab) RepoRawFile(projID int, branch string, filename string) (content []byte, err error) {
- var (
- opt = &gitlab.GetRawFileOptions{
- Ref: &branch,
- }
- )
- if content, _, err = g.client.RepositoryFiles.GetRawFile(projID, filename, opt); err != nil {
- return
- }
- return
- }
|