diff options
author | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2015-08-11 15:33:31 +0300 |
---|---|---|
committer | Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com> | 2015-08-11 15:33:31 +0300 |
commit | 3e259ea8bc198b7a5c67bd1e03dc9d44c7dd5854 (patch) | |
tree | f726369d15ae21d54272c586a30db4102817af6e /app | |
parent | c0bf026ed8253e9bf749546e40f968dbc20aaac1 (diff) |
Revert "Merge branch 'revert-satellites' into 'master'
"
This reverts commit 5daf44b7c86e0e2641a902b1da8b01d91fa3dbfa, reversing
changes made to 2f706fbd231cabe7a76a5d17ac44285aaaf8592c.
Diffstat (limited to 'app')
57 files changed, 707 insertions, 576 deletions
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 762eec63dee..995a2f24093 100644 --- a/app/assets/javascripts/merge_request_widget.js.coffee +++ b/app/assets/javascripts/merge_request_widget.js.coffee @@ -19,7 +19,7 @@ class @MergeRequestWidget when 'merged' location.reload() else - setTimeout(merge_request_widget.mergeInProgress, 3000) + setTimeout(merge_request_widget.mergeInProgress, 2000) dataType: 'json' getMergeStatus: -> @@ -49,10 +49,8 @@ class @MergeRequestWidget @setMergeButtonClass('btn-danger') showCiCoverage: (coverage) -> - cov_html = $('<span>') - cov_html.addClass('ci-coverage') - cov_html.text('Coverage ' + coverage + '%') - $('.ci_widget:visible').append(cov_html) + text = 'Coverage ' + coverage + '%' + $('.ci_widget:visible .ci-coverage').text(text) setMergeButtonClass: (css_class) -> $('.accept_merge_request').removeClass("btn-create").addClass(css_class) diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index baba6f32129..30bbec7b795 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -1,9 +1,15 @@ - - /** - * MR -> show: Automerge widget +/** + * MR -> show: Automerge widget * */ .mr-state-widget { + background: #FAFAFA; + margin-bottom: 20px; + color: #666; + border: 1px solid #e5e5e5; + @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05)); + @include border-radius(3px); + form { margin-bottom: 0; .clearfix { @@ -20,16 +26,67 @@ display: inline-block; margin: 0; margin-left: 20px; - padding: 10px 0; + padding: 5px; line-height: 20px; - font-weight: bold; .remove_source_checkbox { margin: 0; - font-weight: bold; } } } + + .ci_widget { + border-bottom: 1px solid #EEE; + + i { + margin-right: 4px; + } + + &.ci-success { + color: $gl-success; + } + + &.ci-skipped { + background-color: #eee; + color: #888; + } + + &.ci-pending, + &.ci-running { + color: $gl-warning; + } + + &.ci-failed, + &.ci-canceled, + &.ci-error { + color: $gl-danger; + } + } + + .mr-widget-body, + .ci_widget, + .mr-widget-footer { + padding: 15px; + } + + .mr-widget-body { + h4 { + font-weight: bold; + margin: 5px 0; + } + + p:last-child { + margin-bottom: 0; + } + } + + .mr-widget-footer { + border-top: 1px solid #EEE; + } + + .ci-coverage { + float: right; + } } @media(min-width: $screen-sm-max) { @@ -61,23 +118,10 @@ } .label-branch { - @include border-radius(4px); - padding: 3px 4px; - border: none; - background: $hover; - color: #333; + color: #222; font-family: $monospace_font; - font-weight: normal; + font-weight: bold; overflow: hidden; - - .label-project { - @include border-radius-left(4px); - padding: 3px 4px; - background: #279; - position: relative; - left: -4px; - letter-spacing: -1px; - } } .mr-list { @@ -124,64 +168,6 @@ display: none; } -.mr-state-widget { - font-size: 13px; - background: #FAFAFA; - margin-bottom: 20px; - color: #666; - border: 1px solid #e5e5e5; - @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05)); - @include border-radius(3px); - - .ci_widget { - padding: 10px 15px; - font-size: 15px; - border-bottom: 1px solid #EEE; - - &.ci-success { - color: $gl-success; - } - - &.ci-skipped { - background-color: #eee; - color: #888; - } - - &.ci-pending, - &.ci-running { - color: $gl-warning; - } - - &.ci-failed, - &.ci-canceled, - &.ci-error { - color: $gl-danger; - } - } - - .mr-widget-body { - padding: 10px 15px; - - h4 { - font-weight: bold; - margin: 5px 0; - } - - p:last-child { - margin-bottom: 0; - } - } - - .mr-widget-footer { - padding: 10px 15px; - border-top: 1px solid #EEE; - } - - .ci-coverage { - float: right; - } -} - .merge-request-show-labels { a { margin-right: 5px; @@ -196,3 +182,7 @@ .merge-request-form .select2-container { width: 250px !important; } + +#modal_merge_info .modal-dialog { + width: 600px; +} diff --git a/app/controllers/projects/blob_controller.rb b/app/controllers/projects/blob_controller.rb index b762518d377..100d3d3b317 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -13,27 +13,20 @@ class Projects::BlobController < Projects::ApplicationController before_action :commit, except: [:new, :create] before_action :blob, except: [:new, :create] before_action :from_merge_request, only: [:edit, :update] - before_action :after_edit_path, only: [:edit, :update] before_action :require_branch_head, only: [:edit, :update] + before_action :editor_variables, except: [:show, :preview, :diff] + before_action :after_edit_path, only: [:edit, :update] def new commit unless @repository.empty? end def create - file_path = File.join(@path, File.basename(params[:file_name])) - result = Files::CreateService.new( - @project, - current_user, - params.merge(new_branch: sanitized_new_branch_name), - @ref, - file_path - ).execute + result = Files::CreateService.new(@project, current_user, @commit_params).execute if result[:status] == :success flash[:notice] = "Your changes have been successfully committed" - ref = sanitized_new_branch_name.presence || @ref - redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(ref, file_path)) + redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) else flash[:alert] = result[:message] render :new @@ -48,22 +41,10 @@ class Projects::BlobController < Projects::ApplicationController end def update - result = Files::UpdateService. - new( - @project, - current_user, - params.merge(new_branch: sanitized_new_branch_name), - @ref, - @path - ).execute + result = Files::UpdateService.new(@project, current_user, @commit_params).execute if result[:status] == :success flash[:notice] = "Your changes have been successfully committed" - - if from_merge_request - from_merge_request.reload_code - end - redirect_to after_edit_path else flash[:alert] = result[:message] @@ -80,12 +61,11 @@ class Projects::BlobController < Projects::ApplicationController end def destroy - result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute + result = Files::DeleteService.new(@project, current_user, @commit_params).execute if result[:status] == :success flash[:notice] = "Your changes have been successfully committed" - redirect_to namespace_project_tree_path(@project.namespace, @project, - @ref) + redirect_to namespace_project_tree_path(@project.namespace, @project, @target_branch) else flash[:alert] = result[:message] render :show @@ -135,7 +115,6 @@ class Projects::BlobController < Projects::ApplicationController @id = params[:id] @ref, @path = extract_ref(@id) - rescue InvalidPathError not_found! end @@ -145,8 +124,8 @@ class Projects::BlobController < Projects::ApplicationController if from_merge_request diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) + "#file-path-#{hexdigest(@path)}" - elsif sanitized_new_branch_name.present? - namespace_project_blob_path(@project.namespace, @project, File.join(sanitized_new_branch_name, @path)) + elsif @target_branch.present? + namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @path)) else namespace_project_blob_path(@project.namespace, @project, @id) end @@ -160,4 +139,25 @@ class Projects::BlobController < Projects::ApplicationController def sanitized_new_branch_name @new_branch ||= sanitize(strip_tags(params[:new_branch])) end + + def editor_variables + @current_branch = @ref + @target_branch = (sanitized_new_branch_name || @ref) + + @file_path = + if action_name.to_s == 'create' + File.join(@path, File.basename(params[:file_name])) + else + @path + end + + @commit_params = { + file_path: @file_path, + current_branch: @current_branch, + target_branch: @target_branch, + commit_message: params[:commit_message], + file_content: params[:content], + file_content_encoding: params[:encoding] + } + end end diff --git a/app/controllers/projects/compare_controller.rb b/app/controllers/projects/compare_controller.rb index c5f085c236f..d9b3adae95b 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -13,13 +13,8 @@ class Projects::CompareController < Projects::ApplicationController base_ref = Addressable::URI.unescape(params[:from]) @ref = head_ref = Addressable::URI.unescape(params[:to]) - compare_result = CompareService.new.execute( - current_user, - @project, - head_ref, - @project, - base_ref - ) + compare_result = CompareService.new. + execute(@project, head_ref, @project, base_ref) @commits = compare_result.commits @diffs = compare_result.diffs diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d1265198318..f3054881daf 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -1,9 +1,7 @@ -require 'gitlab/satellite/satellite' - class Projects::MergeRequestsController < Projects::ApplicationController before_action :module_enabled before_action :merge_request, only: [ - :edit, :update, :show, :diffs, :commits, :automerge, :automerge_check, + :edit, :update, :show, :diffs, :commits, :merge, :merge_check, :ci_status, :toggle_subscription ] before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits] @@ -137,7 +135,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end end - def automerge_check + def merge_check if @merge_request.unchecked? @merge_request.check_if_can_be_merged end @@ -147,11 +145,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController render partial: "projects/merge_requests/widget/show.html.haml", layout: false end - def automerge + def merge return access_denied! unless @merge_request.can_be_merged_by?(current_user) - if @merge_request.automergeable? - AutoMergeWorker.perform_async(@merge_request.id, current_user.id, params) + if @merge_request.mergeable? + MergeWorker.perform_async(@merge_request.id, current_user.id, params) @status = true else @status = false diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 45ee4fe4135..f8169b4f288 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -61,4 +61,14 @@ module MergeRequestsHelper } ) end + + def source_branch_with_namespace(merge_request) + if merge_request.for_fork? + namespace = link_to(merge_request.source_project_namespace, + project_path(merge_request.source_project)) + namespace + ":#{merge_request.source_branch}" + else + merge_request.source_branch + end + end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 324d1795ab4..467b90861f9 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -41,8 +41,6 @@ class MergeRequest < ActiveRecord::Base delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil - attr_accessor :should_remove_source_branch - # When this attribute is true some MR validation is ignored # It allows us to close or modify broken merge requests attr_accessor :allow_broken @@ -57,7 +55,7 @@ class MergeRequest < ActiveRecord::Base transition [:reopened, :opened] => :closed end - event :merge do + event :mark_as_merged do transition [:reopened, :opened, :locked] => :merged end @@ -205,7 +203,10 @@ class MergeRequest < ActiveRecord::Base end def check_if_can_be_merged - if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? + can_be_merged = + project.repository.can_be_merged?(source_sha, target_branch) + + if can_be_merged mark_as_mergeable else mark_as_unmergeable @@ -220,18 +221,6 @@ class MergeRequest < ActiveRecord::Base self.target_project.events.where(target_id: self.id, target_type: "MergeRequest", action: Event::CLOSED).last end - def automerge!(current_user, commit_message = nil) - return unless automergeable? - - MergeRequests::AutoMergeService. - new(target_project, current_user). - execute(self, commit_message) - end - - def remove_source_branch? - self.should_remove_source_branch && !self.source_project.root_ref?(self.source_branch) && !self.for_fork? - end - def open? opened? || reopened? end @@ -240,11 +229,11 @@ class MergeRequest < ActiveRecord::Base title =~ /\A\[?WIP\]?:? /i end - def automergeable? + def mergeable? open? && !work_in_progress? && can_be_merged? end - def automerge_status + def gitlab_merge_status if work_in_progress? "work_in_progress" else @@ -271,14 +260,14 @@ class MergeRequest < ActiveRecord::Base # # see "git diff" def to_diff(current_user) - Gitlab::Satellite::MergeAction.new(current_user, self).diff_in_satellite + target_project.repository.diff_text(target_branch, source_sha) end # Returns the commit as a series of email patches. # # see "git format-patch" def to_patch(current_user) - Gitlab::Satellite::MergeAction.new(current_user, self).format_patch + target_project.repository.format_patch(target_branch, source_sha) end def hook_attrs @@ -429,4 +418,30 @@ class MergeRequest < ActiveRecord::Base "Open" end end + + def target_sha + @target_sha ||= target_project. + repository.commit(target_branch).sha + end + + def source_sha + commits.first.sha + end + + def fetch_ref + target_project.repository.fetch_ref( + source_project.repository.path_to_repo, + "refs/heads/#{source_branch}", + "refs/merge-requests/#{iid}/head" + ) + end + + def in_locked_state + begin + lock_mr + yield + ensure + unlock_mr if locked? + end + end end diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb index df1c2b78758..e317c8eac4d 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -16,9 +16,8 @@ require Rails.root.join("app/models/commit") class MergeRequestDiff < ActiveRecord::Base include Sortable - # Prevent store of diff - # if commits amount more then 200 - COMMITS_SAFE_SIZE = 200 + # Prevent store of diff if commits amount more then 500 + COMMITS_SAFE_SIZE = 500 attr_reader :commits, :diffs @@ -124,12 +123,12 @@ class MergeRequestDiff < ActiveRecord::Base if new_diffs.any? if new_diffs.size > Commit::DIFF_HARD_LIMIT_FILES self.state = :overflow_diff_files_limit - new_diffs = [] + new_diffs = new_diffs.first[Commit::DIFF_HARD_LIMIT_LINES] end if new_diffs.sum { |diff| diff.diff.lines.count } > Commit::DIFF_HARD_LIMIT_LINES self.state = :overflow_diff_lines_limit - new_diffs = [] + new_diffs = new_diffs.first[Commit::DIFF_HARD_LIMIT_LINES] end end @@ -160,12 +159,21 @@ class MergeRequestDiff < ActiveRecord::Base private def compare_result - @compare_result ||= CompareService.new.execute( - merge_request.author, - merge_request.source_project, - merge_request.source_branch, - merge_request.target_project, - merge_request.target_branch, - ) + @compare_result ||= + begin + # Update ref for merge request + merge_request.fetch_ref + + # Get latest sha of branch from source project + source_sha = merge_request.source_project.commit(source_branch).sha + + Gitlab::CompareResult.new( + Gitlab::Git::Compare.new( + merge_request.target_project.repository.raw_repository, + merge_request.target_branch, + source_sha, + ) + ) + end end end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 30ffacadded..161a16ca61c 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -118,12 +118,11 @@ class Namespace < ActiveRecord::Base gitlab_shell.add_namespace(path_was) if gitlab_shell.mv_namespace(path_was, path) - # If repositories moved successfully we need to remove old satellites - # and send update instructions to users. + # If repositories moved successfully we need to + # send update instructions to users. # However we cannot allow rollback since we moved namespace dir # So we basically we mute exceptions in next actions begin - gitlab_shell.rm_satellites(path_was) send_update_instructions rescue # Returning false does not rollback after_* transaction but gives diff --git a/app/models/project.rb b/app/models/project.rb index 3dc1729e812..4628f478ca6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -520,14 +520,6 @@ class Project < ActiveRecord::Base !repository.exists? || repository.empty? end - def ensure_satellite_exists - self.satellite.create unless self.satellite.exists? - end - - def satellite - @satellite ||= Gitlab::Satellite::Satellite.new(self) - end - def repo repository.raw end @@ -597,14 +589,11 @@ class Project < ActiveRecord::Base new_path_with_namespace = File.join(namespace_dir, path) if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace) - # If repository moved successfully we need to remove old satellite - # and send update instructions to users. + # If repository moved successfully we need to send update instructions to users. # However we cannot allow rollback since we moved repository # So we basically we mute exceptions in next actions begin gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki") - gitlab_shell.rm_satellites(old_path_with_namespace) - ensure_satellite_exists send_move_instructions reset_events_cache rescue @@ -702,7 +691,6 @@ class Project < ActiveRecord::Base def create_repository if forked? if gitlab_shell.fork_repository(forked_from_project.path_with_namespace, self.namespace.path) - ensure_satellite_exists true else errors.add(:base, 'Failed to fork repository via gitlab-shell') diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb index 5aaa4e85cbc..ecdcd48ae60 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -74,6 +74,8 @@ class GitlabCiService < CiService else :error end + rescue Errno::ECONNREFUSED + :error end def fork_registration(new_project, private_token) @@ -103,6 +105,8 @@ class GitlabCiService < CiService if response.code == 200 and response["coverage"] response["coverage"] end + rescue Errno::ECONNREFUSED + nil end def build_page(sha, ref) diff --git a/app/models/repository.rb b/app/models/repository.rb index 0a62980f93a..46efbede2a2 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -364,6 +364,83 @@ class Repository @root_ref ||= raw_repository.root_ref end + def commit_file(user, path, content, message, ref) + path[0] = '' if path[0] == '/' + + committer = user_to_comitter(user) + options = {} + options[:committer] = committer + options[:author] = committer + options[:commit] = { + message: message, + branch: ref + } + + options[:file] = { + content: content, + path: path + } + + Gitlab::Git::Blob.commit(raw_repository, options) + end + + def remove_file(user, path, message, ref) + path[0] = '' if path[0] == '/' + + committer = user_to_comitter(user) + options = {} + options[:committer] = committer + options[:author] = committer + options[:commit] = { + message: message, + branch: ref + } + + options[:file] = { + path: path + } + + Gitlab::Git::Blob.remove(raw_repository, options) + end + + def user_to_comitter(user) + { + email: user.email, + name: user.name, + time: Time.now + } + end + + def can_be_merged?(source_sha, target_branch) + our_commit = rugged.branches[target_branch].target + their_commit = rugged.lookup(source_sha) + + if our_commit && their_commit + !rugged.merge_commits(our_commit, their_commit).conflicts? + else + false + end + end + + def merge(source_sha, target_branch, options = {}) + our_commit = rugged.branches[target_branch].target + their_commit = rugged.lookup(source_sha) + + raise "Invalid merge target" if our_commit.nil? + raise "Invalid merge source" if their_commit.nil? + + merge_index = rugged.merge_commits(our_commit, their_commit) + return false if merge_index.conflicts? + + actual_options = options.merge( + parents: [our_commit, their_commit], + tree: merge_index.write_tree(rugged), + update_ref: "refs/heads/#{target_branch}" + ) + + Rugged::Commit.create(rugged, actual_options) + end + def search_files(query, ref) offset = 2 args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref}) @@ -397,6 +474,11 @@ class Repository ) end + def fetch_ref(source_path, source_ref, target_ref) + args = %W(git fetch #{source_path} #{source_ref}:#{target_ref}) + Gitlab::Popen.popen(args, path_to_repo) + end + private def cache diff --git a/app/services/base_service.rb b/app/services/base_service.rb index 6d9ed345914..f00ec7408b6 100644 --- a/app/services/base_service.rb +++ b/app/services/base_service.rb @@ -31,6 +31,10 @@ class BaseService SystemHooksService.new end + def repository + project.repository + end + # Add an error to the specified model for restricted visibility levels def deny_visibility_level(model, denied_visibility_level = nil) denied_visibility_level ||= model.visibility_level diff --git a/app/services/compare_service.rb b/app/services/compare_service.rb index 6aa9df4b194..70f642baaaa 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -1,27 +1,28 @@ +require 'securerandom' + # Compare 2 branches for one repo or between repositories # and return Gitlab::CompareResult object that responds to commits and diffs class CompareService - def execute(current_user, source_project, source_branch, target_project, target_branch) - # Try to compare branches to get commits list and diffs - # - # Note: Use satellite only when need to compare between two repos - # because satellites are slower than operations on bare repo - if target_project == source_project - Gitlab::CompareResult.new( - Gitlab::Git::Compare.new( - target_project.repository.raw_repository, - target_branch, - source_branch, - ) + def execute(source_project, source_branch, target_project, target_branch) + source_sha = source_project.commit(source_branch).sha + + # If compare with other project we need to fetch ref first + unless target_project == source_project + random_string = SecureRandom.hex + + target_project.repository.fetch_ref( + source_project.repository.path_to_repo, + "refs/heads/#{source_branch}", + "refs/tmp/#{random_string}/head" ) - else - Gitlab::Satellite::CompareAction.new( - current_user, - target_project, - target_branch, - source_project, - source_branch - ).result end + + Gitlab::CompareResult.new( + Gitlab::Git::Compare.new( + target_project.repository.raw_repository, + target_branch, + source_sha, + ) + ) end end diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index bd245100955..d7b40ee8906 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -1,17 +1,80 @@ module Files class BaseService < ::BaseService - attr_reader :ref, :path + class ValidationError < StandardError; end - def initialize(project, user, params, ref, path = nil) - @project, @current_user, @params = project, user, params.dup - @ref = ref - @path = path + def execute + @current_branch = params[:current_branch] + @target_branch = params[:target_branch] + @commit_message = params[:commit_message] + @file_path = params[:file_path] + @file_content = if params[:file_content_encoding] == 'base64' + Base64.decode64(params[:file_content]) + else + params[:file_content] + end + + # Validate parameters + validate + + # Create new branch if it different from current_branch + if @target_branch != @current_branch + create_target_branch + end + + if sha = commit + after_commit(sha, @target_branch) + success + else + error("Something went wrong. Your changes were not committed") + end + rescue ValidationError => ex + error(ex.message) end private - def repository - project.repository + def after_commit(sha, branch) + PostCommitService.new(project, current_user).execute(sha, branch) + end + + def current_branch + @current_branch ||= params[:current_branch] + end + + def target_branch + @target_branch ||= params[:target_branch] + end + + def raise_error(message) + raise ValidationError.new(message) + end + + def validate + allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(@target_branch) + + unless allowed + raise_error("You are not allowed to push into this branch") + end + + unless project.empty_repo? + unless repository.branch_names.include?(@current_branch) + raise_error("You can only create files if you are on top of a branch") + end + + if @current_branch != @target_branch + if repository.branch_names.include?(@target_branch) + raise_error("Branch with such name already exists. You need to switch to this branch in order to make changes") + end + end + end + end + + def create_target_branch + result = CreateBranchService.new(project, current_user).execute(@target_branch, @current_branch) + + unless result[:status] == :success + raise_error("Something went wrong when we tried to create #{@target_branch} for you") + end end end end diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index 23833aa78ec..91d715b2d63 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -1,52 +1,30 @@ require_relative "base_service" module Files - class CreateService < BaseService - def execute - allowed = Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref) + class CreateService < Files::BaseService + def commit + repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch) + end - unless allowed - return error("You are not allowed to create file in this branch") - end + def validate + super - file_name = File.basename(path) - file_path = path + file_name = File.basename(@file_path) unless file_name =~ Gitlab::Regex.file_name_regex - return error( + raise_error( 'Your changes could not be committed, because the file name ' + Gitlab::Regex.file_name_regex_message ) end - if project.empty_repo? - # everything is ok because repo does not have a commits yet - else - unless repository.branch_names.include?(ref) - return error("You can only create files if you are on top of a branch") - end - - blob = repository.blob_at_branch(ref, file_path) + unless project.empty_repo? + blob = repository.blob_at_branch(@current_branch, @file_path) if blob - return error("Your changes could not be committed, because file with such name exists") + raise_error("Your changes could not be committed, because file with such name exists") end end - - - new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path) - created_successfully = new_file_action.commit!( - params[:content], - params[:commit_message], - params[:encoding], - params[:new_branch] - ) - - if created_successfully - success - else - error("Your changes could not be committed, because the file has been changed") - end end end end diff --git a/app/services/files/delete_service.rb b/app/services/files/delete_service.rb index 1497a0f883b..27c881c3430 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -1,36 +1,9 @@ require_relative "base_service" module Files - class DeleteService < BaseService - def execute - allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref) - - unless allowed - return error("You are not allowed to push into this branch") - end - - unless repository.branch_names.include?(ref) - return error("You can only create files if you are on top of a branch") - end - - blob = repository.blob_at_branch(ref, path) - - unless blob - return error("You can only edit text files") - end - - delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path) - - deleted_successfully = delete_file_action.commit!( - nil, - params[:commit_message] - ) - - if deleted_successfully - success - else - error("Your changes could not be committed, because the file has been changed") - end + class DeleteService < Files::BaseService + def commit + repository.remove_file(current_user, @file_path, @commit_message, @target_branch) end end end diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index 0724d3ae634..a20903c6f02 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -1,39 +1,9 @@ require_relative "base_service" module Files - class UpdateService < BaseService - def execute - allowed = ::Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref) - - unless allowed - return error("You are not allowed to push into this branch") - end - - unless repository.branch_names.include?(ref) - return error("You can only create files if you are on top of a branch") - end - - blob = repository.blob_at_branch(ref, path) - - unless blob - return error("You can only edit text files") - end - - edit_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path) - edit_file_action.commit!( - params[:content], - params[:commit_message], - params[:encoding], - params[:new_branch] - ) - - success - rescue Gitlab::Satellite::CheckoutFailed => ex - error("Your changes could not be committed because ref '#{ref}' could not be checked out", 400) - rescue Gitlab::Satellite::CommitFailed => ex - error("Your changes could not be committed. Maybe there was nothing to commit?", 409) - rescue Gitlab::Satellite::PushFailed => ex - error("Your changes could not be committed. Maybe the file was changed by another process?", 409) + class UpdateService < Files::BaseService + def commit + repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch) end end end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 5a2c97b08af..81535450ac1 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -10,16 +10,14 @@ class GitPushService # # Next, this method: # 1. Creates the push event - # 2. Ensures that the project satellite exists - # 3. Updates merge requests - # 4. Recognizes cross-references from commit messages - # 5. Executes the project's web hooks - # 6. Executes the project's services + # 2. Updates merge requests + # 3. Recognizes cross-references from commit messages + # 4. Executes the project's web hooks + # 5. Executes the project's services # def execute(project, user, oldrev, newrev, ref) @project, @user = project, user - project.ensure_satellite_exists project.repository.expire_cache if push_remove_branch?(ref, newrev) @@ -133,7 +131,8 @@ class GitPushService end def is_default_branch?(ref) - Gitlab::Git.branch_ref?(ref) && Gitlab::Git.ref_name(ref) == project.default_branch + Gitlab::Git.branch_ref?(ref) && + (Gitlab::Git.ref_name(ref) == project.default_branch || project.default_branch.nil?) end def commit_user(commit) diff --git a/app/services/merge_requests/auto_merge_service.rb b/app/services/merge_requests/auto_merge_service.rb deleted file mode 100644 index cdedf48b0c0..00000000000 --- a/app/services/merge_requests/auto_merge_service.rb +++ /dev/null @@ -1,30 +0,0 @@ -module MergeRequests - # AutoMergeService class - # - # Do git merge in satellite and in case of success - # mark merge request as merged and execute all hooks and notifications - # Called when you do merge via GitLab UI - class AutoMergeService < BaseMergeService - def execute(merge_request, commit_message) - merge_request.lock_mr - - if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message) - merge_request.merge - - create_merge_event(merge_request, current_user) - create_note(merge_request) - notification_service.merge_mr(merge_request, current_user) - execute_hooks(merge_request, 'merge') - - true - else - merge_request.unlock_mr - false - end - rescue - merge_request.unlock_mr if merge_request.locked? - merge_request.mark_as_unmergeable - false - end - end -end diff --git a/app/services/merge_requests/base_merge_service.rb b/app/services/merge_requests/base_merge_service.rb deleted file mode 100644 index 9579573adf9..00000000000 --- a/app/services/merge_requests/base_merge_service.rb +++ /dev/null @@ -1,10 +0,0 @@ -module MergeRequests - class BaseMergeService < MergeRequests::BaseService - - private - - def create_merge_event(merge_request, current_user) - EventCreateService.new.merge_mr(merge_request, current_user) - end - end -end diff --git a/app/services/merge_requests/build_service.rb b/app/services/merge_requests/build_service.rb index 956480938c3..a9b29f9654d 100644 --- a/app/services/merge_requests/build_service.rb +++ b/app/services/merge_requests/build_service.rb @@ -12,12 +12,16 @@ module MergeRequests merge_request.target_project ||= (project.forked_from_project || project) merge_request.target_branch ||= merge_request.target_project.default_branch - unless merge_request.target_branch && merge_request.source_branch - return build_failed(merge_request, nil) + if merge_request.target_branch.blank? || merge_request.source_branch.blank? + message = + if params[:source_branch] || params[:target_branch] + "You must select source and target branch" + end + + return build_failed(merge_request, message) end compare_result = CompareService.new.execute( - current_user, merge_request.source_project, merge_request.source_branch, merge_request.target_project, @@ -40,7 +44,6 @@ module MergeRequests merge_request.compare_diffs = diffs elsif diffs == false - # satellite timeout return false merge_request.can_be_created = false merge_request.compare_failed = true end @@ -59,9 +62,6 @@ module MergeRequests end merge_request - - rescue Gitlab::Satellite::BranchesWithoutParent - return build_failed(merge_request, "Selected branches have no common commit so they cannot be merged.") end def build_failed(merge_request, message) diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 327ead4ff3f..2107529a21a 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -1,22 +1,57 @@ module MergeRequests # MergeService class # - # Mark existing merge request as merged - # and execute all hooks and notifications - # Called when you do merge via command line and push code - # to target branch - class MergeService < BaseMergeService + # Do git merge and in case of success + # mark merge request as merged and execute all hooks and notifications + # Executed when you do merge via GitLab UI + # + class MergeService < MergeRequests::BaseService + attr_reader :merge_request, :commit_message + def execute(merge_request, commit_message) - merge_request.merge + @commit_message = commit_message + @merge_request = merge_request - create_merge_event(merge_request, current_user) - create_note(merge_request) - notification_service.merge_mr(merge_request, current_user) - execute_hooks(merge_request, 'merge') + unless @merge_request.mergeable? + return error('Merge request is not mergeable') + end + + merge_request.in_locked_state do + if merge_changes + after_merge + success + else + error('Can not merge changes') + end + end + end + + private + + def merge_changes + if sha = commit + after_commit(sha, merge_request.target_branch) + end + end + + def commit + committer = repository.user_to_comitter(current_user) + + options = { + message: commit_message, + author: committer, + committer: committer + } + + repository.merge(merge_request.source_sha, merge_request.target_branch, options) + end + + def after_commit(sha, branch) + PostCommitService.new(project, current_user).execute(sha, branch) + end - true - rescue - false + def after_merge + MergeRequests::PostMergeService.new(project, current_user).execute(merge_request) end end end diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb new file mode 100644 index 00000000000..aceb8cb9021 --- /dev/null +++ b/app/services/merge_requests/post_merge_service.rb @@ -0,0 +1,22 @@ +module MergeRequests + # PostMergeService class + # + # Mark existing merge request as merged + # and execute all hooks and notifications + # + class PostMergeService < MergeRequests::BaseService + def execute(merge_request) + merge_request.mark_as_merged + create_merge_event(merge_request, current_user) + create_note(merge_request) + notification_service.merge_mr(merge_request, current_user) + execute_hooks(merge_request, 'merge') + end + + private + + def create_merge_event(merge_request, current_user) + EventCreateService.new.merge_mr(merge_request, current_user) + end + end +end diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index d0648da049b..e903e48e3cd 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -33,9 +33,9 @@ module MergeRequests merge_requests.uniq.select(&:source_project).each do |merge_request| - MergeRequests::MergeService. + MergeRequests::PostMergeService. new(merge_request.target_project, @current_user). - execute(merge_request, nil) + execute(merge_request) end end diff --git a/app/services/post_commit_service.rb b/app/services/post_commit_service.rb new file mode 100644 index 00000000000..8592c8d238b --- /dev/null +++ b/app/services/post_commit_service.rb @@ -0,0 +1,71 @@ +class PostCommitService < BaseService + include Gitlab::Popen + + attr_reader :changes, :repo_path + + def execute(sha, branch) + commit = repository.commit(sha) + full_ref = Gitlab::Git::BRANCH_REF_PREFIX + branch + old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA + @changes = "#{old_sha} #{sha} #{full_ref}" + @repo_path = repository.path_to_repo + + post_receive + end + + private + + def post_receive + hook = hook_file('post-receive', repo_path) + return true if hook.nil? + call_receive_hook(hook) + end + + def call_receive_hook(hook) + # function will return true if succesful + exit_status = false + + vars = { + 'GL_ID' => Gitlab::ShellEnv.gl_id(current_user), + 'PWD' => repo_path + } + + options = { + chdir: repo_path + } + + # we combine both stdout and stderr as we don't know what stream + # will be used by the custom hook + Open3.popen2e(vars, hook, options) do |stdin, stdout_stderr, wait_thr| + exit_status = true + stdin.sync = true + + # in git, pre- and post- receive hooks may just exit without + # reading stdin. We catch the exception to avoid a broken pipe + # warning + begin + # inject all the changes as stdin to the hook + changes.lines do |line| + stdin.puts line + end + rescue Errno::EPIPE + end + + # need to close stdin before reading stdout + stdin.close + + # only output stdut_stderr if scripts doesn't return 0 + unless wait_thr.value == 0 + exit_status = false + end + end + + exit_status + end + + def hook_file(hook_type, repo_path) + hook_path = File.join(repo_path.strip, 'hooks') + hook_file = "#{hook_path}/#{hook_type}" + hook_file if File.exist?(hook_file) + end +end diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index 403f419ec50..28872c89259 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -27,7 +27,6 @@ module Projects end end - project.satellite.destroy log_info("Project \"#{project.name}\" was removed") system_hook_service.execute_hooks_for(project, :destroy) true diff --git a/app/services/projects/transfer_service.rb b/app/services/projects/transfer_service.rb index f43c0ef70e9..550ed6897dd 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -33,9 +33,6 @@ module Projects raise TransferError.new("Project with same path in target namespace already exists") end - # Remove old satellite - project.satellite.destroy - # Apply new namespace id project.namespace = new_namespace project.save! @@ -51,9 +48,6 @@ module Projects # Move wiki repo also if present gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki") - # Create a new satellite (reload project from DB) - Project.find(project.id).ensure_satellite_exists - # clear project cached events project.reset_events_cache diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index 96f188e4aa7..9c3e1703c89 100644 --- a/app/views/projects/blob/_editor.html.haml +++ b/app/views/projects/blob/_editor.html.haml @@ -12,8 +12,8 @@ \/ = text_field_tag 'file_name', params[:file_name], placeholder: "File name", required: true, class: 'form-control new-file-name' - .pull-right - = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control' + .pull-right + = select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control' .file-content.code %pre.js-edit-mode-pane#editor diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml index dac984f8c31..7c2a4fece94 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -6,11 +6,12 @@ = render 'shared/commit_message_container', params: params, placeholder: 'Add new file' - .form-group.branch - = label_tag 'branch', class: 'control-label' do - Branch - .col-sm-10 - = text_field_tag 'new_branch', @ref, class: "form-control" + - unless @project.empty_repo? + .form-group.branch + = label_tag 'branch', class: 'control-label' do + Branch + .col-sm-10 + = text_field_tag 'new_branch', @ref, class: "form-control" = hidden_field_tag 'content', '', id: 'file-content' = render 'projects/commit_button', ref: @ref, diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml index ff9c0cdb283..7709330611a 100644 --- a/app/views/projects/merge_requests/_new_compare.html.haml +++ b/app/views/projects/merge_requests/_new_compare.html.haml @@ -35,7 +35,7 @@ - if @merge_request.compare_failed .alert.alert-danger %h4 Compare failed - %p We can't compare selected branches. It may be because of huge diff or satellite timeout. Please try again or select different branches. + %p We can't compare selected branches. It may be because of huge diff. Please try again or select different branches. - else .light-well .center diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml index 633a54f3620..76f44211dac 100644 --- a/app/views/projects/merge_requests/_new_submit.html.haml +++ b/app/views/projects/merge_requests/_new_submit.html.haml @@ -24,7 +24,7 @@ = icon('history') Commits %span.badge= @commits.size - %li.diffs-tab + %li.diffs-tab.active = link_to url_for(params), data: {target: '#diffs', action: 'diffs', toggle: 'tab'} do = icon('list-alt') Changes @@ -33,7 +33,7 @@ .tab-content #commits.commits.tab-pane = render "projects/commits/commits", project: @project - #diffs.diffs.tab-pane + #diffs.diffs.tab-pane.active - if @diffs.present? = render "projects/diffs/diffs", diffs: @diffs, project: @project - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index c57eee14143..2662e3aff6b 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -6,40 +6,25 @@ = render "projects/merge_requests/show/mr_box" %hr .append-bottom-20 - .slead - %span From - - if @merge_request.for_fork? - %strong.label-branch< - - if @merge_request.source_project - = link_to @merge_request.source_project_namespace, namespace_project_path(@merge_request.source_project.namespace, @merge_request.source_project) - - else - \ #{@merge_request.source_project_namespace} - \:#{@merge_request.source_branch} + - if @merge_request.open? + .btn-group.btn-group-sm.pull-right + %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} } + = icon('download') + Download as + %span.caret + %ul.dropdown-menu + %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) + %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) + .light + %div + %span From + %span.label-branch #{source_branch_with_namespace(@merge_request)} %span into - %strong.label-branch #{@merge_request.target_project_namespace}:#{@merge_request.target_branch} - - else - %strong.label-branch #{@merge_request.source_branch} - %span into - %strong.label-branch #{@merge_request.target_branch} - - if @merge_request.open? - .btn-group.btn-group-sm.pull-right - %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} } - = icon('download') - Download as - %span.caret - %ul.dropdown-menu - %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) - %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) - - - if @merge_request.open? and @merge_request.source_branch_exists? - .append-bottom-20 - .slead - %span - Fetch the branch with - %strong.label-branch< - git fetch - \ #{@merge_request.source_project.http_url_to_repo} - \ #{@merge_request.source_branch} + %span.label-branch #{@merge_request.target_branch} + - if @merge_request.open? && !@merge_request.branch_missing? + %div + If you want to try or merge this request manually, you can use the + = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" = render "projects/merge_requests/show/how_to_merge" = render "projects/merge_requests/widget/show.html.haml" diff --git a/app/views/projects/merge_requests/automerge.js.haml b/app/views/projects/merge_requests/merge.js.haml index 33321651e32..33321651e32 100644 --- a/app/views/projects/merge_requests/automerge.js.haml +++ b/app/views/projects/merge_requests/merge.js.haml diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml index 3b7f283daf0..a71b181a6a5 100644 --- a/app/views/projects/merge_requests/show/_commits.html.haml +++ b/app/views/projects/merge_requests/show/_commits.html.haml @@ -1 +1 @@ -= render "projects/commits/commits", project: @merge_request.source_project += render "projects/commits/commits", project: @merge_request.project diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index 786b5f39063..626970f39be 100644 --- a/app/views/projects/merge_requests/show/_diffs.html.haml +++ b/app/views/projects/merge_requests/show/_diffs.html.haml @@ -1,5 +1,5 @@ - if @merge_request_diff.collected? - = render "projects/diffs/diffs", diffs: @merge_request.diffs, project: @merge_request.source_project + = render "projects/diffs/diffs", diffs: @merge_request.diffs, project: @merge_request.project - elsif @merge_request_diff.empty? .nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch} - else diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml index 22f601ac99e..db1575f899a 100644 --- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml +++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml @@ -3,42 +3,45 @@ .modal-content .modal-header %a.close{href: "#", "data-dismiss" => "modal"} × - %h3 How to merge + %h3 Check out, review and merge locally .modal-body - - if @merge_request.for_fork? - - source_remote = @merge_request.source_project.namespace.nil? ? "source" :@merge_request.source_project.namespace.path - - target_remote = @merge_request.target_project.namespace.nil? ? "target" :@merge_request.target_project.namespace.path - %p - %strong Step 1. - Fetch the code and create a new branch pointing to it - %pre.dark + %p + %strong Step 1. + Fetch and check out the branch for this merge request + %pre.dark + - if @merge_request.for_fork? :preserve git fetch #{@merge_request.source_project.http_url_to_repo} #{@merge_request.source_branch} git checkout -b #{@merge_request.source_project_path}-#{@merge_request.source_branch} FETCH_HEAD - %p - %strong Step 2. - Merge the branch and push the changes to GitLab - %pre.dark - :preserve - git checkout #{@merge_request.target_branch} - git merge --no-ff #{@merge_request.source_project_path}-#{@merge_request.source_branch} - git push origin #{@merge_request.target_branch} - - else - %p - %strong Step 1. - Update the repo and checkout the branch we are going to merge - %pre.dark + - else :preserve git fetch origin git checkout -b #{@merge_request.source_branch} origin/#{@merge_request.source_branch} - %p - %strong Step 2. - Merge the branch and push the changes to GitLab - %pre.dark + %p + %strong Step 2. + Review the changes locally + + %p + %strong Step 3. + Merge the branch and fix any conflicts that come up + %pre.dark + - if @merge_request.for_fork? + :preserve + git checkout #{@merge_request.target_branch} + git merge --no-ff #{@merge_request.source_project_path}-#{@merge_request.source_branch} + - else :preserve git checkout #{@merge_request.target_branch} git merge --no-ff #{@merge_request.source_branch} - git push origin #{@merge_request.target_branch} + %p + %strong Step 4. + Push the result of the merge to GitLab + %pre.dark + :preserve + git push origin #{@merge_request.target_branch} + - unless @merge_request.can_be_merged_by?(current_user) + %p + Note that pushing to GitLab requires write access to this repository. :javascript $(function(){ diff --git a/app/views/projects/merge_requests/widget/_closed.html.haml b/app/views/projects/merge_requests/widget/_closed.html.haml index b5704c502c8..f3cc0e7e8a1 100644 --- a/app/views/projects/merge_requests/widget/_closed.html.haml +++ b/app/views/projects/merge_requests/widget/_closed.html.haml @@ -6,4 +6,7 @@ - if @merge_request.closed_event by #{link_to_member(@project, @merge_request.closed_event.author, avatar: true)} #{time_ago_with_tooltip(@merge_request.closed_event.created_at)} - %p Changes were not merged into target branch + %p + = succeed '.' do + The changes were not merged into + %span.label-branch= @merge_request.target_branch diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml index f04eac0e3bb..4d4e2f68f61 100644 --- a/app/views/projects/merge_requests/widget/_heading.html.haml +++ b/app/views/projects/merge_requests/widget/_heading.html.haml @@ -1,49 +1,28 @@ - if @merge_request.has_ci? .mr-widget-heading - .ci_widget.ci-success{style: "display:none"} - = icon("check") - %span CI build passed - for #{@merge_request.last_commit_short_sha}. - = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" - - .ci_widget.ci-skipped{style: "display:none"} - = icon("check") - %span CI build skipped - for #{@merge_request.last_commit_short_sha}. - = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" - - .ci_widget.ci-failed{style: "display:none"} - = icon("times") - %span CI build failed - for #{@merge_request.last_commit_short_sha}. - = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" - - - [:running, :pending].each do |status| + - [:success, :skipped, :canceled, :failed, :running, :pending].each do |status| .ci_widget{class: "ci-#{status}", style: "display:none"} - = icon("clock-o") + - if status == :success + - status = "passed" + = icon("check-circle") + - else + = icon("circle") %span CI build #{status} for #{@merge_request.last_commit_short_sha}. - = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + %span.ci-coverage + = link_to "View build details", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" .ci_widget = icon("spinner spin") - Checking for CI status for #{@merge_request.last_commit_short_sha} + Checking CI status for #{@merge_request.last_commit_short_sha}… .ci_widget.ci-not_found{style: "display:none"} - = icon("times") - %span Can not find commit in the CI server - for #{@merge_request.last_commit_short_sha}. - - - .ci_widget.ci-canceled{style: "display:none"} - = icon("times") - %span CI build canceled - for #{@merge_request.last_commit_short_sha}. - = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = icon("times-circle") + Could not find CI status for #{@merge_request.last_commit_short_sha}. .ci_widget.ci-error{style: "display:none"} - = icon("times") - %span Cannot connect to the CI server. Please check your settings and try again. + = icon("times-circle") + Could not connect to the CI server. Please check your settings and try again. :coffeescript $ -> diff --git a/app/views/projects/merge_requests/widget/_locked.html.haml b/app/views/projects/merge_requests/widget/_locked.html.haml index 13ec278847b..78d0783cba0 100644 --- a/app/views/projects/merge_requests/widget/_locked.html.haml +++ b/app/views/projects/merge_requests/widget/_locked.html.haml @@ -2,7 +2,8 @@ = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 - Merge in progress... + = icon("spinner spin") + Merge in progress… %p - Merging is in progress. While merging this request is locked and cannot be closed. + This merge request is in the process of being merged, during which time it is locked and cannot be closed. diff --git a/app/views/projects/merge_requests/widget/_merged.html.haml b/app/views/projects/merge_requests/widget/_merged.html.haml index a3b13140810..d22dfa085b8 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -7,23 +7,31 @@ by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)} #{time_ago_with_tooltip(@merge_request.merge_event.created_at)} %div - - if @source_branch.blank? - Source branch has been removed + - if !@merge_request.source_branch_exists? + = succeed '.' do + The changes were merged into + %span.label-branch= @merge_request.target_branch + The source branch has been removed. - - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && @merge_request.merged? + - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) .remove_source_branch_widget - %p Changes merged into #{@merge_request.target_branch}. You can remove source branch now + %p + = succeed '.' do + The changes were merged into + %span.label-branch= @merge_request.target_branch + You can remove the source branch now. = link_to namespace_project_branch_path(@merge_request.source_project.namespace, @merge_request.source_project, @source_branch), remote: true, method: :delete, class: "btn btn-primary btn-sm remove_source_branch" do %i.fa.fa-times Remove Source Branch .remove_source_branch_widget.failed.hide - Failed to remove source branch '#{@merge_request.source_branch}' + %p + Failed to remove source branch '#{@merge_request.source_branch}'. .remove_source_branch_in_progress.hide - %i.fa.fa-spinner.fa-spin - - Removing source branch '#{@merge_request.source_branch}'. Please wait. Page will be automatically reloaded. + %p + = icon('spinner spin') + Removing source branch '#{@merge_request.source_branch}'. Please wait. This page will be automatically reload. :coffeescript $('.remove_source_branch').on 'click', -> diff --git a/app/views/projects/merge_requests/widget/_open.html.haml b/app/views/projects/merge_requests/widget/_open.html.haml index bb794912f8f..0aad9bb3e88 100644 --- a/app/views/projects/merge_requests/widget/_open.html.haml +++ b/app/views/projects/merge_requests/widget/_open.html.haml @@ -3,8 +3,6 @@ .mr-widget-body - if @project.archived? = render 'projects/merge_requests/widget/open/archived' - - elsif !@project.satellite.exists? - = render 'projects/merge_requests/widget/open/no_satellite' - elsif @merge_request.commits.blank? = render 'projects/merge_requests/widget/open/nothing' - elsif @merge_request.branch_missing? @@ -24,6 +22,6 @@ .mr-widget-footer %span %i.fa.fa-check - Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'} + Accepting this merge request will close #{"issue".pluralize(@closes_issues.size)} = succeed '.' do != gfm(issues_sentence(@closes_issues)) diff --git a/app/views/projects/merge_requests/widget/_show.html.haml b/app/views/projects/merge_requests/widget/_show.html.haml index 263cab7a9e8..a489d4f9b24 100644 --- a/app/views/projects/merge_requests/widget/_show.html.haml +++ b/app/views/projects/merge_requests/widget/_show.html.haml @@ -11,10 +11,10 @@ var merge_request_widget; merge_request_widget = new MergeRequestWidget({ - url_to_automerge_check: "#{automerge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", + url_to_automerge_check: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", ci_enable: #{@project.ci_service ? "true" : "false"}, - current_status: "#{@merge_request.automerge_status}", + current_status: "#{@merge_request.gitlab_merge_status}", }); diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index f5bacaf280a..e1525f6aeb7 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -1,4 +1,4 @@ -= form_for [:automerge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f| += form_for [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f| = hidden_field_tag :authenticity_token, form_authenticity_token .accept-merge-holder.clearfix.js-toggle-container .accept-action @@ -8,22 +8,16 @@ .accept-control.checkbox = label_tag :should_remove_source_branch, class: "remove_source_checkbox" do = check_box_tag :should_remove_source_branch - Remove source-branch + Remove source branch .accept-control - = link_to "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message" do - %i.fa.fa-edit + = link_to "#", class: "modify-merge-commit-link js-toggle-button" do + = icon('edit') Modify commit message .js-toggle-content.hide.prepend-top-20 = render 'shared/commit_message_container', params: params, text: @merge_request.merge_commit_message, rows: 14, hint: true - %br - .light - If you want to merge this request manually, you can use the - %strong - = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" - :coffeescript $('.accept-mr-form').on 'ajax:before', -> btn = $('.accept_merge_request') diff --git a/app/views/projects/merge_requests/widget/open/_archived.html.haml b/app/views/projects/merge_requests/widget/open/_archived.html.haml index eaf113ee568..ab30fa6b243 100644 --- a/app/views/projects/merge_requests/widget/open/_archived.html.haml +++ b/app/views/projects/merge_requests/widget/open/_archived.html.haml @@ -1,2 +1,4 @@ +%h4 + Project is archived %p - %strong Archived projects do not provide commit access. + This merge request cannot be merged because archived projects cannot be written to. diff --git a/app/views/projects/merge_requests/widget/open/_check.html.haml b/app/views/projects/merge_requests/widget/open/_check.html.haml index e775447cb75..b6b8974297e 100644 --- a/app/views/projects/merge_requests/widget/open/_check.html.haml +++ b/app/views/projects/merge_requests/widget/open/_check.html.haml @@ -1,6 +1,6 @@ %strong - %i.fa.fa-spinner.fa-spin - Checking automatic merge… + = icon("spinner spin") + Checking ability to merge automatically… :coffeescript $ -> diff --git a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml index 7dc3b4eb2cc..e6c089fefb2 100644 --- a/app/views/projects/merge_requests/widget/open/_conflicts.html.haml +++ b/app/views/projects/merge_requests/widget/open/_conflicts.html.haml @@ -1,10 +1,10 @@ -- if @merge_request.can_be_merged_by?(current_user) - %h4 - This merge request contains merge conflicts that must be resolved. - %p - You can merge it manually using the - %strong - = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" -- else - %strong This merge request contains merge conflicts that must be resolved. - Only those with write access to this repository can merge merge requests. +%h4 + = icon("exclamation-triangle") + This merge request contains merge conflicts + +%p + Please resolve these conflicts or + - if @merge_request.can_be_merged_by?(current_user) + #{link_to "merge this request manually", "#modal_merge_info", class: "how_to_merge_link vlink", "data-toggle" => "modal"}. + - else + ask someone with write access to this repository to merge this request manually. diff --git a/app/views/projects/merge_requests/widget/open/_missing_branch.html.haml b/app/views/projects/merge_requests/widget/open/_missing_branch.html.haml index 1c565bae80a..c9f07629493 100644 --- a/app/views/projects/merge_requests/widget/open/_missing_branch.html.haml +++ b/app/views/projects/merge_requests/widget/open/_missing_branch.html.haml @@ -1,16 +1,16 @@ -%h4 - Can't be merged -%p - This merge request can not be accepted because branch - - unless @merge_request.source_branch_exists? - %span.label.label-inverse= @merge_request.source_branch - does not exist in - %span.label.label-info= @merge_request.source_project_path - %br - %strong Please close this merge request and open a new merge request to change source branches. - - else - %span.label.label-inverse= @merge_request.target_branch - does not exist in - %span.label.label-info= @merge_request.target_project_path - %br - %strong Please close this merge request or change to another target branch. +- unless @merge_request.source_branch_exists? + %h4 + = icon("exclamation-triangle") + Source branch + %span.label-branch= source_branch_with_namespace(@merge_request) + does not exist + %p + Please restore the source branch or close this merge request and open a new merge request with a different source branch. +- else + %h4 + = icon("exclamation-triangle") + Target branch + %span.label-branch= @merge_request.target_branch + does not exist + %p + Please restore the target branch or use a different target branch. diff --git a/app/views/projects/merge_requests/widget/open/_no_satellite.html.haml b/app/views/projects/merge_requests/widget/open/_no_satellite.html.haml deleted file mode 100644 index 3718cfd8333..00000000000 --- a/app/views/projects/merge_requests/widget/open/_no_satellite.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%p - %span - %strong This repository does not have a satellite. Please ask an administrator to fix this issue! diff --git a/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml b/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml index 82f6ffd8fcb..a8145558ca8 100644 --- a/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml +++ b/app/views/projects/merge_requests/widget/open/_not_allowed.html.haml @@ -1,2 +1,4 @@ -%strong This request can be merged automatically. -Only those with write access to this repository can merge merge requests. +%h4 + Ready to be merged automatically +%p + Ask someone with write access to this repository to merge this request. diff --git a/app/views/projects/merge_requests/widget/open/_nothing.html.haml b/app/views/projects/merge_requests/widget/open/_nothing.html.haml index 4d526576bc2..35626b624b7 100644 --- a/app/views/projects/merge_requests/widget/open/_nothing.html.haml +++ b/app/views/projects/merge_requests/widget/open/_nothing.html.haml @@ -1,8 +1,8 @@ -%h4 Nothing to merge -%p +%h4 + = icon("exclamation-triangle") Nothing to merge from - %span.label-branch #{@merge_request.source_branch} - to - %span.label-branch #{@merge_request.target_branch} - %br - Try to use different branches or push new code. + %span.label-branch= source_branch_with_namespace(@merge_request) + into + %span.label-branch= @merge_request.target_branch +%p + Please push new commits to the source branch or use a different target branch. diff --git a/app/views/projects/merge_requests/widget/open/_reload.html.haml b/app/views/projects/merge_requests/widget/open/_reload.html.haml index 5787f6efea4..acfc31725eb 100644 --- a/app/views/projects/merge_requests/widget/open/_reload.html.haml +++ b/app/views/projects/merge_requests/widget/open/_reload.html.haml @@ -1 +1,6 @@ -This merge request cannot be merged. Try to reload the page. +%h4 + = icon("exclamation-triangle") + This merge request failed to be merged automatically + +%p + Please reload the page to find out the reason. diff --git a/app/views/projects/merge_requests/widget/open/_wip.html.haml b/app/views/projects/merge_requests/widget/open/_wip.html.haml index 4ce3ab31278..0cf16542cc1 100644 --- a/app/views/projects/merge_requests/widget/open/_wip.html.haml +++ b/app/views/projects/merge_requests/widget/open/_wip.html.haml @@ -1,13 +1,5 @@ -- if @merge_request.can_be_merged_by?(current_user) - %h4 - This merge request cannot be accepted because it is marked as Work In Progress. +%h4 + This merge request is currently a Work In Progress - %p - %button.btn.disabled{:type => 'button'} - %i.fa.fa-warning - Accept Merge Request - - When the merge request is ready, remove the "WIP" prefix from the title to allow it to be accepted. -- else - %strong This merge request is marked as Work In Progress. - Only those with write access to this repository can merge merge requests. +%p + When this merge request is ready, remove the "WIP" prefix from the title to allow it to be merged. diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index ac8c1936c9e..3489bf3f191 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -16,10 +16,10 @@ %p.help-block - if issuable.work_in_progress? Remove the <code>WIP</code> prefix from the title to allow this - <strong>Work In Progress</strong> merge request to be accepted when it's ready. + <strong>Work In Progress</strong> merge request to be merged when it's ready. - else Start the title with <code>[WIP]</code> or <code>WIP:</code> to prevent a - <strong>Work In Progress</strong> merge request from being accepted before it's ready. + <strong>Work In Progress</strong> merge request from being merged before it's ready. .form-group.issuable-description = f.label :description, 'Description', class: 'control-label' .col-sm-10 diff --git a/app/workers/auto_merge_worker.rb b/app/workers/auto_merge_worker.rb deleted file mode 100644 index a6dd73eee5f..00000000000 --- a/app/workers/auto_merge_worker.rb +++ /dev/null @@ -1,13 +0,0 @@ -class AutoMergeWorker - include Sidekiq::Worker - - sidekiq_options queue: :default - - def perform(merge_request_id, current_user_id, params) - params = params.with_indifferent_access - current_user = User.find(current_user_id) - merge_request = MergeRequest.find(merge_request_id) - merge_request.should_remove_source_branch = params[:should_remove_source_branch] - merge_request.automerge!(current_user, params[:commit_message]) - end -end diff --git a/app/workers/merge_worker.rb b/app/workers/merge_worker.rb new file mode 100644 index 00000000000..6a8665c179a --- /dev/null +++ b/app/workers/merge_worker.rb @@ -0,0 +1,19 @@ +class MergeWorker + include Sidekiq::Worker + + sidekiq_options queue: :default + + def perform(merge_request_id, current_user_id, params) + params = params.with_indifferent_access + current_user = User.find(current_user_id) + merge_request = MergeRequest.find(merge_request_id) + + result = MergeRequests::MergeService.new(merge_request.target_project, current_user). + execute(merge_request, params[:commit_message]) + + if result[:status] == :success && params[:should_remove_source_branch].present? + DeleteBranchService.new(merge_request.source_project, current_user). + execute(merge_request.source_branch) + end + end +end diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb index 94832872d13..b546f8777e1 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -27,7 +27,6 @@ class RepositoryImportWorker project.import_finish project.save - project.satellite.create unless project.satellite.exists? ProjectCacheWorker.perform_async(project.id) Gitlab::BitbucketImport::KeyDeleter.new(project).execute if project.import_type == 'bitbucket' end |