Refactor JobRequest response structure
This commit is contained in:
parent
3d26a8d0b6
commit
3eafffcef0
|
@ -508,6 +508,35 @@ module Ci
|
|||
]
|
||||
end
|
||||
|
||||
def steps
|
||||
[
|
||||
Gitlab::Ci::Build::Response::Step.from_commands(self),
|
||||
Gitlab::Ci::Build::Response::Step.from_after_script(self)
|
||||
].compact
|
||||
end
|
||||
|
||||
def image
|
||||
image = Gitlab::Ci::Build::Response::Image.new(options[:image])
|
||||
return unless image.valid?
|
||||
image
|
||||
end
|
||||
|
||||
def services
|
||||
services = options[:services].map do |service|
|
||||
Gitlab::Ci::Build::Response::Image.new(service)
|
||||
end
|
||||
|
||||
services.select(&:valid?).compact
|
||||
end
|
||||
|
||||
def artifacts
|
||||
options[:artifacts]
|
||||
end
|
||||
|
||||
def cache
|
||||
options[:cache]
|
||||
end
|
||||
|
||||
def credentials
|
||||
Gitlab::Ci::Build::Credentials::Factory.new(self).create!
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
module Ci
|
||||
# This class responsible for assigning
|
||||
# proper pending build to runner on runner API request
|
||||
class RegisterBuildService
|
||||
class RegisterJobService
|
||||
include Gitlab::CurrentSettings
|
||||
|
||||
attr_reader :runner
|
|
@ -698,42 +698,82 @@ module API
|
|||
expose :active?, as: :active
|
||||
end
|
||||
|
||||
module JobRequest
|
||||
class JobInfo < Grape::Entity
|
||||
expose :name, :stage
|
||||
expose :project_id, :project_name
|
||||
end
|
||||
|
||||
class GitInfo < Grape::Entity
|
||||
expose :repo_url, :ref, :sha, :before_sha
|
||||
expose :ref_type do |model|
|
||||
if model.tag
|
||||
'tag'
|
||||
else
|
||||
'branch'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class RunnerInfo < Grape::Entity
|
||||
expose :timeout
|
||||
end
|
||||
|
||||
class Step < Grape::Entity
|
||||
expose :name, :script, :timeout, :condition, :result
|
||||
end
|
||||
|
||||
class Image < Grape::Entity
|
||||
expose :name
|
||||
end
|
||||
|
||||
class Artifacts < Grape::Entity
|
||||
expose :name, :untracked, :paths, :when, :expire_in
|
||||
end
|
||||
|
||||
class Cache < Grape::Entity
|
||||
expose :key, :untracked, :paths
|
||||
end
|
||||
|
||||
class Credentials < Grape::Entity
|
||||
expose :type, :url, :username, :password
|
||||
end
|
||||
|
||||
class ArtifactFile < Grape::Entity
|
||||
expose :filename, :size
|
||||
end
|
||||
|
||||
class JobCredentials < Grape::Entity
|
||||
expose :type, :url, :username, :password
|
||||
class Dependency < Grape::Entity
|
||||
expose :id, :name
|
||||
expose :artifacts_file, using: ArtifactFile, if: ->(job, _) { job.artifacts? }
|
||||
end
|
||||
|
||||
class JobResponse < Grape::Entity
|
||||
expose :id, :ref, :tag, :sha, :status
|
||||
expose :name, :token, :stage
|
||||
expose :project_id
|
||||
expose :project_name
|
||||
expose :artifacts_file, using: ArtifactFile, if: ->(build, _) { build.artifacts? }
|
||||
end
|
||||
|
||||
class RequestJobResponse < JobResponse
|
||||
expose :commands
|
||||
expose :repo_url
|
||||
expose :before_sha
|
||||
expose :allow_git_fetch
|
||||
class Response < Grape::Entity
|
||||
expose :id
|
||||
expose :token
|
||||
expose :artifacts_expire_at, if: ->(build, _) { build.artifacts? }
|
||||
expose :allow_git_fetch
|
||||
|
||||
expose :options do |model|
|
||||
model.options
|
||||
expose :job_info, using: JobInfo do |model|
|
||||
model
|
||||
end
|
||||
|
||||
expose :timeout do |model|
|
||||
model.timeout
|
||||
expose :git_info, using: GitInfo do |model|
|
||||
model
|
||||
end
|
||||
|
||||
expose :runner_info, using: RunnerInfo do |model|
|
||||
model
|
||||
end
|
||||
|
||||
expose :variables
|
||||
expose :depends_on_builds, using: JobResponse
|
||||
|
||||
expose :credentials, using: JobCredentials
|
||||
expose :steps, using: Step
|
||||
expose :image, using: Image
|
||||
expose :services, using: Image
|
||||
expose :artifacts, using: Artifacts
|
||||
expose :cache, using: Cache
|
||||
expose :credentials, using: Credentials
|
||||
expose :depends_on_builds, as: :dependencies, using: Dependency
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -51,7 +51,7 @@ module API
|
|||
|
||||
resource :jobs do
|
||||
desc 'Request a job' do
|
||||
success Entities::RequestJobResponse
|
||||
success Entities::JobRequest::Response
|
||||
end
|
||||
params do
|
||||
requires :token, type: String, desc: %q(Runner's authentication token)
|
||||
|
@ -68,13 +68,13 @@ module API
|
|||
end
|
||||
|
||||
new_update = current_runner.ensure_runner_queue_value
|
||||
result = ::Ci::RegisterBuildService.new(current_runner).execute
|
||||
result = ::Ci::RegisterJobService.new(current_runner).execute
|
||||
|
||||
if result.valid?
|
||||
if result.build
|
||||
Gitlab::Metrics.add_event(:build_found,
|
||||
project: result.build.project.path_with_namespace)
|
||||
present result.build, with: Entities::RequestJobResponse
|
||||
present result.build, with: Entities::JobRequest::Response
|
||||
else
|
||||
Gitlab::Metrics.add_event(:build_not_found)
|
||||
header 'X-GitLab-Last-Update', new_update
|
||||
|
|
|
@ -24,7 +24,7 @@ module Ci
|
|||
|
||||
new_update = current_runner.ensure_runner_queue_value
|
||||
|
||||
result = Ci::RegisterBuildService.new(current_runner).execute
|
||||
result = Ci::RegisterJobService.new(current_runner).execute
|
||||
|
||||
if result.valid?
|
||||
if result.build
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
module Build
|
||||
module Response
|
||||
class Image
|
||||
attr_reader :name
|
||||
|
||||
def initialize(image)
|
||||
type = image.class
|
||||
@name = image if type == String
|
||||
end
|
||||
|
||||
def valid?
|
||||
@name != nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,46 @@
|
|||
module Gitlab
|
||||
module Ci
|
||||
module Build
|
||||
module Response
|
||||
class Step
|
||||
CONDITION_IF_SUCCEEDED = 'run_if_succeeded'
|
||||
CONDITION_ALWAYS = 'run_always'
|
||||
|
||||
RESULT_FAILS_JOB = 'fails_job'
|
||||
RESULT_DOESNT_FAIL_JOB = 'doesnt_fail_job'
|
||||
|
||||
attr_reader :name, :script, :condition, :result, :timeout
|
||||
|
||||
class << self
|
||||
def from_commands(build)
|
||||
self.new(:script,
|
||||
build.commands,
|
||||
build.timeout,
|
||||
CONDITION_IF_SUCCEEDED,
|
||||
RESULT_FAILS_JOB)
|
||||
end
|
||||
|
||||
def from_after_script(build)
|
||||
after_script = build.options[:after_script]
|
||||
return unless after_script
|
||||
|
||||
self.new(:after_script,
|
||||
after_script,
|
||||
build.timeout,
|
||||
CONDITION_ALWAYS,
|
||||
RESULT_DOESNT_FAIL_JOB)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(name, script, timeout, condition = CONDITION_IF_SUCCEEDED, result = RESULT_FAILS_JOB)
|
||||
@name = name
|
||||
@script = script.split("\n")
|
||||
@timeout = timeout
|
||||
@condition = condition
|
||||
@result = result
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -15,8 +15,8 @@ FactoryGirl.define do
|
|||
|
||||
options do
|
||||
{
|
||||
image: "ruby:2.1",
|
||||
services: ["postgres"]
|
||||
image: 'ruby:2.1',
|
||||
services: ['postgres']
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -151,5 +151,27 @@ FactoryGirl.define do
|
|||
allow(build).to receive(:commit).and_return build(:commit)
|
||||
end
|
||||
end
|
||||
|
||||
trait :extended_options do
|
||||
options do
|
||||
{
|
||||
image: 'ruby:2.1',
|
||||
services: ['postgres'],
|
||||
after_script: "ls\ndate",
|
||||
artifacts: {
|
||||
name: 'artifacts_file',
|
||||
untracked: false,
|
||||
paths: ['out/'],
|
||||
when: 'always',
|
||||
expire_in: '7d'
|
||||
},
|
||||
cache: {
|
||||
key: 'cache_key',
|
||||
untracked: false,
|
||||
paths: ['vendor/*']
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -152,8 +152,8 @@ describe API::Runner do
|
|||
describe '/api/v4/jobs' do
|
||||
let(:project) { create(:empty_project, shared_runners_enabled: false) }
|
||||
let(:pipeline) { create(:ci_pipeline_without_jobs, project: project, ref: 'master') }
|
||||
let!(:job) { create(:ci_build, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
|
||||
let(:runner) { create(:ci_runner) }
|
||||
let!(:job) { create(:ci_build, :artifacts, :extended_options, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, commands: "ls\ndate") }
|
||||
|
||||
before { project.runners << runner }
|
||||
|
||||
|
@ -271,14 +271,44 @@ describe API::Runner do
|
|||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(response.headers).not_to have_key('X-GitLab-Last-Update')
|
||||
expect(json_response['sha']).to eq(job.sha)
|
||||
expect(json_response['options']).to eq({'image' => 'ruby:2.1', 'services' => ['postgres']})
|
||||
expect(json_response['variables']).to include(
|
||||
{'key' => 'CI_BUILD_NAME', 'value' => 'spinach', 'public' => true},
|
||||
{'key' => 'CI_BUILD_STAGE', 'value' => 'test', 'public' => true},
|
||||
{'key' => 'DB_NAME', 'value' => 'postgres', 'public' => true}
|
||||
)
|
||||
expect(runner.reload.platform).to eq('darwin')
|
||||
|
||||
expect(json_response['id']).to eq(job.id)
|
||||
expect(json_response['token']).to eq(job.token)
|
||||
expect(json_response['job_info']).to include({ 'name' => job.name },
|
||||
{ 'stage' => job.stage })
|
||||
expect(json_response['git_info']).to include({ 'sha' => job.sha },
|
||||
{ 'repo_url' => job.repo_url })
|
||||
expect(json_response['image']).to include({ 'name' => 'ruby:2.1' })
|
||||
expect(json_response['services']).to include({ 'name' => 'postgres' })
|
||||
expect(json_response['steps']).to include({ 'name' => 'after_script',
|
||||
'script' => ['ls', 'date'],
|
||||
'timeout' => job.timeout,
|
||||
'condition' => Gitlab::Ci::Build::Response::Step::CONDITION_ALWAYS,
|
||||
'result' => Gitlab::Ci::Build::Response::Step::RESULT_DOESNT_FAIL_JOB })
|
||||
expect(json_response['variables']).to include({ 'key' => 'CI_BUILD_NAME', 'value' => 'spinach', 'public' => true },
|
||||
{ 'key' => 'CI_BUILD_STAGE', 'value' => 'test', 'public' => true },
|
||||
{ 'key' => 'DB_NAME', 'value' => 'postgres', 'public' => true })
|
||||
expect(json_response['artifacts']).to include({ 'name' => 'artifacts_file' },
|
||||
{ 'paths' => ['out/'] })
|
||||
end
|
||||
|
||||
context 'when job is made for tag' do
|
||||
let!(:job) { create(:ci_build_tag, pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0) }
|
||||
|
||||
it 'sets branch as ref_type' do
|
||||
request_job
|
||||
expect(response).to have_http_status(201)
|
||||
expect(json_response['git_info']['ref_type']).to eq('tag')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when job is made for branch' do
|
||||
it 'sets tag as ref_type' do
|
||||
request_job
|
||||
expect(response).to have_http_status(201)
|
||||
expect(json_response['git_info']['ref_type']).to eq('branch')
|
||||
end
|
||||
end
|
||||
|
||||
it 'updates runner info' do
|
||||
|
@ -322,8 +352,8 @@ describe API::Runner do
|
|||
|
||||
expect(response).to have_http_status(201)
|
||||
expect(json_response['id']).to eq(test_job.id)
|
||||
expect(json_response['depends_on_builds'].count).to eq(1)
|
||||
expect(json_response['depends_on_builds'][0]).to include('id' => job.id, 'name' => 'spinach')
|
||||
expect(json_response['dependencies'].count).to eq(1)
|
||||
expect(json_response['dependencies'][0]).to include('id' => job.id, 'name' => 'spinach')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -381,6 +411,7 @@ describe API::Runner do
|
|||
|
||||
it 'sends registry credentials key' do
|
||||
request_job
|
||||
|
||||
expect(json_response).to have_key('credentials')
|
||||
expect(json_response['credentials']).to include(registry_credentials)
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
module Ci
|
||||
describe RegisterBuildService, services: true do
|
||||
describe RegisterJobService, services: true do
|
||||
let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
|
||||
let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
|
||||
let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline }
|
Loading…
Reference in New Issue