jobs.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  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. package gitlab
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io"
  21. "net/url"
  22. "time"
  23. )
  24. // JobsService handles communication with the ci builds related methods
  25. // of the GitLab API.
  26. //
  27. // GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
  28. type JobsService struct {
  29. client *Client
  30. }
  31. // Job represents a ci build.
  32. //
  33. // GitLab API docs: https://docs.gitlab.com/ce/api/jobs.html
  34. type Job struct {
  35. Commit *Commit `json:"commit"`
  36. CreatedAt *time.Time `json:"created_at"`
  37. Coverage float64 `json:"coverage"`
  38. ArtifactsFile struct {
  39. Filename string `json:"filename"`
  40. Size int `json:"size"`
  41. } `json:"artifacts_file"`
  42. FinishedAt *time.Time `json:"finished_at"`
  43. ID int `json:"id"`
  44. Name string `json:"name"`
  45. Ref string `json:"ref"`
  46. Runner struct {
  47. ID int `json:"id"`
  48. Description string `json:"description"`
  49. Active bool `json:"active"`
  50. IsShared bool `json:"is_shared"`
  51. Name string `json:"name"`
  52. } `json:"runner"`
  53. Stage string `json:"stage"`
  54. StartedAt *time.Time `json:"started_at"`
  55. Status string `json:"status"`
  56. Tag bool `json:"tag"`
  57. User *User `json:"user"`
  58. WebURL string `json:"web_url"`
  59. }
  60. // ListJobsOptions are options for two list apis
  61. type ListJobsOptions struct {
  62. ListOptions
  63. Scope []BuildStateValue `url:"scope,omitempty" json:"scope,omitempty"`
  64. }
  65. // ListProjectJobs gets a list of jobs in a project.
  66. //
  67. // The scope of jobs to show, one or array of: created, pending, running,
  68. // failed, success, canceled, skipped; showing all jobs if none provided
  69. //
  70. // GitLab API docs:
  71. // https://docs.gitlab.com/ce/api/jobs.html#list-project-jobs
  72. func (s *JobsService) ListProjectJobs(pid interface{}, opts *ListJobsOptions, options ...OptionFunc) ([]Job, *Response, error) {
  73. project, err := parseID(pid)
  74. if err != nil {
  75. return nil, nil, err
  76. }
  77. u := fmt.Sprintf("projects/%s/jobs", url.QueryEscape(project))
  78. req, err := s.client.NewRequest("GET", u, opts, options)
  79. if err != nil {
  80. return nil, nil, err
  81. }
  82. var jobs []Job
  83. resp, err := s.client.Do(req, &jobs)
  84. if err != nil {
  85. return nil, resp, err
  86. }
  87. return jobs, resp, err
  88. }
  89. // ListPipelineJobs gets a list of jobs for specific pipeline in a
  90. // project. If the pipeline ID is not found, it will respond with 404.
  91. //
  92. // GitLab API docs:
  93. // https://docs.gitlab.com/ce/api/jobs.html#list-pipeline-jobs
  94. func (s *JobsService) ListPipelineJobs(pid interface{}, pipelineID int, opts *ListJobsOptions, options ...OptionFunc) ([]*Job, *Response, error) {
  95. project, err := parseID(pid)
  96. if err != nil {
  97. return nil, nil, err
  98. }
  99. u := fmt.Sprintf("projects/%s/pipelines/%d/jobs", url.QueryEscape(project), pipelineID)
  100. req, err := s.client.NewRequest("GET", u, opts, options)
  101. if err != nil {
  102. return nil, nil, err
  103. }
  104. var jobs []*Job
  105. resp, err := s.client.Do(req, &jobs)
  106. if err != nil {
  107. return nil, resp, err
  108. }
  109. return jobs, resp, err
  110. }
  111. // GetJob gets a single job of a project.
  112. //
  113. // GitLab API docs:
  114. // https://docs.gitlab.com/ce/api/jobs.html#get-a-single-job
  115. func (s *JobsService) GetJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
  116. project, err := parseID(pid)
  117. if err != nil {
  118. return nil, nil, err
  119. }
  120. u := fmt.Sprintf("projects/%s/jobs/%d", url.QueryEscape(project), jobID)
  121. req, err := s.client.NewRequest("GET", u, nil, options)
  122. if err != nil {
  123. return nil, nil, err
  124. }
  125. job := new(Job)
  126. resp, err := s.client.Do(req, job)
  127. if err != nil {
  128. return nil, resp, err
  129. }
  130. return job, resp, err
  131. }
  132. // GetJobArtifacts get jobs artifacts of a project
  133. //
  134. // GitLab API docs:
  135. // https://docs.gitlab.com/ce/api/jobs.html#get-job-artifacts
  136. func (s *JobsService) GetJobArtifacts(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
  137. project, err := parseID(pid)
  138. if err != nil {
  139. return nil, nil, err
  140. }
  141. u := fmt.Sprintf("projects/%s/jobs/%d/artifacts", url.QueryEscape(project), jobID)
  142. req, err := s.client.NewRequest("GET", u, nil, options)
  143. if err != nil {
  144. return nil, nil, err
  145. }
  146. artifactsBuf := new(bytes.Buffer)
  147. resp, err := s.client.Do(req, artifactsBuf)
  148. if err != nil {
  149. return nil, resp, err
  150. }
  151. return artifactsBuf, resp, err
  152. }
  153. // DownloadArtifactsFile download the artifacts file from the given
  154. // reference name and job provided the job finished successfully.
  155. //
  156. // GitLab API docs:
  157. // https://docs.gitlab.com/ce/api/jobs.html#download-the-artifacts-file
  158. func (s *JobsService) DownloadArtifactsFile(pid interface{}, refName string, job string, options ...OptionFunc) (io.Reader, *Response, error) {
  159. project, err := parseID(pid)
  160. if err != nil {
  161. return nil, nil, err
  162. }
  163. u := fmt.Sprintf("projects/%s/jobs/artifacts/%s/download?job=%s", url.QueryEscape(project), refName, job)
  164. req, err := s.client.NewRequest("GET", u, nil, options)
  165. if err != nil {
  166. return nil, nil, err
  167. }
  168. artifactsBuf := new(bytes.Buffer)
  169. resp, err := s.client.Do(req, artifactsBuf)
  170. if err != nil {
  171. return nil, resp, err
  172. }
  173. return artifactsBuf, resp, err
  174. }
  175. // DownloadSingleArtifactsFile download a file from the artifacts from the
  176. // given reference name and job provided the job finished successfully.
  177. // Only a single file is going to be extracted from the archive and streamed
  178. // to a client.
  179. //
  180. // GitLab API docs:
  181. // https://docs.gitlab.com/ce/api/jobs.html#download-a-single-artifact-file
  182. func (s *JobsService) DownloadSingleArtifactsFile(pid interface{}, jobID int, artifactPath string, options ...OptionFunc) (io.Reader, *Response, error) {
  183. project, err := parseID(pid)
  184. if err != nil {
  185. return nil, nil, err
  186. }
  187. u := fmt.Sprintf(
  188. "projects/%s/jobs/%d/artifacts/%s",
  189. url.QueryEscape(project),
  190. jobID,
  191. artifactPath,
  192. )
  193. req, err := s.client.NewRequest("GET", u, nil, options)
  194. if err != nil {
  195. return nil, nil, err
  196. }
  197. artifactBuf := new(bytes.Buffer)
  198. resp, err := s.client.Do(req, artifactBuf)
  199. if err != nil {
  200. return nil, resp, err
  201. }
  202. return artifactBuf, resp, err
  203. }
  204. // GetTraceFile gets a trace of a specific job of a project
  205. //
  206. // GitLab API docs:
  207. // https://docs.gitlab.com/ce/api/jobs.html#get-a-trace-file
  208. func (s *JobsService) GetTraceFile(pid interface{}, jobID int, options ...OptionFunc) (io.Reader, *Response, error) {
  209. project, err := parseID(pid)
  210. if err != nil {
  211. return nil, nil, err
  212. }
  213. u := fmt.Sprintf("projects/%s/jobs/%d/trace", url.QueryEscape(project), jobID)
  214. req, err := s.client.NewRequest("GET", u, nil, options)
  215. if err != nil {
  216. return nil, nil, err
  217. }
  218. traceBuf := new(bytes.Buffer)
  219. resp, err := s.client.Do(req, traceBuf)
  220. if err != nil {
  221. return nil, resp, err
  222. }
  223. return traceBuf, resp, err
  224. }
  225. // CancelJob cancels a single job of a project.
  226. //
  227. // GitLab API docs:
  228. // https://docs.gitlab.com/ce/api/jobs.html#cancel-a-job
  229. func (s *JobsService) CancelJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
  230. project, err := parseID(pid)
  231. if err != nil {
  232. return nil, nil, err
  233. }
  234. u := fmt.Sprintf("projects/%s/jobs/%d/cancel", url.QueryEscape(project), jobID)
  235. req, err := s.client.NewRequest("POST", u, nil, options)
  236. if err != nil {
  237. return nil, nil, err
  238. }
  239. job := new(Job)
  240. resp, err := s.client.Do(req, job)
  241. if err != nil {
  242. return nil, resp, err
  243. }
  244. return job, resp, err
  245. }
  246. // RetryJob retries a single job of a project
  247. //
  248. // GitLab API docs:
  249. // https://docs.gitlab.com/ce/api/jobs.html#retry-a-job
  250. func (s *JobsService) RetryJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
  251. project, err := parseID(pid)
  252. if err != nil {
  253. return nil, nil, err
  254. }
  255. u := fmt.Sprintf("projects/%s/jobs/%d/retry", url.QueryEscape(project), jobID)
  256. req, err := s.client.NewRequest("POST", u, nil, options)
  257. if err != nil {
  258. return nil, nil, err
  259. }
  260. job := new(Job)
  261. resp, err := s.client.Do(req, job)
  262. if err != nil {
  263. return nil, resp, err
  264. }
  265. return job, resp, err
  266. }
  267. // EraseJob erases a single job of a project, removes a job
  268. // artifacts and a job trace.
  269. //
  270. // GitLab API docs:
  271. // https://docs.gitlab.com/ce/api/jobs.html#erase-a-job
  272. func (s *JobsService) EraseJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
  273. project, err := parseID(pid)
  274. if err != nil {
  275. return nil, nil, err
  276. }
  277. u := fmt.Sprintf("projects/%s/jobs/%d/erase", url.QueryEscape(project), jobID)
  278. req, err := s.client.NewRequest("POST", u, nil, options)
  279. if err != nil {
  280. return nil, nil, err
  281. }
  282. job := new(Job)
  283. resp, err := s.client.Do(req, job)
  284. if err != nil {
  285. return nil, resp, err
  286. }
  287. return job, resp, err
  288. }
  289. // KeepArtifacts prevents artifacts from being deleted when
  290. // expiration is set.
  291. //
  292. // GitLab API docs:
  293. // https://docs.gitlab.com/ce/api/jobs.html#keep-artifacts
  294. func (s *JobsService) KeepArtifacts(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
  295. project, err := parseID(pid)
  296. if err != nil {
  297. return nil, nil, err
  298. }
  299. u := fmt.Sprintf("projects/%s/jobs/%d/artifacts/keep", url.QueryEscape(project), jobID)
  300. req, err := s.client.NewRequest("POST", u, nil, options)
  301. if err != nil {
  302. return nil, nil, err
  303. }
  304. job := new(Job)
  305. resp, err := s.client.Do(req, job)
  306. if err != nil {
  307. return nil, resp, err
  308. }
  309. return job, resp, err
  310. }
  311. // PlayJob triggers a manual action to start a job.
  312. //
  313. // GitLab API docs:
  314. // https://docs.gitlab.com/ce/api/jobs.html#play-a-job
  315. func (s *JobsService) PlayJob(pid interface{}, jobID int, options ...OptionFunc) (*Job, *Response, error) {
  316. project, err := parseID(pid)
  317. if err != nil {
  318. return nil, nil, err
  319. }
  320. u := fmt.Sprintf("projects/%s/jobs/%d/play", url.QueryEscape(project), jobID)
  321. req, err := s.client.NewRequest("POST", u, nil, options)
  322. if err != nil {
  323. return nil, nil, err
  324. }
  325. job := new(Job)
  326. resp, err := s.client.Do(req, job)
  327. if err != nil {
  328. return nil, resp, err
  329. }
  330. return job, resp, err
  331. }