PageRenderTime 28ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/spec/services/merge_requests/refresh_service_spec.rb

https://gitlab.com/gwawr/gitlab-ee
Ruby | 312 lines | 261 code | 47 blank | 4 comment | 0 complexity | 3ec7259b54f38cb40f1ee995a7f319ef MD5 | raw file
  1. require 'spec_helper'
  2. describe MergeRequests::RefreshService, services: true do
  3. let(:project) { create(:project) }
  4. let(:user) { create(:user) }
  5. let(:service) { MergeRequests::RefreshService }
  6. describe '#execute' do
  7. before do
  8. @user = create(:user)
  9. group = create(:group)
  10. group.add_owner(@user)
  11. @project = create(:project, namespace: group, approvals_before_merge: 1, reset_approvals_on_push: true)
  12. @fork_project = Projects::ForkService.new(@project, @user).execute
  13. # The call to project.repository.after_import in RepositoryForkWorker does
  14. # not reset the @exists variable of @fork_project.repository so we have to
  15. # explicitely call this method to clear the @exists variable.
  16. @fork_project.repository.after_import
  17. @merge_request = create(:merge_request,
  18. source_project: @project,
  19. source_branch: 'master',
  20. target_branch: 'feature',
  21. target_project: @project,
  22. merge_when_build_succeeds: true,
  23. merge_user: @user)
  24. @fork_merge_request = create(:merge_request,
  25. source_project: @fork_project,
  26. source_branch: 'master',
  27. target_branch: 'feature',
  28. target_project: @project)
  29. @merge_request.approvals.create(user_id: user.id)
  30. @fork_merge_request.approvals.create(user_id: user.id)
  31. @build_failed_todo = create(:todo,
  32. :build_failed,
  33. user: @user,
  34. project: @project,
  35. target: @merge_request,
  36. author: @user)
  37. @fork_build_failed_todo = create(:todo,
  38. :build_failed,
  39. user: @user,
  40. project: @project,
  41. target: @merge_request,
  42. author: @user)
  43. @commits = @merge_request.commits
  44. @oldrev = @commits.last.id
  45. @newrev = @commits.first.id
  46. end
  47. context 'push to origin repo source branch' do
  48. let(:refresh_service) { service.new(@project, @user) }
  49. before do
  50. allow(refresh_service).to receive(:execute_hooks)
  51. refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
  52. reload_mrs
  53. end
  54. it 'executes hooks with update action' do
  55. expect(refresh_service).to have_received(:execute_hooks).
  56. with(@merge_request, 'update', @oldrev)
  57. end
  58. it { expect(@merge_request.notes).not_to be_empty }
  59. it { expect(@merge_request).to be_open }
  60. it { expect(@merge_request.approvals).to be_empty }
  61. it { expect(@merge_request.merge_when_build_succeeds).to be_falsey }
  62. it { expect(@merge_request.diff_head_sha).to eq(@newrev) }
  63. it { expect(@fork_merge_request).to be_open }
  64. it { expect(@fork_merge_request.notes).to be_empty }
  65. it { expect(@build_failed_todo).to be_done }
  66. it { expect(@fork_build_failed_todo).to be_done }
  67. it { expect(@fork_merge_request.approvals).not_to be_empty }
  68. end
  69. context 'push to origin repo target branch' do
  70. before do
  71. service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
  72. reload_mrs
  73. end
  74. it { expect(@merge_request.notes.last.note).to include('merged') }
  75. it { expect(@merge_request).to be_merged }
  76. it { expect(@merge_request.approvals).not_to be_empty }
  77. it { expect(@fork_merge_request).to be_merged }
  78. it { expect(@fork_merge_request.notes.last.note).to include('merged') }
  79. it { expect(@fork_merge_request.approvals).not_to be_empty }
  80. it { expect(@build_failed_todo).to be_done }
  81. it { expect(@fork_build_failed_todo).to be_done }
  82. end
  83. context 'manual merge of source branch' do
  84. before do
  85. # Merge master -> feature branch
  86. author = { email: 'test@gitlab.com', time: Time.now, name: "Me" }
  87. commit_options = { message: 'Test message', committer: author, author: author }
  88. @project.repository.merge(@user, @merge_request, commit_options)
  89. commit = @project.repository.commit('feature')
  90. service.new(@project, @user).execute(@oldrev, commit.id, 'refs/heads/feature')
  91. reload_mrs
  92. end
  93. it { expect(@merge_request.notes.last.note).to include('merged') }
  94. it { expect(@merge_request).to be_merged }
  95. it { expect(@merge_request.diffs.size).to be > 0 }
  96. it { expect(@fork_merge_request).to be_merged }
  97. it { expect(@fork_merge_request.notes.last.note).to include('merged') }
  98. it { expect(@build_failed_todo).to be_done }
  99. it { expect(@fork_build_failed_todo).to be_done }
  100. end
  101. context 'push to fork repo source branch' do
  102. let(:refresh_service) { service.new(@fork_project, @user) }
  103. before do
  104. allow(refresh_service).to receive(:execute_hooks)
  105. refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
  106. reload_mrs
  107. end
  108. it 'executes hooks with update action' do
  109. expect(refresh_service).to have_received(:execute_hooks).
  110. with(@fork_merge_request, 'update', @oldrev)
  111. end
  112. it { expect(@merge_request.notes).to be_empty }
  113. it { expect(@merge_request).to be_open }
  114. it { expect(@merge_request.approvals).not_to be_empty }
  115. it { expect(@fork_merge_request.notes.last.note).to include('added 28 commits') }
  116. it { expect(@fork_merge_request).to be_open }
  117. it { expect(@build_failed_todo).to be_pending }
  118. it { expect(@fork_build_failed_todo).to be_pending }
  119. it { expect(@fork_merge_request.approvals).to be_empty }
  120. end
  121. context 'push to fork repo target branch' do
  122. before do
  123. service.new(@fork_project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
  124. reload_mrs
  125. end
  126. it { expect(@merge_request.notes).to be_empty }
  127. it { expect(@merge_request).to be_open }
  128. it { expect(@merge_request.approvals).not_to be_empty }
  129. it { expect(@fork_merge_request.notes).to be_empty }
  130. it { expect(@fork_merge_request).to be_open }
  131. it { expect(@build_failed_todo).to be_pending }
  132. it { expect(@fork_build_failed_todo).to be_pending }
  133. it { expect(@fork_merge_request.approvals).not_to be_empty }
  134. end
  135. context 'push to origin repo target branch after fork project was removed' do
  136. before do
  137. @fork_project.destroy
  138. service.new(@project, @user).execute(@oldrev, @newrev, 'refs/heads/feature')
  139. reload_mrs
  140. end
  141. it { expect(@merge_request.notes.last.note).to include('merged') }
  142. it { expect(@merge_request).to be_merged }
  143. it { expect(@merge_request.approvals).not_to be_empty }
  144. it { expect(@fork_merge_request).to be_open }
  145. it { expect(@fork_merge_request.notes).to be_empty }
  146. it { expect(@build_failed_todo).to be_done }
  147. it { expect(@fork_build_failed_todo).to be_done }
  148. it { expect(@fork_merge_request.approvals).not_to be_empty }
  149. end
  150. context 'resetting approvals if they are enabled' do
  151. context 'when approvals_before_merge is disabled' do
  152. before do
  153. @project.update(approvals_before_merge: 0)
  154. refresh_service = service.new(@project, @user)
  155. allow(refresh_service).to receive(:execute_hooks)
  156. refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
  157. reload_mrs
  158. end
  159. it 'does not reset approvals' do
  160. expect(@merge_request.approvals).not_to be_empty
  161. end
  162. end
  163. context 'when approvals_before_merge is disabled' do
  164. before do
  165. @project.update(reset_approvals_on_push: false)
  166. refresh_service = service.new(@project, @user)
  167. allow(refresh_service).to receive(:execute_hooks)
  168. refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
  169. reload_mrs
  170. end
  171. it 'does not reset approvals' do
  172. expect(@merge_request.approvals).not_to be_empty
  173. end
  174. end
  175. context 'when the rebase_commit_sha on the MR matches the pushed SHA' do
  176. before do
  177. @merge_request.update(rebase_commit_sha: @newrev)
  178. refresh_service = service.new(@project, @user)
  179. allow(refresh_service).to receive(:execute_hooks)
  180. refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
  181. reload_mrs
  182. end
  183. it 'does not reset approvals' do
  184. expect(@merge_request.approvals).not_to be_empty
  185. end
  186. end
  187. context 'when there are approvals to be reset' do
  188. before do
  189. refresh_service = service.new(@project, @user)
  190. allow(refresh_service).to receive(:execute_hooks)
  191. refresh_service.execute(@oldrev, @newrev, 'refs/heads/master')
  192. reload_mrs
  193. end
  194. it 'resets the approvals' do
  195. expect(@merge_request.approvals).to be_empty
  196. end
  197. end
  198. end
  199. context 'push new branch that exists in a merge request' do
  200. let(:refresh_service) { service.new(@fork_project, @user) }
  201. it 'refreshes the merge request' do
  202. expect(refresh_service).to receive(:execute_hooks).
  203. with(@fork_merge_request, 'update', Gitlab::Git::BLANK_SHA)
  204. allow_any_instance_of(Repository).to receive(:merge_base).and_return(@oldrev)
  205. refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master')
  206. reload_mrs
  207. expect(@merge_request.notes).to be_empty
  208. expect(@merge_request).to be_open
  209. notes = @fork_merge_request.notes.reorder(:created_at).map(&:note)
  210. expect(notes[0]).to include('restored source branch `master`')
  211. expect(notes[1]).to include('added 28 commits')
  212. expect(@fork_merge_request).to be_open
  213. end
  214. end
  215. context 'merge request metrics' do
  216. let(:issue) { create :issue, project: @project }
  217. let(:commit_author) { create :user }
  218. let(:commit) { project.commit }
  219. before do
  220. project.team << [commit_author, :developer]
  221. project.team << [user, :developer]
  222. allow(commit).to receive_messages(
  223. safe_message: "Closes #{issue.to_reference}",
  224. references: [issue],
  225. author_name: commit_author.name,
  226. author_email: commit_author.email,
  227. committed_date: Time.now
  228. )
  229. allow_any_instance_of(MergeRequest).to receive(:commits).and_return([commit])
  230. end
  231. context 'when the merge request is sourced from the same project' do
  232. it 'creates a `MergeRequestsClosingIssues` record for each issue closed by a commit' do
  233. merge_request = create(:merge_request, target_branch: 'master', source_branch: 'feature', source_project: @project)
  234. refresh_service = service.new(@project, @user)
  235. allow(refresh_service).to receive(:execute_hooks)
  236. refresh_service.execute(@oldrev, @newrev, 'refs/heads/feature')
  237. issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
  238. expect(issue_ids).to eq([issue.id])
  239. end
  240. end
  241. context 'when the merge request is sourced from a different project' do
  242. it 'creates a `MergeRequestsClosingIssues` record for each issue closed by a commit' do
  243. forked_project = create(:project)
  244. create(:forked_project_link, forked_to_project: forked_project, forked_from_project: @project)
  245. merge_request = create(:merge_request,
  246. target_branch: 'master',
  247. source_branch: 'feature',
  248. target_project: @project,
  249. source_project: forked_project)
  250. refresh_service = service.new(@project, @user)
  251. allow(refresh_service).to receive(:execute_hooks)
  252. refresh_service.execute(@oldrev, @newrev, 'refs/heads/feature')
  253. issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
  254. expect(issue_ids).to eq([issue.id])
  255. end
  256. end
  257. end
  258. def reload_mrs
  259. @merge_request.reload
  260. @fork_merge_request.reload
  261. @build_failed_todo.reload
  262. @fork_build_failed_todo.reload
  263. end
  264. end
  265. end