Introduce source to pipeline entity
This commit is contained in:
		
							parent
							
								
									19ee16a0f8
								
							
						
					
					
						commit
						161af17c1b
					
				|  | @ -58,7 +58,7 @@ class Projects::PipelinesController < Projects::ApplicationController | |||
|   def create | ||||
|     @pipeline = Ci::CreatePipelineService | ||||
|       .new(project, current_user, create_params) | ||||
|       .execute(ignore_skip_ci: true, save_on_errors: false) | ||||
|       .execute(:web, ignore_skip_ci: true, save_on_errors: false) | ||||
| 
 | ||||
|     if @pipeline.persisted? | ||||
|       redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline) | ||||
|  |  | |||
|  | @ -30,6 +30,7 @@ module Ci | |||
| 
 | ||||
|     delegate :id, to: :project, prefix: true | ||||
| 
 | ||||
|     validates :source, exclusion: { in: %w(unknown), unless: :importing? }, on: :create | ||||
|     validates :sha, presence: { unless: :importing? } | ||||
|     validates :ref, presence: { unless: :importing? } | ||||
|     validates :status, presence: { unless: :importing? } | ||||
|  | @ -37,6 +38,16 @@ module Ci | |||
| 
 | ||||
|     after_create :keep_around_commits, unless: :importing? | ||||
| 
 | ||||
|     enum source: { | ||||
|       unknown: nil, | ||||
|       push: 1, | ||||
|       web: 2, | ||||
|       trigger: 3, | ||||
|       schedule: 4, | ||||
|       api: 5, | ||||
|       external: 6 | ||||
|     } | ||||
| 
 | ||||
|     state_machine :status, initial: :created do | ||||
|       event :enqueue do | ||||
|         transition created: :pending | ||||
|  | @ -269,10 +280,6 @@ module Ci | |||
|       commit.sha == sha | ||||
|     end | ||||
| 
 | ||||
|     def triggered? | ||||
|       trigger_requests.any? | ||||
|     end | ||||
| 
 | ||||
|     def retried | ||||
|       @retried ||= (statuses.order(id: :desc) - statuses.latest) | ||||
|     end | ||||
|  |  | |||
|  | @ -1064,11 +1064,6 @@ class Project < ActiveRecord::Base | |||
|     pipelines.order(id: :desc).find_by(sha: sha, ref: ref) | ||||
|   end | ||||
| 
 | ||||
|   def ensure_pipeline(ref, sha, current_user = nil) | ||||
|     pipeline_for(ref, sha) || | ||||
|       pipelines.create(sha: sha, ref: ref, user: current_user) | ||||
|   end | ||||
| 
 | ||||
|   def enable_ci | ||||
|     project_feature.update_attribute(:builds_access_level, ProjectFeature::ENABLED) | ||||
|   end | ||||
|  |  | |||
|  | @ -5,6 +5,7 @@ class PipelineEntity < Grape::Entity | |||
|   expose :user, using: UserEntity | ||||
|   expose :active?, as: :active | ||||
|   expose :coverage | ||||
|   expose :source | ||||
| 
 | ||||
