create_pipeline_service_spec.rb 7.0 KB
Newer Older
1 2 3
require 'spec_helper'

describe Ci::CreatePipelineService, services: true do
4
  let(:project) { create(:project, :repository) }
5 6 7 8 9 10 11
  let(:user) { create(:admin) }

  before do
    stub_ci_pipeline_to_return_yaml_file
  end

  describe '#execute' do
12 13 14 15 16 17
    def execute_service(after: project.commit.id, message: 'Message', ref: 'refs/heads/master')
      params = { ref: ref,
                 before: '00000000',
                 after: after,
                 commits: [{ message: message }] }

18 19 20
      described_class.new(project, user, params).execute
    end

21
    shared_examples 'a pending pipeline' do
22 23 24 25
      it { expect(pipeline).to be_kind_of(Ci::Pipeline) }
      it { expect(pipeline).to be_valid }
      it { expect(pipeline).to eq(project.pipelines.last) }
      it { expect(pipeline).to have_attributes(user: user) }
26
      it { expect(pipeline).to have_attributes(status: 'pending') }
27 28 29
      it { expect(pipeline.builds.first).to be_kind_of(Ci::Build) }
    end

30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
    context 'valid params' do
      let(:pipeline) { execute_service }

      it_behaves_like 'a pending pipeline'

      context 'auto-cancel enabled' do
        let(:pipeline_on_previous_commit) do
          execute_service(
            after: previous_commit_sha_from_ref('master')
          )
        end

        def previous_commit_sha_from_ref(ref)
          project.repository.find_commits(ref: ref, max_count: 2)[1].id
        end

        before do
          project.update(auto_cancel_pending_pipelines: 'enabled')
        end

        it_behaves_like 'a pending pipeline'

        it 'auto cancel pending non-HEAD pipelines' do
          pending_pipeline = pipeline_on_previous_commit
          pipeline

          expect(pending_pipeline.reload).to have_attributes(status: 'canceled', auto_canceled_by: pipeline.id)
        end

        it 'does not cancel running outdated pipelines' do
          running_pipeline = pipeline_on_previous_commit
          running_pipeline.run
          execute_service

          expect(running_pipeline.reload).to have_attributes(status: 'running', auto_canceled_by: nil)
        end

        it 'cancel created outdated pipelines' do
          created_pipeline = pipeline_on_previous_commit
          created_pipeline.update(status: 'created')
          pipeline

          expect(created_pipeline.reload).to have_attributes(status: 'canceled', auto_canceled_by: pipeline.id)
        end

        it 'does not cancel pipelines from the other branches' do
          pending_pipeline = execute_service(
            ref: 'refs/heads/feature',
            after: previous_commit_sha_from_ref('feature')
          )
          pipeline

          expect(pending_pipeline.reload).to have_attributes(status: 'pending', auto_canceled_by: nil)
        end
      end
    end

87 88
    context "skip tag if there is no build for it" do
      it "creates commit if there is appropriate job" do
89
        expect(execute_service).to be_persisted
90 91 92 93 94 95
      end

      it "creates commit if there is no appropriate job but deploy job has right ref setting" do
        config = YAML.dump({ deploy: { script: "ls", only: ["master"] } })
        stub_ci_pipeline_yaml_file(config)

96
        expect(execute_service).to be_persisted
97 98 99 100 101 102
      end
    end

    it 'skips creating pipeline for refs without .gitlab-ci.yml' do
      stub_ci_pipeline_yaml_file(nil)

103
      expect(execute_service).not_to be_persisted
104 105 106
      expect(Ci::Pipeline.count).to eq(0)
    end

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    shared_examples 'a failed pipeline' do
      it 'creates failed pipeline' do
        stub_ci_pipeline_yaml_file(ci_yaml)

        pipeline = execute_service(message: message)

        expect(pipeline).to be_persisted
        expect(pipeline.builds.any?).to be false
        expect(pipeline.status).to eq('failed')
        expect(pipeline.yaml_errors).not_to be_nil
      end
    end

    context 'when yaml is invalid' do
      let(:ci_yaml) { 'invalid: file: fiile' }
      let(:message) { 'Message' }

      it_behaves_like 'a failed pipeline'

      context 'when receive git commit' do
        before do
          allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
        end

        it_behaves_like 'a failed pipeline'
      end
133 134 135 136
    end

    context 'when commit contains a [ci skip] directive' do
      let(:message) { "some message[ci skip]" }
137 138 139 140 141 142 143 144 145 146 147

      ci_messages = [
        "some message[ci skip]",
        "some message[skip ci]",
        "some message[CI SKIP]",
        "some message[SKIP CI]",
        "some message[ci_skip]",
        "some message[skip_ci]",
        "some message[ci-skip]",
        "some message[skip-ci]"
      ]
148 149 150 151 152

      before do
        allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
      end

153 154
      ci_messages.each do |ci_message|
        it "skips builds creation if the commit message is #{ci_message}" do
155
          pipeline = execute_service(message: ci_message)
156 157 158 159 160

          expect(pipeline).to be_persisted
          expect(pipeline.builds.any?).to be false
          expect(pipeline.status).to eq("skipped")
        end
161 162
      end

163 164 165
      shared_examples 'creating a pipeline' do
        it 'does not skips pipeline creation' do
          allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { commit_message }
166

167
          pipeline = execute_service(message: commit_message)
168

169 170 171
          expect(pipeline).to be_persisted
          expect(pipeline.builds.first.name).to eq("rspec")
        end
172 173
      end

174 175
      context 'when commit message does not contain [ci skip] nor [skip ci]' do
        let(:commit_message) { 'some message' }
176

177
        it_behaves_like 'creating a pipeline'
178 179
      end

180 181
      context 'when commit message is nil' do
        let(:commit_message) { nil }
182

183
        it_behaves_like 'creating a pipeline'
184 185
      end

186 187 188 189 190
      context 'when there is [ci skip] tag in commit message and yaml is invalid' do
        let(:ci_yaml) { 'invalid: file: fiile' }

        it_behaves_like 'a failed pipeline'
      end
191 192 193 194 195 196 197 198 199
    end

    context 'when there are no jobs for this pipeline' do
      before do
        config = YAML.dump({ test: { script: 'ls', only: ['feature'] } })
        stub_ci_pipeline_yaml_file(config)
      end

      it 'does not create a new pipeline' do
200
        result = execute_service
201 202 203 204 205 206 207 208 209 210 211 212 213 214

        expect(result).not_to be_persisted
        expect(Ci::Build.all).to be_empty
        expect(Ci::Pipeline.count).to eq(0)
      end
    end

    context 'with manual actions' do
      before do
        config = YAML.dump({ deploy: { script: 'ls', when: 'manual' } })
        stub_ci_pipeline_yaml_file(config)
      end

      it 'does not create a new pipeline' do
215
        result = execute_service
216 217 218 219 220

        expect(result).to be_persisted
        expect(result.manual_actions).not_to be_empty
      end
    end
221 222 223

    context 'with environment' do
      before do
Z
Z.J. van de Weg 已提交
224
        config = YAML.dump(deploy: { environment: { name: "review/$CI_COMMIT_REF_NAME" }, script: 'ls' })
225 226 227 228
        stub_ci_pipeline_yaml_file(config)
      end

      it 'creates the environment' do
229
        result = execute_service
230 231 232 233 234

        expect(result).to be_persisted
        expect(Environment.find_by(name: "review/master")).not_to be_nil
      end
    end
235 236
  end
end