Skip to content

Instantly share code, notes, and snippets.

@josephspurrier
Created July 30, 2019 22:36
Show Gist options
  • Save josephspurrier/0f4ed19a479bcd7f03a526d19373f4fb to your computer and use it in GitHub Desktop.
Save josephspurrier/0f4ed19a479bcd7f03a526d19373f4fb to your computer and use it in GitHub Desktop.
GitLab Private API for Reading Issue Order in a List
// Package main is an example of how to use the GitLab private API.
// Related: https://gitlab.com/gitlab-org/gitlab-ce/issues/43674
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
"os"
"strings"
"time"
)
var (
// GitLabURL is the URL to GitLab.
GitLabURL = "https://gitlab.domain.com"
)
// PrivateTicket is a private ticket from GitLab.
type PrivateTicket struct {
Issues []struct {
ID int `json:"id"`
Iid int `json:"iid"`
Title string `json:"title"`
Confidential bool `json:"confidential"`
DueDate interface{} `json:"due_date"`
ProjectID int `json:"project_id"`
RelativePosition int `json:"relative_position"`
Project struct {
ID int `json:"id"`
Path string `json:"path"`
} `json:"project"`
Milestone struct {
ID int `json:"id"`
Title string `json:"title"`
} `json:"milestone"`
Assignees []struct {
ID int `json:"id"`
Name string `json:"name"`
Username string `json:"username"`
AvatarURL string `json:"avatar_url"`
} `json:"assignees"`
Labels []struct {
ID int `json:"id"`
Title string `json:"title"`
Color string `json:"color"`
Description string `json:"description"`
TextColor string `json:"text_color"`
Priority int `json:"priority"`
} `json:"labels"`
ReferencePath string `json:"reference_path"`
RealPath string `json:"real_path"`
IssueSidebarEndpoint string `json:"issue_sidebar_endpoint"`
ToggleSubscriptionEndpoint string `json:"toggle_subscription_endpoint"`
AssignableLabelsEndpoint string `json:"assignable_labels_endpoint"`
} `json:"issues"`
Size int `json:"size"`
}
func main() {
cookies, csrf, err := LoginCookie()
if err != nil {
log.Println(err)
return
}
cookies, err = Login(cookies, csrf)
if err != nil {
log.Println(err)
return
}
queryParam := "Milestone"
// These are hard coded to match the board numbers.
for _, listID := range []string{
"5",
"40",
} {
tickets := PrivateTicket{}
page := 1
// Should loop through pages here.
err := PrivateGet(fmt.Sprintf("/-/boards/3/lists/%v/issues?id=4&scope=all&milestone_title=%v&page=%v", listID, url.QueryEscape(queryParam), page), cookies, &tickets)
if err != nil {
log.Println(err)
return
}
// Do logic here.
}
}
// LoginCookie gets the login cookies.
func LoginCookie() ([]*http.Cookie, string, error) {
req, err := http.NewRequest("GET", GitLabURL+"/users/sign_in", nil)
if err != nil {
return nil, "", err
}
client := http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
return nil, "", err
}
if resp.StatusCode != http.StatusOK {
return nil, "", fmt.Errorf("bad status code: %v", resp.StatusCode)
}
b, _ := ioutil.ReadAll(resp.Body)
s := string(b)
find := `<meta name="csrf-token" content="`
index := strings.Index(s, find)
section := s[index+len(find) : index+len(find)+200]
csrf := section[:strings.Index(section, `"`)]
return resp.Cookies(), csrf, nil
}
// Login will login to GitLab.
func Login(cookies []*http.Cookie, csrf string) ([]*http.Cookie, error) {
form := url.Values{}
user := os.Getenv("GITLABUSER")
pass := os.Getenv("GITLABPASS")
form.Add("user[login]", user)
form.Add("user[password]", pass)
form.Add("authenticity_token", csrf)
req, err := http.NewRequest("POST", GitLabURL+"/users/sign_in", strings.NewReader(form.Encode()))
if err != nil {
return nil, err
}
for _, cookie := range cookies {
req.AddCookie(cookie)
}
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
client := http.Client{
Timeout: 5 * time.Second,
CheckRedirect: func(req *http.Request, via []*http.Request) error {
return http.ErrUseLastResponse
},
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusFound {
return nil, fmt.Errorf("bad status code: %v", resp.StatusCode)
}
resp.Body.Close()
return resp.Cookies(), nil
}
// PrivateGet makes a gitlab get request to the private API.
func PrivateGet(URL string, cookies []*http.Cookie, i interface{}) error {
req, err := http.NewRequest("GET", GitLabURL+URL, nil)
if err != nil {
return err
}
for _, cookie := range cookies {
req.AddCookie(cookie)
}
client := http.Client{
Timeout: 5 * time.Second,
}
resp, err := client.Do(req)
if err != nil {
return err
}
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("bad status code: %v", resp.StatusCode)
}
err = json.NewDecoder(resp.Body).Decode(i)
if err != nil {
return fmt.Errorf("could not decode response: %v", err)
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment