create_pipeline_service_spec.rb 7.2 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
    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)
43
          project.commit(ref).parent.sha
44 45 46 47 48 49
        end

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

50 51 52 53 54 55 56
        it 'does not cancel HEAD pipeline' do
          pipeline
          previous_pipeline = pipeline_on_previous_commit

          expect(pipeline.reload)
            .to have_attributes(status: 'pending', auto_canceled_by: nil)
        end
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 87 88 89 90 91 92

        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

93 94
    context "skip tag if there is no build for it" do
      it "creates commit if there is appropriate job" do
95
        expect(execute_service).to be_persisted
96 97 98 99 100 101
      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)

102
        expect(execute_service).to be_persisted
103 104 105 106 107 108
      end
    end

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

109
      expect(execute_service).not_to be_persisted
110 111 112
      expect(Ci::Pipeline.count).to eq(0)
    end

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
    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
139 140 141 142
    end

    context 'when commit contains a [ci skip] directive' do
      let(:message) { "some message[ci skip]" }
143 144 145 146 147 148 149 150 151 152 153

      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]"
      ]
154 155 156 157 158

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

159 160
      ci_messages.each do |ci_message|
        it "skips builds creation if the commit message is #{ci_message}" do
161
          pipeline = execute_service(message: ci_message)
162 163 164 165 166

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

169
      shared_examples 'creating a pipeline' do
R
Rydkin Maxim 已提交
170
        it 'does not skip pipeline creation' do
171
          allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { commit_message }
172

173
          pipeline = execute_service(message: commit_message)
174

175 176 177
          expect(pipeline).to be_persisted
          expect(pipeline.builds.first.name).to eq("rspec")
        end
178 179
      end

180 181
      context 'when commit message does not contain [ci skip] nor [skip ci]' do
        let(:commit_message) { 'some message' }
182

183
        it_behaves_like 'creating a pipeline'
184 185
      end

186 187
      context 'when commit message is nil' do
        let(:commit_message) { nil }
188

189
        it_behaves_like 'creating a pipeline'
190 191
      end

192 193 194 195 196
      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
197 198 199 200 201 202 203 204 205
    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
206
        result = execute_service
207 208 209 210 211 212 213 214 215 216 217 218 219 220

        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
221
        result = execute_service
222 223 224 225 226

        expect(result).to be_persisted
        expect(result.manual_actions).not_to be_empty
      end
    end
227 228 229

    context 'with environment' do
      before do
Z
Z.J. van de Weg 已提交
230
        config = YAML.dump(deploy: { environment: { name: "review/$CI_COMMIT_REF_NAME" }, script: 'ls' })
231 232 233 234
        stub_ci_pipeline_yaml_file(config)
      end

      it 'creates the environment' do
235
        result = execute_service
236 237 238 239 240

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