BigW Consortium Gitlab

jobs.rb 5.36 KB
Newer Older
1
module API
2
  class Jobs < Grape::API
3 4
    include PaginationParams

5 6
    before { authenticate! }

Robert Schilling committed
7 8 9
    params do
      requires :id, type: String, desc: 'The ID of a project'
    end
10
    resource :projects, requirements: API::PROJECT_ENDPOINT_REQUIREMENTS do
Robert Schilling committed
11 12 13
      helpers do
        params :optional_scope do
          optional :scope, types: [String, Array[String]], desc: 'The scope of builds to show',
14
                           values: ::CommitStatus::AVAILABLE_STATUSES,
Robert Schilling committed
15
                           coerce_with: ->(scope) {
16 17
                             case scope
                             when String
Robert Schilling committed
18
                               [scope]
19
                             when ::Hash
Robert Schilling committed
20
                               scope.values
21
                             when ::Array
22
                               scope
Robert Schilling committed
23 24 25 26 27 28 29
                             else
                               ['unknown']
                             end
                           }
        end
      end

30 31
      desc 'Get a projects jobs' do
        success Entities::Job
Robert Schilling committed
32 33 34
      end
      params do
        use :optional_scope
35
        use :pagination
Robert Schilling committed
36
      end
37
      get ':id/jobs' do
38 39
        builds = user_project.builds.order('id DESC')
        builds = filter_builds(builds, params[:scope])
40

41
        builds = builds.preload(:user, :job_artifacts_archive, :runner, pipeline: :project)
42
        present paginate(builds), with: Entities::Job
43
      end
44

45 46 47 48 49 50 51 52 53 54 55 56 57
      desc 'Get pipeline jobs' do
        success Entities::Job
      end
      params do
        requires :pipeline_id, type: Integer,  desc: 'The pipeline ID'
        use :optional_scope
        use :pagination
      end
      get ':id/pipelines/:pipeline_id/jobs' do
        pipeline = user_project.pipelines.find(params[:pipeline_id])
        builds = pipeline.builds
        builds = filter_builds(builds, params[:scope])

58
        present paginate(builds), with: Entities::Job
59 60
      end

61 62
      desc 'Get a specific job of a project' do
        success Entities::Job
Robert Schilling committed
63 64
      end
      params do
65
        requires :job_id, type: Integer, desc: 'The ID of a job'
Robert Schilling committed
66
      end
67
      get ':id/jobs/:job_id' do
68 69
        authorize_read_builds!

70
        build = find_build!(params[:job_id])
71

72
        present build, with: Entities::Job
73 74
      end

75 76 77
      # TODO: We should use `present_file!` and leave this implementation for backward compatibility (when build trace
      #       is saved in the DB instead of file). But before that, we need to consider how to replace the value of
      #       `runners_token` with some mask (like `xxxxxx`) when sending trace file directly by workhorse.
78
      desc 'Get a trace of a specific job of a project'
Robert Schilling committed
79
      params do
80
        requires :job_id, type: Integer, desc: 'The ID of a job'
Robert Schilling committed
81
      end
82
      get ':id/jobs/:job_id/trace' do
83 84
        authorize_read_builds!

85
        build = find_build!(params[:job_id])
86 87 88 89

        header 'Content-Disposition', "infile; filename=\"#{build.id}.log\""
        content_type 'text/plain'
        env['api.format'] = :binary
90

91
        trace = build.trace.raw
92
        body trace
93
      end
94

95 96
      desc 'Cancel a specific job of a project' do
        success Entities::Job
Robert Schilling committed
97 98
      end
      params do
99
        requires :job_id, type: Integer, desc: 'The ID of a job'
Robert Schilling committed
100
      end
101
      post ':id/jobs/:job_id/cancel' do
102
        authorize_update_builds!
103

104
        build = find_build!(params[:job_id])
105
        authorize!(:update_build, build)
106 107 108

        build.cancel

109
        present build, with: Entities::Job
110 111
      end

Robert Schilling committed
112
      desc 'Retry a specific build of a project' do
113
        success Entities::Job
Robert Schilling committed
114 115
      end
      params do
116
        requires :job_id, type: Integer, desc: 'The ID of a build'
Robert Schilling committed
117
      end
118
      post ':id/jobs/:job_id/retry' do
119
        authorize_update_builds!
120

121
        build = find_build!(params[:job_id])
122
        authorize!(:update_build, build)
123
        return forbidden!('Job is not retryable') unless build.retryable?
124

125
        build = Ci::Build.retry(build, current_user)
126

127
        present build, with: Entities::Job
128
      end
129

130 131
      desc 'Erase job (remove artifacts and the trace)' do
        success Entities::Job
Robert Schilling committed
132 133
      end
      params do
134
        requires :job_id, type: Integer, desc: 'The ID of a build'
Robert Schilling committed
135
      end
136
      post ':id/jobs/:job_id/erase' do
137
        authorize_update_builds!
138

139
        build = find_build!(params[:job_id])
140
        authorize!(:erase_build, build)
141
        return forbidden!('Job is not erasable!') unless build.erasable?
142

143
        build.erase(erased_by: current_user)
144
        present build, with: Entities::Job
145
      end
146

147 148
      desc 'Trigger a manual job' do
        success Entities::Job
149 150 151
        detail 'This feature was added in GitLab 8.11'
      end
      params do
152
        requires :job_id, type: Integer, desc: 'The ID of a Job'
153
      end
154
      post ":id/jobs/:job_id/play" do
155 156
        authorize_read_builds!

157
        build = find_build!(params[:job_id])
158

159
        authorize!(:update_build, build)
Filipa Lacerda committed
160
        bad_request!("Unplayable Job") unless build.playable?
Z.J. van de Weg committed
161 162 163 164

        build.play(current_user)

        status 200
165
        present build, with: Entities::Job
166
      end
167 168 169
    end

    helpers do
170
      def filter_builds(builds, scope)
171 172
        return builds if scope.nil? || scope.empty?

173
        available_statuses = ::CommitStatus::AVAILABLE_STATUSES
174

175 176
        unknown = scope - available_statuses
        render_api_error!('Scope contains invalid value(s)', 400) unless unknown.empty?
177

178
        builds.where(status: available_statuses && scope)
179
      end
180 181 182
    end
  end
end