|   expose :path do |pipeline| | ||||
|     namespace_project_pipeline_path( | ||||
|  | @ -24,7 +25,6 @@ class PipelineEntity < Grape::Entity | |||
| 
 | ||||
|   expose :flags do | ||||
|     expose :latest?, as: :latest | ||||
|     expose :triggered?, as: :triggered | ||||
|     expose :stuck?, as: :stuck | ||||
|     expose :has_yaml_errors?, as: :yaml_errors | ||||
|     expose :can_retry?, as: :retryable | ||||
|  |  | |||
|  | @ -2,8 +2,9 @@ module Ci | |||
|   class CreatePipelineService < BaseService | ||||
|     attr_reader :pipeline | ||||
| 
 | ||||
|     def execute(ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil) | ||||
|     def execute(source, ignore_skip_ci: false, save_on_errors: true, trigger_request: nil, schedule: nil) | ||||
|       @pipeline = Ci::Pipeline.new( | ||||
|         source: source, | ||||
|         project: project, | ||||
|         ref: ref, | ||||
|         sha: sha, | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ module Ci | |||
|       trigger_request = trigger.trigger_requests.create(variables: variables) | ||||
| 
 | ||||
|       pipeline = Ci::CreatePipelineService.new(project, trigger.owner, ref: ref). | ||||
|         execute(ignore_skip_ci: true, trigger_request: trigger_request) | ||||
|         execute(:trigger, ignore_skip_ci: true, trigger_request: trigger_request) | ||||
| 
 | ||||
|       trigger_request if pipeline.persisted? | ||||
|     end | ||||
|  |  | |||
|  | @ -106,7 +106,7 @@ class GitPushService < BaseService | |||
|     EventCreateService.new.push(@project, current_user, build_push_data) | ||||
|     @project.execute_hooks(build_push_data.dup, :push_hooks) | ||||
|     @project.execute_services(build_push_data.dup, :push_hooks) | ||||
|     Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute | ||||
|     Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute(:push) | ||||
| 
 | ||||
|     if push_remove_branch? | ||||
|       AfterBranchDeleteService | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ class GitTagPushService < BaseService | |||
|     SystemHooksService.new.execute_hooks(build_system_push_data.dup, :tag_push_hooks) | ||||
|     project.execute_hooks(@push_data.dup, :tag_push_hooks) | ||||
|     project.execute_services(@push_data.dup, :tag_push_hooks) | ||||
|     Ci::CreatePipelineService.new(project, current_user, @push_data).execute | ||||
|     Ci::CreatePipelineService.new(project, current_user, @push_data).execute(:push) | ||||
|     ProjectCacheWorker.perform_async(project.id, [], [:commit_count, :repository_size]) | ||||
| 
 | ||||
|     true | ||||
|  |  | |||
|  | @ -14,7 +14,7 @@ class PipelineScheduleWorker | |||
|         Ci::CreatePipelineService.new(schedule.project, | ||||
|                                       schedule.owner, | ||||
|                                       ref: schedule.ref) | ||||
|           .execute(save_on_errors: false, schedule: schedule) | ||||
|           .execute(:schedule, save_on_errors: false, schedule: schedule) | ||||
|       rescue => e | ||||
|         Rails.logger.error "#{schedule.id}: Failed to create a scheduled pipeline: #{e.message}" | ||||
|       ensure | ||||
|  |  | |||
|  | @ -0,0 +1,4 @@ | |||
| --- | ||||
| title: Introduce source to Pipeline entity | ||||
| merge_request: | ||||
| author: | ||||
|  | @ -98,7 +98,7 @@ class Gitlab::Seeder::Pipelines | |||
| 
 | ||||
| 
 | ||||
|   def create_pipeline!(project, ref, commit) | ||||
|     project.pipelines.create(sha: commit.id, ref: ref) | ||||
|     project.pipelines.create(sha: commit.id, ref: ref, source: :push) | ||||
|   end | ||||
| 
 | ||||
|   def build_create!(pipeline, opts = {}) | ||||
|  |  | |||
|  | @ -190,7 +190,7 @@ class Gitlab::Seeder::CycleAnalytics | |||
|       service = Ci::CreatePipelineService.new(merge_request.project, | ||||
|                                               @user, | ||||
|                                               ref: "refs/heads/#{merge_request.source_branch}") | ||||
|       pipeline = service.execute(ignore_skip_ci: true, save_on_errors: false) | ||||
|       pipeline = service.execute(:push, ignore_skip_ci: true, save_on_errors: false) | ||||
| 
 | ||||
|       pipeline.run! | ||||
|       Timecop.travel rand(1..6).hours.from_now | ||||
|  |  | |||
|  | @ -0,0 +1,9 @@ | |||
| class AddSourceToCiPipeline < ActiveRecord::Migration | ||||
|   include Gitlab::Database::MigrationHelpers | ||||
| 
 | ||||
|   DOWNTIME = false | ||||
| 
 | ||||
|   def change | ||||
|     add_column :ci_pipelines, :source, :integer | ||||
|   end | ||||
| end | ||||
|  | @ -11,7 +11,7 @@ | |||
| # | ||||
| # It's strongly recommended that you check this file into your version control system. | ||||
| 
 | ||||
| ActiveRecord::Schema.define(version: 20170523091700) do | ||||
| ActiveRecord::Schema.define(version: 20170524125940) do | ||||
| 
 | ||||
|   # These are extensions that must be enabled in order to support this database | ||||
|   enable_extension "plpgsql" | ||||
|  | @ -283,6 +283,7 @@ ActiveRecord::Schema.define(version: 20170523091700) do | |||
|     t.integer "lock_version" | ||||
|     t.integer "auto_canceled_by_id" | ||||
|     t.integer "pipeline_schedule_id" | ||||
|     t.integer "source" | ||||
|   end | ||||
| 
 | ||||
|   add_index "ci_pipelines", ["auto_canceled_by_id"], name: "index_ci_pipelines_on_auto_canceled_by_id", using: :btree | ||||
|  |  | |||
|  | @ -35,7 +35,7 @@ class Spinach::Features::ProjectPages < Spinach::FeatureSteps | |||
|   end | ||||
| 
 | ||||
|   step 'pages are deployed' do | ||||
|     pipeline = @project.ensure_pipeline('HEAD', @project.commit('HEAD').sha) | ||||
|     pipeline = @project.pipelines.create(ref: 'HEAD', sha: @project.commit('HEAD').sha) | ||||
|     build = build(:ci_build, | ||||
|                   project: @project, | ||||
|                   pipeline: pipeline, | ||||
|  |  | |||
|  | @ -68,7 +68,14 @@ module API | |||
| 
 | ||||
|         name = params[:name] || params[:context] || 'default' | ||||
| 
 | ||||
|         pipeline = @project.ensure_pipeline(ref, commit.sha, current_user) | ||||
|         pipeline = @project.pipeline_for(ref, commit.sha) | ||||
|         unless pipeline | ||||
|           pipeline = @project.pipelines.create!( | ||||
|             source: :external, | ||||
|             sha: commit.sha, | ||||
|             ref: ref, | ||||
|             user: current_user) | ||||
|         end | ||||
| 
 | ||||
|         status = GenericCommitStatus.running_or_pending.find_or_initialize_by( | ||||
|           project: @project, | ||||
|  |  | |||
|  | @ -47,7 +47,7 @@ module API | |||
|         new_pipeline = Ci::CreatePipelineService.new(user_project, | ||||
|                                                      current_user, | ||||
|                                                      declared_params(include_missing: false)) | ||||
|                            .execute(ignore_skip_ci: true, save_on_errors: false) | ||||
|                            .execute(:api, ignore_skip_ci: true, save_on_errors: false) | ||||
|         if new_pipeline.persisted? | ||||
|           present new_pipeline, with: Entities::Pipeline | ||||
|         else | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| FactoryGirl.define do | ||||
|   factory :ci_empty_pipeline, class: Ci::Pipeline do | ||||
|     source :push | ||||
|     ref 'master' | ||||
|     sha '97de212e80737a608d939f648d959671fb0a0142' | ||||
|     status 'pending' | ||||
|  |  | |||
|  | @ -442,6 +442,8 @@ describe 'Pipelines', :feature, :js do | |||
|           it 'creates a new pipeline' do | ||||
|             expect { click_on 'Create pipeline' } | ||||
|               .to change { Ci::Pipeline.count }.by(1) | ||||
| 
 | ||||
|             expect(Ci::Pipeline.last).to be_web | ||||
|           end | ||||
|         end | ||||
| 
 | ||||
|  |  | |||
|  | @ -191,6 +191,7 @@ Ci::Pipeline: | |||
| - lock_version | ||||
| - auto_canceled_by_id | ||||
| - pipeline_schedule_id | ||||
| - source | ||||
| CommitStatus: | ||||
| - id | ||||
| - project_id | ||||
|  |  | |||
|  | @ -21,13 +21,35 @@ describe Ci::Pipeline, models: true do | |||
|   it { is_expected.to have_many(:auto_canceled_pipelines) } | ||||
|   it { is_expected.to have_many(:auto_canceled_jobs) } | ||||
| 
 | ||||
|   it { is_expected.to validate_presence_of :sha } | ||||
|   it { is_expected.to validate_presence_of :status } | ||||
|   it { is_expected.to validate_presence_of(:sha) } | ||||
|   it { is_expected.to validate_presence_of(:status) } | ||||
| 
 | ||||
|   it { is_expected.to respond_to :git_author_name } | ||||
|   it { is_expected.to respond_to :git_author_email } | ||||
|   it { is_expected.to respond_to :short_sha } | ||||
| 
 | ||||
|   describe '#source' do | ||||
|     context 'when creating new pipeline' do | ||||
|       let(:pipeline) do | ||||
|         build(:ci_empty_pipeline, status: :created, project: project, source: nil) | ||||
|       end | ||||
| 
 | ||||
|       it "prevents from creating an object" do | ||||
|         expect(pipeline).not_to be_valid | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'when updating existing pipeline' do | ||||
|       before do | ||||
|         pipeline.update_attribute(:source, nil) | ||||
|       end | ||||
| 
 | ||||
|       it "object is valid" do | ||||
|         expect(pipeline).to be_valid | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe '#block' do | ||||
|     it 'changes pipeline status to manual' do | ||||
|       expect(pipeline.block).to be true | ||||
|  |  | |||
|  | @ -16,8 +16,8 @@ describe API::CommitStatuses do | |||
|     let(:get_url) { "/projects/#{project.id}/repository/commits/#{sha}/statuses" } | ||||
| 
 | ||||
|     context 'ci commit exists' do | ||||
|       let!(:master) { project.pipelines.create(sha: commit.id, ref: 'master') } | ||||
|       let!(:develop) { project.pipelines.create(sha: commit.id, ref: 'develop') } | ||||
|       let!(:master) { project.pipelines.create(source: :push, sha: commit.id, ref: 'master') } | ||||
|       let!(:develop) { project.pipelines.create(source: :push, sha: commit.id, ref: 'develop') } | ||||
| 
 | ||||
|       context "reporter user" do | ||||
|         let(:statuses_id) { json_response.map { |status| status['id'] } } | ||||
|  |  | |||
|  | @ -485,7 +485,7 @@ describe API::Commits do | |||
|       end | ||||
| 
 | ||||
|       it "returns status for CI" do | ||||
|         pipeline = project.ensure_pipeline('master', project.repository.commit.sha) | ||||
|         pipeline = project.pipelines.create(source: :push, ref: 'master', sha: project.repository.commit.sha) | ||||
|         pipeline.update(status: 'success') | ||||
| 
 | ||||
|         get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) | ||||
|  | @ -495,7 +495,7 @@ describe API::Commits do | |||
|       end | ||||
| 
 | ||||
|       it "returns status for CI when pipeline is created" do | ||||
|         project.ensure_pipeline('master', project.repository.commit.sha) | ||||
|         project.pipelines.create(source: :push, ref: 'master', sha: project.repository.commit.sha) | ||||
| 
 | ||||
|         get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) | ||||
| 
 | ||||
|  |  | |||
|  | @ -386,7 +386,7 @@ describe API::V3::Commits do | |||
|       end | ||||
| 
 | ||||
|       it "returns status for CI" do | ||||
|         pipeline = project.ensure_pipeline('master', project.repository.commit.sha) | ||||
|         pipeline = project.pipelines.create(source: :push, ref: 'master', sha: project.repository.commit.sha) | ||||
|         pipeline.update(status: 'success') | ||||
| 
 | ||||
|         get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) | ||||
|  | @ -396,7 +396,7 @@ describe API::V3::Commits do | |||
|       end | ||||
| 
 | ||||
|       it "returns status for CI when pipeline is created" do | ||||
|         project.ensure_pipeline('master', project.repository.commit.sha) | ||||
|         project.pipelines.create(source: :push, ref: 'master', sha: project.repository.commit.sha) | ||||
| 
 | ||||
|         get v3_api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) | ||||
| 
 | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ describe PipelineEntity do | |||
