Commit 3d7194f0112da12e8732df9ffe8b34fe7d0a9f6b
Committed by
Izaak Alpert
1 parent
fd033671
Exists in
master
and in
4 other branches
Merge Request on forked projects
The good: - You can do a merge request for a forked commit and it will merge properly (i.e. it does work). - Push events take into account merge requests on forked projects - Tests around merge_actions now present, spinach, and other rspec tests - Satellites now clean themselves up rather then recreate The questionable: - Events only know about target projects - Project's merge requests only hold on to MR's where they are the target - All operations performed in the satellite The bad: - Duplication between project's repositories and satellites (e.g. commits_between) (for reference: http://feedback.gitlab.com/forums/176466-general/suggestions/3456722-merge-requests-between-projects-repos) Fixes: Make test repos/satellites only create when needed -Spinach/Rspec now only initialize test directory, and setup stubs (things that are relatively cheap) -project_with_code, source_project_with_code, and target_project_with_code now create/destroy their repos individually -fixed remote removal -How to merge renders properly -Update emails to show project/branches -Edit MR doesn't set target branch -Fix some failures on editing/creating merge requests, added a test -Added back a test around merge request observer -Clean up project_transfer_spec, Remove duplicate enable/disable observers -Ensure satellite lock files are cleaned up, Attempted to add some testing around these as well -Signifant speed ups for tests -Update formatting ordering in notes_on_merge_requests -Remove wiki schema update Fixes for search/search results -Search results was using by_project for a list of projects, updated this to use in_projects -updated search results to reference the correct (target) project -udpated search results to print both sides of the merge request Change-Id: I19407990a0950945cc95d62089cbcc6262dab1a8
Showing
97 changed files
with
1584 additions
and
476 deletions
Show diff stats
app/assets/stylesheets/common.scss
@@ -415,6 +415,17 @@ img.emoji { | @@ -415,6 +415,17 @@ img.emoji { | ||
415 | @extend .light-well; | 415 | @extend .light-well; |
416 | @extend .light; | 416 | @extend .light; |
417 | margin-bottom: 10px; | 417 | margin-bottom: 10px; |
418 | + | ||
419 | +.label-project { | ||
420 | + @include border-radius(4px); | ||
421 | + padding: 2px 4px; | ||
422 | + border: none; | ||
423 | + font-size: 14px; | ||
424 | + background: #474D57; | ||
425 | + color: #fff; | ||
426 | + font-family: $monospace_font; | ||
427 | + text-shadow: 0 1px 1px #111; | ||
428 | + font-weight: normal; | ||
418 | } | 429 | } |
419 | 430 | ||
420 | .group-name { | 431 | .group-name { |
app/contexts/filter_context.rb
@@ -12,7 +12,7 @@ class FilterContext | @@ -12,7 +12,7 @@ class FilterContext | ||
12 | 12 | ||
13 | def apply_filter items | 13 | def apply_filter items |
14 | if params[:project_id] | 14 | if params[:project_id] |
15 | - items = items.where(project_id: params[:project_id]) | 15 | + items = items.by_project(params[:project_id]) |
16 | end | 16 | end |
17 | 17 | ||
18 | if params[:search].present? | 18 | if params[:search].present? |
@@ -20,12 +20,12 @@ class FilterContext | @@ -20,12 +20,12 @@ class FilterContext | ||
20 | end | 20 | end |
21 | 21 | ||
22 | case params[:status] | 22 | case params[:status] |
23 | - when 'closed' | ||
24 | - items.closed | ||
25 | - when 'all' | ||
26 | - items | ||
27 | - else | ||
28 | - items.opened | 23 | + when 'closed' |
24 | + items.closed | ||
25 | + when 'all' | ||
26 | + items | ||
27 | + else | ||
28 | + items.opened | ||
29 | end | 29 | end |
30 | end | 30 | end |
31 | end | 31 | end |
app/contexts/merge_requests_load_context.rb
@@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext | @@ -14,7 +14,7 @@ class MergeRequestsLoadContext < BaseContext | ||
14 | end | 14 | end |
15 | 15 | ||
16 | merge_requests = merge_requests.page(params[:page]).per(20) | 16 | merge_requests = merge_requests.page(params[:page]).per(20) |
17 | - merge_requests = merge_requests.includes(:author, :project).order("created_at desc") | 17 | + merge_requests = merge_requests.includes(:author, :source_project, :target_project).order("created_at desc") |
18 | 18 | ||
19 | # Filter by specific assignee_id (or lack thereof)? | 19 | # Filter by specific assignee_id (or lack thereof)? |
20 | if params[:assignee_id].present? | 20 | if params[:assignee_id].present? |
app/contexts/search_context.rb
@@ -19,7 +19,7 @@ class SearchContext | @@ -19,7 +19,7 @@ class SearchContext | ||
19 | if params[:search_code].present? | 19 | if params[:search_code].present? |
20 | result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo? | 20 | result[:blobs] = project.repository.search_files(query, params[:repository_ref]) unless project.empty_repo? |
21 | else | 21 | else |
22 | - result[:merge_requests] = MergeRequest.where(project_id: project_ids).search(query).limit(10) | 22 | + result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).limit(10) |
23 | result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10) | 23 | result[:issues] = Issue.where(project_id: project_ids).search(query).limit(10) |
24 | result[:wiki_pages] = [] | 24 | result[:wiki_pages] = [] |
25 | end | 25 | end |
app/controllers/projects/merge_requests_controller.rb
@@ -24,8 +24,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -24,8 +24,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
24 | format.html | 24 | format.html |
25 | format.js | 25 | format.js |
26 | 26 | ||
27 | - format.diff { render text: @merge_request.to_diff } | ||
28 | - format.patch { render text: @merge_request.to_patch } | 27 | + format.diff { render text: @merge_request.to_diff(current_user) } |
28 | + format.patch { render text: @merge_request.to_patch(current_user) } | ||
29 | end | 29 | end |
30 | end | 30 | end |
31 | 31 | ||
@@ -33,25 +33,39 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -33,25 +33,39 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
33 | @commit = @merge_request.last_commit | 33 | @commit = @merge_request.last_commit |
34 | 34 | ||
35 | @comments_allowed = @reply_allowed = true | 35 | @comments_allowed = @reply_allowed = true |
36 | - @comments_target = { noteable_type: 'MergeRequest', | ||
37 | - noteable_id: @merge_request.id } | 36 | + @comments_target = {noteable_type: 'MergeRequest', |
37 | + noteable_id: @merge_request.id} | ||
38 | @line_notes = @merge_request.notes.where("line_code is not null") | 38 | @line_notes = @merge_request.notes.where("line_code is not null") |
39 | end | 39 | end |
40 | 40 | ||
41 | def new | 41 | def new |
42 | @merge_request = @project.merge_requests.new(params[:merge_request]) | 42 | @merge_request = @project.merge_requests.new(params[:merge_request]) |
43 | + | ||
44 | + if params[:merge_request] && params[:merge_request][:source_project_id] | ||
45 | + @merge_request.source_project = Project.find_by_id(params[:merge_request][:source_project_id]) | ||
46 | + else | ||
47 | + @merge_request.source_project = @project | ||
48 | + end | ||
49 | + if params[:merge_request] && params[:merge_request][:target_project_id] | ||
50 | + @merge_request.target_project = Project.find_by_id(params[:merge_request][:target_project_id]) | ||
51 | + end | ||
52 | + @target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names | ||
53 | + @merge_request | ||
43 | end | 54 | end |
44 | 55 | ||
45 | def edit | 56 | def edit |
57 | + @target_branches = @merge_request.target_project.repository.branch_names | ||
46 | end | 58 | end |
47 | 59 | ||
48 | def create | 60 | def create |
49 | @merge_request = @project.merge_requests.new(params[:merge_request]) | 61 | @merge_request = @project.merge_requests.new(params[:merge_request]) |
50 | @merge_request.author = current_user | 62 | @merge_request.author = current_user |
51 | - | 63 | + @merge_request.source_project_id = params[:merge_request][:source_project_id].to_i |
64 | + @merge_request.target_project_id = params[:merge_request][:target_project_id].to_i | ||
65 | + @target_branches ||= [] | ||
52 | if @merge_request.save | 66 | if @merge_request.save |
53 | @merge_request.reload_code | 67 | @merge_request.reload_code |
54 | - redirect_to [@project, @merge_request], notice: 'Merge request was successfully created.' | 68 | + redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully created.' |
55 | else | 69 | else |
56 | render "new" | 70 | render "new" |
57 | end | 71 | end |
@@ -89,22 +103,36 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -89,22 +103,36 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
89 | end | 103 | end |
90 | 104 | ||
91 | def branch_from | 105 | def branch_from |
106 | + #This is always source | ||
92 | @commit = @repository.commit(params[:ref]) | 107 | @commit = @repository.commit(params[:ref]) |
93 | end | 108 | end |
94 | 109 | ||
95 | def branch_to | 110 | def branch_to |
96 | - @commit = @repository.commit(params[:ref]) | 111 | + @target_project = selected_target_project |
112 | + @commit = @target_project.repository.commit(params[:ref]) | ||
97 | end | 113 | end |
98 | 114 | ||
115 | + def update_branches | ||
116 | + @target_project = selected_target_project | ||
117 | + @target_branches = (@target_project.repository.branch_names).unshift("Select branch") | ||
118 | + @target_branches | ||
119 | + end | ||
120 | + | ||
121 | + | ||
99 | def ci_status | 122 | def ci_status |
100 | status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha) | 123 | status = project.gitlab_ci_service.commit_status(merge_request.last_commit.sha) |
101 | - response = { status: status } | 124 | + response = {status: status} |
102 | 125 | ||
103 | render json: response | 126 | render json: response |
104 | end | 127 | end |
105 | 128 | ||
106 | protected | 129 | protected |
107 | 130 | ||
131 | + def selected_target_project | ||
132 | + ((@project.id.to_s == params[:target_project_id]) || @project.forked_project_link.nil?) ? @project : @project.forked_project_link.forked_from_project | ||
133 | + end | ||
134 | + | ||
135 | + | ||
108 | def merge_request | 136 | def merge_request |
109 | @merge_request ||= @project.merge_requests.find(params[:id]) | 137 | @merge_request ||= @project.merge_requests.find(params[:id]) |
110 | end | 138 | end |
@@ -123,11 +151,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController | @@ -123,11 +151,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController | ||
123 | 151 | ||
124 | def validates_merge_request | 152 | def validates_merge_request |
125 | # Show git not found page if target branch doesn't exist | 153 | # Show git not found page if target branch doesn't exist |
126 | - return invalid_mr unless @project.repository.branch_names.include?(@merge_request.target_branch) | 154 | + return invalid_mr unless @merge_request.target_project.repository.branch_names.include?(@merge_request.target_branch) |
127 | 155 | ||
128 | # Show git not found page if source branch doesn't exist | 156 | # Show git not found page if source branch doesn't exist |
129 | # and there is no saved commits between source & target branch | 157 | # and there is no saved commits between source & target branch |
130 | - return invalid_mr if !@project.repository.branch_names.include?(@merge_request.source_branch) && @merge_request.commits.blank? | 158 | + return invalid_mr if !@merge_request.source_project.repository.branch_names.include?(@merge_request.source_branch) && @merge_request.commits.blank? |
131 | end | 159 | end |
132 | 160 | ||
133 | def define_show_vars | 161 | def define_show_vars |
app/helpers/commits_helper.rb
@@ -108,8 +108,8 @@ module CommitsHelper | @@ -108,8 +108,8 @@ module CommitsHelper | ||
108 | end | 108 | end |
109 | end | 109 | end |
110 | 110 | ||
111 | - def commit_to_html commit | ||
112 | - escape_javascript(render 'projects/commits/commit', commit: commit) | 111 | + def commit_to_html commit, project |
112 | + escape_javascript(render 'projects/commits/commit', commit: commit, project: project) unless commit.nil? | ||
113 | end | 113 | end |
114 | 114 | ||
115 | def diff_line_content(line) | 115 | def diff_line_content(line) |
app/helpers/merge_requests_helper.rb
1 | module MergeRequestsHelper | 1 | module MergeRequestsHelper |
2 | def new_mr_path_from_push_event(event) | 2 | def new_mr_path_from_push_event(event) |
3 | new_project_merge_request_path( | 3 | new_project_merge_request_path( |
4 | - event.project, | ||
5 | - merge_request: { | 4 | + event.project, |
5 | + new_mr_from_push_event(event, event.project) | ||
6 | + ) | ||
7 | + end | ||
8 | + | ||
9 | + def new_mr_path_for_fork_from_push_event(event) | ||
10 | + new_project_merge_request_path( | ||
11 | + event.project, | ||
12 | + new_mr_from_push_event(event, event.project.forked_from_project) | ||
13 | + ) | ||
14 | + end | ||
15 | + | ||
16 | + | ||
17 | + def new_mr_from_push_event(event, target_project) | ||
18 | + return :merge_request => { | ||
19 | + source_project_id: event.project.id, | ||
20 | + target_project_id: target_project.id, | ||
6 | source_branch: event.branch_name, | 21 | source_branch: event.branch_name, |
7 | - target_branch: event.project.repository.root_ref, | 22 | + target_branch: target_project.repository.root_ref, |
8 | title: event.branch_name.titleize | 23 | title: event.branch_name.titleize |
9 | - } | ||
10 | - ) | 24 | + } |
11 | end | 25 | end |
12 | 26 | ||
13 | def mr_css_classes mr | 27 | def mr_css_classes mr |
@@ -18,6 +32,6 @@ module MergeRequestsHelper | @@ -18,6 +32,6 @@ module MergeRequestsHelper | ||
18 | end | 32 | end |
19 | 33 | ||
20 | def ci_build_details_path merge_request | 34 | def ci_build_details_path merge_request |
21 | - merge_request.project.gitlab_ci_service.build_page(merge_request.last_commit.sha) | 35 | + merge_request.source_project.gitlab_ci_service.build_page(merge_request.last_commit.sha) |
22 | end | 36 | end |
23 | end | 37 | end |
app/mailers/emails/merge_requests.rb
@@ -2,28 +2,65 @@ module Emails | @@ -2,28 +2,65 @@ module Emails | ||
2 | module MergeRequests | 2 | module MergeRequests |
3 | def new_merge_request_email(recipient_id, merge_request_id) | 3 | def new_merge_request_email(recipient_id, merge_request_id) |
4 | @merge_request = MergeRequest.find(merge_request_id) | 4 | @merge_request = MergeRequest.find(merge_request_id) |
5 | - @project = @merge_request.project | ||
6 | - mail(to: recipient(recipient_id), subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) | 5 | + mail(to: @merge_request.assignee_email, subject: subject("new merge request !#{@merge_request.id}", @merge_request.title)) |
7 | end | 6 | end |
8 | 7 | ||
9 | def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) | 8 | def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id) |
10 | @merge_request = MergeRequest.find(merge_request_id) | 9 | @merge_request = MergeRequest.find(merge_request_id) |
11 | @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id | 10 | @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id |
12 | - @project = @merge_request.project | ||
13 | mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) | 11 | mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.id}", @merge_request.title)) |
14 | end | 12 | end |
15 | 13 | ||
16 | def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) | 14 | def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id) |
17 | @merge_request = MergeRequest.find(merge_request_id) | 15 | @merge_request = MergeRequest.find(merge_request_id) |
18 | - @project = @merge_request.project | ||
19 | @updated_by = User.find updated_by_user_id | 16 | @updated_by = User.find updated_by_user_id |
20 | mail(to: recipient(recipient_id), subject: subject("Closed merge request !#{@merge_request.id}", @merge_request.title)) | 17 | mail(to: recipient(recipient_id), subject: subject("Closed merge request !#{@merge_request.id}", @merge_request.title)) |
21 | end | 18 | end |
22 | 19 | ||
23 | def merged_merge_request_email(recipient_id, merge_request_id) | 20 | def merged_merge_request_email(recipient_id, merge_request_id) |
24 | @merge_request = MergeRequest.find(merge_request_id) | 21 | @merge_request = MergeRequest.find(merge_request_id) |
25 | - @project = @merge_request.project | ||
26 | mail(to: recipient(recipient_id), subject: subject("Accepted merge request !#{@merge_request.id}", @merge_request.title)) | 22 | mail(to: recipient(recipient_id), subject: subject("Accepted merge request !#{@merge_request.id}", @merge_request.title)) |
27 | end | 23 | end |
28 | end | 24 | end |
25 | + | ||
26 | + | ||
27 | + # Over rides default behavour to show source/target | ||
28 | + # Formats arguments into a String suitable for use as an email subject | ||
29 | + # | ||
30 | + # extra - Extra Strings to be inserted into the subject | ||
31 | + # | ||
32 | + # Examples | ||
33 | + # | ||
34 | + # >> subject('Lorem ipsum') | ||
35 | + # => "GitLab Merge Request | Lorem ipsum" | ||
36 | + # | ||
37 | + # # Automatically inserts Project name: | ||
38 | + # Forked MR | ||
39 | + # => source project => <Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> | ||
40 | + # => target project => <Project id: 2, name: "My Ror", path: "ruby_on_rails", ...> | ||
41 | + # => source branch => source | ||
42 | + # => target branch => target | ||
43 | + # >> subject('Lorem ipsum') | ||
44 | + # => "GitLab Merge Request | Ruby on Rails:source >> My Ror:target | Lorem ipsum " | ||
45 | + # | ||
46 | + # Non Forked MR | ||
47 | + # => source project => <Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> | ||
48 | + # => target project => <Project id: 1, name: "Ruby on Rails", path: "ruby_on_rails", ...> | ||
49 | + # => source branch => source | ||
50 | + # => target branch => target | ||
51 | + # >> subject('Lorem ipsum') | ||
52 | + # => "GitLab Merge Request | Ruby on Rails | source >> target | Lorem ipsum " | ||
53 | + # # Accepts multiple arguments | ||
54 | + # >> subject('Lorem ipsum', 'Dolor sit amet') | ||
55 | + # => "GitLab Merge Request | Lorem ipsum | Dolor sit amet" | ||
56 | + def subject(*extra) | ||
57 | + subject = "GitLab Merge Request |" | ||
58 | + if @merge_request.for_fork? | ||
59 | + subject << "#{@merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} >> #{@merge_request.target_project.name_with_namespace}:#{merge_request.target_branch}" | ||
60 | + else | ||
61 | + subject << "#{@merge_request.source_project.name_with_namespace} | #{merge_request.source_branch} >> #{merge_request.target_branch}" | ||
62 | + end | ||
63 | + subject << " | " + extra.join(' | ') if extra.present? | ||
64 | + subject | ||
65 | + end | ||
29 | end | 66 | end |
app/models/concerns/issuable.rb
@@ -9,19 +9,14 @@ module Issuable | @@ -9,19 +9,14 @@ module Issuable | ||
9 | include Mentionable | 9 | include Mentionable |
10 | 10 | ||
11 | included do | 11 | included do |
12 | - belongs_to :project | ||
13 | belongs_to :author, class_name: "User" | 12 | belongs_to :author, class_name: "User" |
14 | belongs_to :assignee, class_name: "User" | 13 | belongs_to :assignee, class_name: "User" |
15 | belongs_to :milestone | 14 | belongs_to :milestone |
16 | has_many :notes, as: :noteable, dependent: :destroy | 15 | has_many :notes, as: :noteable, dependent: :destroy |
17 | 16 | ||
18 | - validates :project, presence: true | ||
19 | validates :author, presence: true | 17 | validates :author, presence: true |
20 | validates :title, presence: true, length: { within: 0..255 } | 18 | validates :title, presence: true, length: { within: 0..255 } |
21 | 19 | ||
22 | - scope :opened, -> { with_state(:opened) } | ||
23 | - scope :closed, -> { with_state(:closed) } | ||
24 | - scope :of_group, ->(group) { where(project_id: group.project_ids) } | ||
25 | scope :assigned_to, ->(u) { where(assignee_id: u.id)} | 20 | scope :assigned_to, ->(u) { where(assignee_id: u.id)} |
26 | scope :recent, -> { order("created_at DESC") } | 21 | scope :recent, -> { order("created_at DESC") } |
27 | scope :assigned, -> { where("assignee_id IS NOT NULL") } | 22 | scope :assigned, -> { where("assignee_id IS NOT NULL") } |
app/models/issue.rb
@@ -17,8 +17,18 @@ | @@ -17,8 +17,18 @@ | ||
17 | # | 17 | # |
18 | 18 | ||
19 | class Issue < ActiveRecord::Base | 19 | class Issue < ActiveRecord::Base |
20 | + | ||
20 | include Issuable | 21 | include Issuable |
21 | 22 | ||
23 | + belongs_to :project | ||
24 | + validates :project, presence: true | ||
25 | + | ||
26 | + scope :of_group, ->(group) { where(project_id: group.project_ids) } | ||
27 | + scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } | ||
28 | + scope :opened, -> { with_state(:opened) } | ||
29 | + scope :closed, -> { with_state(:closed) } | ||
30 | + scope :by_project, ->(project_id) {where(project_id:project_id)} | ||
31 | + | ||
22 | attr_accessible :title, :assignee_id, :position, :description, | 32 | attr_accessible :title, :assignee_id, :position, :description, |
23 | :milestone_id, :label_list, :author_id_of_changes, | 33 | :milestone_id, :label_list, :author_id_of_changes, |
24 | :state_event | 34 | :state_event |
app/models/merge_request.rb
@@ -2,30 +2,37 @@ | @@ -2,30 +2,37 @@ | ||
2 | # | 2 | # |
3 | # Table name: merge_requests | 3 | # Table name: merge_requests |
4 | # | 4 | # |
5 | -# id :integer not null, primary key | ||
6 | -# target_branch :string(255) not null | ||
7 | -# source_branch :string(255) not null | ||
8 | -# project_id :integer not null | ||
9 | -# author_id :integer | ||
10 | -# assignee_id :integer | ||
11 | -# title :string(255) | ||
12 | -# created_at :datetime | ||
13 | -# updated_at :datetime | ||
14 | -# st_commits :text(2147483647) | ||
15 | -# st_diffs :text(2147483647) | ||
16 | -# milestone_id :integer | ||
17 | -# state :string(255) | ||
18 | -# merge_status :string(255) | 5 | +# id :integer not null, primary key |
6 | +# target_project_id :integer not null | ||
7 | +# target_branch :string(255) not null | ||
8 | +# source_project_id :integer not null | ||
9 | +# source_branch :string(255) not null | ||
10 | +# author_id :integer | ||
11 | +# assignee_id :integer | ||
12 | +# title :string(255) | ||
13 | +# created_at :datetime | ||
14 | +# updated_at :datetime | ||
15 | +# st_commits :text(2147483647) | ||
16 | +# st_diffs :text(2147483647) | ||
17 | +# milestone_id :integer | ||
18 | +# state :string(255) | ||
19 | +# merge_status :string(255) | ||
19 | # | 20 | # |
20 | 21 | ||
21 | require Rails.root.join("app/models/commit") | 22 | require Rails.root.join("app/models/commit") |
22 | require Rails.root.join("lib/static_model") | 23 | require Rails.root.join("lib/static_model") |
23 | 24 | ||
24 | class MergeRequest < ActiveRecord::Base | 25 | class MergeRequest < ActiveRecord::Base |
26 | + | ||
25 | include Issuable | 27 | include Issuable |
26 | 28 | ||
27 | - attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, | ||
28 | - :author_id_of_changes, :state_event | 29 | + belongs_to :target_project,:foreign_key => :target_project_id, class_name: "Project" |
30 | + belongs_to :source_project, :foreign_key => :source_project_id,class_name: "Project" | ||
31 | + | ||
32 | + BROKEN_DIFF = "--broken-diff" | ||
33 | + | ||
34 | + attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id,:author_id_of_changes, :state_event | ||
35 | + | ||
29 | 36 | ||
30 | attr_accessor :should_remove_source_branch | 37 | attr_accessor :should_remove_source_branch |
31 | 38 | ||
@@ -74,22 +81,29 @@ class MergeRequest < ActiveRecord::Base | @@ -74,22 +81,29 @@ class MergeRequest < ActiveRecord::Base | ||
74 | serialize :st_commits | 81 | serialize :st_commits |
75 | serialize :st_diffs | 82 | serialize :st_diffs |
76 | 83 | ||
84 | + validates :source_project, presence: true | ||
77 | validates :source_branch, presence: true | 85 | validates :source_branch, presence: true |
86 | + validates :target_project, presence: true | ||
78 | validates :target_branch, presence: true | 87 | validates :target_branch, presence: true |
79 | - validate :validate_branches | 88 | + validate :validate_branches |
80 | 89 | ||
90 | + scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)",group_project_ids:group.project_ids) } | ||
91 | + scope :of_user_team, ->(team) { where("(source_project_id in (:team_project_ids) OR target_project_id in (:team_project_ids) AND assignee_id in (:team_member_ids))",team_project_ids:team.project_ids,team_member_ids:team.member_ids) } | ||
92 | + scope :opened, -> { with_state(:opened) } | ||
93 | + scope :closed, -> { with_state(:closed) } | ||
81 | scope :merged, -> { with_state(:merged) } | 94 | scope :merged, -> { with_state(:merged) } |
82 | - scope :by_branch, ->(branch_name) { where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) } | 95 | + scope :by_branch, ->(branch_name) { where("(source_branch LIKE :branch) OR (target_branch LIKE :branch)", branch: branch_name) } |
83 | scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } | 96 | scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } |
84 | scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } | 97 | scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } |
85 | - | 98 | + scope :by_project, ->(project_id) { where("source_project_id = :project_id OR target_project_id = :project_id", project_id: project_id) } |
99 | + scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) } | ||
86 | # Closed scope for merge request should return | 100 | # Closed scope for merge request should return |
87 | # both merged and closed mr's | 101 | # both merged and closed mr's |
88 | scope :closed, -> { with_states(:closed, :merged) } | 102 | scope :closed, -> { with_states(:closed, :merged) } |
89 | 103 | ||
90 | def validate_branches | 104 | def validate_branches |
91 | - if target_branch == source_branch | ||
92 | - errors.add :branch_conflict, "You can not use same branch for source and target branches" | 105 | + if target_project==source_project && target_branch == source_branch |
106 | + errors.add :branch_conflict, "You can not use same project/branch for source and target" | ||
93 | end | 107 | end |
94 | 108 | ||
95 | if opened? || reopened? | 109 | if opened? || reopened? |
@@ -137,7 +151,14 @@ class MergeRequest < ActiveRecord::Base | @@ -137,7 +151,14 @@ class MergeRequest < ActiveRecord::Base | ||
137 | end | 151 | end |
138 | 152 | ||
139 | def unmerged_diffs | 153 | def unmerged_diffs |
140 | - project.repository.diffs_between(source_branch, target_branch) | 154 | + #TODO:[IA-8] this needs to be handled better -- logged etc |
155 | + diffs = Gitlab::Satellite::MergeAction.new(author, self).diffs_between_satellite | ||
156 | + if diffs | ||
157 | + diffs = diffs.map { |diff| Gitlab::Git::Diff.new(diff) } | ||
158 | + else | ||
159 | + diffs = [] | ||
160 | + end | ||
161 | + diffs | ||
141 | end | 162 | end |
142 | 163 | ||
143 | def last_commit | 164 | def last_commit |
@@ -145,11 +166,11 @@ class MergeRequest < ActiveRecord::Base | @@ -145,11 +166,11 @@ class MergeRequest < ActiveRecord::Base | ||
145 | end | 166 | end |
146 | 167 | ||
147 | def merge_event | 168 | def merge_event |
148 | - self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last | 169 | + self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::MERGED).last |
149 | end | 170 | end |
150 | 171 | ||
151 | def closed_event | 172 | def closed_event |
152 | - self.project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last | 173 | + self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last |
153 | end | 174 | end |
154 | 175 | ||
155 | def commits | 176 | def commits |
@@ -158,24 +179,30 @@ class MergeRequest < ActiveRecord::Base | @@ -158,24 +179,30 @@ class MergeRequest < ActiveRecord::Base | ||
158 | 179 | ||
159 | def probably_merged? | 180 | def probably_merged? |
160 | unmerged_commits.empty? && | 181 | unmerged_commits.empty? && |
161 | - commits.any? && opened? | 182 | + commits.any? && opened? |
162 | end | 183 | end |
163 | 184 | ||
164 | def reloaded_commits | 185 | def reloaded_commits |
165 | if opened? && unmerged_commits.any? | 186 | if opened? && unmerged_commits.any? |
166 | self.st_commits = dump_commits(unmerged_commits) | 187 | self.st_commits = dump_commits(unmerged_commits) |
167 | save | 188 | save |
189 | + | ||
168 | end | 190 | end |
169 | commits | 191 | commits |
170 | end | 192 | end |
171 | 193 | ||
172 | def unmerged_commits | 194 | def unmerged_commits |
173 | - self.project.repository. | ||
174 | - commits_between(self.target_branch, self.source_branch). | ||
175 | - sort_by(&:created_at). | ||
176 | - reverse | 195 | + commits = Gitlab::Satellite::MergeAction.new(self.author,self).commits_between |
196 | + commits = commits.map{ |commit| Gitlab::Git::Commit.new(commit, nil) } | ||
197 | + if commits.present? | ||
198 | + commits = Commit.decorate(commits). | ||
199 | + sort_by(&:created_at). | ||
200 | + reverse | ||
201 | + end | ||
202 | + commits | ||
177 | end | 203 | end |
178 | 204 | ||
205 | + | ||
179 | def merge!(user_id) | 206 | def merge!(user_id) |
180 | self.author_id_of_changes = user_id | 207 | self.author_id_of_changes = user_id |
181 | self.merge | 208 | self.merge |
@@ -195,25 +222,33 @@ class MergeRequest < ActiveRecord::Base | @@ -195,25 +222,33 @@ class MergeRequest < ActiveRecord::Base | ||
195 | commit_ids = commits.map(&:id) | 222 | commit_ids = commits.map(&:id) |
196 | Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) | 223 | Note.where("(noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR (noteable_type = 'Commit' AND commit_id IN (:commit_ids))", mr_id: id, commit_ids: commit_ids) |
197 | end | 224 | end |
198 | - | ||
199 | # Returns the raw diff for this merge request | 225 | # Returns the raw diff for this merge request |
200 | # | 226 | # |
201 | # see "git diff" | 227 | # see "git diff" |
202 | - def to_diff | ||
203 | - project.repo.git.native(:diff, {timeout: 30, raise: true}, "#{target_branch}...#{source_branch}") | 228 | + def to_diff(current_user) |
229 | + Gitlab::Satellite::MergeAction.new(current_user, self).diff_in_satellite | ||
204 | end | 230 | end |
205 | 231 | ||
232 | + | ||
206 | # Returns the commit as a series of email patches. | 233 | # Returns the commit as a series of email patches. |
207 | # | 234 | # |
208 | # see "git format-patch" | 235 | # see "git format-patch" |
209 | - def to_patch | ||
210 | - project.repo.git.format_patch({timeout: 30, raise: true, stdout: true}, "#{target_branch}..#{source_branch}") | 236 | + def to_patch(current_user) |
237 | + Gitlab::Satellite::MergeAction.new(current_user, self).format_patch | ||
211 | end | 238 | end |
212 | 239 | ||
213 | def last_commit_short_sha | 240 | def last_commit_short_sha |
214 | @last_commit_short_sha ||= last_commit.sha[0..10] | 241 | @last_commit_short_sha ||= last_commit.sha[0..10] |
215 | end | 242 | end |
216 | 243 | ||
244 | + def for_fork? | ||
245 | + target_project != source_project | ||
246 | + end | ||
247 | + | ||
248 | + def disallow_source_branch_removal? | ||
249 | + (source_project.root_ref? source_branch) || for_fork? | ||
250 | + end | ||
251 | + | ||
217 | private | 252 | private |
218 | 253 | ||
219 | def dump_commits(commits) | 254 | def dump_commits(commits) |
app/models/note.rb
@@ -32,8 +32,8 @@ class Note < ActiveRecord::Base | @@ -32,8 +32,8 @@ class Note < ActiveRecord::Base | ||
32 | delegate :name, :email, to: :author, prefix: true | 32 | delegate :name, :email, to: :author, prefix: true |
33 | 33 | ||
34 | validates :note, :project, presence: true | 34 | validates :note, :project, presence: true |
35 | - validates :line_code, format: { with: /\A[a-z0-9]+_\d+_\d+\Z/ }, allow_blank: true | ||
36 | - validates :attachment, file_size: { maximum: 10.megabytes.to_i } | 35 | + validates :line_code, format: {with: /\A[a-z0-9]+_\d+_\d+\Z/}, allow_blank: true |
36 | + validates :attachment, file_size: {maximum: 10.megabytes.to_i} | ||
37 | 37 | ||
38 | validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' } | 38 | validates :noteable_id, presence: true, if: ->(n) { n.noteable_type.present? && n.noteable_type != 'Commit' } |
39 | validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' } | 39 | validates :commit_id, presence: true, if: ->(n) { n.noteable_type == 'Commit' } |
@@ -45,24 +45,24 @@ class Note < ActiveRecord::Base | @@ -45,24 +45,24 @@ class Note < ActiveRecord::Base | ||
45 | scope :inline, -> { where("line_code IS NOT NULL") } | 45 | scope :inline, -> { where("line_code IS NOT NULL") } |
46 | scope :not_inline, -> { where(line_code: [nil, '']) } | 46 | scope :not_inline, -> { where(line_code: [nil, '']) } |
47 | 47 | ||
48 | - scope :common, ->{ where(noteable_type: ["", nil]) } | ||
49 | - scope :fresh, ->{ order("created_at ASC, id ASC") } | ||
50 | - scope :inc_author_project, ->{ includes(:project, :author) } | ||
51 | - scope :inc_author, ->{ includes(:author) } | 48 | + scope :common, -> { where(noteable_type: ["", nil]) } |
49 | + scope :fresh, -> { order("created_at ASC, id ASC") } | ||
50 | + scope :inc_author_project, -> { includes(:project, :author) } | ||
51 | + scope :inc_author, -> { includes(:author) } | ||
52 | 52 | ||
53 | - def self.create_status_change_note(noteable, author, status) | 53 | + def self.create_status_change_note(noteable, project, author, status) |
54 | create({ | 54 | create({ |
55 | - noteable: noteable, | ||
56 | - project: noteable.project, | ||
57 | - author: author, | ||
58 | - note: "_Status changed to #{status}_" | ||
59 | - }, without_protection: true) | 55 | + noteable: noteable, |
56 | + project: project, | ||
57 | + author: author, | ||
58 | + note: "_Status changed to #{status}_" | ||
59 | + }, without_protection: true) | ||
60 | end | 60 | end |
61 | 61 | ||
62 | def commit_author | 62 | def commit_author |
63 | @commit_author ||= | 63 | @commit_author ||= |
64 | - project.users.find_by_email(noteable.author_email) || | ||
65 | - project.users.find_by_name(noteable.author_name) | 64 | + project.users.find_by_email(noteable.author_email) || |
65 | + project.users.find_by_name(noteable.author_name) | ||
66 | rescue | 66 | rescue |
67 | nil | 67 | nil |
68 | end | 68 | end |
@@ -97,8 +97,8 @@ class Note < ActiveRecord::Base | @@ -97,8 +97,8 @@ class Note < ActiveRecord::Base | ||
97 | # otherwise false is returned | 97 | # otherwise false is returned |
98 | def downvote? | 98 | def downvote? |
99 | votable? && (note.start_with?('-1') || | 99 | votable? && (note.start_with?('-1') || |
100 | - note.start_with?(':-1:') | ||
101 | - ) | 100 | + note.start_with?(':-1:') |
101 | + ) | ||
102 | end | 102 | end |
103 | 103 | ||
104 | def for_commit? | 104 | def for_commit? |
@@ -136,8 +136,8 @@ class Note < ActiveRecord::Base | @@ -136,8 +136,8 @@ class Note < ActiveRecord::Base | ||
136 | else | 136 | else |
137 | super | 137 | super |
138 | end | 138 | end |
139 | - # Temp fix to prevent app crash | ||
140 | - # if note commit id doesn't exist | 139 | + # Temp fix to prevent app crash |
140 | + # if note commit id doesn't exist | ||
141 | rescue | 141 | rescue |
142 | nil | 142 | nil |
143 | end | 143 | end |
@@ -146,8 +146,8 @@ class Note < ActiveRecord::Base | @@ -146,8 +146,8 @@ class Note < ActiveRecord::Base | ||
146 | # otherwise false is returned | 146 | # otherwise false is returned |
147 | def upvote? | 147 | def upvote? |
148 | votable? && (note.start_with?('+1') || | 148 | votable? && (note.start_with?('+1') || |
149 | - note.start_with?(':+1:') | ||
150 | - ) | 149 | + note.start_with?(':+1:') |
150 | + ) | ||
151 | end | 151 | end |
152 | 152 | ||
153 | def votable? | 153 | def votable? |
app/models/project.rb
@@ -53,7 +53,7 @@ class Project < ActiveRecord::Base | @@ -53,7 +53,7 @@ class Project < ActiveRecord::Base | ||
53 | 53 | ||
54 | has_many :services, dependent: :destroy | 54 | has_many :services, dependent: :destroy |
55 | has_many :events, dependent: :destroy | 55 | has_many :events, dependent: :destroy |
56 | - has_many :merge_requests, dependent: :destroy | 56 | + has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id" |
57 | has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC" | 57 | has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC" |
58 | has_many :milestones, dependent: :destroy | 58 | has_many :milestones, dependent: :destroy |
59 | has_many :notes, dependent: :destroy | 59 | has_many :notes, dependent: :destroy |
app/observers/activity_observer.rb
1 | class ActivityObserver < BaseObserver | 1 | class ActivityObserver < BaseObserver |
2 | - observe :issue, :merge_request, :note, :milestone | 2 | + observe :issue, :note, :milestone |
3 | 3 | ||
4 | def after_create(record) | 4 | def after_create(record) |
5 | event_author_id = record.author_id | 5 | event_author_id = record.author_id |
@@ -13,47 +13,27 @@ class ActivityObserver < BaseObserver | @@ -13,47 +13,27 @@ class ActivityObserver < BaseObserver | ||
13 | end | 13 | end |
14 | 14 | ||
15 | if event_author_id | 15 | if event_author_id |
16 | - Event.create( | ||
17 | - project: record.project, | ||
18 | - target_id: record.id, | ||
19 | - target_type: record.class.name, | ||
20 | - action: Event.determine_action(record), | ||
21 | - author_id: event_author_id | ||
22 | - ) | 16 | + create_event(record, Event.determine_action(record)) |
23 | end | 17 | end |
24 | end | 18 | end |
25 | 19 | ||
26 | def after_close(record, transition) | 20 | def after_close(record, transition) |
27 | - Event.create( | ||
28 | - project: record.project, | ||
29 | - target_id: record.id, | ||
30 | - target_type: record.class.name, | ||
31 | - action: Event::CLOSED, | ||
32 | - author_id: record.author_id_of_changes | ||
33 | - ) | 21 | + create_event(record, Event::CLOSED) |
34 | end | 22 | end |
35 | 23 | ||
36 | def after_reopen(record, transition) | 24 | def after_reopen(record, transition) |
37 | - Event.create( | ||
38 | - project: record.project, | ||
39 | - target_id: record.id, | ||
40 | - target_type: record.class.name, | ||
41 | - action: Event::REOPENED, | ||
42 | - author_id: record.author_id_of_changes | ||
43 | - ) | 25 | + create_event(record, Event::REOPENED) |
44 | end | 26 | end |
45 | 27 | ||
46 | - def after_merge(record, transition) | ||
47 | - # Since MR can be merged via sidekiq | ||
48 | - # to prevent event duplication do this check | ||
49 | - return true if record.merge_event | 28 | + protected |
50 | 29 | ||
30 | + def create_event(record, status) | ||
51 | Event.create( | 31 | Event.create( |
52 | - project: record.project, | ||
53 | - target_id: record.id, | ||
54 | - target_type: record.class.name, | ||
55 | - action: Event::MERGED, | ||
56 | - author_id: record.author_id_of_changes | 32 | + project: record.project, |
33 | + target_id: record.id, | ||
34 | + target_type: record.class.name, | ||
35 | + action: status, | ||
36 | + author_id: record.author_id | ||
57 | ) | 37 | ) |
58 | end | 38 | end |
59 | end | 39 | end |
app/observers/issue_observer.rb
@@ -23,6 +23,6 @@ class IssueObserver < BaseObserver | @@ -23,6 +23,6 @@ class IssueObserver < BaseObserver | ||
23 | 23 | ||
24 | # Create issue note with service comment like 'Status changed to closed' | 24 | # Create issue note with service comment like 'Status changed to closed' |
25 | def create_note(issue) | 25 | def create_note(issue) |
26 | - Note.create_status_change_note(issue, current_user, issue.state) | 26 | + Note.create_status_change_note(issue, issue.project, current_user, issue.state) |
27 | end | 27 | end |
28 | end | 28 | end |
app/observers/merge_request_observer.rb
1 | -class MergeRequestObserver < BaseObserver | 1 | +class MergeRequestObserver < ActivityObserver |
2 | + observe :merge_request | ||
3 | + cattr_accessor :current_user | ||
4 | + | ||
2 | def after_create(merge_request) | 5 | def after_create(merge_request) |
6 | + event_author_id = merge_request.author_id | ||
7 | + if event_author_id | ||
8 | + create_event(merge_request, Event.determine_action(merge_request)) | ||
9 | + end | ||
10 | + | ||
3 | notification.new_merge_request(merge_request, current_user) | 11 | notification.new_merge_request(merge_request, current_user) |
4 | end | 12 | end |
5 | 13 | ||
6 | def after_close(merge_request, transition) | 14 | def after_close(merge_request, transition) |
7 | - Note.create_status_change_note(merge_request, current_user, merge_request.state) | 15 | + create_event(merge_request, Event::CLOSED) |
16 | + Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state) | ||
8 | 17 | ||
9 | notification.close_mr(merge_request, current_user) | 18 | notification.close_mr(merge_request, current_user) |
10 | end | 19 | end |
11 | 20 | ||
12 | def after_merge(merge_request, transition) | 21 | def after_merge(merge_request, transition) |
13 | notification.merge_mr(merge_request) | 22 | notification.merge_mr(merge_request) |
23 | + # Since MR can be merged via sidekiq | ||
24 | + # to prevent event duplication do this check | ||
25 | + return true if merge_request.merge_event | ||
26 | + | ||
27 | + Event.create( | ||
28 | + project: merge_request.target_project, | ||
29 | + target_id: merge_request.id, | ||
30 | + target_type: merge_request.class.name, | ||
31 | + action: Event::MERGED, | ||
32 | + author_id: merge_request.author_id_of_changes | ||
33 | + ) | ||
14 | end | 34 | end |
15 | 35 | ||
16 | def after_reopen(merge_request, transition) | 36 | def after_reopen(merge_request, transition) |
17 | - Note.create_status_change_note(merge_request, current_user, merge_request.state) | 37 | + create_event(merge_request, Event::REOPENED) |
38 | + Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state) | ||
18 | end | 39 | end |
19 | 40 | ||
20 | def after_update(merge_request) | 41 | def after_update(merge_request) |
21 | notification.reassigned_merge_request(merge_request, current_user) if merge_request.is_being_reassigned? | 42 | notification.reassigned_merge_request(merge_request, current_user) if merge_request.is_being_reassigned? |
22 | end | 43 | end |
44 | + | ||
45 | + | ||
46 | + def create_event(record, status) | ||
47 | + Event.create( | ||
48 | + project: record.target_project, | ||
49 | + target_id: record.id, | ||
50 | + target_type: record.class.name, | ||
51 | + action: status, | ||
52 | + author_id: record.author_id | ||
53 | + ) | ||
54 | + end | ||
55 | + | ||
23 | end | 56 | end |
app/services/notification_service.rb
@@ -23,7 +23,7 @@ class NotificationService | @@ -23,7 +23,7 @@ class NotificationService | ||
23 | # * project team members with notification level higher then Participating | 23 | # * project team members with notification level higher then Participating |
24 | # | 24 | # |
25 | def new_issue(issue, current_user) | 25 | def new_issue(issue, current_user) |
26 | - new_resource_email(issue, 'new_issue_email') | 26 | + new_resource_email(issue, issue.project, 'new_issue_email') |
27 | end | 27 | end |
28 | 28 | ||
29 | # When we close an issue we should send next emails: | 29 | # When we close an issue we should send next emails: |
@@ -33,7 +33,7 @@ class NotificationService | @@ -33,7 +33,7 @@ class NotificationService | ||
33 | # * project team members with notification level higher then Participating | 33 | # * project team members with notification level higher then Participating |
34 | # | 34 | # |
35 | def close_issue(issue, current_user) | 35 | def close_issue(issue, current_user) |
36 | - close_resource_email(issue, current_user, 'closed_issue_email') | 36 | + close_resource_email(issue, issue.project, current_user, 'closed_issue_email') |
37 | end | 37 | end |
38 | 38 | ||
39 | # When we reassign an issue we should send next emails: | 39 | # When we reassign an issue we should send next emails: |
@@ -42,7 +42,7 @@ class NotificationService | @@ -42,7 +42,7 @@ class NotificationService | ||
42 | # * issue new assignee if his notification level is not Disabled | 42 | # * issue new assignee if his notification level is not Disabled |
43 | # | 43 | # |
44 | def reassigned_issue(issue, current_user) | 44 | def reassigned_issue(issue, current_user) |
45 | - reassign_resource_email(issue, current_user, 'reassigned_issue_email') | 45 | + reassign_resource_email(issue, issue.project, current_user, 'reassigned_issue_email') |
46 | end | 46 | end |
47 | 47 | ||
48 | 48 | ||
@@ -51,7 +51,7 @@ class NotificationService | @@ -51,7 +51,7 @@ class NotificationService | ||
51 | # * mr assignee if his notification level is not Disabled | 51 | # * mr assignee if his notification level is not Disabled |
52 | # | 52 | # |
53 | def new_merge_request(merge_request, current_user) | 53 | def new_merge_request(merge_request, current_user) |
54 | - new_resource_email(merge_request, 'new_merge_request_email') | 54 | + new_resource_email(merge_request, merge_request.target_project, 'new_merge_request_email') |
55 | end | 55 | end |
56 | 56 | ||
57 | # When we reassign a merge_request we should send next emails: | 57 | # When we reassign a merge_request we should send next emails: |
@@ -60,7 +60,7 @@ class NotificationService | @@ -60,7 +60,7 @@ class NotificationService | ||
60 | # * merge_request assignee if his notification level is not Disabled | 60 | # * merge_request assignee if his notification level is not Disabled |
61 | # | 61 | # |
62 | def reassigned_merge_request(merge_request, current_user) | 62 | def reassigned_merge_request(merge_request, current_user) |
63 | - reassign_resource_email(merge_request, current_user, 'reassigned_merge_request_email') | 63 | + reassign_resource_email(merge_request, merge_request.target_project, current_user, 'reassigned_merge_request_email') |
64 | end | 64 | end |
65 | 65 | ||
66 | # When we close a merge request we should send next emails: | 66 | # When we close a merge request we should send next emails: |
@@ -70,7 +70,7 @@ class NotificationService | @@ -70,7 +70,7 @@ class NotificationService | ||
70 | # * project team members with notification level higher then Participating | 70 | # * project team members with notification level higher then Participating |
71 | # | 71 | # |
72 | def close_mr(merge_request, current_user) | 72 | def close_mr(merge_request, current_user) |
73 | - close_resource_email(merge_request, current_user, 'closed_merge_request_email') | 73 | + close_resource_email(merge_request, merge_request.target_project, current_user, 'closed_merge_request_email') |
74 | end | 74 | end |
75 | 75 | ||
76 | # When we merge a merge request we should send next emails: | 76 | # When we merge a merge request we should send next emails: |
@@ -80,8 +80,10 @@ class NotificationService | @@ -80,8 +80,10 @@ class NotificationService | ||
80 | # * project team members with notification level higher then Participating | 80 | # * project team members with notification level higher then Participating |
81 | # | 81 | # |
82 | def merge_mr(merge_request) | 82 | def merge_mr(merge_request) |
83 | - recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.project) | ||
84 | - recipients = recipients.concat(project_watchers(merge_request.project)).uniq | 83 | + recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.source_project) |
84 | + recipients = recipients.concat(reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)) | ||
85 | + recipients = recipients.concat(project_watchers(merge_request.source_project)) | ||
86 | + recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq | ||
85 | 87 | ||
86 | recipients.each do |recipient| | 88 | recipients.each do |recipient| |
87 | mailer.merged_merge_request_email(recipient.id, merge_request.id) | 89 | mailer.merged_merge_request_email(recipient.id, merge_request.id) |
@@ -102,7 +104,7 @@ class NotificationService | @@ -102,7 +104,7 @@ class NotificationService | ||
102 | # ignore wall messages | 104 | # ignore wall messages |
103 | return true unless note.noteable_type.present? | 105 | return true unless note.noteable_type.present? |
104 | 106 | ||
105 | - opts = { noteable_type: note.noteable_type, project_id: note.project_id } | 107 | + opts = {noteable_type: note.noteable_type, project_id: note.project_id} |
106 | 108 | ||
107 | if note.commit_id.present? | 109 | if note.commit_id.present? |
108 | opts.merge!(commit_id: note.commit_id) | 110 | opts.merge!(commit_id: note.commit_id) |
@@ -191,14 +193,14 @@ class NotificationService | @@ -191,14 +193,14 @@ class NotificationService | ||
191 | end | 193 | end |
192 | end | 194 | end |
193 | 195 | ||
194 | - def new_resource_email(target, method) | 196 | + def new_resource_email(target, project, method) |
195 | if target.respond_to?(:participants) | 197 | if target.respond_to?(:participants) |
196 | recipients = target.participants | 198 | recipients = target.participants |
197 | else | 199 | else |
198 | recipients = [] | 200 | recipients = [] |
199 | end | 201 | end |
200 | - recipients = reject_muted_users(recipients, target.project) | ||
201 | - recipients = recipients.concat(project_watchers(target.project)).uniq | 202 | + recipients = reject_muted_users(recipients, project) |
203 | + recipients = recipients.concat(project_watchers(project)).uniq | ||
202 | recipients.delete(target.author) | 204 | recipients.delete(target.author) |
203 | 205 | ||
204 | recipients.each do |recipient| | 206 | recipients.each do |recipient| |
@@ -206,9 +208,9 @@ class NotificationService | @@ -206,9 +208,9 @@ class NotificationService | ||
206 | end | 208 | end |
207 | end | 209 | end |
208 | 210 | ||
209 | - def close_resource_email(target, current_user, method) | ||
210 | - recipients = reject_muted_users([target.author, target.assignee], target.project) | ||
211 | - recipients = recipients.concat(project_watchers(target.project)).uniq | 211 | + def close_resource_email(target, project, current_user, method) |
212 | + recipients = reject_muted_users([target.author, target.assignee], project) | ||
213 | + recipients = recipients.concat(project_watchers(project)).uniq | ||
212 | recipients.delete(current_user) | 214 | recipients.delete(current_user) |
213 | 215 | ||
214 | recipients.each do |recipient| | 216 | recipients.each do |recipient| |
@@ -216,14 +218,14 @@ class NotificationService | @@ -216,14 +218,14 @@ class NotificationService | ||
216 | end | 218 | end |
217 | end | 219 | end |
218 | 220 | ||
219 | - def reassign_resource_email(target, current_user, method) | 221 | + def reassign_resource_email(target, project, current_user, method) |
220 | recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) | 222 | recipients = User.where(id: [target.assignee_id, target.assignee_id_was]) |
221 | 223 | ||
222 | # Add watchers to email list | 224 | # Add watchers to email list |
223 | - recipients = recipients.concat(project_watchers(target.project)) | 225 | + recipients = recipients.concat(project_watchers(project)) |
224 | 226 | ||
225 | # reject users with disabled notifications | 227 | # reject users with disabled notifications |
226 | - recipients = reject_muted_users(recipients, target.project) | 228 | + recipients = reject_muted_users(recipients, project) |
227 | 229 | ||
228 | # Reject me from recipients if I reassign an item | 230 | # Reject me from recipients if I reassign an item |
229 | recipients.delete(current_user) | 231 | recipients.delete(current_user) |
app/views/events/_event_last_push.html.haml
@@ -9,6 +9,9 @@ | @@ -9,6 +9,9 @@ | ||
9 | = time_ago_in_words(event.created_at) | 9 | = time_ago_in_words(event.created_at) |
10 | ago. | 10 | ago. |
11 | .pull-right | 11 | .pull-right |
12 | - = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-small" do | 12 | + = link_to new_mr_path_from_push_event(event), title: "New Merge Request", class: "btn btn-new-mr" do |
13 | Create Merge Request | 13 | Create Merge Request |
14 | + - if !event.project.nil? && event.project.forked? | ||
15 | + = link_to new_mr_path_for_fork_from_push_event(event), title: "New Merge Request", class: "btn btn-create btn-small" do | ||
16 | + Create Merge Request on fork | ||
14 | %hr | 17 | %hr |
app/views/notify/closed_merge_request_email.html.haml
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | %p | 3 | %p |
4 | = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | 4 | = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) |
5 | %p | 5 | %p |
6 | - Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | 6 | + Projects:Branches: #{@merge_request.source_project.path_with_namespace}:#{@merge_request.source_branch} → #{@merge_request.target_project.path_with_namespace}:#{@merge_request.target_branch} |
7 | %p | 7 | %p |
8 | Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | 8 | Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} |
9 | 9 |
app/views/notify/closed_merge_request_email.text.haml
1 | = "Merge Request #{@merge_request.id} was closed by #{@updated_by.name}" | 1 | = "Merge Request #{@merge_request.id} was closed by #{@updated_by.name}" |
2 | 2 | ||
3 | -Merge Request url: #{project_merge_request_url(@merge_request.project, @merge_request)} | 3 | +Merge Request url: #{project_merge_request_url(@merge_request.target_project, @merge_request)} |
4 | 4 | ||
5 | -Branches: #{@merge_request.source_branch} - #{@merge_request.target_branch} | 5 | +Project:Branches: #{@merge_request.source_project.path_with_namespace}/#{@merge_request.source_branch} - #{@merge_request.target_project.path_with_namespace}#{@merge_request.target_branch} |
6 | 6 | ||
7 | Author: #{@merge_request.author_name} | 7 | Author: #{@merge_request.author_name} |
8 | Assignee: #{@merge_request.assignee_name} | 8 | Assignee: #{@merge_request.assignee_name} |
app/views/notify/merged_merge_request_email.html.haml
1 | %p | 1 | %p |
2 | = "Merge Request #{@merge_request.id} was merged" | 2 | = "Merge Request #{@merge_request.id} was merged" |
3 | %p | 3 | %p |
4 | - = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | 4 | + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.target_project, @merge_request) |
5 | %p | 5 | %p |
6 | - Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | 6 | + Projects:Branches: #{@merge_request.source_project.path_with_namespace}:#{@merge_request.source_branch} → #{@merge_request.target_project.path_with_namespace}:#{@merge_request.target_branch} |
7 | %p | 7 | %p |
8 | Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | 8 | Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} |
9 | 9 |
app/views/notify/merged_merge_request_email.text.haml
1 | = "Merge Request #{@merge_request.id} was merged" | 1 | = "Merge Request #{@merge_request.id} was merged" |
2 | 2 | ||
3 | -Merge Request Url: #{project_merge_request_url(@merge_request.project, @merge_request)} | 3 | +Merge Request Url: #{project_merge_request_url(@merge_request.target_project, @merge_request)} |
4 | 4 | ||
5 | -Branches: #{@merge_request.source_branch} - #{@merge_request.target_branch} | 5 | +Project:Branches: #{@merge_request.source_project.path_with_namespace}/#{@merge_request.source_branch} - #{@merge_request.target_project.path_with_namespace}#{@merge_request.target_branch} |
6 | 6 | ||
7 | Author: #{@merge_request.author_name} | 7 | Author: #{@merge_request.author_name} |
8 | Assignee: #{@merge_request.assignee_name} | 8 | Assignee: #{@merge_request.assignee_name} |
app/views/notify/new_merge_request_email.html.haml
1 | %p | 1 | %p |
2 | = "New Merge Request !#{@merge_request.id}" | 2 | = "New Merge Request !#{@merge_request.id}" |
3 | %p | 3 | %p |
4 | - = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.project, @merge_request) | 4 | + = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.target_project, @merge_request) |
5 | %p | 5 | %p |
6 | - Branches: #{@merge_request.source_branch} → #{@merge_request.target_branch} | 6 | + Project:Branches: #{@merge_request.source_project.path_with_namespace}/#{@merge_request.source_branch} - #{@merge_request.target_project.path_with_namespace}#{@merge_request.target_branch} |
7 | %p | 7 | %p |
8 | Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} | 8 | Assignee: #{@merge_request.author_name} → #{@merge_request.assignee_name} |
9 | 9 |
app/views/notify/new_merge_request_email.text.erb
1 | New Merge Request <%= @merge_request.id %> | 1 | New Merge Request <%= @merge_request.id %> |
2 | 2 | ||
3 | -<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %> | ||
4 | - | 3 | +<%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %> |
5 | 4 | ||
6 | -Branches: <%= @merge_request.source_branch %> to <%= @merge_request.target_branch %> | 5 | +From: <%= @merge_request.source_project.path_with_namespace%>:<%= @merge_request.source_branch %> to <%= @merge_request.target_project.path_with_namespace%>:<%= @merge_request.target_branch %> |
7 | Author: <%= @merge_request.author_name %> | 6 | Author: <%= @merge_request.author_name %> |
8 | Asignee: <%= @merge_request.assignee_name %> | 7 | Asignee: <%= @merge_request.assignee_name %> |
9 | 8 |
app/views/notify/note_merge_request_email.html.haml
1 | %p | 1 | %p |
2 | - if @note.for_diff_line? | 2 | - if @note.for_diff_line? |
3 | - = link_to "New comment on diff", diffs_project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") | 3 | + = link_to "New comment on diff", diffs_project_merge_request_url(@merge_request.target_project, @merge_request, anchor: "note_#{@note.id}") |
4 | - else | 4 | - else |
5 | - = link_to "New comment", project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}") | 5 | + = link_to "New comment", project_merge_request_url(@merge_request.target_project, @merge_request, anchor: "note_#{@note.id}") |
6 | for Merge Request ##{@merge_request.id} | 6 | for Merge Request ##{@merge_request.id} |
7 | %cite "#{truncate(@merge_request.title, length: 20)}" | 7 | %cite "#{truncate(@merge_request.title, length: 20)}" |
8 | = render 'note_message' | 8 | = render 'note_message' |
app/views/notify/note_merge_request_email.text.erb
1 | New comment for Merge Request <%= @merge_request.id %> | 1 | New comment for Merge Request <%= @merge_request.id %> |
2 | 2 | ||
3 | -<%= url_for(project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}")) %> | 3 | +<%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request, anchor: "note_#{@note.id}")) %> |
4 | 4 | ||
5 | 5 | ||
6 | <%= @note.author_name %> | 6 | <%= @note.author_name %> |
app/views/notify/reassigned_merge_request_email.html.haml
1 | %p | 1 | %p |
2 | = "Reassigned Merge Request !#{@merge_request.id}" | 2 | = "Reassigned Merge Request !#{@merge_request.id}" |
3 | - = link_to_gfm truncate(@merge_request.title, length: 30), project_merge_request_url(@merge_request.project, @merge_request) | 3 | + = link_to_gfm truncate(@merge_request.title, length: 30), project_merge_request_url(@merge_request.target_project, @merge_request) |
4 | %p | 4 | %p |
5 | Assignee changed | 5 | Assignee changed |
6 | - if @previous_assignee | 6 | - if @previous_assignee |
app/views/notify/reassigned_merge_request_email.text.erb
1 | Reassigned Merge Request <%= @merge_request.id %> | 1 | Reassigned Merge Request <%= @merge_request.id %> |
2 | 2 | ||
3 | -<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %> | 3 | +<%= url_for(project_merge_request_url(@merge_request.target_project, @merge_request)) %> |
4 | 4 | ||
5 | 5 | ||
6 | Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee %> to <%= @merge_request.assignee_name %> | 6 | Assignee changed <%= "from #{@previous_assignee.name}" if @previous_assignee %> to <%= @merge_request.assignee_name %> |
app/views/projects/commits/_commit.html.haml
1 | %li.commit | 1 | %li.commit |
2 | .browse_code_link_holder | 2 | .browse_code_link_holder |
3 | %p | 3 | %p |
4 | - %strong= link_to "Browse Code »", project_tree_path(@project, commit), class: "right" | 4 | + %strong= link_to "Browse Code »", project_tree_path(project, commit), class: "right" |
5 | %p | 5 | %p |
6 | - = link_to commit.short_id(8), project_commit_path(@project, commit), class: "commit_short_id" | 6 | + = link_to commit.short_id(8), project_commit_path(project, commit), class: "commit_short_id" |
7 | = commit_author_link(commit, avatar: true, size: 24) | 7 | = commit_author_link(commit, avatar: true, size: 24) |
8 | | 8 | |
9 | - = link_to_gfm truncate(commit.title, length: 70), project_commit_path(@project, commit.id), class: "row_title" | 9 | + = link_to_gfm truncate(commit.title, length: 70), project_commit_path(project, commit.id), class: "row_title" |
10 | 10 | ||
11 | %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") } | 11 | %time.committed_ago{ datetime: commit.committed_date, title: commit.committed_date.stamp("Aug 21, 2011 9:23pm") } |
12 | = time_ago_in_words(commit.committed_date) | 12 | = time_ago_in_words(commit.committed_date) |
@@ -14,7 +14,7 @@ | @@ -14,7 +14,7 @@ | ||
14 | | 14 | |
15 | 15 | ||
16 | %span.notes_count | 16 | %span.notes_count |
17 | - - notes = @project.notes.for_commit_id(commit.id) | 17 | + - notes = project.notes.for_commit_id(commit.id) |
18 | - if notes.any? | 18 | - if notes.any? |
19 | %span.badge.badge-info | 19 | %span.badge.badge-info |
20 | %i.icon-comment | 20 | %i.icon-comment |
app/views/projects/commits/_commits.html.haml
@@ -3,7 +3,6 @@ | @@ -3,7 +3,6 @@ | ||
3 | .title | 3 | .title |
4 | %i.icon-calendar | 4 | %i.icon-calendar |
5 | %span= day.stamp("28 Aug, 2010") | 5 | %span= day.stamp("28 Aug, 2010") |
6 | - | ||
7 | .pull-right | 6 | .pull-right |
8 | %small= pluralize(commits.count, 'commit') | 7 | %small= pluralize(commits.count, 'commit') |
9 | - %ul.well-list= render commits | 8 | + %ul.well-list= render commits, :project => @project |
app/views/projects/compare/show.html.haml
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | %div.ui-box | 15 | %div.ui-box |
16 | .title | 16 | .title |
17 | Commits (#{@commits.count}) | 17 | Commits (#{@commits.count}) |
18 | - %ul.well-list= render Commit.decorate(@commits) | 18 | + %ul.well-list= render Commit.decorate(@commits), project: @project |
19 | 19 | ||
20 | - unless @diffs.empty? | 20 | - unless @diffs.empty? |
21 | %h4 Diff | 21 | %h4 Diff |
app/views/projects/merge_requests/_form.html.haml
1 | -= form_for [@project, @merge_request], html: { class: "#{controller.action_name}-merge-request form-horizontal" } do |f| | 1 | += form_for [@project, @merge_request], html: { class: "#{controller.action_name}-merge-request form-horizontal" } do |form_helper| |
2 | -if @merge_request.errors.any? | 2 | -if @merge_request.errors.any? |
3 | .alert.alert-error | 3 | .alert.alert-error |
4 | %ul | 4 | %ul |
@@ -12,18 +12,20 @@ | @@ -12,18 +12,20 @@ | ||
12 | .row | 12 | .row |
13 | .span5 | 13 | .span5 |
14 | .light-well | 14 | .light-well |
15 | - %h5.cgray From (Head Branch) | ||
16 | - = f.select(:source_branch, @repository.branch_names, { include_blank: "Select branch" }, {class: 'chosen span4'}) | 15 | + %h5.cgray From |
16 | + .padded= form_helper.select(:source_project_id,[[@merge_request.source_project.path_with_namespace,@merge_request.source_project.id]] , {}, {class: 'source_project chosen span4'}) | ||
17 | + .padded= form_helper.select(:source_branch, @merge_request.source_project.repository.branch_names, { include_blank: "Select branch" }, {class: 'source_branch chosen span4'}) | ||
17 | .mr_source_commit.prepend-top-10 | 18 | .mr_source_commit.prepend-top-10 |
18 | - | ||
19 | .span2 | 19 | .span2 |
20 | %h1.merge-request-angle | 20 | %h1.merge-request-angle |
21 | %i.icon-angle-right | 21 | %i.icon-angle-right |
22 | .span5 | 22 | .span5 |
23 | .light-well | 23 | .light-well |
24 | - %h5.cgray To (Base Branch) | ||
25 | - = f.select(:target_branch, @repository.branch_names, { include_blank: "Select branch" }, {class: 'chosen span4'}) | ||
26 | - .mr_target_commit.prepend-top-10 | 24 | + %h5.cgray To |
25 | + - projects = @project.forked_from_project.nil? ? [@project] : [ @project,@project.forked_from_project] | ||
26 | + .padded= form_helper.select(:target_project_id, projects.map { |proj| [proj.path_with_namespace,proj.id] }, {include_blank: "Select Target Project" }, {class: 'target_project chosen span4'}) | ||
27 | + .padded= form_helper.select(:target_branch, @target_branches, { include_blank: "Select branch" }, {class: 'target_branch chosen span4'}) | ||
28 | + .mr_target_commit.prepend-top-10 | ||
27 | 29 | ||
28 | %hr | 30 | %hr |
29 | 31 | ||
@@ -47,12 +49,11 @@ | @@ -47,12 +49,11 @@ | ||
47 | Milestone | 49 | Milestone |
48 | .input= f.select(:milestone_id, @project.milestones.active.all.map {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) | 50 | .input= f.select(:milestone_id, @project.milestones.active.all.map {|p| [ p.title, p.id ] }, { include_blank: "Select milestone" }, {class: 'chosen'}) |
49 | 51 | ||
50 | - | ||
51 | .form-actions | 52 | .form-actions |
52 | - if @merge_request.new_record? | 53 | - if @merge_request.new_record? |
53 | - = f.submit 'Submit merge request', class: "btn btn-create" | 54 | + = form_helper.submit 'Submit merge request', class: "btn btn-create" |
54 | -else | 55 | -else |
55 | - = f.submit 'Save changes', class: "btn btn-save" | 56 | + = form_helper.submit 'Save changes', class: "btn btn-save" |
56 | - if @merge_request.new_record? | 57 | - if @merge_request.new_record? |
57 | = link_to project_merge_requests_path(@project), class: "btn btn-cancel" do | 58 | = link_to project_merge_requests_path(@project), class: "btn btn-cancel" do |
58 | Cancel | 59 | Cancel |
@@ -63,16 +64,23 @@ | @@ -63,16 +64,23 @@ | ||
63 | :javascript | 64 | :javascript |
64 | disableButtonIfEmptyField("#merge_request_title", ".btn-save"); | 65 | disableButtonIfEmptyField("#merge_request_title", ".btn-save"); |
65 | 66 | ||
66 | - var source_branch = $("#merge_request_source_branch") | ||
67 | - , target_branch = $("#merge_request_target_branch"); | 67 | + var source_branch = $("#merge_request_source_branch") |
68 | + , target_branch = $("#merge_request_target_branch") | ||
69 | + , target_project = $("#merge_request_target_project_id"); | ||
68 | 70 | ||
69 | - $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); | ||
70 | - $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: target_branch.val() }); | 71 | + $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: source_branch.val() }); |
72 | + $.get("#{branch_to_project_merge_requests_path(@project)}", {target_project_id: target_project.val(),ref: target_branch.val() }); | ||
71 | 73 | ||
72 | - source_branch.live("change", function() { | ||
73 | - $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: $(this).val() }); | ||
74 | - }); | 74 | + target_project.live("change", function() { |
75 | + $.get("#{update_branches_project_merge_requests_path(@project)}", {target_project_id: $(this).val() }); | ||
76 | + }); | ||
77 | + source_branch.live("change", function() { | ||
78 | + $.get("#{branch_from_project_merge_requests_path(@project)}", {ref: $(this).val() }); | ||
79 | + }); | ||
80 | + target_branch.live("change", function() { | ||
81 | + $.get("#{branch_to_project_merge_requests_path(@project)}", {target_project_id: target_project.val(),ref: $(this).val() }); | ||
82 | + }); | ||
75 | 83 | ||
76 | - target_branch.live("change", function() { | ||
77 | - $.get("#{branch_to_project_merge_requests_path(@project)}", {ref: $(this).val() }); | ||
78 | }); | 84 | }); |
85 | + | ||
86 | + |
app/views/projects/merge_requests/_merge_request.html.haml
1 | %li{ class: mr_css_classes(merge_request) } | 1 | %li{ class: mr_css_classes(merge_request) } |
2 | .merge-request-title | 2 | .merge-request-title |
3 | %span.light= "##{merge_request.id}" | 3 | %span.light= "##{merge_request.id}" |
4 | - = link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.project, merge_request), class: "row_title" | 4 | + = link_to_gfm truncate(merge_request.title, length: 80), project_merge_request_path(merge_request.target_project, merge_request), class: "row_title" |
5 | - if merge_request.merged? | 5 | - if merge_request.merged? |
6 | %small.pull-right | 6 | %small.pull-right |
7 | %i.icon-ok | 7 | %i.icon-ok |
8 | = "MERGED" | 8 | = "MERGED" |
9 | - else | 9 | - else |
10 | %span.pull-right | 10 | %span.pull-right |
11 | + = "#{merge_request.source_project.path_with_namespace}/#{merge_request.source_branch}" | ||
11 | %i.icon-angle-right | 12 | %i.icon-angle-right |
12 | - = merge_request.target_branch | 13 | + = "#{merge_request.target_project.path_with_namespace}/#{merge_request.target_branch}" |
13 | .merge-request-info | 14 | .merge-request-info |
14 | - if merge_request.author | 15 | - if merge_request.author |
15 | - authored by #{link_to_member(@project, merge_request.author)} | 16 | + authored by #{link_to_member(merge_request.source_project, merge_request.author)} |
16 | - if merge_request.votes_count > 0 | 17 | - if merge_request.votes_count > 0 |
17 | = render 'votes/votes_inline', votable: merge_request | 18 | = render 'votes/votes_inline', votable: merge_request |
18 | - if merge_request.notes.any? | 19 | - if merge_request.notes.any? |
app/views/projects/merge_requests/branch_from.js.haml
app/views/projects/merge_requests/branch_to.js.haml
app/views/projects/merge_requests/show/_commits.html.haml
@@ -7,19 +7,19 @@ | @@ -7,19 +7,19 @@ | ||
7 | - if @commits.count > 8 | 7 | - if @commits.count > 8 |
8 | %ul.first-commits.well-list | 8 | %ul.first-commits.well-list |
9 | - @commits.first(8).each do |commit| | 9 | - @commits.first(8).each do |commit| |
10 | - = render "projects/commits/commit", commit: commit | 10 | + = render "projects/commits/commit", commit: commit, project: @merge_request.source_project |
11 | %li.bottom | 11 | %li.bottom |
12 | 8 of #{@commits.count} commits displayed. | 12 | 8 of #{@commits.count} commits displayed. |
13 | %strong | 13 | %strong |
14 | %a.show-all-commits Click here to show all | 14 | %a.show-all-commits Click here to show all |
15 | %ul.all-commits.hide.well-list | 15 | %ul.all-commits.hide.well-list |
16 | - @commits.each do |commit| | 16 | - @commits.each do |commit| |
17 | - = render "projects/commits/commit", commit: commit | 17 | + = render "projects/commits/commit", commit: commit, project: @merge_request.source_project |
18 | 18 | ||
19 | - else | 19 | - else |
20 | %ul.well-list | 20 | %ul.well-list |
21 | - @commits.each do |commit| | 21 | - @commits.each do |commit| |
22 | - = render "projects/commits/commit", commit: commit | 22 | + = render "projects/commits/commit", commit: commit, project: @merge_request.source_project |
23 | 23 | ||
24 | - else | 24 | - else |
25 | %h4.nothing_here_message | 25 | %h4.nothing_here_message |
app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -3,17 +3,49 @@ | @@ -3,17 +3,49 @@ | ||
3 | %a.close{href: "#"} × | 3 | %a.close{href: "#"} × |
4 | %h3 How To Merge | 4 | %h3 How To Merge |
5 | .modal-body | 5 | .modal-body |
6 | - %p | ||
7 | - %strong Step 1. | ||
8 | - Checkout target branch and get recent objects from GitLab | ||
9 | - %pre.dark | ||
10 | - :preserve | ||
11 | - git checkout #{@merge_request.target_branch} | ||
12 | - git fetch origin | ||
13 | - %p | ||
14 | - %strong Step 2. | ||
15 | - Merge source branch into target branch and push changes to GitLab | ||
16 | - %pre.dark | ||
17 | - :preserve | ||
18 | - git merge origin/#{@merge_request.source_branch} | ||
19 | - git push origin #{@merge_request.target_branch} | 6 | + - if @merge_request.for_fork? |
7 | + - source_remote = @merge_request.source_project.namespace.nil? ? "source" :@merge_request.source_project.namespace.path | ||
8 | + - target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path | ||
9 | + %p | ||
10 | + %strong Step 1. | ||
11 | + Checkout target branch and get recent objects from GitLab | ||
12 | + Assuming remote for #{@merge_request.target_project.path_with_namespace} is called #{target_remote} | ||
13 | + remote for #{@merge_request.source_project.path_with_namespace} is called #{source_remote} | ||
14 | + %pre.dark | ||
15 | + :preserve | ||
16 | + git checkout #{target_remote} #{@merge_request.target_branch} | ||
17 | + git fetch #{source_remote} | ||
18 | + %p | ||
19 | + %strong Step 2. | ||
20 | + Merge source branch into target branch and push changes to GitLab | ||
21 | + %pre.dark | ||
22 | + :preserve | ||
23 | + git merge #{source_remote}/#{@merge_request.source_branch} | ||
24 | + git push #{target_remote} #{@merge_request.target_branch} | ||
25 | + - else | ||
26 | + %p | ||
27 | + %strong Step 1. | ||
28 | + Checkout target branch and get recent objects from GitLab | ||
29 | + %pre.dark | ||
30 | + :preserve | ||
31 | + git checkout #{@merge_request.target_branch} | ||
32 | + git fetch origin | ||
33 | + %p | ||
34 | + %strong Step 2. | ||
35 | + Merge source branch into target branch and push changes to GitLab | ||
36 | + %pre.dark | ||
37 | + :preserve | ||
38 | + git merge origin/#{@merge_request.source_branch} | ||
39 | + git push origin #{@merge_request.target_branch} | ||
40 | + | ||
41 | + | ||
42 | +:javascript | ||
43 | + $(function(){ | ||
44 | + var modal = $('#modal_merge_info').modal({modal: true, show:false}); | ||
45 | + $('.how_to_merge_link').bind("click", function(){ | ||
46 | + modal.show(); | ||
47 | + }); | ||
48 | + $('.modal-header .close').bind("click", function(){ | ||
49 | + modal.hide(); | ||
50 | + }) | ||
51 | + }) |
app/views/projects/merge_requests/show/_mr_accept.html.haml
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | for instructions | 15 | for instructions |
16 | .accept_group | 16 | .accept_group |
17 | = f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request" | 17 | = f.submit "Accept Merge Request", class: "btn btn-create accept_merge_request" |
18 | - - unless @project.root_ref? @merge_request.source_branch | 18 | + - unless @merge_request.disallow_source_branch_removal? |
19 | .remove_branch_holder | 19 | .remove_branch_holder |
20 | = label_tag :should_remove_source_branch, class: "checkbox" do | 20 | = label_tag :should_remove_source_branch, class: "checkbox" do |
21 | = check_box_tag :should_remove_source_branch | 21 | = check_box_tag :should_remove_source_branch |
app/views/projects/merge_requests/show/_mr_title.html.haml
1 | %h3.page-title | 1 | %h3.page-title |
2 | = "Merge Request ##{@merge_request.id}:" | 2 | = "Merge Request ##{@merge_request.id}:" |
3 | | 3 | |
4 | + %span.label-project= @merge_request.source_project.path_with_namespace | ||
4 | %span.label-branch= @merge_request.source_branch | 5 | %span.label-branch= @merge_request.source_branch |
5 | → | 6 | → |
7 | + %span.label-project= @merge_request.target_project.path_with_namespace | ||
6 | %span.label-branch= @merge_request.target_branch | 8 | %span.label-branch= @merge_request.target_branch |
7 | 9 | ||
8 | %span.pull-right | 10 | %span.pull-right |
app/views/search/_result.html.haml
@@ -22,11 +22,11 @@ | @@ -22,11 +22,11 @@ | ||
22 | - @merge_requests.each do |merge_request| | 22 | - @merge_requests.each do |merge_request| |
23 | %li | 23 | %li |
24 | merge request: | 24 | merge request: |
25 | - = link_to [merge_request.project, merge_request] do | 25 | + = link_to [merge_request.target_project, merge_request] do |
26 | %span ##{merge_request.id} | 26 | %span ##{merge_request.id} |
27 | %strong.term | 27 | %strong.term |
28 | = truncate merge_request.title, length: 50 | 28 | = truncate merge_request.title, length: 50 |
29 | - %span.light (#{merge_request.project.name_with_namespace}) | 29 | + %span.light (#{merge_request.source_project.name_with_namespace}:#{merge_request.source_branch} → #{merge_request.target_project.name_with_namespace}:#{merge_request.target_branch}) |
30 | - @issues.each do |issue| | 30 | - @issues.each do |issue| |
31 | %li | 31 | %li |
32 | issue: | 32 | issue: |
app/views/shared/_merge_requests.html.haml
config/routes.rb
db/fixtures/development/10_merge_requests.rb
@@ -23,7 +23,8 @@ Gitlab::Seeder.quiet do | @@ -23,7 +23,8 @@ Gitlab::Seeder.quiet do | ||
23 | id: i, | 23 | id: i, |
24 | source_branch: branches.first, | 24 | source_branch: branches.first, |
25 | target_branch: branches.last, | 25 | target_branch: branches.last, |
26 | - project_id: project.id, | 26 | + source_project_id: project.id, |
27 | + target_project_id: project.id, | ||
27 | author_id: user_id, | 28 | author_id: user_id, |
28 | assignee_id: user_id, | 29 | assignee_id: user_id, |
29 | milestone: project.milestones.sample, | 30 | milestone: project.milestones.sample, |
db/fixtures/test/001_repo.rb
@@ -19,5 +19,15 @@ FileUtils.cd(REPO_PATH) do | @@ -19,5 +19,15 @@ FileUtils.cd(REPO_PATH) do | ||
19 | # Remove the copy | 19 | # Remove the copy |
20 | FileUtils.rm(SEED_REPO) | 20 | FileUtils.rm(SEED_REPO) |
21 | end | 21 | end |
22 | +puts ' done.' | ||
23 | +print "Creating seed satellite..." | ||
22 | 24 | ||
25 | +SATELLITE_PATH = Rails.root.join('tmp', 'satellite') | ||
26 | +# Make directory | ||
27 | +FileUtils.mkdir_p(SATELLITE_PATH) | ||
28 | +# Chdir, clone from the seed | ||
29 | +FileUtils.cd(SATELLITE_PATH) do | ||
30 | + # Clone the satellite | ||
31 | + `git clone --quiet #{REPO_PATH}/gitlabhq #{SATELLITE_PATH}/gitlabhq` | ||
32 | +end | ||
23 | puts ' done.' | 33 | puts ' done.' |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +class AllowMergesForForks < ActiveRecord::Migration | ||
2 | + | ||
3 | + def self.up | ||
4 | + add_column :merge_requests, :target_project_id, :integer, :null => false | ||
5 | + MergeRequest.connection.execute("update merge_requests set target_project_id=project_id") | ||
6 | + rename_column :merge_requests, :project_id, :source_project_id | ||
7 | + end | ||
8 | + | ||
9 | + def self.down | ||
10 | + remove_column :merge_requests, :target_project_id | ||
11 | + rename_column :merge_requests, :source_project_id,:project_id | ||
12 | + end | ||
13 | + | ||
14 | +end |
db/schema.rb
@@ -84,9 +84,9 @@ ActiveRecord::Schema.define(:version => 20130624162710) do | @@ -84,9 +84,9 @@ ActiveRecord::Schema.define(:version => 20130624162710) do | ||
84 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" | 84 | add_index "keys", ["user_id"], :name => "index_keys_on_user_id" |
85 | 85 | ||
86 | create_table "merge_requests", :force => true do |t| | 86 | create_table "merge_requests", :force => true do |t| |
87 | - t.string "target_branch", :null => false | ||
88 | - t.string "source_branch", :null => false | ||
89 | - t.integer "project_id", :null => false | 87 | + t.string "target_branch", :null => false |
88 | + t.string "source_branch", :null => false | ||
89 | + t.integer "source_project_id", :null => false | ||
90 | t.integer "author_id" | 90 | t.integer "author_id" |
91 | t.integer "assignee_id" | 91 | t.integer "assignee_id" |
92 | t.string "title" | 92 | t.string "title" |
@@ -97,14 +97,15 @@ ActiveRecord::Schema.define(:version => 20130624162710) do | @@ -97,14 +97,15 @@ ActiveRecord::Schema.define(:version => 20130624162710) do | ||
97 | t.integer "milestone_id" | 97 | t.integer "milestone_id" |
98 | t.string "state" | 98 | t.string "state" |
99 | t.string "merge_status" | 99 | t.string "merge_status" |
100 | + t.integer "target_project_id", :null => false | ||
100 | end | 101 | end |
101 | 102 | ||
102 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" | 103 | add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" |
103 | add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" | 104 | add_index "merge_requests", ["author_id"], :name => "index_merge_requests_on_author_id" |
104 | add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" | 105 | add_index "merge_requests", ["created_at"], :name => "index_merge_requests_on_created_at" |
105 | add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" | 106 | add_index "merge_requests", ["milestone_id"], :name => "index_merge_requests_on_milestone_id" |
106 | - add_index "merge_requests", ["project_id"], :name => "index_merge_requests_on_project_id" | ||
107 | add_index "merge_requests", ["source_branch"], :name => "index_merge_requests_on_source_branch" | 107 | add_index "merge_requests", ["source_branch"], :name => "index_merge_requests_on_source_branch" |
108 | + add_index "merge_requests", ["source_project_id"], :name => "index_merge_requests_on_project_id" | ||
108 | add_index "merge_requests", ["target_branch"], :name => "index_merge_requests_on_target_branch" | 109 | add_index "merge_requests", ["target_branch"], :name => "index_merge_requests_on_target_branch" |
109 | add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" | 110 | add_index "merge_requests", ["title"], :name => "index_merge_requests_on_title" |
110 | 111 |
features/dashboard/dashboard.feature
@@ -16,6 +16,7 @@ Feature: Dashboard | @@ -16,6 +16,7 @@ Feature: Dashboard | ||
16 | And I visit dashboard page | 16 | And I visit dashboard page |
17 | Then I should see groups list | 17 | Then I should see groups list |
18 | 18 | ||
19 | + @javascript | ||
19 | Scenario: I should see last push widget | 20 | Scenario: I should see last push widget |
20 | Then I should see last push widget | 21 | Then I should see last push widget |
21 | And I click "Create Merge Request" link | 22 | And I click "Create Merge Request" link |
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +Feature: Project Forked Merge Requests | ||
2 | + Background: | ||
3 | + Given I sign in as a user | ||
4 | + And I am a member of project "Shop" | ||
5 | + And I have a project forked off of "Shop" called "Forked Shop" | ||
6 | + | ||
7 | + | ||
8 | + @javascript | ||
9 | + Scenario: I can visit the target projects commit for a forked merge request | ||
10 | + Given I visit project "Forked Shop" merge requests page | ||
11 | + And I click link "New Merge Request" | ||
12 | + And I fill out a "Merge Request On Forked Project" merge request | ||
13 | + And I follow the target commit link | ||
14 | + Then I should see the commit under the forked from project | ||
15 | + | ||
16 | + Scenario: I submit new unassigned merge request to a forked project | ||
17 | + Given I visit project "Forked Shop" merge requests page | ||
18 | + And I click link "New Merge Request" | ||
19 | + And I fill out a "Merge Request On Forked Project" merge request | ||
20 | + And I submit the merge request | ||
21 | + Then I should see merge request "Merge Request On Forked Project" | ||
22 | + | ||
23 | + | ||
24 | + Scenario: I should see a push widget for forked merge requests | ||
25 | + Given project "Forked Shop" has push event | ||
26 | + And I visit dashboard page | ||
27 | + Then I should see last push widget | ||
28 | + And I click "Create Merge Request on fork" link | ||
29 | + Then I see prefilled new Merge Request page for the forked project | ||
30 | + | ||
31 | + | ||
32 | + Scenario: I can edit a forked merge request | ||
33 | + Given I visit project "Forked Shop" merge requests page | ||
34 | + And I click link "New Merge Request" | ||
35 | + And I fill out a "Merge Request On Forked Project" merge request | ||
36 | + And I submit the merge request | ||
37 | + And I should see merge request "Merge Request On Forked Project" | ||
38 | + And I click link edit "Merge Request On Forked Project" | ||
39 | + Then I see prefilled "Merge Request On Forked Project" | ||
40 | + | ||
41 | + |
features/project/merge_requests.feature
@@ -29,6 +29,7 @@ Feature: Project Merge Requests | @@ -29,6 +29,7 @@ Feature: Project Merge Requests | ||
29 | And I click link "Close" | 29 | And I click link "Close" |
30 | Then I should see closed merge request "Bug NS-04" | 30 | Then I should see closed merge request "Bug NS-04" |
31 | 31 | ||
32 | + @javascript | ||
32 | Scenario: I submit new unassigned merge request | 33 | Scenario: I submit new unassigned merge request |
33 | Given I click link "New Merge Request" | 34 | Given I click link "New Merge Request" |
34 | And I submit new merge request "Wiki Feature" | 35 | And I submit new merge request "Wiki Feature" |
features/steps/dashboard/dashboard.rb
@@ -22,6 +22,7 @@ class Dashboard < Spinach::FeatureSteps | @@ -22,6 +22,7 @@ class Dashboard < Spinach::FeatureSteps | ||
22 | 22 | ||
23 | Then 'I see prefilled new Merge Request page' do | 23 | Then 'I see prefilled new Merge Request page' do |
24 | current_path.should == new_project_merge_request_path(@project) | 24 | current_path.should == new_project_merge_request_path(@project) |
25 | + find("#merge_request_target_project_id").value.should == @project.id.to_s | ||
25 | find("#merge_request_source_branch").value.should == "new_design" | 26 | find("#merge_request_source_branch").value.should == "new_design" |
26 | find("#merge_request_target_branch").value.should == "master" | 27 | find("#merge_request_target_branch").value.should == "master" |
27 | find("#merge_request_title").value.should == "New Design" | 28 | find("#merge_request_title").value.should == "New Design" |
features/steps/dashboard/dashboard_event_filters.rb
@@ -61,7 +61,7 @@ class EventFilters < Spinach::FeatureSteps | @@ -61,7 +61,7 @@ class EventFilters < Spinach::FeatureSteps | ||
61 | end | 61 | end |
62 | 62 | ||
63 | And 'this project has merge request event' do | 63 | And 'this project has merge request event' do |
64 | - merge_request = create :merge_request, author: @user, project: @project | 64 | + merge_request = create :merge_request, author: @user, source_project: @project, target_project: @project |
65 | Event.create( | 65 | Event.create( |
66 | project: @project, | 66 | project: @project, |
67 | action: Event::MERGED, | 67 | action: Event::MERGED, |
features/steps/dashboard/dashboard_merge_requests.rb
@@ -6,18 +6,24 @@ class DashboardMergeRequests < Spinach::FeatureSteps | @@ -6,18 +6,24 @@ class DashboardMergeRequests < Spinach::FeatureSteps | ||
6 | merge_requests = @user.merge_requests | 6 | merge_requests = @user.merge_requests |
7 | merge_requests.each do |mr| | 7 | merge_requests.each do |mr| |
8 | page.should have_content(mr.title[0..10]) | 8 | page.should have_content(mr.title[0..10]) |
9 | - page.should have_content(mr.project.name) | 9 | + page.should have_content(mr.target_project.name) |
10 | + page.should have_content(mr.source_project.name) | ||
10 | end | 11 | end |
11 | end | 12 | end |
12 | 13 | ||
13 | And 'I have authored merge requests' do | 14 | And 'I have authored merge requests' do |
14 | - project1 = create :project | ||
15 | - project2 = create :project | 15 | + project1_source = create :project |
16 | + project1_target= create :project | ||
17 | + project2_source = create :project | ||
18 | + project2_target = create :project | ||
16 | 19 | ||
17 | - project1.team << [@user, :master] | ||
18 | - project2.team << [@user, :master] | ||
19 | 20 | ||
20 | - merge_request1 = create :merge_request, author: @user, project: project1 | ||
21 | - merge_request2 = create :merge_request, author: @user, project: project2 | 21 | + project1_source.team << [@user, :master] |
22 | + project1_target.team << [@user, :master] | ||
23 | + project2_source.team << [@user, :master] | ||
24 | + project2_target.team << [@user, :master] | ||
25 | + | ||
26 | + merge_request1 = create :merge_request, author: @user, source_project: project1_source, target_project: project1_target | ||
27 | + merge_request2 = create :merge_request, author: @user, source_project: project2_source, target_project: project2_target | ||
22 | end | 28 | end |
23 | end | 29 | end |
features/steps/group/group.rb
@@ -60,7 +60,8 @@ class Groups < Spinach::FeatureSteps | @@ -60,7 +60,8 @@ class Groups < Spinach::FeatureSteps | ||
60 | 60 | ||
61 | Given 'project from group has merge requests assigned to me' do | 61 | Given 'project from group has merge requests assigned to me' do |
62 | create :merge_request, | 62 | create :merge_request, |
63 | - project: project, | 63 | + source_project: project, |
64 | + target_project: project, | ||
64 | assignee: current_user, | 65 | assignee: current_user, |
65 | author: current_user | 66 | author: current_user |
66 | end | 67 | end |
features/steps/project/deploy_keys.rb
@@ -3,10 +3,13 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps | @@ -3,10 +3,13 @@ class Spinach::Features::ProjectDeployKeys < Spinach::FeatureSteps | ||
3 | include SharedProject | 3 | include SharedProject |
4 | include SharedPaths | 4 | include SharedPaths |
5 | 5 | ||
6 | + | ||
7 | + | ||
6 | step 'project has deploy key' do | 8 | step 'project has deploy key' do |
7 | create(:deploy_keys_project, project: @project) | 9 | create(:deploy_keys_project, project: @project) |
8 | end | 10 | end |
9 | 11 | ||
12 | + | ||
10 | step 'I should see project deploy keys' do | 13 | step 'I should see project deploy keys' do |
11 | within '.enabled-keys' do | 14 | within '.enabled-keys' do |
12 | page.should have_content deploy_key.title | 15 | page.should have_content deploy_key.title |
features/steps/project/project_fork.rb
@@ -4,6 +4,8 @@ class ForkProject < Spinach::FeatureSteps | @@ -4,6 +4,8 @@ class ForkProject < Spinach::FeatureSteps | ||
4 | include SharedProject | 4 | include SharedProject |
5 | 5 | ||
6 | step 'I click link "Fork"' do | 6 | step 'I click link "Fork"' do |
7 | + page.should have_content "Shop" | ||
8 | + page.should have_content "Fork" | ||
7 | Gitlab::Shell.any_instance.stub(:fork_repository).and_return(true) | 9 | Gitlab::Shell.any_instance.stub(:fork_repository).and_return(true) |
8 | click_link "Fork" | 10 | click_link "Fork" |
9 | end | 11 | end |
@@ -14,12 +16,17 @@ class ForkProject < Spinach::FeatureSteps | @@ -14,12 +16,17 @@ class ForkProject < Spinach::FeatureSteps | ||
14 | @project.team << [@user, :reporter] | 16 | @project.team << [@user, :reporter] |
15 | end | 17 | end |
16 | 18 | ||
19 | + | ||
17 | step 'I should see the forked project page' do | 20 | step 'I should see the forked project page' do |
18 | page.should have_content "Project was successfully forked." | 21 | page.should have_content "Project was successfully forked." |
19 | current_path.should include current_user.namespace.path | 22 | current_path.should include current_user.namespace.path |
23 | + @forked_project = Project.find_by_namespace_id(current_user.namespace.path) | ||
20 | end | 24 | end |
21 | 25 | ||
22 | step 'I already have a project named "Shop" in my namespace' do | 26 | step 'I already have a project named "Shop" in my namespace' do |
27 | + current_user.namespace ||= create(:namespace) | ||
28 | + current_user.namespace.should_not be_nil | ||
29 | + current_user.namespace.path.should_not be_nil | ||
23 | @my_project = create(:project_with_code, name: "Shop", namespace: current_user.namespace) | 30 | @my_project = create(:project_with_code, name: "Shop", namespace: current_user.namespace) |
24 | end | 31 | end |
25 | 32 |
@@ -0,0 +1,138 @@ | @@ -0,0 +1,138 @@ | ||
1 | +class ProjectForkedMergeRequests < Spinach::FeatureSteps | ||
2 | + include SharedAuthentication | ||
3 | + include SharedProject | ||
4 | + include SharedNote | ||
5 | + include SharedPaths | ||
6 | + | ||
7 | + | ||
8 | + Given 'I am a member of project "Shop"' do | ||
9 | + @project = Project.find_by_name "Shop" | ||
10 | + @project ||= create(:project_with_code, name: "Shop") | ||
11 | + @project.team << [@user, :reporter] | ||
12 | + end | ||
13 | + | ||
14 | + And 'I have a project forked off of "Shop" called "Forked Shop"' do | ||
15 | + @forking_user = @user | ||
16 | + forked_project_link = build(:forked_project_link) | ||
17 | + @forked_project = Project.find_by_name "Forked Shop" | ||
18 | + @forked_project ||= create(:source_project_with_code, name: "Forked Shop", forked_project_link: forked_project_link, creator_id: @forking_user.id) | ||
19 | + forked_project_link.forked_from_project = @project | ||
20 | + forked_project_link.forked_to_project = @forked_project | ||
21 | + forked_project_link.save! | ||
22 | + end | ||
23 | + | ||
24 | + | ||
25 | + Given 'I click link "New Merge Request"' do | ||
26 | + click_link "New Merge Request" | ||
27 | + end | ||
28 | + | ||
29 | + | ||
30 | + Then 'I should see merge request "Merge Request On Forked Project"' do | ||
31 | + page.should have_content "Merge Request On Forked Project" | ||
32 | + @project.merge_requests.size.should >= 1 | ||
33 | + @merge_request = @project.merge_requests.last | ||
34 | + current_path.should == project_merge_request_path(@project, @merge_request) | ||
35 | + @merge_request.title.should == "Merge Request On Forked Project" | ||
36 | + @merge_request.source_project.should == @forked_project | ||
37 | + end | ||
38 | + | ||
39 | + And 'I fill out a "Merge Request On Forked Project" merge request' do | ||
40 | + fill_in "merge_request_title", with: "Merge Request On Forked Project" | ||
41 | + find(:select, "merge_request_source_project_id", {}).value.should == @forked_project.id.to_s | ||
42 | + find(:select, "merge_request_target_project_id", {}).value.should == @forked_project.id.to_s | ||
43 | + | ||
44 | + select @project.path_with_namespace, from: "merge_request_target_project_id" | ||
45 | + find(:select, "merge_request_target_project_id", {}).value.should == @project.id.to_s | ||
46 | + | ||
47 | + select "master", from: "merge_request_source_branch" | ||
48 | + find(:select, "merge_request_source_branch", {}).value.should == "master" | ||
49 | + select "stable", from: "merge_request_target_branch" | ||
50 | + find(:select, "merge_request_target_branch", {}).value.should == "stable" | ||
51 | + end | ||
52 | + | ||
53 | + And 'I submit the merge request' do | ||
54 | + click_button "Submit merge request" | ||
55 | + end | ||
56 | + | ||
57 | + And 'I follow the target commit link' do | ||
58 | + commit = @project.repository.commit | ||
59 | + click_link commit.short_id(8) | ||
60 | + end | ||
61 | + | ||
62 | + Then 'I should see the commit under the forked from project' do | ||
63 | + commit = @project.repository.commit | ||
64 | + page.should have_content(commit.message) | ||
65 | + end | ||
66 | + | ||
67 | + And 'I click "Create Merge Request on fork" link' do | ||
68 | + click_link "Create Merge Request on fork" | ||
69 | + end | ||
70 | + | ||
71 | + Then 'I see prefilled new Merge Request page for the forked project' do | ||
72 | + current_path.should == new_project_merge_request_path(@forked_project) | ||
73 | + find("#merge_request_source_project_id").value.should == @forked_project.id.to_s | ||
74 | + find("#merge_request_target_project_id").value.should == @project.id.to_s | ||
75 | + find("#merge_request_source_branch").value.should == "new_design" | ||
76 | + find("#merge_request_target_branch").value.should == "master" | ||
77 | + find("#merge_request_title").value.should == "New Design" | ||
78 | + end | ||
79 | + | ||
80 | + Then 'I should see last push widget' do | ||
81 | + page.should have_content "You pushed to new_design" | ||
82 | + page.should have_link "Create Merge Request" | ||
83 | + end | ||
84 | + | ||
85 | + Given 'project "Forked Shop" has push event' do | ||
86 | + @forked_project = Project.find_by_name("Forked Shop") | ||
87 | + | ||
88 | + data = { | ||
89 | + before: "0000000000000000000000000000000000000000", | ||
90 | + after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", | ||
91 | + ref: "refs/heads/new_design", | ||
92 | + user_id: @user.id, | ||
93 | + user_name: @user.name, | ||
94 | + repository: { | ||
95 | + name: @forked_project.name, | ||
96 | + url: "localhost/rubinius", | ||
97 | + description: "", | ||
98 | + homepage: "localhost/rubinius", | ||
99 | + private: true | ||
100 | + } | ||
101 | + } | ||
102 | + | ||
103 | + @event = Event.create( | ||
104 | + project: @forked_project, | ||
105 | + action: Event::PUSHED, | ||
106 | + data: data, | ||
107 | + author_id: @user.id | ||
108 | + ) | ||
109 | + end | ||
110 | + | ||
111 | + | ||
112 | + Then 'I click link edit "Merge Request On Forked Project"' do | ||
113 | + #there are other edit buttons in this page for replies | ||
114 | +# links = page.all("a.btn.grouped") | ||
115 | +# links.each {|e|puts e.inspect } | ||
116 | + #TODO:[IA-08] there has got to be a better way to find this button -- there are multiple "Edit" buttons, so that won't work, maybe if we give it an explicit class in the haml | ||
117 | + #click_link "Edit" # doesn't work, multiple "Edit" buttons | ||
118 | + # find(:link, "a.btn:nth-child(3)").click | ||
119 | + # find(:link, "/html/body/div[2]/div/div/h3/span[5]/a[2]").click | ||
120 | + page.first(:xpath, "/html/body/div[2]/div/div/h3/span[5]/a[2]").click | ||
121 | + end | ||
122 | + | ||
123 | + Then 'I see prefilled "Merge Request On Forked Project"' do | ||
124 | + current_path.should == edit_project_merge_request_path(@project, @merge_request) | ||
125 | + page.should have_content "Edit merge request #{@merge_request.id}" | ||
126 | + find("#merge_request_source_project_id").value.should == @forked_project.id.to_s | ||
127 | + find("#merge_request_target_project_id").value.should == @project.id.to_s | ||
128 | + find("#merge_request_source_branch").value.should == "master" | ||
129 | + find("#merge_request_target_branch").value.should == "stable" | ||
130 | + find("#merge_request_title").value.should == "Merge Request On Forked Project" | ||
131 | + end | ||
132 | + | ||
133 | + | ||
134 | + def project | ||
135 | + @project ||= Project.find_by_name!("Shop") | ||
136 | + end | ||
137 | + | ||
138 | +end |
features/steps/project/project_merge_requests.rb
@@ -24,6 +24,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps | @@ -24,6 +24,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps | ||
24 | page.should have_content "Wiki Feature" | 24 | page.should have_content "Wiki Feature" |
25 | end | 25 | end |
26 | 26 | ||
27 | + | ||
27 | Then 'I should see closed merge request "Bug NS-04"' do | 28 | Then 'I should see closed merge request "Bug NS-04"' do |
28 | merge_request = MergeRequest.find_by_title!("Bug NS-04") | 29 | merge_request = MergeRequest.find_by_title!("Bug NS-04") |
29 | merge_request.closed?.should be_true | 30 | merge_request.closed?.should be_true |
@@ -56,30 +57,35 @@ class ProjectMergeRequests < Spinach::FeatureSteps | @@ -56,30 +57,35 @@ class ProjectMergeRequests < Spinach::FeatureSteps | ||
56 | end | 57 | end |
57 | 58 | ||
58 | And 'I submit new merge request "Wiki Feature"' do | 59 | And 'I submit new merge request "Wiki Feature"' do |
59 | - fill_in "merge_request_title", with: "Wiki Feature" | ||
60 | - select "bootstrap", from: "merge_request_source_branch" | ||
61 | - select "master", from: "merge_request_target_branch" | 60 | + fill_in "merge_request_title", :with => "Wiki Feature" |
61 | + select project.path_with_namespace, :from => "merge_request_target_project_id" | ||
62 | + select "master", :from => "merge_request_source_branch" | ||
63 | + select "stable", :from => "merge_request_target_branch" | ||
64 | + find(:select, "merge_request_target_branch", {}).find(:option, "stable", {}).value.should == "stable" | ||
62 | click_button "Submit merge request" | 65 | click_button "Submit merge request" |
63 | end | 66 | end |
64 | 67 | ||
65 | And 'project "Shop" have "Bug NS-04" open merge request' do | 68 | And 'project "Shop" have "Bug NS-04" open merge request' do |
66 | create(:merge_request, | 69 | create(:merge_request, |
67 | title: "Bug NS-04", | 70 | title: "Bug NS-04", |
68 | - project: project, | 71 | + source_project: project, |
72 | + target_project: project, | ||
69 | author: project.users.first) | 73 | author: project.users.first) |
70 | end | 74 | end |
71 | 75 | ||
72 | And 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do | 76 | And 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do |
73 | create(:merge_request_with_diffs, | 77 | create(:merge_request_with_diffs, |
74 | title: "Bug NS-05", | 78 | title: "Bug NS-05", |
75 | - project: project, | 79 | + source_project: project, |
80 | + target_project: project, | ||
76 | author: project.users.first) | 81 | author: project.users.first) |
77 | end | 82 | end |
78 | 83 | ||
79 | And 'project "Shop" have "Feature NS-03" closed merge request' do | 84 | And 'project "Shop" have "Feature NS-03" closed merge request' do |
80 | create(:closed_merge_request, | 85 | create(:closed_merge_request, |
81 | title: "Feature NS-03", | 86 | title: "Feature NS-03", |
82 | - project: project, | 87 | + source_project: project, |
88 | + target_project: project, | ||
83 | author: project.users.first) | 89 | author: project.users.first) |
84 | end | 90 | end |
85 | 91 |
features/steps/shared/paths.rb
@@ -184,6 +184,10 @@ module SharedPaths | @@ -184,6 +184,10 @@ module SharedPaths | ||
184 | visit project_path(project) | 184 | visit project_path(project) |
185 | end | 185 | end |
186 | 186 | ||
187 | + step 'I visit project "Forked Shop" merge requests page' do | ||
188 | + visit project_merge_requests_path(@forked_project) | ||
189 | + end | ||
190 | + | ||
187 | step 'I visit edit project "Shop" page' do | 191 | step 'I visit edit project "Shop" page' do |
188 | visit edit_project_path(project) | 192 | visit edit_project_path(project) |
189 | end | 193 | end |
@@ -239,18 +243,22 @@ module SharedPaths | @@ -239,18 +243,22 @@ module SharedPaths | ||
239 | 243 | ||
240 | step 'I visit merge request page "Bug NS-04"' do | 244 | step 'I visit merge request page "Bug NS-04"' do |
241 | mr = MergeRequest.find_by_title("Bug NS-04") | 245 | mr = MergeRequest.find_by_title("Bug NS-04") |
242 | - visit project_merge_request_path(mr.project, mr) | 246 | + visit project_merge_request_path(mr.target_project, mr) |
243 | end | 247 | end |
244 | 248 | ||
245 | step 'I visit merge request page "Bug NS-05"' do | 249 | step 'I visit merge request page "Bug NS-05"' do |
246 | mr = MergeRequest.find_by_title("Bug NS-05") | 250 | mr = MergeRequest.find_by_title("Bug NS-05") |
247 | - visit project_merge_request_path(mr.project, mr) | 251 | + visit project_merge_request_path(mr.target_project, mr) |
248 | end | 252 | end |
249 | 253 | ||
250 | step 'I visit project "Shop" merge requests page' do | 254 | step 'I visit project "Shop" merge requests page' do |
251 | visit project_merge_requests_path(project) | 255 | visit project_merge_requests_path(project) |
252 | end | 256 | end |
253 | 257 | ||
258 | + step 'I visit forked project "Shop" merge requests page' do | ||
259 | + visit project_merge_requests_path(project) | ||
260 | + end | ||
261 | + | ||
254 | step 'I visit project "Shop" milestones page' do | 262 | step 'I visit project "Shop" milestones page' do |
255 | visit project_milestones_path(project) | 263 | visit project_milestones_path(project) |
256 | end | 264 | end |
features/support/env.rb
@@ -35,8 +35,7 @@ Capybara.ignore_hidden_elements = false | @@ -35,8 +35,7 @@ Capybara.ignore_hidden_elements = false | ||
35 | DatabaseCleaner.strategy = :truncation | 35 | DatabaseCleaner.strategy = :truncation |
36 | 36 | ||
37 | Spinach.hooks.before_scenario do | 37 | Spinach.hooks.before_scenario do |
38 | - TestEnv.init(mailer: false) | ||
39 | - | 38 | + TestEnv.setup_stubs |
40 | DatabaseCleaner.start | 39 | DatabaseCleaner.start |
41 | end | 40 | end |
42 | 41 | ||
@@ -45,6 +44,7 @@ Spinach.hooks.after_scenario do | @@ -45,6 +44,7 @@ Spinach.hooks.after_scenario do | ||
45 | end | 44 | end |
46 | 45 | ||
47 | Spinach.hooks.before_run do | 46 | Spinach.hooks.before_run do |
47 | + TestEnv.init(mailer: false, init_repos: true, repos: false) | ||
48 | RSpec::Mocks::setup self | 48 | RSpec::Mocks::setup self |
49 | 49 | ||
50 | include FactoryGirl::Syntax::Methods | 50 | include FactoryGirl::Syntax::Methods |
lib/api/merge_requests.rb
@@ -51,9 +51,10 @@ module API | @@ -51,9 +51,10 @@ module API | ||
51 | # | 51 | # |
52 | # Parameters: | 52 | # Parameters: |
53 | # | 53 | # |
54 | - # id (required) - The ID of a project | 54 | + # id (required) - The ID of a project - this will be the source of the merge request |
55 | # source_branch (required) - The source branch | 55 | # source_branch (required) - The source branch |
56 | # target_branch (required) - The target branch | 56 | # target_branch (required) - The target branch |
57 | + # target_project - The target project of the merge request defaults to the :id of the project | ||
57 | # assignee_id - Assignee user ID | 58 | # assignee_id - Assignee user ID |
58 | # title (required) - Title of MR | 59 | # title (required) - Title of MR |
59 | # | 60 | # |
@@ -63,11 +64,15 @@ module API | @@ -63,11 +64,15 @@ module API | ||
63 | post ":id/merge_requests" do | 64 | post ":id/merge_requests" do |
64 | authorize! :write_merge_request, user_project | 65 | authorize! :write_merge_request, user_project |
65 | required_attributes! [:source_branch, :target_branch, :title] | 66 | required_attributes! [:source_branch, :target_branch, :title] |
66 | - | ||
67 | - attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title] | 67 | + attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id] |
68 | merge_request = user_project.merge_requests.new(attrs) | 68 | merge_request = user_project.merge_requests.new(attrs) |
69 | merge_request.author = current_user | 69 | merge_request.author = current_user |
70 | - | 70 | + merge_request.source_project = user_project |
71 | + if !attrs[:target_project_id].nil? && user_project.forked? && user_project.forked_from_project.id.to_s == attrs[:target_project_id] | ||
72 | + merge_request.target_project = Project.find_by_id(attrs[:target_project_id]) | ||
73 | + elsif attrs[:target_project].nil? | ||
74 | + merge_request.target_project = user_project | ||
75 | + end | ||
71 | if merge_request.save | 76 | if merge_request.save |
72 | merge_request.reload_code | 77 | merge_request.reload_code |
73 | present merge_request, with: Entities::MergeRequest | 78 | present merge_request, with: Entities::MergeRequest |
lib/gitlab/satellite/action.rb
1 | module Gitlab | 1 | module Gitlab |
2 | module Satellite | 2 | module Satellite |
3 | class Action | 3 | class Action |
4 | - DEFAULT_OPTIONS = { git_timeout: 30.seconds } | 4 | + DEFAULT_OPTIONS = { git_timeout: 30.seconds} |
5 | 5 | ||
6 | attr_accessor :options, :project, :user | 6 | attr_accessor :options, :project, :user |
7 | 7 | ||
@@ -34,16 +34,19 @@ module Gitlab | @@ -34,16 +34,19 @@ module Gitlab | ||
34 | Gitlab::ShellEnv.reset_env | 34 | Gitlab::ShellEnv.reset_env |
35 | end | 35 | end |
36 | 36 | ||
37 | - # * Clears the satellite | ||
38 | - # * Updates the satellite from Gitolite | 37 | + # * Recreates the satellite |
39 | # * Sets up Git variables for the user | 38 | # * Sets up Git variables for the user |
40 | # | 39 | # |
41 | # Note: use this within #in_locked_and_timed_satellite | 40 | # Note: use this within #in_locked_and_timed_satellite |
42 | def prepare_satellite!(repo) | 41 | def prepare_satellite!(repo) |
43 | project.satellite.clear_and_update! | 42 | project.satellite.clear_and_update! |
44 | 43 | ||
45 | - repo.git.config({}, "user.name", user.name) | ||
46 | - repo.git.config({}, "user.email", user.email) | 44 | + repo.config['user.name']=user.name |
45 | + repo.config['user.email']=user.email | ||
46 | + end | ||
47 | + | ||
48 | + def default_options(options = {}) | ||
49 | + {raise: true, timeout: true}.merge(options) | ||
47 | end | 50 | end |
48 | end | 51 | end |
49 | end | 52 | end |
lib/gitlab/satellite/merge_action.rb
@@ -5,37 +5,37 @@ module Gitlab | @@ -5,37 +5,37 @@ module Gitlab | ||
5 | attr_accessor :merge_request | 5 | attr_accessor :merge_request |
6 | 6 | ||
7 | def initialize(user, merge_request) | 7 | def initialize(user, merge_request) |
8 | - super user, merge_request.project | 8 | + super user, merge_request.target_project |
9 | @merge_request = merge_request | 9 | @merge_request = merge_request |
10 | end | 10 | end |
11 | 11 | ||
12 | # Checks if a merge request can be executed without user interaction | 12 | # Checks if a merge request can be executed without user interaction |
13 | def can_be_merged? | 13 | def can_be_merged? |
14 | in_locked_and_timed_satellite do |merge_repo| | 14 | in_locked_and_timed_satellite do |merge_repo| |
15 | + prepare_satellite!(merge_repo) | ||
15 | merge_in_satellite!(merge_repo) | 16 | merge_in_satellite!(merge_repo) |
16 | end | 17 | end |
17 | end | 18 | end |
18 | 19 | ||
19 | # Merges the source branch into the target branch in the satellite and | 20 | # Merges the source branch into the target branch in the satellite and |
20 | - # pushes it back to Gitolite. | ||
21 | - # It also removes the source branch if requested in the merge request. | 21 | + # pushes it back to the repository. |
22 | + # It also removes the source branch if requested in the merge request (and this is permitted by the merge request). | ||
22 | # | 23 | # |
23 | # Returns false if the merge produced conflicts | 24 | # Returns false if the merge produced conflicts |
24 | - # Returns false if pushing from the satellite to Gitolite failed or was rejected | 25 | + # Returns false if pushing from the satellite to the repository failed or was rejected |
25 | # Returns true otherwise | 26 | # Returns true otherwise |
26 | def merge! | 27 | def merge! |
27 | in_locked_and_timed_satellite do |merge_repo| | 28 | in_locked_and_timed_satellite do |merge_repo| |
29 | + prepare_satellite!(merge_repo) | ||
28 | if merge_in_satellite!(merge_repo) | 30 | if merge_in_satellite!(merge_repo) |
29 | # push merge back to Gitolite | 31 | # push merge back to Gitolite |
30 | # will raise CommandFailed when push fails | 32 | # will raise CommandFailed when push fails |
31 | - merge_repo.git.push({raise: true, timeout: true}, :origin, merge_request.target_branch) | ||
32 | - | 33 | + merge_repo.git.push(default_options, :origin, merge_request.target_branch) |
33 | # remove source branch | 34 | # remove source branch |
34 | if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) | 35 | if merge_request.should_remove_source_branch && !project.root_ref?(merge_request.source_branch) |
35 | # will raise CommandFailed when push fails | 36 | # will raise CommandFailed when push fails |
36 | - merge_repo.git.push({raise: true, timeout: true}, :origin, ":#{merge_request.source_branch}") | 37 | + merge_repo.git.push(default_options, :origin, ":#{merge_request.source_branch}") |
37 | end | 38 | end |
38 | - | ||
39 | # merge, push and branch removal successful | 39 | # merge, push and branch removal successful |
40 | true | 40 | true |
41 | end | 41 | end |
@@ -45,6 +45,82 @@ module Gitlab | @@ -45,6 +45,82 @@ module Gitlab | ||
45 | false | 45 | false |
46 | end | 46 | end |
47 | 47 | ||
48 | + | ||
49 | + # Get a raw diff of the source to the target | ||
50 | + def diff_in_satellite | ||
51 | + in_locked_and_timed_satellite do |merge_repo| | ||
52 | + prepare_satellite!(merge_repo) | ||
53 | + | ||
54 | + update_satellite_source_and_target!(merge_repo) | ||
55 | + if merge_request.for_fork? | ||
56 | + diff = merge_repo.git.native(:diff, default_options, "origin/#{merge_request.target_branch}", "source/#{merge_request.source_branch}") | ||
57 | + else | ||
58 | + diff = merge_repo.git.native(:diff, default_options, "#{merge_request.target_branch}", "#{merge_request.source_branch}") | ||
59 | + | ||
60 | + end | ||
61 | + return diff | ||
62 | + end | ||
63 | + rescue Grit::Git::CommandFailed => ex | ||
64 | + Gitlab::GitLogger.error(ex.message) | ||
65 | + false | ||
66 | + end | ||
67 | + | ||
68 | + # Only show what is new in the source branch compared to the target branch, not the other way around. | ||
69 | + # The line below with merge_base is equivalent to diff with three dots (git diff branch1...branch2) | ||
70 | + # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B" | ||
71 | + def diffs_between_satellite | ||
72 | + in_locked_and_timed_satellite do |merge_repo| | ||
73 | + prepare_satellite!(merge_repo) | ||
74 | + update_satellite_source_and_target!(merge_repo) | ||
75 | + if merge_request.for_fork? | ||
76 | + common_commit = merge_repo.git.native(:merge_base, default_options, ["origin/#{merge_request.target_branch}", "source/#{merge_request.source_branch}"]).strip | ||
77 | + diffs = merge_repo.diff(default_options, common_commit, "source/#{merge_request.source_branch}") | ||
78 | + else | ||
79 | + common_commit = merge_repo.git.native(:merge_base, default_options, ["#{merge_request.target_branch}", "#{merge_request.source_branch}"]).strip | ||
80 | + diffs = merge_repo.diff(default_options, common_commit, "#{merge_request.source_branch}") | ||
81 | + end | ||
82 | + return diffs | ||
83 | + end | ||
84 | + rescue Grit::Git::CommandFailed => ex | ||
85 | + Gitlab::GitLogger.error(ex.message) | ||
86 | + false | ||
87 | + end | ||
88 | + | ||
89 | + # Get commit as an email patch | ||
90 | + def format_patch | ||
91 | + in_locked_and_timed_satellite do |merge_repo| | ||
92 | + prepare_satellite!(merge_repo) | ||
93 | + update_satellite_source_and_target!(merge_repo) | ||
94 | + if (merge_request.for_fork?) | ||
95 | + patch = merge_repo.git.format_patch(default_options({stdout: true}), "origin/#{merge_request.target_branch}...source/#{merge_request.source_branch}") | ||
96 | + else | ||
97 | + patch = merge_repo.git.format_patch(default_options({stdout: true}), "#{merge_request.target_branch}...#{merge_request.source_branch}") | ||
98 | + end | ||
99 | + return patch | ||
100 | + end | ||
101 | + rescue Grit::Git::CommandFailed => ex | ||
102 | + Gitlab::GitLogger.error(ex.message) | ||
103 | + false | ||
104 | + end | ||
105 | + | ||
106 | + # Retrieve an array of commits between the source and the target | ||
107 | + def commits_between | ||
108 | + in_locked_and_timed_satellite do |merge_repo| | ||
109 | + prepare_satellite!(merge_repo) | ||
110 | + update_satellite_source_and_target!(merge_repo) | ||
111 | + if (merge_request.for_fork?) | ||
112 | + commits = merge_repo.commits_between("origin/#{merge_request.target_branch}", "source/#{merge_request.source_branch}") | ||
113 | + else | ||
114 | + commits = merge_repo.commits_between("#{merge_request.target_branch}", "#{merge_request.source_branch}") | ||
115 | + end | ||
116 | + return commits | ||
117 | + | ||
118 | + end | ||
119 | + rescue Grit::Git::CommandFailed => ex | ||
120 | + Gitlab::GitLogger.error(ex.message) | ||
121 | + false | ||
122 | + end | ||
123 | + | ||
48 | private | 124 | private |
49 | 125 | ||
50 | # Merges the source_branch into the target_branch in the satellite. | 126 | # Merges the source_branch into the target_branch in the satellite. |
@@ -54,18 +130,38 @@ module Gitlab | @@ -54,18 +130,38 @@ module Gitlab | ||
54 | # Returns false if the merge produced conflicts | 130 | # Returns false if the merge produced conflicts |
55 | # Returns true otherwise | 131 | # Returns true otherwise |
56 | def merge_in_satellite!(repo) | 132 | def merge_in_satellite!(repo) |
57 | - prepare_satellite!(repo) | ||
58 | - | ||
59 | - # create target branch in satellite at the corresponding commit from Gitolite | ||
60 | - repo.git.checkout({raise: true, timeout: true, b: true}, merge_request.target_branch, "origin/#{merge_request.target_branch}") | 133 | + update_satellite_source_and_target!(repo) |
61 | 134 | ||
62 | - # merge the source branch from Gitolite into the satellite | 135 | + # merge the source branch into the satellite |
63 | # will raise CommandFailed when merge fails | 136 | # will raise CommandFailed when merge fails |
64 | - repo.git.pull({raise: true, timeout: true, no_ff: true}, :origin, merge_request.source_branch) | 137 | + if merge_request.for_fork? |
138 | + repo.git.pull(default_options({no_ff: true}), 'source', merge_request.source_branch) | ||
139 | + else | ||
140 | + repo.git.pull(default_options({no_ff: true}), 'origin', merge_request.source_branch) | ||
141 | + end | ||
142 | + rescue Grit::Git::CommandFailed => ex | ||
143 | + Gitlab::GitLogger.error(ex.message) | ||
144 | + false | ||
145 | + end | ||
146 | + | ||
147 | + # Assumes a satellite exists that is a fresh clone of the projects repo, prepares satellite for merges, diffs etc | ||
148 | + def update_satellite_source_and_target!(repo) | ||
149 | + if merge_request.for_fork? | ||
150 | + repo.remote_add('source', merge_request.source_project.repository.path_to_repo) | ||
151 | + repo.remote_fetch('source') | ||
152 | + repo.git.checkout(default_options({b: true}), merge_request.target_branch, "origin/#{merge_request.target_branch}") | ||
153 | + else | ||
154 | + # We can't trust the input here being branch names, we can't always check it out because it could be a relative ref i.e. HEAD~3 | ||
155 | + # we could actually remove the if true, because it should never ever happen (as long as the satellite has been prepared) | ||
156 | + repo.git.checkout(default_options, "#{merge_request.source_branch}") | ||
157 | + repo.git.checkout(default_options, "#{merge_request.target_branch}") | ||
158 | + end | ||
65 | rescue Grit::Git::CommandFailed => ex | 159 | rescue Grit::Git::CommandFailed => ex |
66 | Gitlab::GitLogger.error(ex.message) | 160 | Gitlab::GitLogger.error(ex.message) |
67 | false | 161 | false |
68 | end | 162 | end |
163 | + | ||
164 | + | ||
69 | end | 165 | end |
70 | end | 166 | end |
71 | end | 167 | end |
lib/gitlab/satellite/satellite.rb
1 | module Gitlab | 1 | module Gitlab |
2 | - class SatelliteNotExistError < StandardError; end | 2 | + class SatelliteNotExistError < StandardError; |
3 | + end | ||
3 | 4 | ||
4 | module Satellite | 5 | module Satellite |
5 | class Satellite | 6 | class Satellite |
@@ -21,11 +22,14 @@ module Gitlab | @@ -21,11 +22,14 @@ module Gitlab | ||
21 | raise SatelliteNotExistError.new("Satellite doesn't exist") | 22 | raise SatelliteNotExistError.new("Satellite doesn't exist") |
22 | end | 23 | end |
23 | 24 | ||
25 | + | ||
24 | def clear_and_update! | 26 | def clear_and_update! |
25 | raise_no_satellite unless exists? | 27 | raise_no_satellite unless exists? |
26 | - | 28 | + File.exists? path |
29 | + @repo = nil | ||
27 | clear_working_dir! | 30 | clear_working_dir! |
28 | delete_heads! | 31 | delete_heads! |
32 | + remove_remotes! | ||
29 | update_from_source! | 33 | update_from_source! |
30 | end | 34 | end |
31 | 35 | ||
@@ -55,14 +59,16 @@ module Gitlab | @@ -55,14 +59,16 @@ module Gitlab | ||
55 | raise_no_satellite unless exists? | 59 | raise_no_satellite unless exists? |
56 | 60 | ||
57 | File.open(lock_file, "w+") do |f| | 61 | File.open(lock_file, "w+") do |f| |
58 | - f.flock(File::LOCK_EX) | ||
59 | - | ||
60 | - Dir.chdir(path) do | ||
61 | - return yield | 62 | + begin |
63 | + f.flock File::LOCK_EX | ||
64 | + Dir.chdir(path) { return yield } | ||
65 | + ensure | ||
66 | + f.flock File::LOCK_UN | ||
62 | end | 67 | end |
63 | end | 68 | end |
64 | end | 69 | end |
65 | 70 | ||
71 | + | ||
66 | def lock_file | 72 | def lock_file |
67 | create_locks_dir unless File.exists?(lock_files_dir) | 73 | create_locks_dir unless File.exists?(lock_files_dir) |
68 | File.join(lock_files_dir, "satellite_#{project.id}.lock") | 74 | File.join(lock_files_dir, "satellite_#{project.id}.lock") |
@@ -100,20 +106,35 @@ module Gitlab | @@ -100,20 +106,35 @@ module Gitlab | ||
100 | if heads.include? PARKING_BRANCH | 106 | if heads.include? PARKING_BRANCH |
101 | repo.git.checkout({}, PARKING_BRANCH) | 107 | repo.git.checkout({}, PARKING_BRANCH) |
102 | else | 108 | else |
103 | - repo.git.checkout({b: true}, PARKING_BRANCH) | 109 | + repo.git.checkout(default_options({b: true}), PARKING_BRANCH) |
104 | end | 110 | end |
105 | 111 | ||
106 | # remove the parking branch from the list of heads ... | 112 | # remove the parking branch from the list of heads ... |
107 | heads.delete(PARKING_BRANCH) | 113 | heads.delete(PARKING_BRANCH) |
108 | # ... and delete all others | 114 | # ... and delete all others |
109 | - heads.each { |head| repo.git.branch({D: true}, head) } | 115 | + heads.each { |head| repo.git.branch(default_options({D: true}), head) } |
116 | + end | ||
117 | + | ||
118 | + # Deletes all remotes except origin | ||
119 | + # | ||
120 | + # This ensures we have no remote name clashes or issues updating branches when | ||
121 | + # working with the satellite. | ||
122 | + def remove_remotes! | ||
123 | + remotes = repo.git.remote.split(' ') | ||
124 | + remotes.delete('origin') | ||
125 | + remotes.each { |name| repo.git.remote(default_options,'rm', name)} | ||
110 | end | 126 | end |
111 | 127 | ||
112 | # Updates the satellite from Gitolite | 128 | # Updates the satellite from Gitolite |
113 | # | 129 | # |
114 | # Note: this will only update remote branches (i.e. origin/*) | 130 | # Note: this will only update remote branches (i.e. origin/*) |
115 | def update_from_source! | 131 | def update_from_source! |
116 | - repo.git.fetch({timeout: true}, :origin) | 132 | + repo.git.fetch(default_options, :origin) |
133 | + end | ||
134 | + | ||
135 | + | ||
136 | + def default_options(options = {}) | ||
137 | + {raise: true, timeout: true}.merge(options) | ||
117 | end | 138 | end |
118 | 139 | ||
119 | # Create directory for stroing | 140 | # Create directory for stroing |
@@ -0,0 +1,57 @@ | @@ -0,0 +1,57 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe FilterContext do | ||
4 | + | ||
5 | + let(:user) { create :user } | ||
6 | + let(:user2) { create :user } | ||
7 | + let(:project1) { create(:project, creator_id: user.id) } | ||
8 | + let(:project2) { create(:project, creator_id: user.id) } | ||
9 | + let(:merge_request1) { create(:merge_request, author_id: user.id, source_project: project1, target_project: project2) } | ||
10 | + let(:merge_request2) { create(:merge_request, author_id: user.id, source_project: project2, target_project: project1) } | ||
11 | + let(:merge_request3) { create(:merge_request, author_id: user.id, source_project: project2, target_project: project2) } | ||
12 | + let(:merge_request4) { create(:merge_request, author_id: user2.id, source_project: project2, target_project: project2) } | ||
13 | + let(:issue1) { create(:issue, assignee_id: user.id, project: project1) } | ||
14 | + let(:issue2) { create(:issue, assignee_id: user.id, project: project2) } | ||
15 | + let(:issue3) { create(:issue, assignee_id: user2.id, project: project2) } | ||
16 | + | ||
17 | + describe 'merge requests' do | ||
18 | + before :each do | ||
19 | + merge_request1 | ||
20 | + merge_request2 | ||
21 | + merge_request3 | ||
22 | + merge_request4 | ||
23 | + end | ||
24 | + it 'should by default filter properly' do | ||
25 | + merge_requests = user.cared_merge_requests | ||
26 | + params ={} | ||
27 | + merge_requests = FilterContext.new(merge_requests, params).execute | ||
28 | + merge_requests.size.should == 3 | ||
29 | + end | ||
30 | + it 'should apply blocks passed in on creation to the filters' do | ||
31 | + merge_requests = user.cared_merge_requests | ||
32 | + params = {:project_id => project1.id} | ||
33 | + merge_requests = FilterContext.new(merge_requests, params).execute | ||
34 | + merge_requests.size.should == 2 | ||
35 | + end | ||
36 | + end | ||
37 | + | ||
38 | + describe 'issues' do | ||
39 | + before :each do | ||
40 | + issue1 | ||
41 | + issue2 | ||
42 | + issue3 | ||
43 | + end | ||
44 | + it 'should by default filter projects properly' do | ||
45 | + issues = user.assigned_issues | ||
46 | + params = {} | ||
47 | + issues = FilterContext.new(issues, params).execute | ||
48 | + issues.size.should == 2 | ||
49 | + end | ||
50 | + it 'should apply blocks passed in on creation to the filters' do | ||
51 | + issues = user.assigned_issues | ||
52 | + params = {:project_id => project1.id} | ||
53 | + issues = FilterContext.new(issues, params).execute | ||
54 | + issues.size.should == 1 | ||
55 | + end | ||
56 | + end | ||
57 | +end | ||
0 | \ No newline at end of file | 58 | \ No newline at end of file |
spec/controllers/commit_controller_spec.rb
@@ -2,12 +2,11 @@ require 'spec_helper' | @@ -2,12 +2,11 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe Projects::CommitController do | 3 | describe Projects::CommitController do |
4 | let(:project) { create(:project_with_code) } | 4 | let(:project) { create(:project_with_code) } |
5 | - let(:user) { create(:user) } | ||
6 | - let(:commit) { project.repository.last_commit_for("master") } | 5 | + let(:user) { create(:user) } |
6 | + let(:commit) { project.repository.last_commit_for("master") } | ||
7 | 7 | ||
8 | before do | 8 | before do |
9 | sign_in(user) | 9 | sign_in(user) |
10 | - | ||
11 | project.team << [user, :master] | 10 | project.team << [user, :master] |
12 | end | 11 | end |
13 | 12 |
spec/controllers/commits_controller_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper' | @@ -2,7 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe Projects::CommitsController do | 3 | describe Projects::CommitsController do |
4 | let(:project) { create(:project_with_code) } | 4 | let(:project) { create(:project_with_code) } |
5 | - let(:user) { create(:user) } | 5 | + let(:user) { create(:user) } |
6 | 6 | ||
7 | before do | 7 | before do |
8 | sign_in(user) | 8 | sign_in(user) |
spec/controllers/merge_requests_controller_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper' | @@ -3,7 +3,7 @@ require 'spec_helper' | ||
3 | describe Projects::MergeRequestsController do | 3 | describe Projects::MergeRequestsController do |
4 | let(:project) { create(:project_with_code) } | 4 | let(:project) { create(:project_with_code) } |
5 | let(:user) { create(:user) } | 5 | let(:user) { create(:user) } |
6 | - let(:merge_request) { create(:merge_request_with_diffs, project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") } | 6 | + let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") } |
7 | 7 | ||
8 | before do | 8 | before do |
9 | sign_in(user) | 9 | sign_in(user) |
@@ -28,7 +28,7 @@ describe Projects::MergeRequestsController do | @@ -28,7 +28,7 @@ describe Projects::MergeRequestsController do | ||
28 | it "should render it" do | 28 | it "should render it" do |
29 | get :show, project_id: project.code, id: merge_request.id, format: format | 29 | get :show, project_id: project.code, id: merge_request.id, format: format |
30 | 30 | ||
31 | - expect(response.body).to eq(merge_request.send(:"to_#{format}")) | 31 | + expect(response.body).to eq((merge_request.send(:"to_#{format}",user)).to_s) |
32 | end | 32 | end |
33 | 33 | ||
34 | it "should not escape Html" do | 34 | it "should not escape Html" do |
spec/factories.rb
1 | +<<<<<<< HEAD | ||
1 | include ActionDispatch::TestProcess | 2 | include ActionDispatch::TestProcess |
3 | +======= | ||
4 | +require Rails.root.join('spec', 'support', 'test_env.rb') | ||
5 | +>>>>>>> Merge Request on forked projects | ||
2 | 6 | ||
3 | FactoryGirl.define do | 7 | FactoryGirl.define do |
4 | sequence :sentence, aliases: [:title, :content] do | 8 | sequence :sentence, aliases: [:title, :content] do |
@@ -29,8 +33,19 @@ FactoryGirl.define do | @@ -29,8 +33,19 @@ FactoryGirl.define do | ||
29 | sequence(:name) { |n| "project#{n}" } | 33 | sequence(:name) { |n| "project#{n}" } |
30 | path { name.downcase.gsub(/\s/, '_') } | 34 | path { name.downcase.gsub(/\s/, '_') } |
31 | creator | 35 | creator |
36 | + | ||
37 | + trait :source do | ||
38 | + sequence(:name) { |n| "source project#{n}" } | ||
39 | + end | ||
40 | + trait :target do | ||
41 | + sequence(:name) { |n| "target project#{n}" } | ||
42 | + end | ||
43 | + | ||
44 | + factory :source_project, traits: [:source] | ||
45 | + factory :target_project, traits: [:target] | ||
32 | end | 46 | end |
33 | 47 | ||
48 | + | ||
34 | factory :redmine_project, parent: :project do | 49 | factory :redmine_project, parent: :project do |
35 | issues_tracker { "redmine" } | 50 | issues_tracker { "redmine" } |
36 | issues_tracker_id { "project_name_in_redmine" } | 51 | issues_tracker_id { "project_name_in_redmine" } |
@@ -39,14 +54,24 @@ FactoryGirl.define do | @@ -39,14 +54,24 @@ FactoryGirl.define do | ||
39 | factory :project_with_code, parent: :project do | 54 | factory :project_with_code, parent: :project do |
40 | path { 'gitlabhq' } | 55 | path { 'gitlabhq' } |
41 | 56 | ||
57 | + trait :source_path do | ||
58 | + path { 'source_gitlabhq' } | ||
59 | + end | ||
60 | + | ||
61 | + trait :target_path do | ||
62 | + path { 'target_gitlabhq' } | ||
63 | + end | ||
64 | + | ||
65 | + factory :source_project_with_code, traits: [:source, :source_path] | ||
66 | + factory :target_project_with_code, traits: [:target, :target_path] | ||
67 | + | ||
42 | after :create do |project| | 68 | after :create do |project| |
43 | - repos_path = Rails.root.join('tmp', 'test-git-base-path') | ||
44 | - seed_repo = Rails.root.join('tmp', 'repositories', 'gitlabhq') | ||
45 | - target_repo = File.join(repos_path, project.path_with_namespace + '.git') | ||
46 | - system("ln -s #{seed_repo} #{target_repo}") | 69 | + TestEnv.clear_repo_dir(project.namespace, project.path) |
70 | + TestEnv.create_repo(project.namespace, project.path) | ||
47 | end | 71 | end |
48 | end | 72 | end |
49 | 73 | ||
74 | + | ||
50 | factory :group do | 75 | factory :group do |
51 | sequence(:name) { |n| "group#{n}" } | 76 | sequence(:name) { |n| "group#{n}" } |
52 | path { name.downcase.gsub(/\s/, '_') } | 77 | path { name.downcase.gsub(/\s/, '_') } |
@@ -86,7 +111,8 @@ FactoryGirl.define do | @@ -86,7 +111,8 @@ FactoryGirl.define do | ||
86 | factory :merge_request do | 111 | factory :merge_request do |
87 | title | 112 | title |
88 | author | 113 | author |
89 | - project factory: :project_with_code | 114 | + source_project factory: :source_project_with_code |
115 | + target_project factory: :target_project_with_code | ||
90 | source_branch "master" | 116 | source_branch "master" |
91 | target_branch "stable" | 117 | target_branch "stable" |
92 | 118 | ||
@@ -96,13 +122,13 @@ FactoryGirl.define do | @@ -96,13 +122,13 @@ FactoryGirl.define do | ||
96 | source_branch "stable" # pretend bcf03b5d | 122 | source_branch "stable" # pretend bcf03b5d |
97 | st_commits do | 123 | st_commits do |
98 | [ | 124 | [ |
99 | - project.repository.commit('bcf03b5d').to_hash, | ||
100 | - project.repository.commit('bcf03b5d~1').to_hash, | ||
101 | - project.repository.commit('bcf03b5d~2').to_hash | 125 | + source_project.repository.commit('bcf03b5d').to_hash, |
126 | + source_project.repository.commit('bcf03b5d~1').to_hash, | ||
127 | + source_project.repository.commit('bcf03b5d~2').to_hash | ||
102 | ] | 128 | ] |
103 | end | 129 | end |
104 | st_diffs do | 130 | st_diffs do |
105 | - project.repo.diff("bcf03b5d~3", "bcf03b5d") | 131 | + source_project.repo.diff("bcf03b5d~3", "bcf03b5d") |
106 | end | 132 | end |
107 | end | 133 | end |
108 | 134 | ||
@@ -133,7 +159,7 @@ FactoryGirl.define do | @@ -133,7 +159,7 @@ FactoryGirl.define do | ||
133 | 159 | ||
134 | trait :on_commit do | 160 | trait :on_commit do |
135 | project factory: :project_with_code | 161 | project factory: :project_with_code |
136 | - commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" | 162 | + commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" |
137 | noteable_type "Commit" | 163 | noteable_type "Commit" |
138 | end | 164 | end |
139 | 165 | ||
@@ -143,12 +169,12 @@ FactoryGirl.define do | @@ -143,12 +169,12 @@ FactoryGirl.define do | ||
143 | 169 | ||
144 | trait :on_merge_request do | 170 | trait :on_merge_request do |
145 | project factory: :project_with_code | 171 | project factory: :project_with_code |
146 | - noteable_id 1 | 172 | + noteable_id 1 |
147 | noteable_type "MergeRequest" | 173 | noteable_type "MergeRequest" |
148 | end | 174 | end |
149 | 175 | ||
150 | trait :on_issue do | 176 | trait :on_issue do |
151 | - noteable_id 1 | 177 | + noteable_id 1 |
152 | noteable_type "Issue" | 178 | noteable_type "Issue" |
153 | end | 179 | end |
154 | 180 |
spec/factories_spec.rb
@@ -5,8 +5,10 @@ INVALID_FACTORIES = [ | @@ -5,8 +5,10 @@ INVALID_FACTORIES = [ | ||
5 | :invalid_key, | 5 | :invalid_key, |
6 | ] | 6 | ] |
7 | 7 | ||
8 | + | ||
8 | FactoryGirl.factories.map(&:name).each do |factory_name| | 9 | FactoryGirl.factories.map(&:name).each do |factory_name| |
9 | next if INVALID_FACTORIES.include?(factory_name) | 10 | next if INVALID_FACTORIES.include?(factory_name) |
11 | + | ||
10 | describe "#{factory_name} factory" do | 12 | describe "#{factory_name} factory" do |
11 | it 'should be valid' do | 13 | it 'should be valid' do |
12 | build(factory_name).should be_valid | 14 | build(factory_name).should be_valid |
spec/features/gitlab_flavored_markdown_spec.rb
@@ -3,11 +3,11 @@ require 'spec_helper' | @@ -3,11 +3,11 @@ require 'spec_helper' | ||
3 | describe "GitLab Flavored Markdown" do | 3 | describe "GitLab Flavored Markdown" do |
4 | let(:project) { create(:project_with_code) } | 4 | let(:project) { create(:project_with_code) } |
5 | let(:issue) { create(:issue, project: project) } | 5 | let(:issue) { create(:issue, project: project) } |
6 | - let(:merge_request) { create(:merge_request, project: project) } | 6 | + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } |
7 | let(:fred) do | 7 | let(:fred) do |
8 | - u = create(:user, name: "fred") | ||
9 | - project.team << [u, :master] | ||
10 | - u | 8 | + u = create(:user, name: "fred") |
9 | + project.team << [u, :master] | ||
10 | + u | ||
11 | end | 11 | end |
12 | 12 | ||
13 | before do | 13 | before do |
@@ -83,9 +83,7 @@ describe "GitLab Flavored Markdown" do | @@ -83,9 +83,7 @@ describe "GitLab Flavored Markdown" do | ||
83 | 83 | ||
84 | describe "for merge requests" do | 84 | describe "for merge requests" do |
85 | before do | 85 | before do |
86 | - @merge_request = create(:merge_request, | ||
87 | - project: project, | ||
88 | - title: "fix ##{issue.id}") | 86 | + @merge_request = create(:merge_request, source_project: project, target_project: project, title: "fix ##{issue.id}") |
89 | end | 87 | end |
90 | 88 | ||
91 | it "should render title in merge_requests#index" do | 89 | it "should render title in merge_requests#index" do |
spec/features/notes_on_merge_requests_spec.rb
@@ -2,8 +2,8 @@ require 'spec_helper' | @@ -2,8 +2,8 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe "On a merge request", js: true do | 3 | describe "On a merge request", js: true do |
4 | let!(:project) { create(:project_with_code) } | 4 | let!(:project) { create(:project_with_code) } |
5 | - let!(:merge_request) { create(:merge_request, project: project) } | ||
6 | - let!(:note) { create(:note_on_merge_request_with_attachment, project: project) } | 5 | + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } |
6 | + let!(:note) { create(:note_on_merge_request_with_attachment, source_project: project, target_project: project) } | ||
7 | 7 | ||
8 | before do | 8 | before do |
9 | login_as :user | 9 | login_as :user |
@@ -62,7 +62,7 @@ describe "On a merge request", js: true do | @@ -62,7 +62,7 @@ describe "On a merge request", js: true do | ||
62 | 62 | ||
63 | it 'should be added and form reset' do | 63 | it 'should be added and form reset' do |
64 | should have_content("This is awsome!") | 64 | should have_content("This is awsome!") |
65 | - within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } | 65 | + within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") } |
66 | within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } | 66 | within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) } |
67 | within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } | 67 | within(".js-main-target-form") { should have_css(".js-note-text", visible: true) } |
68 | end | 68 | end |
@@ -135,8 +135,8 @@ describe "On a merge request", js: true do | @@ -135,8 +135,8 @@ describe "On a merge request", js: true do | ||
135 | end | 135 | end |
136 | 136 | ||
137 | describe "On a merge request diff", js: true, focus: true do | 137 | describe "On a merge request diff", js: true, focus: true do |
138 | - let!(:project) { create(:project_with_code) } | ||
139 | - let!(:merge_request) { create(:merge_request_with_diffs, project: project) } | 138 | + let!(:project) { create(:source_project_with_code) } |
139 | + let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } | ||
140 | 140 | ||
141 | before do | 141 | before do |
142 | login_as :user | 142 | login_as :user |
@@ -144,6 +144,7 @@ describe "On a merge request diff", js: true, focus: true do | @@ -144,6 +144,7 @@ describe "On a merge request diff", js: true, focus: true do | ||
144 | visit diffs_project_merge_request_path(project, merge_request) | 144 | visit diffs_project_merge_request_path(project, merge_request) |
145 | end | 145 | end |
146 | 146 | ||
147 | + | ||
147 | subject { page } | 148 | subject { page } |
148 | 149 | ||
149 | describe "when adding a note" do | 150 | describe "when adding a note" do |
@@ -205,13 +206,13 @@ describe "On a merge request diff", js: true, focus: true do | @@ -205,13 +206,13 @@ describe "On a merge request diff", js: true, focus: true do | ||
205 | 206 | ||
206 | # TODO: fix | 207 | # TODO: fix |
207 | #it 'should check if previews were rendered separately' do | 208 | #it 'should check if previews were rendered separately' do |
208 | - #within("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185'] + .js-temp-notes-holder") do | ||
209 | - #should have_css(".js-note-preview", text: "One comment on line 185") | ||
210 | - #end | 209 | + #within("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185'] + .js-temp-notes-holder") do |
210 | + #should have_css(".js-note-preview", text: "One comment on line 185") | ||
211 | + #end | ||
211 | 212 | ||
212 | - #within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do | ||
213 | - #should have_css(".js-note-preview", text: "Another comment on line 17") | ||
214 | - #end | 213 | + #within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do |
214 | + #should have_css(".js-note-preview", text: "Another comment on line 17") | ||
215 | + #end | ||
215 | #end | 216 | #end |
216 | end | 217 | end |
217 | 218 | ||
@@ -238,39 +239,38 @@ describe "On a merge request diff", js: true, focus: true do | @@ -238,39 +239,38 @@ describe "On a merge request diff", js: true, focus: true do | ||
238 | 239 | ||
239 | # TODO: fix | 240 | # TODO: fix |
240 | #it "should remove last note of a discussion" do | 241 | #it "should remove last note of a discussion" do |
241 | - #within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .notes-holder") do | ||
242 | - #find(".js-note-delete").click | ||
243 | - #end | ||
244 | - | ||
245 | - #should_not have_css(".note_holder") | 242 | + # within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .notes-holder") do |
243 | + # find(".js-note-delete").click | ||
244 | + # end | ||
245 | + # should_not have_css(".note_holder") | ||
246 | #end | 246 | #end |
247 | end | 247 | end |
248 | end | 248 | end |
249 | 249 | ||
250 | # TODO: fix | 250 | # TODO: fix |
251 | #describe "when replying to a note" do | 251 | #describe "when replying to a note" do |
252 | - #before do | ||
253 | - ## create first note | ||
254 | - #find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184"]').click | 252 | + #before do |
253 | + ## create first note | ||
254 | + # find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_184_184"]').click | ||
255 | 255 | ||
256 | - #within(".js-temp-notes-holder") do | ||
257 | - #fill_in "note[note]", with: "One comment on line 184" | ||
258 | - #click_button("Add Comment") | ||
259 | - #end | 256 | + # within(".js-temp-notes-holder") do |
257 | + # fill_in "note[note]", with: "One comment on line 184" | ||
258 | + # click_button("Add Comment") | ||
259 | + #end | ||
260 | 260 | ||
261 | - #within(".js-temp-notes-holder") do | ||
262 | - #find(".js-discussion-reply-button").click | ||
263 | - #fill_in "note[note]", with: "An additional comment in reply" | ||
264 | - #click_button("Add Comment") | ||
265 | - #end | ||
266 | - #end | ||
267 | - | ||
268 | - #it 'should be inserted and form removed from reply' do | ||
269 | - #should have_content("An additional comment in reply") | ||
270 | - #within(".notes_holder") { should have_css(".note", count: 2) } | ||
271 | - #within(".notes_holder") { should have_no_css("form") } | ||
272 | - #within(".notes_holder") { should have_link("Reply") } | ||
273 | - #end | 261 | + # within(".js-temp-notes-holder") do |
262 | + # find(".js-discussion-reply-button").click | ||
263 | + # fill_in "note[note]", with: "An additional comment in reply" | ||
264 | + # click_button("Add Comment") | ||
265 | + # end | ||
266 | + #end | ||
267 | + | ||
268 | + #it 'should be inserted and form removed from reply' do | ||
269 | + # should have_content("An additional comment in reply") | ||
270 | + # within(".notes_holder") { should have_css(".note", count: 2) } | ||
271 | + # within(".notes_holder") { should have_no_css("form") } | ||
272 | + # within(".notes_holder") { should have_link("Reply") } | ||
273 | + # end | ||
274 | #end | 274 | #end |
275 | end | 275 | end |
276 | 276 |
spec/features/profile_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper' | @@ -2,6 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe "Profile account page" do | 3 | describe "Profile account page" do |
4 | before(:each) { enable_observers } | 4 | before(:each) { enable_observers } |
5 | + after(:each) {disable_observers} | ||
5 | let(:user) { create(:user) } | 6 | let(:user) { create(:user) } |
6 | 7 | ||
7 | before do | 8 | before do |
spec/features/projects_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper' | @@ -2,6 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe "Projects" do | 3 | describe "Projects" do |
4 | before(:each) { enable_observers } | 4 | before(:each) { enable_observers } |
5 | + after(:each) {disable_observers} | ||
5 | before { login_as :user } | 6 | before { login_as :user } |
6 | 7 | ||
7 | describe "DELETE /projects/:id" do | 8 | describe "DELETE /projects/:id" do |
spec/features/security/project_access_spec.rb
@@ -14,13 +14,14 @@ describe "Application access" do | @@ -14,13 +14,14 @@ describe "Application access" do | ||
14 | end | 14 | end |
15 | 15 | ||
16 | describe "Project" do | 16 | describe "Project" do |
17 | - let(:project) { create(:project_with_code) } | 17 | + let(:project) { create(:project_with_code) } |
18 | 18 | ||
19 | - let(:master) { create(:user) } | ||
20 | - let(:guest) { create(:user) } | 19 | + let(:master) { create(:user) } |
20 | + let(:guest) { create(:user) } | ||
21 | let(:reporter) { create(:user) } | 21 | let(:reporter) { create(:user) } |
22 | 22 | ||
23 | before do | 23 | before do |
24 | + | ||
24 | # full access | 25 | # full access |
25 | project.team << [master, :master] | 26 | project.team << [master, :master] |
26 | 27 | ||
@@ -108,7 +109,7 @@ describe "Application access" do | @@ -108,7 +109,7 @@ describe "Application access" do | ||
108 | describe "GET /project_code/blob" do | 109 | describe "GET /project_code/blob" do |
109 | before do | 110 | before do |
110 | commit = project.repository.commit | 111 | commit = project.repository.commit |
111 | - path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name | 112 | + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob) }.first.name |
112 | @blob_path = project_blob_path(project, File.join(commit.id, path)) | 113 | @blob_path = project_blob_path(project, File.join(commit.id, path)) |
113 | end | 114 | end |
114 | 115 | ||
@@ -232,13 +233,13 @@ describe "Application access" do | @@ -232,13 +233,13 @@ describe "Application access" do | ||
232 | 233 | ||
233 | 234 | ||
234 | describe "PublicProject" do | 235 | describe "PublicProject" do |
235 | - let(:project) { create(:project_with_code) } | 236 | + let(:project) { create(:project_with_code) } |
236 | 237 | ||
237 | - let(:master) { create(:user) } | ||
238 | - let(:guest) { create(:user) } | 238 | + let(:master) { create(:user) } |
239 | + let(:guest) { create(:user) } | ||
239 | let(:reporter) { create(:user) } | 240 | let(:reporter) { create(:user) } |
240 | 241 | ||
241 | - let(:admin) { create(:user) } | 242 | + let(:admin) { create(:user) } |
242 | 243 | ||
243 | before do | 244 | before do |
244 | # public project | 245 | # public project |
@@ -339,7 +340,7 @@ describe "Application access" do | @@ -339,7 +340,7 @@ describe "Application access" do | ||
339 | describe "GET /project_code/blob" do | 340 | describe "GET /project_code/blob" do |
340 | before do | 341 | before do |
341 | commit = project.repository.commit | 342 | commit = project.repository.commit |
342 | - path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob)}.first.name | 343 | + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob) }.first.name |
343 | @blob_path = project_blob_path(project, File.join(commit.id, path)) | 344 | @blob_path = project_blob_path(project, File.join(commit.id, path)) |
344 | end | 345 | end |
345 | 346 |
spec/helpers/gitlab_markdown_helper_spec.rb
@@ -9,7 +9,7 @@ describe GitlabMarkdownHelper do | @@ -9,7 +9,7 @@ describe GitlabMarkdownHelper do | ||
9 | let(:user) { create(:user, username: 'gfm') } | 9 | let(:user) { create(:user, username: 'gfm') } |
10 | let(:commit) { project.repository.commit } | 10 | let(:commit) { project.repository.commit } |
11 | let(:issue) { create(:issue, project: project) } | 11 | let(:issue) { create(:issue, project: project) } |
12 | - let(:merge_request) { create(:merge_request, project: project) } | 12 | + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } |
13 | let(:snippet) { create(:project_snippet, project: project) } | 13 | let(:snippet) { create(:project_snippet, project: project) } |
14 | let(:member) { project.users_projects.where(user_id: user).first } | 14 | let(:member) { project.users_projects.where(user_id: user).first } |
15 | 15 |
@@ -0,0 +1,131 @@ | @@ -0,0 +1,131 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe 'Gitlab::Satellite::Action' do | ||
4 | + | ||
5 | + | ||
6 | + let(:project) { create(:project_with_code) } | ||
7 | + let(:user) { create(:user) } | ||
8 | + | ||
9 | + | ||
10 | + describe '#prepare_satellite!' do | ||
11 | + | ||
12 | + it 'create a repository with a parking branch and one remote: origin' do | ||
13 | + repo = project.satellite.repo | ||
14 | + | ||
15 | + #now lets dirty it up | ||
16 | + | ||
17 | + starting_remote_count = repo.git.list_remotes.size | ||
18 | + starting_remote_count.should >= 1 | ||
19 | + #kind of hookey way to add a second remote | ||
20 | + origin_uri = repo.git.remote({v: true}).split(" ")[1] | ||
21 | + begin | ||
22 | + repo.git.remote({raise: true}, 'add', 'another-remote', origin_uri) | ||
23 | + repo.git.branch({raise: true}, 'a-new-branch') | ||
24 | + | ||
25 | + repo.heads.size.should > (starting_remote_count) | ||
26 | + repo.git.remote().split(" ").size.should > (starting_remote_count) | ||
27 | + rescue | ||
28 | + end | ||
29 | + | ||
30 | + repo.git.config({}, "user.name", "#{user.name} -- foo") | ||
31 | + repo.git.config({}, "user.email", "#{user.email} -- foo") | ||
32 | + repo.config['user.name'].should =="#{user.name} -- foo" | ||
33 | + repo.config['user.email'].should =="#{user.email} -- foo" | ||
34 | + | ||
35 | + | ||
36 | + #These must happen in the context of the satellite directory... | ||
37 | + satellite_action = Gitlab::Satellite::Action.new(user, project) | ||
38 | + project.satellite.lock { | ||
39 | + #Now clean it up, use send to get around prepare_satellite! being protected | ||
40 | + satellite_action.send(:prepare_satellite!, repo) | ||
41 | + } | ||
42 | + | ||
43 | + #verify it's clean | ||
44 | + heads = repo.heads.map(&:name) | ||
45 | + heads.size.should == 1 | ||
46 | + heads.include?(Gitlab::Satellite::Satellite::PARKING_BRANCH).should == true | ||
47 | + remotes = repo.git.remote().split(' ') | ||
48 | + remotes.size.should == 1 | ||
49 | + remotes.include?('origin').should == true | ||
50 | + repo.config['user.name'].should ==user.name | ||
51 | + repo.config['user.email'].should ==user.email | ||
52 | + end | ||
53 | + | ||
54 | + | ||
55 | + end | ||
56 | + | ||
57 | + | ||
58 | + describe '#in_locked_and_timed_satellite' do | ||
59 | + | ||
60 | + it 'should make use of a lockfile' do | ||
61 | + repo = project.satellite.repo | ||
62 | + called = false | ||
63 | + | ||
64 | + #set assumptions | ||
65 | + File.rm(project.satellite.lock_file) unless !File.exists? project.satellite.lock_file | ||
66 | + | ||
67 | + File.exists?(project.satellite.lock_file).should be_false | ||
68 | + | ||
69 | + satellite_action = Gitlab::Satellite::Action.new(user, project) | ||
70 | + satellite_action.send(:in_locked_and_timed_satellite) do |sat_repo| | ||
71 | + repo.should == sat_repo | ||
72 | + (File.exists? project.satellite.lock_file).should be_true | ||
73 | + called = true | ||
74 | + end | ||
75 | + | ||
76 | + called.should be_true | ||
77 | + | ||
78 | + end | ||
79 | + | ||
80 | + it 'should be able to use the satellite after locking' do | ||
81 | + pending "can't test this, doesn't seem to be a way to the the flock status on a file, throwing piles of processes at it seems lousy too" | ||
82 | + repo = project.satellite.repo | ||
83 | + first_call = false | ||
84 | + | ||
85 | + (File.exists? project.satellite.lock_file).should be_false | ||
86 | + | ||
87 | + test_file = ->(called) { | ||
88 | + File.exists?(project.satellite.lock_file).should be_true | ||
89 | + called.should be_true | ||
90 | + File.readlines.should == "some test code" | ||
91 | + File.truncate(project.satellite.lock, 0) | ||
92 | + File.readlines.should == "" | ||
93 | + } | ||
94 | + | ||
95 | + write_file = ->(called, checker) { | ||
96 | + if (File.exists?(project.satellite.lock_file)) | ||
97 | + file = File.open(project.satellite.lock, '+w') | ||
98 | + file.write("some test code") | ||
99 | + file.close | ||
100 | + checker.call(called) | ||
101 | + end | ||
102 | + } | ||
103 | + | ||
104 | + | ||
105 | + satellite_action = Gitlab::Satellite::Action.new(user, project) | ||
106 | + satellite_action.send(:in_locked_and_timed_satellite) do |sat_repo| | ||
107 | + write_file.call(first_call, test_file) | ||
108 | + first_call = true | ||
109 | + repo.should == sat_repo | ||
110 | + (File.exists? project.satellite.lock_file).should be_true | ||
111 | + | ||
112 | + end | ||
113 | + | ||
114 | + first_call.should be_true | ||
115 | + puts File.stat(project.satellite.lock_file).inspect | ||
116 | + | ||
117 | + second_call = false | ||
118 | + satellite_action.send(:in_locked_and_timed_satellite) do |sat_repo| | ||
119 | + write_file.call(second_call, test_file) | ||
120 | + second_call = true | ||
121 | + repo.should == sat_repo | ||
122 | + (File.exists? project.satellite.lock_file).should be_true | ||
123 | + end | ||
124 | + | ||
125 | + second_call.should be_true | ||
126 | + (File.exists? project.satellite.lock_file).should be_true | ||
127 | + end | ||
128 | + | ||
129 | + end | ||
130 | +end | ||
131 | + |
@@ -0,0 +1,136 @@ | @@ -0,0 +1,136 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe 'Gitlab::Satellite::MergeAction' do | ||
4 | + before(:each) do | ||
5 | +# TestEnv.init(mailer: false, init_repos: true, repos: true) | ||
6 | + @master = ['master', 'bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a'] | ||
7 | + @one_after_stable = ['stable', '6ea87c47f0f8a24ae031c3fff17bc913889ecd00'] #this commit sha is one after stable | ||
8 | + @wiki_branch = ['wiki', '635d3e09b72232b6e92a38de6cc184147e5bcb41'] #this is the commit sha where the wiki branch goes off from master | ||
9 | + @conflicting_metior = ['metior', '313d96e42b313a0af5ab50fa233bf43e27118b3f'] #this branch conflicts with the wiki branch | ||
10 | + | ||
11 | + #these commits are quite close together, itended to make string diffs/format patches small | ||
12 | + @close_commit1 = ['2_3_notes_fix', '8470d70da67355c9c009e4401746b1d5410af2e3'] | ||
13 | + @close_commit2 = ['scss_refactoring', 'f0f14c8eaba69ebddd766498a9d0b0e79becd633'] | ||
14 | + | ||
15 | + end | ||
16 | + | ||
17 | + let(:project) { create(:project_with_code) } | ||
18 | + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } | ||
19 | + let(:merge_request_fork) { create(:merge_request) } | ||
20 | + describe '#commits_between' do | ||
21 | + context 'on fork' do | ||
22 | + it 'should get proper commits between' do | ||
23 | + merge_request_fork.target_branch = @one_after_stable[0] | ||
24 | + merge_request_fork.source_branch = @master[0] | ||
25 | + commits = Gitlab::Satellite::MergeAction.new(merge_request_fork.author, merge_request_fork).commits_between | ||
26 | + commits.first.id.should == @one_after_stable[1] | ||
27 | + commits.last.id.should == @master[1] | ||
28 | + | ||
29 | + merge_request_fork.target_branch = @wiki_branch[0] | ||
30 | + merge_request_fork.source_branch = @master[0] | ||
31 | + commits = Gitlab::Satellite::MergeAction.new(merge_request_fork.author, merge_request_fork).commits_between | ||
32 | + commits.first.id.should == @wiki_branch[1] | ||
33 | + commits.last.id.should == @master[1] | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | + context 'between branches' do | ||
38 | + it 'should get proper commits between' do | ||
39 | + merge_request.target_branch = @one_after_stable[0] | ||
40 | + merge_request.source_branch = @master[0] | ||
41 | + commits = Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between | ||
42 | + commits.first.id.should == @one_after_stable[1] | ||
43 | + commits.last.id.should == @master[1] | ||
44 | + | ||
45 | + merge_request.target_branch = @wiki_branch[0] | ||
46 | + merge_request.source_branch = @master[0] | ||
47 | + commits = Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between | ||
48 | + commits.first.id.should == @wiki_branch[1] | ||
49 | + commits.last.id.should == @master[1] | ||
50 | + end | ||
51 | + end | ||
52 | + end | ||
53 | + | ||
54 | + | ||
55 | + describe '#format_patch' do | ||
56 | + context 'on fork' do | ||
57 | + it 'should build a format patch' do | ||
58 | + merge_request_fork.target_branch = @close_commit1[0] | ||
59 | + merge_request_fork.source_branch = @close_commit2[0] | ||
60 | + patch = Gitlab::Satellite::MergeAction.new(merge_request_fork.author, merge_request_fork).format_patch | ||
61 | + (patch.include? "From #{@close_commit2[1]}").should be_true | ||
62 | + (patch.include? "From #{@close_commit1[1]}").should be_true | ||
63 | + end | ||
64 | + end | ||
65 | + | ||
66 | + context 'between branches' do | ||
67 | + it 'should build a format patch' do | ||
68 | + merge_request.target_branch = @close_commit1[0] | ||
69 | + merge_request.source_branch = @close_commit2[0] | ||
70 | + patch = Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).format_patch | ||
71 | + (patch.include? "From #{@close_commit2[1]}").should be_true | ||
72 | + (patch.include? "From #{@close_commit1[1]}").should be_true | ||
73 | + end | ||
74 | + end | ||
75 | + end | ||
76 | + | ||
77 | + | ||
78 | + describe '#diffs_between_satellite tested against diff_in_satellite' do | ||
79 | + context 'on fork' do | ||
80 | + it 'should get proper diffs' do | ||
81 | + merge_request_fork.target_branch = @close_commit1[0] | ||
82 | + merge_request_fork.source_branch = @master[0] | ||
83 | + diffs = Gitlab::Satellite::MergeAction.new(merge_request_fork.author, merge_request_fork).diffs_between_satellite | ||
84 | + | ||
85 | + merge_request_fork.target_branch = @close_commit1[0] | ||
86 | + merge_request_fork.source_branch = @master[0] | ||
87 | + diff = Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request_fork).diffs_between_satellite | ||
88 | + | ||
89 | + diffs.each {|a_diff| (diff.include? a_diff.diff).should be_true} | ||
90 | + end | ||
91 | + end | ||
92 | + | ||
93 | + context 'between branches' do | ||
94 | + it 'should get proper diffs' do | ||
95 | + merge_request.target_branch = @close_commit1[0] | ||
96 | + merge_request.source_branch = @wiki_branch[0] | ||
97 | + diffs = Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite | ||
98 | + | ||
99 | + | ||
100 | + merge_request.target_branch = @close_commit1[0] | ||
101 | + merge_request.source_branch = @master[0] | ||
102 | + diff = Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite | ||
103 | + | ||
104 | + diffs.each {|a_diff| (diff.include? a_diff.diff).should be_true} | ||
105 | + end | ||
106 | + end | ||
107 | + end | ||
108 | + | ||
109 | + | ||
110 | + describe '#can_be_merged?' do | ||
111 | + context 'on fork' do | ||
112 | + it 'return true or false depending on if something is mergable' do | ||
113 | + merge_request_fork.target_branch = @one_after_stable[0] | ||
114 | + merge_request_fork.source_branch = @master[0] | ||
115 | + Gitlab::Satellite::MergeAction.new(merge_request_fork.author, merge_request_fork).can_be_merged?.should be_true | ||
116 | + | ||
117 | + merge_request_fork.target_branch = @conflicting_metior[0] | ||
118 | + merge_request_fork.source_branch = @wiki_branch[0] | ||
119 | + Gitlab::Satellite::MergeAction.new(merge_request_fork.author, merge_request_fork).can_be_merged?.should be_false | ||
120 | + end | ||
121 | + end | ||
122 | + | ||
123 | + context 'between branches' do | ||
124 | + it 'return true or false depending on if something is mergable' do | ||
125 | + merge_request.target_branch = @one_after_stable[0] | ||
126 | + merge_request.source_branch = @master[0] | ||
127 | + Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).can_be_merged?.should be_true | ||
128 | + | ||
129 | + merge_request.target_branch = @conflicting_metior[0] | ||
130 | + merge_request.source_branch = @wiki_branch[0] | ||
131 | + Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).can_be_merged?.should be_false | ||
132 | + end | ||
133 | + end | ||
134 | + end | ||
135 | + | ||
136 | +end | ||
0 | \ No newline at end of file | 137 | \ No newline at end of file |
spec/mailers/notify_spec.rb
@@ -167,7 +167,7 @@ describe Notify do | @@ -167,7 +167,7 @@ describe Notify do | ||
167 | end | 167 | end |
168 | 168 | ||
169 | context 'for merge requests' do | 169 | context 'for merge requests' do |
170 | - let(:merge_request) { create(:merge_request, assignee: assignee, project: project) } | 170 | + let(:merge_request) { create(:merge_request, assignee: assignee, source_project: project, target_project: project) } |
171 | 171 | ||
172 | describe 'that are new' do | 172 | describe 'that are new' do |
173 | subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) } | 173 | subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) } |
@@ -311,7 +311,7 @@ describe Notify do | @@ -311,7 +311,7 @@ describe Notify do | ||
311 | end | 311 | end |
312 | 312 | ||
313 | describe 'on a merge request' do | 313 | describe 'on a merge request' do |
314 | - let(:merge_request) { create(:merge_request, project: project) } | 314 | + let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } |
315 | let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") } | 315 | let(:note_on_merge_request_path) { project_merge_request_path(project, merge_request, anchor: "note_#{note.id}") } |
316 | before(:each) { note.stub(:noteable).and_return(merge_request) } | 316 | before(:each) { note.stub(:noteable).and_return(merge_request) } |
317 | 317 |
spec/models/commit_spec.rb
@@ -3,7 +3,6 @@ require 'spec_helper' | @@ -3,7 +3,6 @@ require 'spec_helper' | ||
3 | describe Commit do | 3 | describe Commit do |
4 | let(:commit) { create(:project_with_code).repository.commit } | 4 | let(:commit) { create(:project_with_code).repository.commit } |
5 | 5 | ||
6 | - | ||
7 | describe '#title' do | 6 | describe '#title' do |
8 | it "returns no_commit_message when safe_message is blank" do | 7 | it "returns no_commit_message when safe_message is blank" do |
9 | commit.stub(:safe_message).and_return('') | 8 | commit.stub(:safe_message).and_return('') |
spec/models/forked_project_link_spec.rb
@@ -12,9 +12,9 @@ | @@ -12,9 +12,9 @@ | ||
12 | require 'spec_helper' | 12 | require 'spec_helper' |
13 | 13 | ||
14 | describe ForkedProjectLink, "add link on fork" do | 14 | describe ForkedProjectLink, "add link on fork" do |
15 | - let(:project_from) {create(:project)} | ||
16 | - let(:namespace) {create(:namespace)} | ||
17 | - let(:user) {create(:user, namespace: namespace)} | 15 | + let(:project_from) { create(:project) } |
16 | + let(:namespace) { create(:namespace) } | ||
17 | + let(:user) { create(:user, namespace: namespace) } | ||
18 | 18 | ||
19 | before do | 19 | before do |
20 | @project_to = fork_project(project_from, user) | 20 | @project_to = fork_project(project_from, user) |
@@ -30,9 +30,9 @@ describe ForkedProjectLink, "add link on fork" do | @@ -30,9 +30,9 @@ describe ForkedProjectLink, "add link on fork" do | ||
30 | end | 30 | end |
31 | 31 | ||
32 | describe :forked_from_project do | 32 | describe :forked_from_project do |
33 | - let(:forked_project_link) {build(:forked_project_link)} | ||
34 | - let(:project_from) {create(:project)} | ||
35 | - let(:project_to) {create(:project, forked_project_link: forked_project_link)} | 33 | + let(:forked_project_link) { build(:forked_project_link) } |
34 | + let(:project_from) { create(:project) } | ||
35 | + let(:project_to) { create(:project, forked_project_link: forked_project_link) } | ||
36 | 36 | ||
37 | 37 | ||
38 | before :each do | 38 | before :each do |
spec/models/merge_request_spec.rb
@@ -41,15 +41,12 @@ describe MergeRequest do | @@ -41,15 +41,12 @@ describe MergeRequest do | ||
41 | it { should include_module(Issuable) } | 41 | it { should include_module(Issuable) } |
42 | end | 42 | end |
43 | 43 | ||
44 | - describe "#mr_and_commit_notes" do | ||
45 | - | ||
46 | - end | ||
47 | 44 | ||
48 | describe "#mr_and_commit_notes" do | 45 | describe "#mr_and_commit_notes" do |
49 | let!(:merge_request) { create(:merge_request) } | 46 | let!(:merge_request) { create(:merge_request) } |
50 | 47 | ||
51 | before do | 48 | before do |
52 | - merge_request.stub(:commits) { [merge_request.project.repository.commit] } | 49 | + merge_request.stub(:commits) { [merge_request.source_project.repository.commit] } |
53 | create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit') | 50 | create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit') |
54 | create(:note, noteable: merge_request) | 51 | create(:note, noteable: merge_request) |
55 | end | 52 | end |
@@ -71,4 +68,39 @@ describe MergeRequest do | @@ -71,4 +68,39 @@ describe MergeRequest do | ||
71 | subject.is_being_reassigned?.should be_false | 68 | subject.is_being_reassigned?.should be_false |
72 | end | 69 | end |
73 | end | 70 | end |
71 | + | ||
72 | + describe '#for_fork?' do | ||
73 | + it 'returns true if the merge request is for a fork' do | ||
74 | + subject.source_project = create(:source_project) | ||
75 | + subject.target_project = create(:target_project) | ||
76 | + | ||
77 | + subject.for_fork?.should be_true | ||
78 | + end | ||
79 | + it 'returns false if is not for a fork' do | ||
80 | + subject.source_project = create(:source_project) | ||
81 | + subject.target_project = subject.source_project | ||
82 | + subject.for_fork?.should be_false | ||
83 | + end | ||
84 | + end | ||
85 | + | ||
86 | + | ||
87 | + describe '#allow_source_branch_removal?' do | ||
88 | + it 'should not allow removal when mr is a fork' do | ||
89 | + | ||
90 | + subject.disallow_source_branch_removal?.should be_true | ||
91 | + end | ||
92 | + it 'should not allow removal when the mr is not a fork, but the source branch is the root reference' do | ||
93 | + subject.target_project = subject.source_project | ||
94 | + subject.source_branch = subject.source_project.repository.root_ref | ||
95 | + subject.disallow_source_branch_removal?.should be_true | ||
96 | + end | ||
97 | + | ||
98 | + it 'should not disallow removal when the mr is not a fork, and but source branch is not the root reference' do | ||
99 | + subject.target_project = subject.source_project | ||
100 | + subject.source_branch = "Something Different #{subject.source_project.repository.root_ref}" | ||
101 | + subject.for_fork?.should be_false | ||
102 | + subject.disallow_source_branch_removal?.should be_false | ||
103 | + end | ||
104 | + end | ||
105 | + | ||
74 | end | 106 | end |
spec/models/note_spec.rb
@@ -144,12 +144,12 @@ describe Note do | @@ -144,12 +144,12 @@ describe Note do | ||
144 | end | 144 | end |
145 | 145 | ||
146 | describe '#create_status_change_note' do | 146 | describe '#create_status_change_note' do |
147 | - let(:project) { create(:project) } | ||
148 | - let(:thing) { create(:issue, project: project) } | ||
149 | - let(:author) { create(:user) } | ||
150 | - let(:status) { 'new_status' } | 147 | + let(:project) { create(:project) } |
148 | + let(:thing) { create(:issue, project: project) } | ||
149 | + let(:author) { create(:user) } | ||
150 | + let(:status) { 'new_status' } | ||
151 | 151 | ||
152 | - subject { Note.create_status_change_note(thing, author, status) } | 152 | + subject { Note.create_status_change_note(thing, project, author, status) } |
153 | 153 | ||
154 | it 'creates and saves a Note' do | 154 | it 'creates and saves a Note' do |
155 | should be_a Note | 155 | should be_a Note |
@@ -157,9 +157,9 @@ describe Note do | @@ -157,9 +157,9 @@ describe Note do | ||
157 | end | 157 | end |
158 | 158 | ||
159 | its(:noteable) { should == thing } | 159 | its(:noteable) { should == thing } |
160 | - its(:project) { should == thing.project } | ||
161 | - its(:author) { should == author } | ||
162 | - its(:note) { should =~ /Status changed to #{status}/ } | 160 | + its(:project) { should == thing.project } |
161 | + its(:author) { should == author } | ||
162 | + its(:note) { should =~ /Status changed to #{status}/ } | ||
163 | end | 163 | end |
164 | 164 | ||
165 | describe :authorization do | 165 | describe :authorization do |
spec/models/project_spec.rb
@@ -26,6 +26,9 @@ | @@ -26,6 +26,9 @@ | ||
26 | require 'spec_helper' | 26 | require 'spec_helper' |
27 | 27 | ||
28 | describe Project do | 28 | describe Project do |
29 | + before(:each) { enable_observers } | ||
30 | + after(:each) { disable_observers } | ||
31 | + | ||
29 | describe "Associations" do | 32 | describe "Associations" do |
30 | it { should belong_to(:group) } | 33 | it { should belong_to(:group) } |
31 | it { should belong_to(:namespace) } | 34 | it { should belong_to(:namespace) } |
@@ -95,12 +98,11 @@ describe Project do | @@ -95,12 +98,11 @@ describe Project do | ||
95 | end | 98 | end |
96 | 99 | ||
97 | describe "last_activity methods" do | 100 | describe "last_activity methods" do |
98 | - before { enable_observers } | ||
99 | - let(:project) { create(:project) } | 101 | + let(:project) { create(:project) } |
100 | let(:last_event) { double(created_at: Time.now) } | 102 | let(:last_event) { double(created_at: Time.now) } |
101 | 103 | ||
102 | describe "last_activity" do | 104 | describe "last_activity" do |
103 | - it "should alias last_activity to last_event"do | 105 | + it "should alias last_activity to last_event" do |
104 | project.stub(last_event: last_event) | 106 | project.stub(last_event: last_event) |
105 | project.last_activity.should == last_event | 107 | project.last_activity.should == last_event |
106 | end | 108 | end |
@@ -122,7 +124,7 @@ describe Project do | @@ -122,7 +124,7 @@ describe Project do | ||
122 | let(:project) { create(:project_with_code) } | 124 | let(:project) { create(:project_with_code) } |
123 | 125 | ||
124 | before do | 126 | before do |
125 | - @merge_request = create(:merge_request, project: project) | 127 | + @merge_request = create(:merge_request, source_project: project, target_project: project) |
126 | @key = create(:key, user_id: project.owner.id) | 128 | @key = create(:key, user_id: project.owner.id) |
127 | end | 129 | end |
128 | 130 |
spec/observers/activity_observer_spec.rb
@@ -8,18 +8,6 @@ describe ActivityObserver do | @@ -8,18 +8,6 @@ describe ActivityObserver do | ||
8 | it { @event.project.should == project } | 8 | it { @event.project.should == project } |
9 | end | 9 | end |
10 | 10 | ||
11 | - describe "Merge Request created" do | ||
12 | - before do | ||
13 | - MergeRequest.observers.enable :activity_observer do | ||
14 | - @merge_request = create(:merge_request, project: project) | ||
15 | - @event = Event.last | ||
16 | - end | ||
17 | - end | ||
18 | - | ||
19 | - it_should_be_valid_event | ||
20 | - it { @event.action.should == Event::CREATED } | ||
21 | - it { @event.target.should == @merge_request } | ||
22 | - end | ||
23 | 11 | ||
24 | describe "Issue created" do | 12 | describe "Issue created" do |
25 | before do | 13 | before do |
spec/observers/issue_observer_spec.rb
@@ -26,14 +26,13 @@ describe IssueObserver do | @@ -26,14 +26,13 @@ describe IssueObserver do | ||
26 | before { mock_issue.stub(state: 'closed') } | 26 | before { mock_issue.stub(state: 'closed') } |
27 | 27 | ||
28 | it 'note is created if the issue is being closed' do | 28 | it 'note is created if the issue is being closed' do |
29 | - Note.should_receive(:create_status_change_note).with(mock_issue, some_user, 'closed') | 29 | + Note.should_receive(:create_status_change_note).with(mock_issue, mock_issue.project, some_user, 'closed') |
30 | 30 | ||
31 | subject.after_close(mock_issue, nil) | 31 | subject.after_close(mock_issue, nil) |
32 | end | 32 | end |
33 | 33 | ||
34 | it 'trigger notification to send emails' do | 34 | it 'trigger notification to send emails' do |
35 | subject.notification.should_receive(:close_issue).with(mock_issue, some_user) | 35 | subject.notification.should_receive(:close_issue).with(mock_issue, some_user) |
36 | - | ||
37 | subject.after_close(mock_issue, nil) | 36 | subject.after_close(mock_issue, nil) |
38 | end | 37 | end |
39 | end | 38 | end |
@@ -42,8 +41,7 @@ describe IssueObserver do | @@ -42,8 +41,7 @@ describe IssueObserver do | ||
42 | before { mock_issue.stub(state: 'reopened') } | 41 | before { mock_issue.stub(state: 'reopened') } |
43 | 42 | ||
44 | it 'note is created if the issue is being reopened' do | 43 | it 'note is created if the issue is being reopened' do |
45 | - Note.should_receive(:create_status_change_note).with(mock_issue, some_user, 'reopened') | ||
46 | - | 44 | + Note.should_receive(:create_status_change_note).with(mock_issue, mock_issue.project, some_user, 'reopened') |
47 | subject.after_reopen(mock_issue, nil) | 45 | subject.after_reopen(mock_issue, nil) |
48 | end | 46 | end |
49 | end | 47 | end |
spec/observers/merge_request_observer_spec.rb
1 | require 'spec_helper' | 1 | require 'spec_helper' |
2 | 2 | ||
3 | describe MergeRequestObserver do | 3 | describe MergeRequestObserver do |
4 | - let(:some_user) { create :user } | ||
5 | - let(:assignee) { create :user } | ||
6 | - let(:author) { create :user } | ||
7 | - let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } | ||
8 | - let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) } | 4 | + let(:some_user) { create :user } |
5 | + let(:assignee) { create :user } | ||
6 | + let(:author) { create :user } | ||
7 | + let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } | ||
8 | + let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author) } | ||
9 | let(:unassigned_mr) { create(:merge_request, author: author) } | 9 | let(:unassigned_mr) { create(:merge_request, author: author) } |
10 | - let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) } | 10 | + let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author) } |
11 | let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) } | 11 | let(:closed_unassigned_mr) { create(:closed_merge_request, author: author) } |
12 | 12 | ||
13 | before { subject.stub(:current_user).and_return(some_user) } | 13 | before { subject.stub(:current_user).and_return(some_user) } |
14 | before { subject.stub(notification: mock('NotificationService').as_null_object) } | 14 | before { subject.stub(notification: mock('NotificationService').as_null_object) } |
15 | + before { mr_mock.stub(:author_id) } | ||
16 | + before { mr_mock.stub(:target_project) } | ||
15 | before(:each) { enable_observers } | 17 | before(:each) { enable_observers } |
16 | - | 18 | + after(:each) { disable_observers } |
17 | 19 | ||
18 | subject { MergeRequestObserver.instance } | 20 | subject { MergeRequestObserver.instance } |
19 | 21 | ||
@@ -30,7 +32,7 @@ describe MergeRequestObserver do | @@ -30,7 +32,7 @@ describe MergeRequestObserver do | ||
30 | end | 32 | end |
31 | 33 | ||
32 | it 'is called when a merge request is changed' do | 34 | it 'is called when a merge request is changed' do |
33 | - changed = create(:merge_request, project: create(:project)) | 35 | + changed = create(:merge_request, source_project: create(:project)) |
34 | subject.should_receive(:after_update) | 36 | subject.should_receive(:after_update) |
35 | 37 | ||
36 | MergeRequest.observers.enable :merge_request_observer do | 38 | MergeRequest.observers.enable :merge_request_observer do |
@@ -59,13 +61,13 @@ describe MergeRequestObserver do | @@ -59,13 +61,13 @@ describe MergeRequestObserver do | ||
59 | context '#after_close' do | 61 | context '#after_close' do |
60 | context 'a status "closed"' do | 62 | context 'a status "closed"' do |
61 | it 'note is created if the merge request is being closed' do | 63 | it 'note is created if the merge request is being closed' do |
62 | - Note.should_receive(:create_status_change_note).with(assigned_mr, some_user, 'closed') | 64 | + Note.should_receive(:create_status_change_note).with(assigned_mr, assigned_mr.target_project, some_user, 'closed') |
63 | 65 | ||
64 | assigned_mr.close | 66 | assigned_mr.close |
65 | end | 67 | end |
66 | 68 | ||
67 | it 'notification is delivered only to author if the merge request is being closed' do | 69 | it 'notification is delivered only to author if the merge request is being closed' do |
68 | - Note.should_receive(:create_status_change_note).with(unassigned_mr, some_user, 'closed') | 70 | + Note.should_receive(:create_status_change_note).with(unassigned_mr, unassigned_mr.target_project, some_user, 'closed') |
69 | 71 | ||
70 | unassigned_mr.close | 72 | unassigned_mr.close |
71 | end | 73 | end |
@@ -75,16 +77,42 @@ describe MergeRequestObserver do | @@ -75,16 +77,42 @@ describe MergeRequestObserver do | ||
75 | context '#after_reopen' do | 77 | context '#after_reopen' do |
76 | context 'a status "reopened"' do | 78 | context 'a status "reopened"' do |
77 | it 'note is created if the merge request is being reopened' do | 79 | it 'note is created if the merge request is being reopened' do |
78 | - Note.should_receive(:create_status_change_note).with(closed_assigned_mr, some_user, 'reopened') | 80 | + Note.should_receive(:create_status_change_note).with(closed_assigned_mr, closed_assigned_mr.target_project, some_user, 'reopened') |
79 | 81 | ||
80 | closed_assigned_mr.reopen | 82 | closed_assigned_mr.reopen |
81 | end | 83 | end |
82 | 84 | ||
83 | it 'notification is delivered only to author if the merge request is being reopened' do | 85 | it 'notification is delivered only to author if the merge request is being reopened' do |
84 | - Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, some_user, 'reopened') | 86 | + Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, closed_unassigned_mr.target_project, some_user, 'reopened') |
85 | 87 | ||
86 | closed_unassigned_mr.reopen | 88 | closed_unassigned_mr.reopen |
87 | end | 89 | end |
88 | end | 90 | end |
89 | end | 91 | end |
92 | + | ||
93 | + | ||
94 | + describe "Merge Request created" do | ||
95 | + def self.it_should_be_valid_event | ||
96 | + it { @event.should_not be_nil } | ||
97 | + it { @event.should_not be_nil } | ||
98 | + it { @event.project.should == project } | ||
99 | + it { @event.project.should == project } | ||
100 | + end | ||
101 | + | ||
102 | + let(:project) { create(:project) } | ||
103 | + before do | ||
104 | + TestEnv.enable_observers | ||
105 | + @merge_request = create(:merge_request, source_project: project, target_project: project) | ||
106 | + @event = Event.last | ||
107 | + end | ||
108 | + | ||
109 | + after do | ||
110 | + TestEnv.enable_observers | ||
111 | + end | ||
112 | + | ||
113 | + it_should_be_valid_event | ||
114 | + it { @event.action.should == Event::CREATED } | ||
115 | + it { @event.target.should == @merge_request } | ||
116 | + end | ||
117 | + | ||
90 | end | 118 | end |
spec/observers/user_observer_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper' | @@ -2,6 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe UserObserver do | 3 | describe UserObserver do |
4 | before(:each) { enable_observers } | 4 | before(:each) { enable_observers } |
5 | + after(:each) {disable_observers} | ||
5 | subject { UserObserver.instance } | 6 | subject { UserObserver.instance } |
6 | before { subject.stub(notification: mock('NotificationService').as_null_object) } | 7 | before { subject.stub(notification: mock('NotificationService').as_null_object) } |
7 | 8 |
spec/observers/users_project_observer_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper' | @@ -2,6 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe UsersProjectObserver do | 3 | describe UsersProjectObserver do |
4 | before(:each) { enable_observers } | 4 | before(:each) { enable_observers } |
5 | + after(:each) { disable_observers } | ||
5 | 6 | ||
6 | let(:user) { create(:user) } | 7 | let(:user) { create(:user) } |
7 | let(:project) { create(:project) } | 8 | let(:project) { create(:project) } |
spec/requests/api/merge_requests_spec.rb
@@ -3,10 +3,12 @@ require "spec_helper" | @@ -3,10 +3,12 @@ require "spec_helper" | ||
3 | describe API::API do | 3 | describe API::API do |
4 | include ApiHelpers | 4 | include ApiHelpers |
5 | 5 | ||
6 | - let(:user) { create(:user ) } | ||
7 | - let!(:project) { create(:project_with_code, creator_id: user.id) } | ||
8 | - let!(:merge_request) { create(:merge_request, author: user, assignee: user, project: project, title: "Test") } | ||
9 | - before { project.team << [user, :reporters] } | 6 | + let(:user) { create(:user) } |
7 | + let!(:project) {create(:project_with_code, creator_id: user.id) } | ||
8 | + let!(:merge_request) { create(:merge_request, author: user, assignee: user, source_project: project, target_project: project, title: "Test") } | ||
9 | + before { | ||
10 | + project.team << [user, :reporters] | ||
11 | + } | ||
10 | 12 | ||
11 | describe "GET /projects/:id/merge_requests" do | 13 | describe "GET /projects/:id/merge_requests" do |
12 | context "when unauthenticated" do | 14 | context "when unauthenticated" do |
@@ -40,35 +42,91 @@ describe API::API do | @@ -40,35 +42,91 @@ describe API::API do | ||
40 | end | 42 | end |
41 | 43 | ||
42 | describe "POST /projects/:id/merge_requests" do | 44 | describe "POST /projects/:id/merge_requests" do |
43 | - it "should return merge_request" do | ||
44 | - post api("/projects/#{project.id}/merge_requests", user), | ||
45 | - title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user | ||
46 | - response.status.should == 201 | ||
47 | - json_response['title'].should == 'Test merge_request' | ||
48 | - end | 45 | + context 'between branches projects' do |
46 | + it "should return merge_request" do | ||
47 | + post api("/projects/#{project.id}/merge_requests", user), | ||
48 | + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user | ||
49 | + response.status.should == 201 | ||
50 | + json_response['title'].should == 'Test merge_request' | ||
51 | + end | ||
49 | 52 | ||
50 | - it "should return 422 when source_branch equals target_branch" do | ||
51 | - post api("/projects/#{project.id}/merge_requests", user), | ||
52 | - title: "Test merge_request", source_branch: "master", target_branch: "master", author: user | ||
53 | - response.status.should == 422 | ||
54 | - end | 53 | + it "should return 422 when source_branch equals target_branch" do |
54 | + post api("/projects/#{project.id}/merge_requests", user), | ||
55 | + title: "Test merge_request", source_branch: "master", target_branch: "master", author: user | ||
56 | + response.status.should == 422 | ||
57 | + end | ||
55 | 58 | ||
56 | - it "should return 400 when source_branch is missing" do | ||
57 | - post api("/projects/#{project.id}/merge_requests", user), | ||
58 | - title: "Test merge_request", target_branch: "master", author: user | ||
59 | - response.status.should == 400 | ||
60 | - end | 59 | + it "should return 400 when source_branch is missing" do |
60 | + post api("/projects/#{project.id}/merge_requests", user), | ||
61 | + title: "Test merge_request", target_branch: "master", author: user | ||
62 | + response.status.should == 400 | ||
63 | + end | ||
61 | 64 | ||
62 | - it "should return 400 when target_branch is missing" do | ||
63 | - post api("/projects/#{project.id}/merge_requests", user), | ||
64 | - title: "Test merge_request", source_branch: "stable", author: user | ||
65 | - response.status.should == 400 | 65 | + it "should return 400 when target_branch is missing" do |
66 | + post api("/projects/#{project.id}/merge_requests", user), | ||
67 | + title: "Test merge_request", source_branch: "stable", author: user | ||
68 | + response.status.should == 400 | ||
69 | + end | ||
70 | + | ||
71 | + it "should return 400 when title is missing" do | ||
72 | + post api("/projects/#{project.id}/merge_requests", user), | ||
73 | + target_branch: 'master', source_branch: 'stable' | ||
74 | + response.status.should == 400 | ||
75 | + end | ||
66 | end | 76 | end |
67 | 77 | ||
68 | - it "should return 400 when title is missing" do | ||
69 | - post api("/projects/#{project.id}/merge_requests", user), | ||
70 | - target_branch: 'master', source_branch: 'stable' | ||
71 | - response.status.should == 400 | 78 | + context 'forked projects' do |
79 | + let!(:user2) {create(:user)} | ||
80 | + let!(:forked_project_link) { build(:forked_project_link) } | ||
81 | + let!(:fork_project) { create(:source_project_with_code, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } | ||
82 | + | ||
83 | + before :each do |each| | ||
84 | + fork_project.team << [user2, :reporters] | ||
85 | + forked_project_link.forked_from_project = project | ||
86 | + forked_project_link.forked_to_project = fork_project | ||
87 | + forked_project_link.save! | ||
88 | + end | ||
89 | + | ||
90 | + it "should return merge_request" do | ||
91 | + post api("/projects/#{fork_project.id}/merge_requests", user2), | ||
92 | + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user2, target_project_id: project.id | ||
93 | + response.status.should == 201 | ||
94 | + json_response['title'].should == 'Test merge_request' | ||
95 | + end | ||
96 | + | ||
97 | + it "should not return 422 when source_branch equals target_branch" do | ||
98 | + project.id.should_not == fork_project.id | ||
99 | + fork_project.forked?.should be_true | ||
100 | + fork_project.forked_from_project.should == project | ||
101 | + post api("/projects/#{fork_project.id}/merge_requests", user2), | ||
102 | + title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id | ||
103 | + response.status.should == 201 | ||
104 | + json_response['title'].should == 'Test merge_request' | ||
105 | + end | ||
106 | + | ||
107 | + it "should return 400 when source_branch is missing" do | ||
108 | + post api("/projects/#{fork_project.id}/merge_requests", user2), | ||
109 | + title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id | ||
110 | + response.status.should == 400 | ||
111 | + end | ||
112 | + | ||
113 | + it "should return 400 when target_branch is missing" do | ||
114 | + post api("/projects/#{fork_project.id}/merge_requests", user2), | ||
115 | + title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id | ||
116 | + response.status.should == 400 | ||
117 | + end | ||
118 | + | ||
119 | + it "should return 400 when title is missing" do | ||
120 | + post api("/projects/#{fork_project.id}/merge_requests", user2), | ||
121 | + target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: project.id | ||
122 | + response.status.should == 400 | ||
123 | + end | ||
124 | + | ||
125 | + it "should return 400 when target_branch is specified and not a forked project" do | ||
126 | + post api("/projects/#{project.id}/merge_requests", user), | ||
127 | + target_branch: 'master', source_branch: 'stable', author: user, target_project: fork_project.id | ||
128 | + response.status.should == 400 | ||
129 | + end | ||
72 | end | 130 | end |
73 | end | 131 | end |
74 | 132 | ||
@@ -97,14 +155,14 @@ describe API::API do | @@ -97,14 +155,14 @@ describe API::API do | ||
97 | 155 | ||
98 | it "should return 422 when source_branch and target_branch are renamed the same" do | 156 | it "should return 422 when source_branch and target_branch are renamed the same" do |
99 | put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), | 157 | put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), |
100 | - source_branch: "master", target_branch: "master" | 158 | + source_branch: "master", target_branch: "master" |
101 | response.status.should == 422 | 159 | response.status.should == 422 |
102 | end | 160 | end |
103 | 161 | ||
104 | it "should return merge_request with renamed target_branch" do | 162 | it "should return merge_request with renamed target_branch" do |
105 | - put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "test" | 163 | + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), target_branch: "wiki" |
106 | response.status.should == 200 | 164 | response.status.should == 200 |
107 | - json_response['target_branch'].should == 'test' | 165 | + json_response['target_branch'].should == 'wiki' |
108 | end | 166 | end |
109 | end | 167 | end |
110 | 168 |
spec/requests/api/milestones_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper' | @@ -3,6 +3,7 @@ require 'spec_helper' | ||
3 | describe API::API do | 3 | describe API::API do |
4 | include ApiHelpers | 4 | include ApiHelpers |
5 | before(:each) { enable_observers } | 5 | before(:each) { enable_observers } |
6 | + after(:each) {disable_observers} | ||
6 | 7 | ||
7 | let(:user) { create(:user) } | 8 | let(:user) { create(:user) } |
8 | let!(:project) { create(:project, namespace: user.namespace ) } | 9 | let!(:project) { create(:project, namespace: user.namespace ) } |
spec/requests/api/notes_spec.rb
@@ -6,7 +6,7 @@ describe API::API do | @@ -6,7 +6,7 @@ describe API::API do | ||
6 | let(:user) { create(:user) } | 6 | let(:user) { create(:user) } |
7 | let!(:project) { create(:project, namespace: user.namespace ) } | 7 | let!(:project) { create(:project, namespace: user.namespace ) } |
8 | let!(:issue) { create(:issue, project: project, author: user) } | 8 | let!(:issue) { create(:issue, project: project, author: user) } |
9 | - let!(:merge_request) { create(:merge_request, project: project, author: user) } | 9 | + let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } |
10 | let!(:snippet) { create(:project_snippet, project: project, author: user) } | 10 | let!(:snippet) { create(:project_snippet, project: project, author: user) } |
11 | let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } | 11 | let!(:issue_note) { create(:note, noteable: issue, project: project, author: user) } |
12 | let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) } | 12 | let!(:merge_request_note) { create(:note, noteable: merge_request, project: project, author: user) } |
spec/requests/api/projects_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper' | @@ -3,6 +3,7 @@ require 'spec_helper' | ||
3 | describe API::API do | 3 | describe API::API do |
4 | include ApiHelpers | 4 | include ApiHelpers |
5 | before(:each) { enable_observers } | 5 | before(:each) { enable_observers } |
6 | + after(:each) { disable_observers } | ||
6 | 7 | ||
7 | let(:user) { create(:user) } | 8 | let(:user) { create(:user) } |
8 | let(:user2) { create(:user) } | 9 | let(:user2) { create(:user) } |
@@ -14,7 +15,8 @@ describe API::API do | @@ -14,7 +15,8 @@ describe API::API do | ||
14 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } | 15 | let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } |
15 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } | 16 | let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } |
16 | 17 | ||
17 | - before { project.team << [user, :reporter] } | 18 | + before { |
19 | + project.team << [user, :reporter] } | ||
18 | 20 | ||
19 | describe "GET /projects" do | 21 | describe "GET /projects" do |
20 | context "when unauthenticated" do | 22 | context "when unauthenticated" do |
@@ -46,16 +48,16 @@ describe API::API do | @@ -46,16 +48,16 @@ describe API::API do | ||
46 | it "should not create new project" do | 48 | it "should not create new project" do |
47 | expect { | 49 | expect { |
48 | post api("/projects", user2), name: 'foo' | 50 | post api("/projects", user2), name: 'foo' |
49 | - }.to change {Project.count}.by(0) | 51 | + }.to change { Project.count }.by(0) |
50 | end | 52 | end |
51 | end | 53 | end |
52 | 54 | ||
53 | it "should create new project without path" do | 55 | it "should create new project without path" do |
54 | - expect { post api("/projects", user), name: 'foo' }.to change {Project.count}.by(1) | 56 | + expect { post api("/projects", user), name: 'foo' }.to change { Project.count }.by(1) |
55 | end | 57 | end |
56 | 58 | ||
57 | it "should not create new project without name" do | 59 | it "should not create new project without name" do |
58 | - expect { post api("/projects", user) }.to_not change {Project.count} | 60 | + expect { post api("/projects", user) }.to_not change { Project.count } |
59 | end | 61 | end |
60 | 62 | ||
61 | it "should return a 400 error if name not given" do | 63 | it "should return a 400 error if name not given" do |
@@ -89,17 +91,17 @@ describe API::API do | @@ -89,17 +91,17 @@ describe API::API do | ||
89 | 91 | ||
90 | it "should assign attributes to project" do | 92 | it "should assign attributes to project" do |
91 | project = attributes_for(:project, { | 93 | project = attributes_for(:project, { |
92 | - description: Faker::Lorem.sentence, | ||
93 | - default_branch: 'stable', | ||
94 | - issues_enabled: false, | ||
95 | - wall_enabled: false, | ||
96 | - merge_requests_enabled: false, | ||
97 | - wiki_enabled: false | 94 | + description: Faker::Lorem.sentence, |
95 | + default_branch: 'stable', | ||
96 | + issues_enabled: false, | ||
97 | + wall_enabled: false, | ||
98 | + merge_requests_enabled: false, | ||
99 | + wiki_enabled: false | ||
98 | }) | 100 | }) |
99 | 101 | ||
100 | post api("/projects", user), project | 102 | post api("/projects", user), project |
101 | 103 | ||
102 | - project.each_pair do |k,v| | 104 | + project.each_pair do |k, v| |
103 | next if k == :path | 105 | next if k == :path |
104 | json_response[k.to_s].should == v | 106 | json_response[k.to_s].should == v |
105 | end | 107 | end |
@@ -125,11 +127,11 @@ describe API::API do | @@ -125,11 +127,11 @@ describe API::API do | ||
125 | before { admin } | 127 | before { admin } |
126 | 128 | ||
127 | it "should create new project without path" do | 129 | it "should create new project without path" do |
128 | - expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1) | 130 | + expect { post api("/projects/user/#{user.id}", admin), name: 'foo' }.to change { Project.count }.by(1) |
129 | end | 131 | end |
130 | 132 | ||
131 | it "should not create new project without name" do | 133 | it "should not create new project without name" do |
132 | - expect { post api("/projects/user/#{user.id}", admin) }.to_not change {Project.count} | 134 | + expect { post api("/projects/user/#{user.id}", admin) }.to_not change { Project.count } |
133 | end | 135 | end |
134 | 136 | ||
135 | it "should respond with 201 on success" do | 137 | it "should respond with 201 on success" do |
@@ -144,17 +146,17 @@ describe API::API do | @@ -144,17 +146,17 @@ describe API::API do | ||
144 | 146 | ||
145 | it "should assign attributes to project" do | 147 | it "should assign attributes to project" do |
146 | project = attributes_for(:project, { | 148 | project = attributes_for(:project, { |
147 | - description: Faker::Lorem.sentence, | ||
148 | - default_branch: 'stable', | ||
149 | - issues_enabled: false, | ||
150 | - wall_enabled: false, | ||
151 | - merge_requests_enabled: false, | ||
152 | - wiki_enabled: false | 149 | + description: Faker::Lorem.sentence, |
150 | + default_branch: 'stable', | ||
151 | + issues_enabled: false, | ||
152 | + wall_enabled: false, | ||
153 | + merge_requests_enabled: false, | ||
154 | + wiki_enabled: false | ||
153 | }) | 155 | }) |
154 | 156 | ||
155 | post api("/projects/user/#{user.id}", admin), project | 157 | post api("/projects/user/#{user.id}", admin), project |
156 | 158 | ||
157 | - project.each_pair do |k,v| | 159 | + project.each_pair do |k, v| |
158 | next if k == :path | 160 | next if k == :path |
159 | json_response[k.to_s].should == v | 161 | json_response[k.to_s].should == v |
160 | end | 162 | end |
@@ -267,7 +269,7 @@ describe API::API do | @@ -267,7 +269,7 @@ describe API::API do | ||
267 | it "should add user to project team" do | 269 | it "should add user to project team" do |
268 | expect { | 270 | expect { |
269 | post api("/projects/#{project.id}/members", user), user_id: user2.id, | 271 | post api("/projects/#{project.id}/members", user), user_id: user2.id, |
270 | - access_level: UsersProject::DEVELOPER | 272 | + access_level: UsersProject::DEVELOPER |
271 | }.to change { UsersProject.count }.by(1) | 273 | }.to change { UsersProject.count }.by(1) |
272 | 274 | ||
273 | response.status.should == 201 | 275 | response.status.should == 201 |
@@ -277,10 +279,10 @@ describe API::API do | @@ -277,10 +279,10 @@ describe API::API do | ||
277 | 279 | ||
278 | it "should return a 201 status if user is already project member" do | 280 | it "should return a 201 status if user is already project member" do |
279 | post api("/projects/#{project.id}/members", user), user_id: user2.id, | 281 | post api("/projects/#{project.id}/members", user), user_id: user2.id, |
280 | - access_level: UsersProject::DEVELOPER | 282 | + access_level: UsersProject::DEVELOPER |
281 | expect { | 283 | expect { |
282 | post api("/projects/#{project.id}/members", user), user_id: user2.id, | 284 | post api("/projects/#{project.id}/members", user), user_id: user2.id, |
283 | - access_level: UsersProject::DEVELOPER | 285 | + access_level: UsersProject::DEVELOPER |
284 | }.not_to change { UsersProject.count }.by(1) | 286 | }.not_to change { UsersProject.count }.by(1) |
285 | 287 | ||
286 | response.status.should == 201 | 288 | response.status.should == 201 |
@@ -411,8 +413,8 @@ describe API::API do | @@ -411,8 +413,8 @@ describe API::API do | ||
411 | it "should add hook to project" do | 413 | it "should add hook to project" do |
412 | expect { | 414 | expect { |
413 | post api("/projects/#{project.id}/hooks", user), | 415 | post api("/projects/#{project.id}/hooks", user), |
414 | - url: "http://example.com" | ||
415 | - }.to change {project.hooks.count}.by(1) | 416 | + url: "http://example.com" |
417 | + }.to change { project.hooks.count }.by(1) | ||
416 | response.status.should == 201 | 418 | response.status.should == 201 |
417 | end | 419 | end |
418 | 420 | ||
@@ -430,7 +432,7 @@ describe API::API do | @@ -430,7 +432,7 @@ describe API::API do | ||
430 | describe "PUT /projects/:id/hooks/:hook_id" do | 432 | describe "PUT /projects/:id/hooks/:hook_id" do |
431 | it "should update an existing project hook" do | 433 | it "should update an existing project hook" do |
432 | put api("/projects/#{project.id}/hooks/#{hook.id}", user), | 434 | put api("/projects/#{project.id}/hooks/#{hook.id}", user), |
433 | - url: 'http://example.org' | 435 | + url: 'http://example.org' |
434 | response.status.should == 200 | 436 | response.status.should == 200 |
435 | json_response['url'].should == 'http://example.org' | 437 | json_response['url'].should == 'http://example.org' |
436 | end | 438 | end |
@@ -455,7 +457,7 @@ describe API::API do | @@ -455,7 +457,7 @@ describe API::API do | ||
455 | it "should delete hook from project" do | 457 | it "should delete hook from project" do |
456 | expect { | 458 | expect { |
457 | delete api("/projects/#{project.id}/hooks/#{hook.id}", user) | 459 | delete api("/projects/#{project.id}/hooks/#{hook.id}", user) |
458 | - }.to change {project.hooks.count}.by(-1) | 460 | + }.to change { project.hooks.count }.by(-1) |
459 | response.status.should == 200 | 461 | response.status.should == 200 |
460 | end | 462 | end |
461 | 463 | ||
@@ -501,26 +503,26 @@ describe API::API do | @@ -501,26 +503,26 @@ describe API::API do | ||
501 | describe "POST /projects/:id/snippets" do | 503 | describe "POST /projects/:id/snippets" do |
502 | it "should create a new project snippet" do | 504 | it "should create a new project snippet" do |
503 | post api("/projects/#{project.id}/snippets", user), | 505 | post api("/projects/#{project.id}/snippets", user), |
504 | - title: 'api test', file_name: 'sample.rb', code: 'test' | 506 | + title: 'api test', file_name: 'sample.rb', code: 'test' |
505 | response.status.should == 201 | 507 | response.status.should == 201 |
506 | json_response['title'].should == 'api test' | 508 | json_response['title'].should == 'api test' |
507 | end | 509 | end |
508 | 510 | ||
509 | it "should return a 400 error if title is not given" do | 511 | it "should return a 400 error if title is not given" do |
510 | post api("/projects/#{project.id}/snippets", user), | 512 | post api("/projects/#{project.id}/snippets", user), |
511 | - file_name: 'sample.rb', code: 'test' | 513 | + file_name: 'sample.rb', code: 'test' |
512 | response.status.should == 400 | 514 | response.status.should == 400 |
513 | end | 515 | end |
514 | 516 | ||
515 | it "should return a 400 error if file_name not given" do | 517 | it "should return a 400 error if file_name not given" do |
516 | post api("/projects/#{project.id}/snippets", user), | 518 | post api("/projects/#{project.id}/snippets", user), |
517 | - title: 'api test', code: 'test' | 519 | + title: 'api test', code: 'test' |
518 | response.status.should == 400 | 520 | response.status.should == 400 |
519 | end | 521 | end |
520 | 522 | ||
521 | it "should return a 400 error if code not given" do | 523 | it "should return a 400 error if code not given" do |
522 | post api("/projects/#{project.id}/snippets", user), | 524 | post api("/projects/#{project.id}/snippets", user), |
523 | - title: 'api test', file_name: 'sample.rb' | 525 | + title: 'api test', file_name: 'sample.rb' |
524 | response.status.should == 400 | 526 | response.status.should == 400 |
525 | end | 527 | end |
526 | end | 528 | end |
@@ -528,7 +530,7 @@ describe API::API do | @@ -528,7 +530,7 @@ describe API::API do | ||
528 | describe "PUT /projects/:id/snippets/:shippet_id" do | 530 | describe "PUT /projects/:id/snippets/:shippet_id" do |
529 | it "should update an existing project snippet" do | 531 | it "should update an existing project snippet" do |
530 | put api("/projects/#{project.id}/snippets/#{snippet.id}", user), | 532 | put api("/projects/#{project.id}/snippets/#{snippet.id}", user), |
531 | - code: 'updated code' | 533 | + code: 'updated code' |
532 | response.status.should == 200 | 534 | response.status.should == 200 |
533 | json_response['title'].should == 'example' | 535 | json_response['title'].should == 'example' |
534 | snippet.reload.content.should == 'updated code' | 536 | snippet.reload.content.should == 'updated code' |
@@ -536,7 +538,7 @@ describe API::API do | @@ -536,7 +538,7 @@ describe API::API do | ||
536 | 538 | ||
537 | it "should update an existing project snippet with new title" do | 539 | it "should update an existing project snippet with new title" do |
538 | put api("/projects/#{project.id}/snippets/#{snippet.id}", user), | 540 | put api("/projects/#{project.id}/snippets/#{snippet.id}", user), |
539 | - title: 'other api test' | 541 | + title: 'other api test' |
540 | response.status.should == 200 | 542 | response.status.should == 200 |
541 | json_response['title'].should == 'other api test' | 543 | json_response['title'].should == 'other api test' |
542 | end | 544 | end |
@@ -598,7 +600,7 @@ describe API::API do | @@ -598,7 +600,7 @@ describe API::API do | ||
598 | 600 | ||
599 | describe "POST /projects/:id/keys" do | 601 | describe "POST /projects/:id/keys" do |
600 | it "should not create an invalid ssh key" do | 602 | it "should not create an invalid ssh key" do |
601 | - post api("/projects/#{project.id}/keys", user), { title: "invalid key" } | 603 | + post api("/projects/#{project.id}/keys", user), {title: "invalid key"} |
602 | response.status.should == 404 | 604 | response.status.should == 404 |
603 | end | 605 | end |
604 | 606 | ||
@@ -606,7 +608,7 @@ describe API::API do | @@ -606,7 +608,7 @@ describe API::API do | ||
606 | key_attrs = attributes_for :key | 608 | key_attrs = attributes_for :key |
607 | expect { | 609 | expect { |
608 | post api("/projects/#{project.id}/keys", user), key_attrs | 610 | post api("/projects/#{project.id}/keys", user), key_attrs |
609 | - }.to change{ project.deploy_keys.count }.by(1) | 611 | + }.to change { project.deploy_keys.count }.by(1) |
610 | end | 612 | end |
611 | end | 613 | end |
612 | 614 | ||
@@ -616,7 +618,7 @@ describe API::API do | @@ -616,7 +618,7 @@ describe API::API do | ||
616 | it "should delete existing key" do | 618 | it "should delete existing key" do |
617 | expect { | 619 | expect { |
618 | delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user) | 620 | delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user) |
619 | - }.to change{ project.deploy_keys.count }.by(-1) | 621 | + }.to change { project.deploy_keys.count }.by(-1) |
620 | end | 622 | end |
621 | 623 | ||
622 | it "should return 404 Not Found with invalid ID" do | 624 | it "should return 404 Not Found with invalid ID" do |
spec/services/notification_service_spec.rb
@@ -156,7 +156,8 @@ describe NotificationService do | @@ -156,7 +156,8 @@ describe NotificationService do | ||
156 | let(:merge_request) { create :merge_request, assignee: create(:user) } | 156 | let(:merge_request) { create :merge_request, assignee: create(:user) } |
157 | 157 | ||
158 | before do | 158 | before do |
159 | - build_team(merge_request.project) | 159 | + build_team(merge_request.source_project) |
160 | + build_team(merge_request.target_project) | ||
160 | end | 161 | end |
161 | 162 | ||
162 | describe :new_merge_request do | 163 | describe :new_merge_request do |
spec/services/project_transfer_service_spec.rb
@@ -2,6 +2,7 @@ require 'spec_helper' | @@ -2,6 +2,7 @@ require 'spec_helper' | ||
2 | 2 | ||
3 | describe ProjectTransferService do | 3 | describe ProjectTransferService do |
4 | before(:each) { enable_observers } | 4 | before(:each) { enable_observers } |
5 | + after(:each) {disable_observers} | ||
5 | 6 | ||
6 | context 'namespace -> namespace' do | 7 | context 'namespace -> namespace' do |
7 | let(:user) { create(:user) } | 8 | let(:user) { create(:user) } |
@@ -24,6 +25,7 @@ describe ProjectTransferService do | @@ -24,6 +25,7 @@ describe ProjectTransferService do | ||
24 | @result = service.transfer(project, nil) | 25 | @result = service.transfer(project, nil) |
25 | end | 26 | end |
26 | 27 | ||
28 | + | ||
27 | it { @result.should be_true } | 29 | it { @result.should be_true } |
28 | it { project.namespace.should == nil } | 30 | it { project.namespace.should == nil } |
29 | end | 31 | end |
spec/spec_helper.rb
@@ -48,8 +48,11 @@ Spork.prefork do | @@ -48,8 +48,11 @@ Spork.prefork do | ||
48 | # instead of true. | 48 | # instead of true. |
49 | config.use_transactional_fixtures = false | 49 | config.use_transactional_fixtures = false |
50 | 50 | ||
51 | - config.before do | ||
52 | - TestEnv.init(observers: false) | 51 | + config.before(:suite) do |
52 | + TestEnv.init(observers: false, init_repos: true, repos: false) | ||
53 | + end | ||
54 | + config.before(:each) do | ||
55 | + TestEnv.setup_stubs | ||
53 | end | 56 | end |
54 | end | 57 | end |
55 | end | 58 | end |
spec/support/test_env.rb
@@ -27,17 +27,65 @@ module TestEnv | @@ -27,17 +27,65 @@ module TestEnv | ||
27 | 27 | ||
28 | # Disable mailer for spinach tests | 28 | # Disable mailer for spinach tests |
29 | disable_mailer if opts[:mailer] == false | 29 | disable_mailer if opts[:mailer] == false |
30 | + setup_stubs | ||
30 | 31 | ||
31 | 32 | ||
32 | - # Use tmp dir for FS manipulations | ||
33 | - repos_path = Rails.root.join('tmp', 'test-git-base-path') | ||
34 | - Gitlab.config.gitlab_shell.stub(repos_path: repos_path) | ||
35 | - Gitlab::Git::Repository.stub(repos_path: repos_path) | 33 | + clear_test_repo_dir if opts[:init_repos] == true |
34 | + setup_test_repos(opts) if opts[:repos] == true | ||
35 | + end | ||
36 | + | ||
37 | + def testing_path | ||
38 | + Rails.root.join('tmp', 'test-git-base-path') | ||
39 | + end | ||
40 | + | ||
41 | + def seed_repo_path | ||
42 | + Rails.root.join('tmp', 'repositories', 'gitlabhq') | ||
43 | + end | ||
44 | + | ||
45 | + def seed_satellite_path | ||
46 | + Rails.root.join('tmp', 'satellite', 'gitlabhq') | ||
47 | + end | ||
48 | + | ||
49 | + def satellite_path | ||
50 | + "#{testing_path()}/satellite" | ||
51 | + end | ||
52 | + | ||
53 | + def repo(namespace, name) | ||
54 | + unless (namespace.nil? || namespace.path.nil? || namespace.path.strip.empty?) | ||
55 | + repo = File.join(testing_path(), "#{namespace.path}/#{name}.git") | ||
56 | + else | ||
57 | + repo = File.join(testing_path(), "#{name}.git") | ||
58 | + end | ||
59 | + end | ||
60 | + | ||
61 | + def satellite(namespace, name) | ||
62 | + unless (namespace.nil? || namespace.path.nil? || namespace.path.strip.empty?) | ||
63 | + satellite_repo = File.join(satellite_path, namespace.path, name) | ||
64 | + else | ||
65 | + satellite_repo = File.join(satellite_path, name) | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
36 | 69 | ||
70 | + def setup_test_repos(opts ={}) | ||
71 | + create_repo(nil, 'gitlabhq') #unless opts[:repo].nil? || !opts[:repo].include?('') | ||
72 | + create_repo(nil, 'source_gitlabhq') #unless opts[:repo].nil? || !opts[:repo].include?('source_') | ||
73 | + create_repo(nil, 'target_gitlabhq') #unless opts[:repo].nil? || !opts[:repo].include?('target_') | ||
74 | + end | ||
75 | + | ||
76 | + def setup_stubs() | ||
77 | + # Use tmp dir for FS manipulations | ||
78 | + repos_path = testing_path() | ||
37 | GollumWiki.any_instance.stub(:init_repo) do |path| | 79 | GollumWiki.any_instance.stub(:init_repo) do |path| |
38 | create_temp_repo(File.join(repos_path, "#{path}.git")) | 80 | create_temp_repo(File.join(repos_path, "#{path}.git")) |
39 | end | 81 | end |
40 | 82 | ||
83 | + Gitlab.config.gitlab_shell.stub(repos_path: repos_path) | ||
84 | + | ||
85 | + Gitlab.config.satellites.stub(path: satellite_path) | ||
86 | + | ||
87 | + Gitlab::Git::Repository.stub(repos_path: repos_path) | ||
88 | + | ||
41 | Gitlab::Shell.any_instance.stub( | 89 | Gitlab::Shell.any_instance.stub( |
42 | add_repository: true, | 90 | add_repository: true, |
43 | mv_repository: true, | 91 | mv_repository: true, |
@@ -48,24 +96,54 @@ module TestEnv | @@ -48,24 +96,54 @@ module TestEnv | ||
48 | ) | 96 | ) |
49 | 97 | ||
50 | Gitlab::Satellite::Satellite.any_instance.stub( | 98 | Gitlab::Satellite::Satellite.any_instance.stub( |
51 | - exists?: true, | ||
52 | - destroy: true, | ||
53 | - create: true | 99 | + exists?: true, |
100 | + destroy: true, | ||
101 | + create: true, | ||
102 | + lock_files_dir: repos_path | ||
54 | ) | 103 | ) |
55 | 104 | ||
56 | MergeRequest.any_instance.stub( | 105 | MergeRequest.any_instance.stub( |
57 | - check_if_can_be_merged: true | 106 | + check_if_can_be_merged: true |
58 | ) | 107 | ) |
59 | - | ||
60 | Repository.any_instance.stub( | 108 | Repository.any_instance.stub( |
61 | - size: 12.45 | 109 | + size: 12.45 |
62 | ) | 110 | ) |
111 | + end | ||
63 | 112 | ||
113 | + def clear_test_repo_dir | ||
114 | + setup_stubs | ||
115 | + # Use tmp dir for FS manipulations | ||
116 | + repos_path = testing_path() | ||
64 | # Remove tmp/test-git-base-path | 117 | # Remove tmp/test-git-base-path |
65 | FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path | 118 | FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path |
66 | 119 | ||
67 | # Recreate tmp/test-git-base-path | 120 | # Recreate tmp/test-git-base-path |
68 | FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path | 121 | FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path |
122 | + #Since much more is happening in satellites | ||
123 | + FileUtils.mkdir_p Gitlab.config.satellites.path | ||
124 | + end | ||
125 | + | ||
126 | + def clear_repo_dir(namespace, name) | ||
127 | + setup_stubs | ||
128 | + #Clean any .wiki.git that may have been created | ||
129 | + FileUtils.rm_rf File.join(testing_path(), "#{name}.wiki.git") | ||
130 | + end | ||
131 | + | ||
132 | + #Create a repo and it's satellite | ||
133 | + def create_repo(namespace, name) | ||
134 | + setup_stubs | ||
135 | + repo = repo(namespace, name) | ||
136 | + | ||
137 | + # Symlink tmp/repositories/gitlabhq to tmp/test-git-base-path/gitlabhq | ||
138 | + system("ln -s -f #{seed_repo_path()} #{repo}") | ||
139 | + create_satellite(repo, namespace, name) | ||
140 | + end | ||
141 | + | ||
142 | + # Create a testing satellite, and clone the source repo into it | ||
143 | + def create_satellite(source_repo, namespace, satellite_name) | ||
144 | + satellite_repo = satellite(namespace, satellite_name) | ||
145 | + # Symlink tmp/satellite/gitlabhq to tmp/test-git-base-path/satellite/gitlabhq | ||
146 | + system("ln -s -f #{seed_satellite_path()} #{satellite_repo}") | ||
69 | end | 147 | end |
70 | 148 | ||
71 | def create_temp_repo(path) | 149 | def create_temp_repo(path) |