jobs.go

  1//
  2// Copyright 2017, Arkbriar
  3//
  4// Licensed under the Apache License, Version 2.0 (the "License");
  5// you may not use this file except in compliance with the License.
  6// You may obtain a copy of the License at
  7//
  8//     http://www.apache.org/licenses/LICENSE-2.0
  9//
 10// Unless required by applicable law or agreed to in writing, software
 11// distributed under the License is distributed on an "AS IS" BASIS,
 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13// See the License for the specific language governing permissions and
 14// limitations under the License.
 15//
 16
 17package gitlab
 18
 19import (
 20	"bytes"
 21	"fmt"
 22	"io"
 23	"time"
 24)
 25
 26// JobsService handles communication with the ci builds related methods
 27// of the GitLab API.
 28//
 29// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
 30type JobsService struct {
 31	client *Client
 32}
 33
 34// Job represents a ci build.
 35//
 36// GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
 37type Job struct {
 38	Commit        *Commit    `json:"commit"`
 39	CreatedAt     *time.Time `json:"created_at"`
 40	Coverage      float64    `json:"coverage"`
 41	ArtifactsFile struct {
 42		Filename string `json:"filename"`
 43		Size     int    `json:"size"`
 44	} `json:"artifacts_file"`
 45	FinishedAt *time.Time `json:"finished_at"`
 46	ID         int        `json:"id"`
 47	Name       string     `json:"name"`
 48	Pipeline   struct {
 49		ID     int    `json:"id"`
 50		Ref    string `json:"ref"`
 51		Sha    string `json:"sha"`
 52		Status string `json:"status"`
 53	} `json:"pipeline"`
 54	Ref    string `json:"ref"`
 55	Runner struct {
 56		ID          int    `json:"id"`
 57		Description string `json:"description"`
 58		Active      bool   `json:"active"`
 59		IsShared    bool   `json:"is_shared"`
 60		Name        string `json:"name"`
 61	} `json:"runner"`
 62	Stage     string     `json:"stage"`
 63	StartedAt *time.Time `json:"started_at"`
 64	Status    string     `json:"status"`
 65	Tag       bool       `json:"tag"`
 66	User      *User      `json:"user"`
 67	WebURL    string     `json:"web_url"`
 68}
 69
 70// ListJobsOptions are options for two list apis
 71type ListJobsOptions struct {
 72	ListOptions
 73	Scope []BuildStateValue `url:"scope[],omitempty" json:"scope,omitempty"`
 74}
 75
 76// ListProjectJobs gets a list of jobs in a project.
 77//
 78// The scope of jobs to show, one or array of: created, pending, running,
 79// failed, success, canceled, skipped; showing all jobs if none provided
 80//
 81// GitLab API docs:
 82// https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs
 83func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) {
 84	project, err := parseID(pid)
 85	if err != nil {
 86		return nil, nil, err
 87	}
 88	u := fmt.Sprintf("projects/%s/jobs", pathEscape(project))
 89
 90	req, err := s.client.NewRequest("GET", u, opts, options)
 91	if err != nil {
 92		return nil, nil, err
 93	}
 94
 95	var jobs []Job
 96	resp, err := s.client.Do(req, &jobs)
 97	if err != nil {
 98		return nil, resp, err
 99	}
100
101	return jobs, resp, err
102}
103
104// ListPipelineJobs gets a list of jobs for specific pipeline in a
105// project. If the pipeline ID is not found, it will respond with 404.
106//
107// GitLab API docs:
108// https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs
109func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) {
110	project, err := parseID(pid)
111	if err != nil {
112		return nil, nil, err
113	}
114	u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", pathEscape(project), pipelineID)
115
116	req, err := s.client.NewRequest("GET", u, opts, options)
117	if err != nil {
118		return nil, nil, err
119	}
120
121	var jobs []*Job
122	resp, err := s.client.Do(req, &jobs)
123	if err != nil {
124		return nil, resp, err
125	}
126
127	return jobs, resp, err
128}
129
130// GetJob gets a single job of a project.
131//
132// GitLab API docs:
133// https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job
134func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
135	project, err := parseID(pid)
136	if err != nil {
137		return nil, nil, err
138	}
139	u := fmt.Sprintf("projects/%s/jobs/%d", pathEscape(project), jobID)
140
141	req, err := s.client.NewRequest("GET", u, nil, options)
142	if err != nil {
143		return nil, nil, err
144	}
145
146	job := new(Job)
147	resp, err := s.client.Do(req, job)
148	if err != nil {
149		return nil, resp, err
150	}
151
152	return job, resp, err
153}
154
155// GetJobArtifacts get jobs artifacts of a project
156//
157// GitLab API docs:
158// https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts
159func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
160	project, err := parseID(pid)
161	if err != nil {
162		return nil, nil, err
163	}
164	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", pathEscape(project), jobID)
165
166	req, err := s.client.NewRequest("GET", u, nil, options)
167	if err != nil {
168		return nil, nil, err
169	}
170
171	artifactsBuf := new(bytes.Buffer)
172	resp, err := s.client.Do(req, artifactsBuf)
173	if err != nil {
174		return nil, resp, err
175	}
176
177	return artifactsBuf, resp, err
178}
179
180// DownloadArtifactsFileOptions represents the available DownloadArtifactsFile()
181// options.
182//
183// GitLab API docs:
184// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file
185type DownloadArtifactsFileOptions struct {
186	Job *string `url:"job" json:"job"`
187}
188
189// DownloadArtifactsFile download the artifacts file from the given
190// reference name and job provided the job finished successfully.
191//
192// GitLab API docs:
193// https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file
194func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, opt *DownloadArtifactsFileOptions, options ...OptionFunc) (io.Reader, *Response, error) {
195	project, err := parseID(pid)
196	if err != nil {
197		return nil, nil, err
198	}
199	u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download", pathEscape(project), refName)
200
201	req, err := s.client.NewRequest("GET", u, opt, options)
202	if err != nil {
203		return nil, nil, err
204	}
205
206	artifactsBuf := new(bytes.Buffer)
207	resp, err := s.client.Do(req, artifactsBuf)
208	if err != nil {
209		return nil, resp, err
210	}
211
212	return artifactsBuf, resp, err
213}
214
215// DownloadSingleArtifactsFile download a file from the artifacts from the
216// given reference name and job provided the job finished successfully.
217// Only a single file is going to be extracted from the archive and streamed
218// to a client.
219//
220// GitLab API docs:
221// https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file
222func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...OptionFunc) (io.Reader, *Response, error) {
223	project, err := parseID(pid)
224	if err != nil {
225		return nil, nil, err
226	}
227
228	u := fmt.Sprintf(
229		"projects/%s/jobs/%d/artifacts/%s",
230		pathEscape(project),
231		jobID,
232		artifactPath,
233	)
234
235	req, err := s.client.NewRequest("GET", u, nil, options)
236	if err != nil {
237		return nil, nil, err
238	}
239
240	artifactBuf := new(bytes.Buffer)
241	resp, err := s.client.Do(req, artifactBuf)
242	if err != nil {
243		return nil, resp, err
244	}
245
246	return artifactBuf, resp, err
247}
248
249// GetTraceFile gets a trace of a specific job of a project
250//
251// GitLab API docs:
252// https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file
253func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
254	project, err := parseID(pid)
255	if err != nil {
256		return nil, nil, err
257	}
258	u := fmt.Sprintf("projects/%s/jobs/%d/trace", pathEscape(project), jobID)
259
260	req, err := s.client.NewRequest("GET", u, nil, options)
261	if err != nil {
262		return nil, nil, err
263	}
264
265	traceBuf := new(bytes.Buffer)
266	resp, err := s.client.Do(req, traceBuf)
267	if err != nil {
268		return nil, resp, err
269	}
270
271	return traceBuf, resp, err
272}
273
274// CancelJob cancels a single job of a project.
275//
276// GitLab API docs:
277// https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job
278func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
279	project, err := parseID(pid)
280	if err != nil {
281		return nil, nil, err
282	}
283	u := fmt.Sprintf("projects/%s/jobs/%d/cancel", pathEscape(project), jobID)
284
285	req, err := s.client.NewRequest("POST", u, nil, options)
286	if err != nil {
287		return nil, nil, err
288	}
289
290	job := new(Job)
291	resp, err := s.client.Do(req, job)
292	if err != nil {
293		return nil, resp, err
294	}
295
296	return job, resp, err
297}
298
299// RetryJob retries a single job of a project
300//
301// GitLab API docs:
302// https://docs.gitlab.com/ce/api/jobs.html#retry-a-job
303func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
304	project, err := parseID(pid)
305	if err != nil {
306		return nil, nil, err
307	}
308	u := fmt.Sprintf("projects/%s/jobs/%d/retry", pathEscape(project), jobID)
309
310	req, err := s.client.NewRequest("POST", u, nil, options)
311	if err != nil {
312		return nil, nil, err
313	}
314
315	job := new(Job)
316	resp, err := s.client.Do(req, job)
317	if err != nil {
318		return nil, resp, err
319	}
320
321	return job, resp, err
322}
323
324// EraseJob erases a single job of a project, removes a job
325// artifacts and a job trace.
326//
327// GitLab API docs:
328// https://docs.gitlab.com/ce/api/jobs.html#erase-a-job
329func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
330	project, err := parseID(pid)
331	if err != nil {
332		return nil, nil, err
333	}
334	u := fmt.Sprintf("projects/%s/jobs/%d/erase", pathEscape(project), jobID)
335
336	req, err := s.client.NewRequest("POST", u, nil, options)
337	if err != nil {
338		return nil, nil, err
339	}
340
341	job := new(Job)
342	resp, err := s.client.Do(req, job)
343	if err != nil {
344		return nil, resp, err
345	}
346
347	return job, resp, err
348}
349
350// KeepArtifacts prevents artifacts from being deleted when
351// expiration is set.
352//
353// GitLab API docs:
354// https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts
355func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
356	project, err := parseID(pid)
357	if err != nil {
358		return nil, nil, err
359	}
360	u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", pathEscape(project), jobID)
361
362	req, err := s.client.NewRequest("POST", u, nil, options)
363	if err != nil {
364		return nil, nil, err
365	}
366
367	job := new(Job)
368	resp, err := s.client.Do(req, job)
369	if err != nil {
370		return nil, resp, err
371	}
372
373	return job, resp, err
374}
375
376// PlayJob triggers a manual action to start a job.
377//
378// GitLab API docs:
379// https://docs.gitlab.com/ce/api/jobs.html#play-a-job
380func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
381	project, err := parseID(pid)
382	if err != nil {
383		return nil, nil, err
384	}
385	u := fmt.Sprintf("projects/%s/jobs/%d/play", pathEscape(project), jobID)
386
387	req, err := s.client.NewRequest("POST", u, nil, options)
388	if err != nil {
389		return nil, nil, err
390	}
391
392	job := new(Job)
393	resp, err := s.client.Do(req, job)
394	if err != nil {
395		return nil, resp, err
396	}
397
398	return job, resp, err
399}