|       let(:pipeline) { create(:ci_empty_pipeline) } | ||||
| 
 | ||||
|       it 'contains required fields' do | ||||
|         expect(subject).to include :id, :user, :path, :coverage | ||||
|         expect(subject).to include :id, :user, :path, :coverage, :source | ||||
|         expect(subject).to include :ref, :commit | ||||
|         expect(subject).to include :updated_at, :created_at | ||||
|       end | ||||
|  | @ -36,7 +36,7 @@ describe PipelineEntity do | |||
|       it 'contains flags' do | ||||
|         expect(subject).to include :flags | ||||
|         expect(subject[:flags]) | ||||
|           .to include :latest, :triggered, :stuck, | ||||
|           .to include :latest, :stuck, | ||||
|                       :yaml_errors, :retryable, :cancelable | ||||
|       end | ||||
|     end | ||||
|  |  | |||
|  | @ -9,13 +9,13 @@ describe Ci::CreatePipelineService, services: true do | |||
|   end | ||||
| 
 | ||||
|   describe '#execute' do | ||||
|     def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master') | ||||
|     def execute_service(source: :push, after: project.commit.id, message: 'Message', ref: 'refs/heads/master') | ||||
|       params = { ref: ref, | ||||
|                  before: '00000000', | ||||
|                  after: after, | ||||
|                  commits: [{ message: message }] } | ||||
| 
 | ||||
