Commit b1cfdff1 authored by FlakM's avatar FlakM Committed by Sander van Harmelen

Runners api complete implementation (#316)

* impl DisableProjectRunner

* impl ListRunnersJobs

* impl RemoveARunner

* impl UpdateRunnersDetails

* requested changes

* renamed ListRunnersJobs to ListRunnerJobs
parent e9b63f4c
......@@ -19,6 +19,7 @@ package gitlab
import (
"fmt"
"net/url"
"time"
)
// RunnersService handles communication with the runner related methods of the
......@@ -42,6 +43,34 @@ type Runner struct {
Status string `json:"status"`
}
// RunnersDetails represents a GitLab CI RunnerDetails.
//
// GitLab API docs: https://docs.gitlab.com/ce/api/runners.html
type RunnersDetails struct {
Active bool `json:"active"`
Architecture string `json:"architecture"`
Description string `json:"description"`
ID int `json:"id"`
IsShared bool `json:"is_shared"`
ContactedAt *time.Time `json:"contacted_at,omitempty"`
Name string `json:"name"`
Online bool `json:"online"`
Status string `json:"status"`
Platform string `json:"platform,omitempty"`
Projects []struct {
ID int `json:"id"`
Name string `json:"name"`
NameWithNamespace string `json:"name_with_namespace"`
Path string `json:"path"`
PathWithNamespace string `json:"path_with_namespace"`
} `json:"projects"`
Token string `json:"Token"`
Revision string `json:"revision,omitempty"`
TagList []string `json:"tag_list"`
Version string `json:"version,omitempty"`
AccessLevel string `json:"access_level"`
}
// ListRunnersOptions represents the available ListRunners() options.
//
// GitLab API docs:
......@@ -90,6 +119,123 @@ func (s *RunnersService) ListAllRunners(opt *ListRunnersOptions, options ...Opti
return rs, resp, err
}
// GetRunnerDetails returns details for given runner.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#get-runner-39-s-details
func (s *RunnersService) GetRunnerDetails(rid interface{}, options ...OptionFunc) (*RunnersDetails, *Response, error) {
runner, err := parseID(rid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("runners/%s", runner)
req, err := s.client.NewRequest("GET", u, nil, options)
if err != nil {
return nil, nil, err
}
var rs *RunnersDetails
resp, err := s.client.Do(req, &rs)
if err != nil {
return nil, resp, err
}
return rs, resp, err
}
// UpdateRunnersDetailsOptions represents the available UpdateRunnersDetails() options.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details
type UpdateRunnersDetailsOptions struct {
Description *string `url:"description,omitempty" json:"description,omitempty"`
Active *bool `url:"active,omitempty" json:"active,omitempty"`
TagList []string `url:"tag_list[],omitempty" json:"tag_list,omitempty"`
RunUntagged *bool `url:"run_untagged,omitempty" json:"run_untagged,omitempty"`
Locked *bool `url:"locked,omitempty" json:"locked,omitempty"`
AccessLevel *string `url:"access_level,omitempty" json:"access_level,omitempty"`
}
// UpdateRunnersDetails updates runners details
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#update-runner-39-s-details
func (s *RunnersService) UpdateRunnersDetails(rid interface{}, opt *UpdateRunnersDetailsOptions, options ...OptionFunc) (*RunnersDetails, *Response, error) {
runner, err := parseID(rid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("runners/%s", runner)
req, err := s.client.NewRequest("PUT", u, opt, options)
if err != nil {
return nil, nil, err
}
var rs *RunnersDetails
resp, err := s.client.Do(req, &rs)
if err != nil {
return nil, resp, err
}
return rs, resp, err
}
// RemoveARunner removes a runner
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#remove-a-runner
func (s *RunnersService) RemoveARunner(rid interface{}, options ...OptionFunc) (*Response, error) {
runner, err := parseID(rid)
if err != nil {
return nil, err
}
u := fmt.Sprintf("runners/%s", runner)
req, err := s.client.NewRequest("DELETE", u, nil, options)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
// ListRunnersJobsOptions represents the available ListRunnersJobs()
// options. (one of running, success, failed, canceled)
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#list-runner-39-s-jobs
type ListRunnersJobsOptions struct {
ListOptions
Status *BuildState `url:"status,omitempty" json:"status,omitempty"`
}
// ListRunnerJobs gets a list of jobs that are being processed or were processed by specified Runner.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#list-runner-39-s-jobs
func (s *RunnersService) ListRunnerJobs(rid interface{}, opt *ListRunnersJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) {
runner, err := parseID(rid)
if err != nil {
return nil, nil, err
}
u := fmt.Sprintf("runners/%s/jobs", runner)
req, err := s.client.NewRequest("GET", u, opt, options)
if err != nil {
return nil, nil, err
}
var rs []*Job
resp, err := s.client.Do(req, &rs)
if err != nil {
return nil, resp, err
}
return rs, resp, err
}
// ListProjectRunnersOptions represents the available ListProjectRunners()
// options.
//
......@@ -155,3 +301,28 @@ func (s *RunnersService) EnableProjectRunner(pid interface{}, opt *EnableProject
return r, resp, err
}
// DisableProjectRunner disables a specific runner from project.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/runners.html#disable-a-runner-from-project
func (s *RunnersService) DisableProjectRunner(pid interface{}, rid interface{}, options ...OptionFunc) (*Response, error) {
project, err := parseID(pid)
if err != nil {
return nil, err
}
runner, err := parseID(rid)
if err != nil {
return nil, err
}
u := fmt.Sprintf("projects/%s/runners/%s", url.QueryEscape(project), url.QueryEscape(runner))
req, err := s.client.NewRequest("DELETE", u, nil, options)
if err != nil {
return nil, err
}
return s.client.Do(req, nil)
}
//
// Copyright 2017, Sander van Harmelen
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
package gitlab
import (
"fmt"
"net/http"
"reflect"
"testing"
"time"
)
func TestDisableRunner(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/projects/1/runners/2", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Runners.DisableProjectRunner(1, 2, nil)
if err != nil {
t.Fatalf("Runners.DisableProjectRunner returns an error: %v", err)
}
}
func TestListRunnersJobs(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/runners/1/jobs", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, `[{"id":1},{"id":2}]`)
})
opt := &ListRunnersJobsOptions{}
jobs, _, err := client.Runners.ListRunnerJobs(1, opt)
if err != nil {
t.Fatalf("Runners.ListRunnersJobs returns an error: %v", err)
}
want := []*Job{{ID: 1}, {ID: 2}}
if !reflect.DeepEqual(want, jobs) {
t.Errorf("Runners.ListRunnersJobs returned %+v, want %+v", jobs, want)
}
}
func TestRemoveRunner(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/runners/1", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "DELETE")
w.WriteHeader(http.StatusNoContent)
})
_, err := client.Runners.RemoveARunner(1, nil)
if err != nil {
t.Fatalf("Runners.RemoveARunner returns an error: %v", err)
}
}
const exampleDetailRsp = `{
"active": true,
"architecture": null,
"description": "test-1-20150125-test",
"id": 6,
"is_shared": false,
"contacted_at": "2016-01-25T16:39:48.066Z",
"name": null,
"online": true,
"status": "online",
"platform": null,
"projects": [
{
"id": 1,
"name": "GitLab Community Edition",
"name_with_namespace": "GitLab.org / GitLab Community Edition",
"path": "gitlab-ce",
"path_with_namespace": "gitlab-org/gitlab-ce"
}
],
"token": "205086a8e3b9a2b818ffac9b89d102",
"revision": null,
"tag_list": [
"ruby",
"mysql"
],
"version": null,
"access_level": "ref_protected"
}`
func TestUpdateRunnersDetails(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/runners/6", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "PUT")
fmt.Fprint(w, exampleDetailRsp)
})
opt := &UpdateRunnersDetailsOptions{}
details, _, err := client.Runners.UpdateRunnersDetails(6, opt, nil)
if err != nil {
t.Fatalf("Runners.UpdateRunnersDetails returns an error: %v", err)
}
want := expectedParsedDetails()
if !reflect.DeepEqual(want, details) {
t.Errorf("Runners.UpdateRunnersDetails returned %+v, want %+v", details, want)
}
}
func TestGetRunnerDetails(t *testing.T) {
mux, server, client := setup()
defer teardown(server)
mux.HandleFunc("/runners/6", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, exampleDetailRsp)
})
details, _, err := client.Runners.GetRunnerDetails(6, nil)
if err != nil {
t.Fatalf("Runners.GetRunnerDetails returns an error: %v", err)
}
want := expectedParsedDetails()
if !reflect.DeepEqual(want, details) {
t.Errorf("Runners.UpdateRunnersDetails returned %+v, want %+v", details, want)
}
}
// helper function returning expected result for string: &exampleDetailRsp
func expectedParsedDetails() *RunnersDetails {
proj := struct {
ID int `json:"id"`
Name string `json:"name"`
NameWithNamespace string `json:"name_with_namespace"`
Path string `json:"path"`
PathWithNamespace string `json:"path_with_namespace"`
}{ID: 1, Name: "GitLab Community Edition", NameWithNamespace: "GitLab.org / GitLab Community Edition", Path: "gitlab-ce", PathWithNamespace: "gitlab-org/gitlab-ce"}
timestamp, _ := time.Parse("2006-01-02T15:04:05.000Z", "2016-01-25T16:39:48.066Z")
return &RunnersDetails{Active: true, Description: "test-1-20150125-test", ID: 6, IsShared: false, ContactedAt: &timestamp, Online: true, Status: "online", Token: "205086a8e3b9a2b818ffac9b89d102", TagList: []string{"ruby", "mysql"}, AccessLevel: "ref_protected", Projects: []struct {
ID int `json:"id"`
Name string `json:"name"`
NameWithNamespace string `json:"name_with_namespace"`
Path string `json:"path"`
PathWithNamespace string `json:"path_with_namespace"`
}{proj}}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment