Let the CI runner know about builds that this build depends on

This allows us to implement artifacts passing: runner will download artifacts from all prior builds
This commit is contained in:
Kamil Trzcinski 2016-01-14 19:45:43 +01:00
parent ba42b03348
commit ac652d82f1
9 changed files with 125 additions and 19 deletions

View file

@ -20,6 +20,7 @@ v 8.4.0 (unreleased)
- Don't notify users twice if they are both project watchers and subscribers (Stan Hu)
- Implement new UI for group page
- Implement search inside emoji picker
- Let the CI runner know about builds that this build depends on
- Add API support for looking up a user by username (Stan Hu)
- Add project permissions to all project API endpoints (Stan Hu)
- Link to milestone in "Milestone changed" system note

View file

@ -128,6 +128,14 @@ module Ci
!self.commit.latest_builds_for_ref(self.ref).include?(self)
end
def depends_on_builds
# Get builds of the same type
latest_builds = self.commit.builds.similar(self).latest
# Return builds from previous stages
latest_builds.where('stage_idx < ?', stage_idx)
end
def trace_html
html = Ci::Ansi2html::convert(trace) if trace.present?
html || ''

View file

@ -32,6 +32,10 @@ class ArtifactUploader < CarrierWave::Uploader::Base
self.class.storage == CarrierWave::Storage::File
end
def filename
file.try(:filename)
end
def exists?
file.try(:exists?)
end

View file

@ -18,18 +18,64 @@ Returns:
```json
{
"id" : 79,
"commands" : "",
"path" : "",
"ref" : "",
"sha" : "",
"project_id" : 6,
"repo_url" : "git@demo.gitlab.com:gitlab/gitlab-shell.git",
"before_sha" : ""
"id": 48584,
"ref": "0.1.1",
"tag": true,
"sha": "d63117656af6ff57d99e50cc270f854691f335ad",
"status": "success",
"name": "pages",
"token": "9dd60b4f1a439d1765357446c1084c",
"stage": "test",
"project_id": 479,
"project_name": "test",
"commands": "echo commands",
"repo_url": "http://gitlab-ci-token:token@gitlab.example/group/test.git",
"before_sha": "0000000000000000000000000000000000000000",
"allow_git_fetch": false,
"options": {
"image": "docker:image",
"artifacts": {
"paths": [
"public"
]
},
"cache": {
"paths": [
"vendor"
]
}
},
"timeout": 3600,
"variables": [
{
"key": "CI_BUILD_TAG",
"value": "0.1.1",
"public": true
}
],
"dependencies": {
"builds": [
{
"id": 48584,
"ref": "0.1.1",
"tag": true,
"sha": "d63117656af6ff57d99e50cc270f854691f335ad",
"status": "success",
"name": "build",
"token": "9dd60b4f1a439d1765357446c1084c",
"stage": "build",
"project_id": 479,
"project_name": "test",
"artifacts_file": {
"filename": "artifacts.zip",
"size": 0
}
}
]
}
}
```
### Update details of an existing build
PUT /ci/builds/:id

View file

@ -20,7 +20,7 @@ module Ci
if build
update_runner_info
present build, with: Entities::Build
present build, with: Entities::BuildDetails
else
not_found!
end
@ -111,7 +111,7 @@ module Ci
build.artifacts_metadata = metadata
if build.save
present(build, with: Entities::Build)
present(build, with: Entities::BuildDetails)
else
render_validation_error!(build)
end

View file

@ -16,10 +16,19 @@ module Ci
end
class Build < Grape::Entity
expose :id, :commands, :ref, :sha, :status, :project_id, :repo_url,
:before_sha, :allow_git_fetch, :project_name
expose :id, :ref, :tag, :sha, :status
expose :name, :token, :stage
expose :project_id
expose :project_name
expose :artifacts_file, using: ArtifactFile, if: lambda { |build, opts| build.artifacts_file.exists? }
end
class BuildDetails < Build
expose :commands
expose :repo_url
expose :before_sha
expose :allow_git_fetch
expose :token
expose :options do |model|
model.options
@ -30,7 +39,9 @@ module Ci
end
expose :variables
expose :artifacts_file, using: ArtifactFile
expose :dependencies do
expose :depends_on_builds, as: :builds, using: Build
end
end
class Runner < Grape::Entity

View file

@ -426,6 +426,30 @@ describe Ci::Build, models: true do
it { is_expected.to include(project.web_url[7..-1]) }
end
describe :depends_on_builds do
let!(:build) { FactoryGirl.create :ci_build, commit: commit, name: 'build', stage_idx: 0, stage: 'build' }
let!(:rspec_test) { FactoryGirl.create :ci_build, commit: commit, name: 'rspec', stage_idx: 1, stage: 'test' }
let!(:rubocop_test) { FactoryGirl.create :ci_build, commit: commit, name: 'rubocop', stage_idx: 1, stage: 'test' }
let!(:staging) { FactoryGirl.create :ci_build, commit: commit, name: 'staging', stage_idx: 2, stage: 'deploy' }
it 'to have no dependents if this is first build' do
expect(build.depends_on_builds).to be_empty
end
it 'to have one dependent if this is test' do
expect(rspec_test.depends_on_builds.map(&:id)).to contain_exactly(build.id)
end
it 'to have all builds from build and test stage if this is last' do
expect(staging.depends_on_builds.map(&:id)).to contain_exactly(build.id, rspec_test.id, rubocop_test.id)
end
it 'to have retried builds instead the original ones' do
retried_rspec = Ci::Build.retry(rspec_test)
expect(staging.depends_on_builds.map(&:id)).to contain_exactly(build.id, retried_rspec.id, rubocop_test.id)
end
end
def create_mr(build, commit, factory: :merge_request, created_at: Time.now)
FactoryGirl.create(factory,
source_project_id: commit.gl_project_id,

View file

@ -101,6 +101,18 @@ describe Ci::API::API do
{ "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },
])
end
it "returns dependent builds" do
commit = FactoryGirl.create(:ci_commit, project: project)
commit.create_builds('master', false, nil, nil)
commit.builds.where(stage: 'test').each(&:success)
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
expect(response.status).to eq(201)
expect(json_response["dependencies"]["builds"].count).to eq(2)
expect(json_response["dependencies"]["builds"][0]["name"]).to eq("rspec")
end
end
describe "PUT /builds/:id" do

View file

@ -36,8 +36,8 @@ staging:
script: "cap deploy stating"
type: deploy
tags:
- capistrano
- debian
- ruby
- mysql
except:
- stable
@ -47,8 +47,8 @@ production:
- cap deploy production
- cap notify
tags:
- capistrano
- debian
- ruby
- mysql
only:
- master
- /^deploy-.*$/