|       described_class.new(project, user, params).execute | ||||
|       described_class.new(project, user, params).execute(source) | ||||
|     end | ||||
| 
 | ||||
|     context 'valid params' do | ||||
|  | @ -30,6 +30,7 @@ describe Ci::CreatePipelineService, services: true do | |||
|       it 'creates a pipeline' do | ||||
|         expect(pipeline).to be_kind_of(Ci::Pipeline) | ||||
|         expect(pipeline).to be_valid | ||||
|         expect(pipeline).to be_push | ||||
|         expect(pipeline).to eq(project.pipelines.last) | ||||
|         expect(pipeline).to have_attributes(user: user) | ||||
|         expect(pipeline).to have_attributes(status: 'pending') | ||||
|  |  | |||
|  | @ -16,6 +16,7 @@ describe Ci::CreateTriggerRequestService, services: true do | |||
|       context 'without owner' do | ||||
|         it { expect(subject).to be_kind_of(Ci::TriggerRequest) } | ||||
|         it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } | ||||
|         it { expect(subject.pipeline).to be_trigger } | ||||
|         it { expect(subject.builds.first).to be_kind_of(Ci::Build) } | ||||
|       end | ||||
| 
 | ||||
|  | @ -25,6 +26,7 @@ describe Ci::CreateTriggerRequestService, services: true do | |||
| 
 | ||||
