jobs.go 10 KB

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