github.com/nkprince007/lab@v0.6.2-0.20171218071646-19d68b56f403/internal/gitlab/gitlab.go (about)

     1  // Package gitlab is an internal wrapper for the go-gitlab package
     2  //
     3  // Most functions serve to expose debug logging if set and accept a project
     4  // name string over an ID
     5  package gitlab
     6  
     7  import (
     8  	"fmt"
     9  	"io/ioutil"
    10  	"log"
    11  	"net/http"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/davecgh/go-spew/spew"
    17  	"github.com/pkg/errors"
    18  	"github.com/xanzy/go-gitlab"
    19  	"github.com/zaquestion/lab/internal/git"
    20  )
    21  
    22  var (
    23  	ErrProjectNotFound = errors.New("gitlab project not found")
    24  )
    25  
    26  var (
    27  	lab  *gitlab.Client
    28  	host string
    29  	user string
    30  )
    31  
    32  // Host exposes the GitLab scheme://hostname used to interact with the API
    33  func Host() string {
    34  	return host
    35  }
    36  
    37  // User exposes the configured GitLab user
    38  func User() string {
    39  	return user
    40  }
    41  
    42  // Init initializes a gitlab client for use throughout lab.
    43  func Init(_host, _user, _token string) {
    44  	host = _host
    45  	user = _user
    46  	lab = gitlab.NewClient(nil, _token)
    47  	lab.SetBaseURL(host + "/api/v4")
    48  
    49  	if os.Getenv("DEBUG") != "" {
    50  		log.Println("gitlab.host:", host)
    51  		if len(_token) > 12 {
    52  			log.Println("gitlab.token:", "************"+_token[12:])
    53  		} else {
    54  			log.Println("This token looks invalid due to it's length")
    55  			log.Println("gitlab.token:", _token)
    56  		}
    57  		log.Println("gitlab.user:", user)
    58  
    59  		// Test listing projects
    60  		projects, _, err := lab.Projects.ListProjects(&gitlab.ListProjectsOptions{})
    61  		if err != nil {
    62  			log.Fatal("Error: ", err)
    63  		}
    64  		if len(projects) > 0 {
    65  			spew.Dump(projects[0])
    66  		}
    67  	}
    68  }
    69  
    70  // Defines filepath for default GitLab templates
    71  const (
    72  	TmplMR    = "merge_request_templates/default.md"
    73  	TmplIssue = "issue_templates/default.md"
    74  )
    75  
    76  // LoadGitLabTmpl loads gitlab templates for use in creating Issues and MRs
    77  //
    78  // https://gitlab.com/help/user/project/description_templates.md#setting-a-default-template-for-issues-and-merge-requests
    79  func LoadGitLabTmpl(tmplName string) string {
    80  	wd, err := git.WorkingDir()
    81  	if err != nil {
    82  		log.Fatal(err)
    83  	}
    84  
    85  	tmplFile := filepath.Join(wd, ".gitlab", tmplName)
    86  	if os.Getenv("DEBUG") != "" {
    87  		log.Println("tmplFile:", tmplFile)
    88  	}
    89  
    90  	f, err := os.Open(tmplFile)
    91  	if os.IsNotExist(err) {
    92  		return ""
    93  	} else if err != nil {
    94  		log.Fatal(err)
    95  	}
    96  
    97  	tmpl, err := ioutil.ReadAll(f)
    98  	if err != nil {
    99  		log.Fatal(err)
   100  	}
   101  
   102  	return string(tmpl[:len(tmpl)-1])
   103  }
   104  
   105  var (
   106  	localProjects map[string]*gitlab.Project = make(map[string]*gitlab.Project)
   107  )
   108  
   109  // FindProject looks up the Gitlab project. If the namespace is not provided in
   110  // the project string it will search for projects in the users namespace
   111  func FindProject(project string) (*gitlab.Project, error) {
   112  	if target, ok := localProjects[project]; ok {
   113  		return target, nil
   114  	}
   115  
   116  	search := project
   117  	// Assuming that a "/" in the project means its owned by an org
   118  	if !strings.Contains(project, "/") {
   119  		search = user + "/" + project
   120  	}
   121  
   122  	target, resp, err := lab.Projects.GetProject(search)
   123  	if resp.StatusCode == http.StatusNotFound {
   124  		return nil, ErrProjectNotFound
   125  	}
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	if os.Getenv("DEBUG") != "" {
   130  		spew.Dump(target)
   131  	}
   132  
   133  	// fwiw, I feel bad about this
   134  	localProjects[project] = target
   135  
   136  	return target, nil
   137  }
   138  
   139  // Fork creates a user fork of a GitLab project
   140  func Fork(project string) (string, error) {
   141  	if !strings.Contains(project, "/") {
   142  		return "", errors.New("remote must include namespace")
   143  	}
   144  	parts := strings.Split(project, "/")
   145  
   146  	// See if a fork already exists
   147  	target, err := FindProject(parts[1])
   148  	if err == nil {
   149  		return target.SSHURLToRepo, nil
   150  	} else if err != nil && err != ErrProjectNotFound {
   151  		return "", err
   152  	}
   153  
   154  	target, err = FindProject(project)
   155  	if err != nil {
   156  		return "", err
   157  	}
   158  
   159  	fork, _, err := lab.Projects.ForkProject(target.ID)
   160  	if err != nil {
   161  		return "", err
   162  	}
   163  
   164  	return fork.SSHURLToRepo, nil
   165  }
   166  
   167  // MergeRequest opens a merge request on GitLab
   168  func MergeRequest(project string, opts *gitlab.CreateMergeRequestOptions) (string, error) {
   169  	if os.Getenv("DEBUG") != "" {
   170  		spew.Dump(opts)
   171  	}
   172  
   173  	p, err := FindProject(project)
   174  	if err != nil {
   175  		return "", err
   176  	}
   177  
   178  	mr, _, err := lab.MergeRequests.CreateMergeRequest(p.ID, opts)
   179  	if err != nil {
   180  		return "", err
   181  	}
   182  	return mr.WebURL, nil
   183  }
   184  
   185  // GetMR retrieves the merge request from GitLab project
   186  func GetMR(project string, mrNum int) (*gitlab.MergeRequest, error) {
   187  	p, err := FindProject(project)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	mr, _, err := lab.MergeRequests.GetMergeRequest(p.ID, mrNum)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	return mr, nil
   198  }
   199  
   200  // ListMRs lists the MRs on a GitLab project
   201  func ListMRs(project string, opts *gitlab.ListProjectMergeRequestsOptions) ([]*gitlab.MergeRequest, error) {
   202  	p, err := FindProject(project)
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	list, _, err := lab.MergeRequests.ListProjectMergeRequests(p.ID, opts)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	return list, nil
   212  }
   213  
   214  // IssueCreate opens a new issue on a GitLab Project
   215  func IssueCreate(project string, opts *gitlab.CreateIssueOptions) (string, error) {
   216  	if os.Getenv("DEBUG") != "" {
   217  		spew.Dump(opts)
   218  	}
   219  
   220  	p, err := FindProject(project)
   221  	if err != nil {
   222  		return "", err
   223  	}
   224  
   225  	mr, _, err := lab.Issues.CreateIssue(p.ID, opts)
   226  	if err != nil {
   227  		return "", err
   228  	}
   229  	return mr.WebURL, nil
   230  }
   231  
   232  // IssueGet retrieves the issue information from a GitLab project
   233  func IssueGet(project string, issueNum int) (*gitlab.Issue, error) {
   234  	p, err := FindProject(project)
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  
   239  	issue, _, err := lab.Issues.GetIssue(p.ID, issueNum)
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	return issue, nil
   245  }
   246  
   247  // IssueList gets a list of issues on a GitLab Project
   248  func IssueList(project string, opts *gitlab.ListProjectIssuesOptions) ([]*gitlab.Issue, error) {
   249  	if os.Getenv("DEBUG") != "" {
   250  		spew.Dump(opts)
   251  	}
   252  
   253  	p, err := FindProject(project)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  
   258  	list, _, err := lab.Issues.ListProjectIssues(p.ID, opts)
   259  	if err != nil {
   260  		return nil, err
   261  	}
   262  	return list, nil
   263  }
   264  
   265  // BranchPushed checks if a branch exists on a GitLab Project
   266  func BranchPushed(project, branch string) bool {
   267  	p, err := FindProject(project)
   268  	if err != nil {
   269  		return false
   270  	}
   271  
   272  	b, _, err := lab.Branches.GetBranch(p.ID, branch)
   273  	if err != nil {
   274  		return false
   275  	}
   276  	return b != nil
   277  }
   278  
   279  // ProjectSnippetCreate creates a snippet in a project
   280  func ProjectSnippetCreate(pid interface{}, opts *gitlab.CreateProjectSnippetOptions) (*gitlab.Snippet, error) {
   281  	if os.Getenv("DEBUG") != "" {
   282  		spew.Dump(opts)
   283  	}
   284  	snip, resp, err := lab.ProjectSnippets.CreateSnippet(pid, opts)
   285  	if os.Getenv("DEBUG") != "" {
   286  		fmt.Println(resp.Response.Status)
   287  	}
   288  	if err != nil {
   289  		return nil, err
   290  	}
   291  
   292  	return snip, nil
   293  }
   294  
   295  // ProjectSnippetDelete deletes a project snippet
   296  func ProjectSnippetDelete(pid interface{}, id int) error {
   297  	resp, err := lab.ProjectSnippets.DeleteSnippet(pid, id)
   298  	if os.Getenv("DEBUG") != "" {
   299  		fmt.Println(resp.Response.Status)
   300  	}
   301  	return err
   302  }
   303  
   304  // ProjectSnippetList lists snippets on a project
   305  func ProjectSnippetList(pid interface{}, opts *gitlab.ListProjectSnippetsOptions) ([]*gitlab.Snippet, error) {
   306  	if os.Getenv("DEBUG") != "" {
   307  		spew.Dump(opts)
   308  	}
   309  	snips, resp, err := lab.ProjectSnippets.ListSnippets(pid, opts)
   310  	if os.Getenv("DEBUG") != "" {
   311  		fmt.Println(resp.Response.Status)
   312  	}
   313  	if err != nil {
   314  		return nil, err
   315  	}
   316  	return snips, nil
   317  }
   318  
   319  // SnippetCreate creates a personal snippet
   320  func SnippetCreate(opts *gitlab.CreateSnippetOptions) (*gitlab.Snippet, error) {
   321  	if os.Getenv("DEBUG") != "" {
   322  		spew.Dump(opts)
   323  	}
   324  	snip, resp, err := lab.Snippets.CreateSnippet(opts)
   325  	if os.Getenv("DEBUG") != "" {
   326  		fmt.Println(resp.Response.Status)
   327  	}
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  
   332  	return snip, nil
   333  }
   334  
   335  // SnippetDelete deletes a personal snippet
   336  func SnippetDelete(id int) error {
   337  	resp, err := lab.Snippets.DeleteSnippet(id)
   338  	if os.Getenv("DEBUG") != "" {
   339  		fmt.Println(resp.Response.Status)
   340  	}
   341  	return err
   342  }
   343  
   344  // SnippetList lists snippets on a project
   345  func SnippetList(opts *gitlab.ListSnippetsOptions) ([]*gitlab.Snippet, error) {
   346  	if os.Getenv("DEBUG") != "" {
   347  		spew.Dump(opts)
   348  	}
   349  	snips, resp, err := lab.Snippets.ListSnippets(opts)
   350  	if os.Getenv("DEBUG") != "" {
   351  		fmt.Println(resp.Response.Status)
   352  	}
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  	return snips, nil
   357  }