|         it { expect(subject).to be_kind_of(Ci::TriggerRequest) } | ||||
|         it { expect(subject.pipeline).to be_kind_of(Ci::Pipeline) } | ||||
|         it { expect(subject.pipeline).to be_trigger } | ||||
|         it { expect(subject.pipeline.user).to eq(owner) } | ||||
|         it { expect(subject.builds.first).to be_kind_of(Ci::Build) } | ||||
|         it { expect(subject.builds.first.user).to eq(owner) } | ||||
|  |  | |||
|  | @ -131,6 +131,19 @@ describe GitPushService, services: true do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe "Pipelines" do | ||||
|     subject { execute_service(project, user, @oldrev, @newrev, @ref) } | ||||
| 
 | ||||
|     before do | ||||
|       stub_ci_pipeline_to_return_yaml_file | ||||
|     end | ||||
| 
 | ||||
|     it "creates a new pipeline" do | ||||
|       expect{ subject }.to change{ Ci::Pipeline.count } | ||||
|       expect(Ci::Pipeline.last).to be_push | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe "Push Event" do | ||||
|     before do | ||||
|       service = execute_service(project, user, @oldrev, @newrev, @ref ) | ||||
|  |  | |||
|  | @ -30,6 +30,20 @@ describe GitTagPushService, services: true do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe "Pipelines" do | ||||
|     subject { service.execute } | ||||
| 
 | ||||
|     before do | ||||
|       stub_ci_pipeline_to_return_yaml_file | ||||
|       project.team << [user, :developer] | ||||
|     end | ||||
| 
 | ||||
|     it "creates a new pipeline" do | ||||
|       expect{ subject }.to change{ Ci::Pipeline.count } | ||||
|       expect(Ci::Pipeline.last).to be_push | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe "Git Tag Push Data" do | ||||
|     subject { @push_data } | ||||
|     let(:tag) { project.repository.find_tag(tag_name) } | ||||
|  |  | |||
|  | @ -23,7 +23,8 @@ describe PipelineScheduleWorker do | |||
| 
 | ||||
|     context 'when there is a scheduled pipeline within next_run_at' do | ||||
|       it 'creates a new pipeline' do | ||||
|         expect { subject }.to change { project.pipelines.count }.by(1) | ||||
|         expect{ subject }.to change { project.pipelines.count }.by(1) | ||||
|         expect(Ci::Pipeline.last).to be_schedule | ||||
|       end | ||||
| 
 | ||||
|       it 'updates the next_run_at field' do | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue