build_service_spec.rb 10.6 KB
Newer Older
1 2 3 4 5
require 'spec_helper'

describe MergeRequests::BuildService, services: true do
  include RepoHelpers

6
  let(:project) { create(:project, :repository) }
7 8
  let(:source_project) { nil }
  let(:target_project) { nil }
9
  let(:user) { create(:user) }
10 11
  let(:issue_confidential) { false }
  let(:issue) { create(:issue, project: project, title: 'A bug', confidential: issue_confidential) }
12 13 14 15 16 17 18 19 20 21 22 23 24
  let(:description) { nil }
  let(:source_branch) { 'feature-branch' }
  let(:target_branch) { 'master' }
  let(:merge_request) { service.execute }
  let(:compare) { double(:compare, commits: commits) }
  let(:commit_1) { double(:commit_1, safe_message: "Initial commit\n\nCreate the app") }
  let(:commit_2) { double(:commit_2, safe_message: 'This is a bad commit message!') }
  let(:commits) { nil }

  let(:service) do
    MergeRequests::BuildService.new(project, user,
                                    description: description,
                                    source_branch: source_branch,
25 26 27
                                    target_branch: target_branch,
                                    source_project: source_project,
                                    target_project: target_project)
28 29 30
  end

  before do
31 32
    project.team << [user, :guest]

33
    allow(CompareService).to receive_message_chain(:new, :execute).and_return(compare)
34 35
    allow(project).to receive(:commit).and_return(commit_1)
    allow(project).to receive(:commit).and_return(commit_2)
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
  end

  describe 'execute' do
    context 'missing source branch' do
      let(:source_branch) { '' }

      it 'forbids the merge request from being created' do
        expect(merge_request.can_be_created).to eq(false)
      end

      it 'adds an error message to the merge request' do
        expect(merge_request.errors).to contain_exactly('You must select source and target branch')
      end
    end

51 52 53
    context 'when target branch is missing' do
      let(:target_branch) { nil }
      let(:commits) { Commit.decorate([commit_1], project) }
54

55 56 57
      it 'creates compare object with target branch as default branch' do
        expect(merge_request.compare).to be_present
        expect(merge_request.target_branch).to eq(project.default_branch)
58
      end
59 60 61 62

      it 'allows the merge request to be created' do
        expect(merge_request.can_be_created).to eq(true)
      end
63 64
    end

A
Artem Sidorenko 已提交
65 66
    context 'same source and target branch' do
      let(:source_branch) { 'master' }
67 68 69 70

      it 'forbids the merge request from being created' do
        expect(merge_request.can_be_created).to eq(false)
      end
A
Artem Sidorenko 已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86

      it 'adds an error message to the merge request' do
        expect(merge_request.errors).to contain_exactly('You must select different branches')
      end
    end

    context 'no commits in the diff' do
      let(:commits) { [] }

      it 'allows the merge request to be created' do
        expect(merge_request.can_be_created).to eq(true)
      end

      it 'adds a WIP prefix to the merge request title' do
        expect(merge_request.title).to eq('WIP: Feature branch')
      end
87 88 89
    end

    context 'one commit in the diff' do
90
      let(:commits) { Commit.decorate([commit_1], project) }
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112

      it 'allows the merge request to be created' do
        expect(merge_request.can_be_created).to eq(true)
      end

      it 'uses the title of the commit as the title of the merge request' do
        expect(merge_request.title).to eq(commit_1.safe_message.split("\n").first)
      end

      it 'uses the description of the commit as the description of the merge request' do
        expect(merge_request.description).to eq(commit_1.safe_message.split(/\n+/, 2).last)
      end

      context 'merge request already has a description set' do
        let(:description) { 'Merge request description' }

        it 'keeps the description from the initial params' do
          expect(merge_request.description).to eq(description)
        end
      end

      context 'commit has no description' do
113
        let(:commits) { Commit.decorate([commit_2], project) }
114 115 116 117 118 119 120 121 122 123 124 125 126 127

        it 'uses the title of the commit as the title of the merge request' do
          expect(merge_request.title).to eq(commit_2.safe_message)
        end

        it 'sets the description to nil' do
          expect(merge_request.description).to be_nil
        end
      end

      context 'branch starts with issue IID followed by a hyphen' do
        let(:source_branch) { "#{issue.iid}-fix-issue" }

        it 'appends "Closes #$issue-iid" to the description' do
128
          expect(merge_request.description).to eq("#{commit_1.safe_message.split(/\n+/, 2).last}\n\nCloses ##{issue.iid}")
129 130 131 132 133 134
        end

        context 'merge request already has a description set' do
          let(:description) { 'Merge request description' }

          it 'appends "Closes #$issue-iid" to the description' do
135
            expect(merge_request.description).to eq("#{description}\n\nCloses ##{issue.iid}")
136 137 138 139
          end
        end

        context 'commit has no description' do
140
          let(:commits) { Commit.decorate([commit_2], project) }
141 142 143 144 145 146 147 148 149

          it 'sets the description to "Closes #$issue-iid"' do
            expect(merge_request.description).to eq("Closes ##{issue.iid}")
          end
        end
      end
    end

    context 'more than one commit in the diff' do
