Refactor JobRequest response structure
This commit is contained in:
parent
3d26a8d0b6
commit
3eafffcef0
|
@ -508,6 +508,35 @@ module Ci
|
||||||
]
|
]
|
||||||
end
|
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
|
def credentials
|
||||||
Gitlab::Ci::Build::Credentials::Factory.new(self).create!
|
Gitlab::Ci::Build::Credentials::Factory.new(self).create!
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
module Ci
|
module Ci
|
||||||
# This class responsible for assigning
|
# This class responsible for assigning
|
||||||
# proper pending build to runner on runner API request
|
# proper pending build to runner on runner API request
|
||||||
class RegisterBuildService
|
class RegisterJobService
|
||||||
include Gitlab::CurrentSettings
|
include Gitlab::CurrentSettings
|
||||||
|
|
||||||
attr_reader :runner
|
attr_reader :runner
|
|
@ -698,42 +698,82 @@ module API
|
||||||
expose :active?, as: :active
|
expose :active?, as: :active
|
||||||
end
|
end
|
||||||
|
|
||||||
class ArtifactFile < Grape::Entity
|
module JobRequest
|
||||||
expose :filename, :size
|
class JobInfo < Grape::Entity
|
||||||
end
|
expose :name, :stage
|
||||||
|
expose :project_id, :project_name
|
||||||
class JobCredentials < Grape::Entity
|
|
||||||
expose :type, :url, :username, :password
|
|
||||||
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
|
|
||||||
expose :token
|
|
||||||
expose :artifacts_expire_at, if: ->(build, _) { build.artifacts? }
|
|
||||||
|
|
||||||
expose :options do |model|
|
|
||||||
model.options
|
|
||||||
end
|
end
|
||||||
|
|
||||||
expose :timeout do |model|
|
class GitInfo < Grape::Entity
|
||||||
model.timeout
|
expose :repo_url, :ref, :sha, :before_sha
|
||||||
|
expose :ref_type do |model|
|
||||||
|
if model.tag
|
||||||
|
'tag'
|
||||||
|
else
|
||||||
|
'branch'
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
expose :variables
|
class RunnerInfo < Grape::Entity
|
||||||
expose :depends_on_builds, using: JobResponse
|
expose :timeout
|
||||||
|
end
|
||||||
|
|
||||||
expose :credentials, using: JobCredentials
|
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 Dependency < Grape::Entity
|
||||||
|
expose :id, :name
|
||||||
|
expose :artifacts_file, using: ArtifactFile, if: ->(job, _) { job.artifacts? }
|
||||||
|
end
|
||||||
|
|
||||||
|
class Response < Grape::Entity
|
||||||
|
expose :id
|
||||||
|
expose :token
|
||||||
|
expose :allow_git_fetch
|
||||||
|
|
||||||
|
expose :job_info, using: JobInfo do |model|
|
||||||
|
model
|
||||||
|
end
|
||||||
|
|
||||||
|
expose :git_info, using: GitInfo do |model|
|
||||||
|
model
|
||||||
|
end
|
||||||
|
|
||||||
|
expose :runner_info, using: RunnerInfo do |model|
|
||||||
|
model
|
||||||
|
end
|
||||||
|
|
||||||
|
expose :variables
|
||||||
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,7 +51,7 @@ module API
|
||||||
|
|
||||||
resource :jobs do
|
resource :jobs do
|
||||||
desc 'Request a job' do
|
desc 'Request a job' do
|
||||||
success Entities::RequestJobResponse
|
success Entities::JobRequest::Response
|
||||||
end
|
end
|
||||||
params do
|
params do
|
||||||
requires :token, type: String, desc: %q(Runner's authentication token)
|
requires :token, type: String, desc: %q(Runner's authentication token)
|
||||||
|
@ -68,13 +68,13 @@ module API
|
||||||
end
|
end
|
||||||
|
|
||||||
new_update = current_runner.ensure_runner_queue_value
|
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.valid?
|
||||||
if result.build
|
if result.build
|
||||||
Gitlab::Metrics.add_event(:build_found,
|
Gitlab::Metrics.add_event(:build_found,
|
||||||
project: result.build.project.path_with_namespace)
|
project: result.build.project.path_with_namespace)
|
||||||
present result.build, with: Entities::RequestJobResponse
|
present result.build, with: Entities::JobRequest::Response
|
||||||
else
|
else
|
||||||
Gitlab::Metrics.add_event(:build_not_found)
|
Gitlab::Metrics.add_event(:build_not_found)
|
||||||
header 'X-GitLab-Last-Update', new_update
|
header 'X-GitLab-Last-Update', new_update
|
||||||
|
|
|
@ -24,7 +24,7 @@ module Ci
|
||||||
|
|
||||||
new_update = current_runner.ensure_runner_queue_value
|
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.valid?
|
||||||
if result.build
|
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
|
options do
|
||||||
{
|
{
|
||||||
image: "ruby:2.1",
|
image: 'ruby:2.1',
|
||||||
services: ["postgres"]
|
services: ['postgres']
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -151,5 +151,27 @@ FactoryGirl.define do
|
||||||
allow(build).to receive(:commit).and_return build(:commit)
|
allow(build).to receive(:commit).and_return build(:commit)
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
|
@ -152,8 +152,8 @@ describe API::Runner do
|
||||||
describe '/api/v4/jobs' do
|
describe '/api/v4/jobs' do
|
||||||
let(:project) { create(:empty_project, shared_runners_enabled: false) }
|
let(:project) { create(:empty_project, shared_runners_enabled: false) }
|
||||||
let(:pipeline) { create(:ci_pipeline_without_jobs, project: project, ref: 'master') }
|
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(: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 }
|
before { project.runners << runner }
|
||||||
|
|
||||||
|
@ -271,14 +271,44 @@ describe API::Runner do
|
||||||
|
|
||||||
expect(response).to have_http_status(201)
|
expect(response).to have_http_status(201)
|
||||||
expect(response.headers).not_to have_key('X-GitLab-Last-Update')
|
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(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
|
end
|
||||||
|
|
||||||
it 'updates runner info' do
|
it 'updates runner info' do
|
||||||
|
@ -322,8 +352,8 @@ describe API::Runner do
|
||||||
|
|
||||||
expect(response).to have_http_status(201)
|
expect(response).to have_http_status(201)
|
||||||
expect(json_response['id']).to eq(test_job.id)
|
expect(json_response['id']).to eq(test_job.id)
|
||||||
expect(json_response['depends_on_builds'].count).to eq(1)
|
expect(json_response['dependencies'].count).to eq(1)
|
||||||
expect(json_response['depends_on_builds'][0]).to include('id' => job.id, 'name' => 'spinach')
|
expect(json_response['dependencies'][0]).to include('id' => job.id, 'name' => 'spinach')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -381,6 +411,7 @@ describe API::Runner do
|
||||||
|
|
||||||
it 'sends registry credentials key' do
|
it 'sends registry credentials key' do
|
||||||
request_job
|
request_job
|
||||||
|
|
||||||
expect(json_response).to have_key('credentials')
|
expect(json_response).to have_key('credentials')
|
||||||
expect(json_response['credentials']).to include(registry_credentials)
|
expect(json_response['credentials']).to include(registry_credentials)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
module Ci
|
module Ci
|
||||||
describe RegisterBuildService, services: true do
|
describe RegisterJobService, services: true do
|
||||||
let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
|
let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false }
|
||||||
let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
|
let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project }
|
||||||
let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline }
|
let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline }
|
Loading…
Reference in New Issue