150
      let(:commits) { Commit.decorate([commit_1, commit_2], project) }
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

      it 'allows the merge request to be created' do
        expect(merge_request.can_be_created).to eq(true)
      end

      it 'uses the title of the branch as the merge request title' do
        expect(merge_request.title).to eq('Feature branch')
      end

      it 'does not add a description' do
        expect(merge_request.description).to be_nil
      end

      context 'merge request already has a description set' do
        let(:description) { 'Merge request description' }

        it 'keeps the description from the initial params' do
          expect(merge_request.description).to eq(description)
        end
      end
171 172 173 174 175 176 177 178

      context 'branch starts with GitLab issue IID followed by a hyphen' do
        let(:source_branch) { "#{issue.iid}-fix-issue" }

        it 'sets the title to: Resolves "$issue-title"' do
          expect(merge_request.title).to eq("Resolve \"#{issue.title}\"")
        end

179 180 181 182 183 184 185 186 187 188
        context 'when issue is not accessible to user' do
          before do
            project.team.truncate
          end

          it 'uses branch title as the merge request title' do
            expect(merge_request.title).to eq("#{issue.iid} fix issue")
          end
        end

189 190 191 192 193 194 195
        context 'issue does not exist' do
          let(:source_branch) { "#{issue.iid.succ}-fix-issue" }

          it 'uses the title of the branch as the merge request title' do
            expect(merge_request.title).to eq("#{issue.iid.succ} fix issue")
          end
        end
196 197 198 199 200 201 202 203

        context 'issue is confidential' do
          let(:issue_confidential) { true }

          it 'uses the title of the branch as the merge request title' do
            expect(merge_request.title).to eq("#{issue.iid} fix issue")
          end
        end
204 205 206 207 208
      end

      context 'branch starts with external issue IID followed by a hyphen' do
        let(:source_branch) { '12345-fix-issue' }

209
        before do
210
          allow(project).to receive(:external_issue_tracker).and_return(true)
211
        end
212 213 214 215 216

        it 'sets the title to: Resolves External Issue $issue-iid' do
          expect(merge_request.title).to eq('Resolve External Issue 12345')
        end
      end
217
    end
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264

    context 'source branch does not exist' do
      before do
        allow(project).to receive(:commit).with(source_branch).and_return(nil)
        allow(project).to receive(:commit).with(target_branch).and_return(commit_1)
      end

      it 'forbids the merge request from being created' do
        expect(merge_request.can_be_created).to eq(false)
      end

      it 'adds an error message to the merge request' do
        expect(merge_request.errors).to contain_exactly('Source branch "feature-branch" does not exist')
      end
    end

    context 'target branch does not exist' do
      before do
        allow(project).to receive(:commit).with(source_branch).and_return(commit_1)
        allow(project).to receive(:commit).with(target_branch).and_return(nil)
      end

      it 'forbids the merge request from being created' do
        expect(merge_request.can_be_created).to eq(false)
      end

      it 'adds an error message to the merge request' do
        expect(merge_request.errors).to contain_exactly('Target branch "master" does not exist')
      end
    end

    context 'both source and target branches do not exist' do
      before do
        allow(project).to receive(:commit).and_return(nil)
      end

      it 'forbids the merge request from being created' do
        expect(merge_request.can_be_created).to eq(false)
      end

      it 'adds both error messages to the merge request' do
        expect(merge_request.errors).to contain_exactly(
          'Source branch "feature-branch" does not exist',
          'Target branch "master" does not exist'
        )
      end
    end
265

266 267 268 269 270 271 272 273 274 275
    context 'upstream project has disabled merge requests' do
      let(:upstream_project) { create(:empty_project, :merge_requests_disabled) }
      let(:project) { create(:empty_project, forked_from_project: upstream_project) }
      let(:commits) { Commit.decorate([commit_1], project) }

      it 'sets target project correctly' do
        expect(merge_request.target_project).to eq(project)
      end
    end

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
    context 'target_project is set and accessible by current_user' do
      let(:target_project) { create(:project, :public, :repository)}
      let(:commits) { Commit.decorate([commit_1], project) }

      it 'sets target project correctly' do
        expect(merge_request.target_project).to eq(target_project)
      end
    end

    context 'target_project is set but not accessible by current_user' do
      let(:target_project) { create(:project, :private, :repository)}
      let(:commits) { Commit.decorate([commit_1], project) }

      it 'sets target project correctly' do
        expect(merge_request.target_project).to eq(project)
      end
    end

    context 'source_project is set and accessible by current_user' do
      let(:source_project) { create(:project, :public, :repository)}
      let(:commits) { Commit.decorate([commit_1], project) }

      it 'sets target project correctly' do
        expect(merge_request.source_project).to eq(source_project)
      end
    end

    context 'source_project is set but not accessible by current_user' do
      let(:source_project) { create(:project, :private, :repository)}
      let(:commits) { Commit.decorate([commit_1], project) }

      it 'sets target project correctly' do
        expect(merge_request.source_project).to eq(project)
      end
    end
311 312
  end
end