diff options
Diffstat (limited to 'app')
63 files changed, 615 insertions, 741 deletions
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee index 995a2f24093..762eec63dee 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, 2000) + setTimeout(merge_request_widget.mergeInProgress, 3000) dataType: 'json' getMergeStatus: -> @@ -49,8 +49,10 @@ class @MergeRequestWidget @setMergeButtonClass('btn-danger') showCiCoverage: (coverage) -> - text = 'Coverage ' + coverage + '%' - $('.ci_widget:visible .ci-coverage').text(text) + cov_html = $('<span>') + cov_html.addClass('ci-coverage') + cov_html.text('Coverage ' + coverage + '%') + $('.ci_widget:visible').append(cov_html) 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 30bbec7b795..baba6f32129 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -1,15 +1,9 @@ -/** - * 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 { @@ -26,67 +20,16 @@ display: inline-block; margin: 0; margin-left: 20px; - padding: 5px; + padding: 10px 0; 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) { @@ -118,10 +61,23 @@ } .label-branch { - color: #222; + @include border-radius(4px); + padding: 3px 4px; + border: none; + background: $hover; + color: #333; font-family: $monospace_font; - font-weight: bold; + font-weight: normal; overflow: hidden; + + .label-project { + @include border-radius-left(4px); + padding: 3px 4px; + background: #279; + position: relative; + left: -4px; + letter-spacing: -1px; + } } .mr-list { @@ -168,6 +124,64 @@ 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; @@ -182,7 +196,3 @@ .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 100d3d3b317..b762518d377 100644 --- a/app/controllers/projects/blob_controller.rb +++ b/app/controllers/projects/blob_controller.rb @@ -13,20 +13,27 @@ 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 :require_branch_head, only: [:edit, :update] - before_action :editor_variables, except: [:show, :preview, :diff] before_action :after_edit_path, only: [:edit, :update] + before_action :require_branch_head, only: [:edit, :update] def new commit unless @repository.empty? end def create - result = Files::CreateService.new(@project, current_user, @commit_params).execute + 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 if result[:status] == :success flash[:notice] = "Your changes have been successfully committed" - redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) + ref = sanitized_new_branch_name.presence || @ref + redirect_to namespace_project_blob_path(@project.namespace, @project, File.join(ref, file_path)) else flash[:alert] = result[:message] render :new @@ -41,10 +48,22 @@ class Projects::BlobController < Projects::ApplicationController end def update - result = Files::UpdateService.new(@project, current_user, @commit_params).execute + result = Files::UpdateService. + new( + @project, + current_user, + params.merge(new_branch: sanitized_new_branch_name), + @ref, + @path + ).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] @@ -61,11 +80,12 @@ class Projects::BlobController < Projects::ApplicationController end def destroy - result = Files::DeleteService.new(@project, current_user, @commit_params).execute + result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute if result[:status] == :success flash[:notice] = "Your changes have been successfully committed" - redirect_to namespace_project_tree_path(@project.namespace, @project, @target_branch) + redirect_to namespace_project_tree_path(@project.namespace, @project, + @ref) else flash[:alert] = result[:message] render :show @@ -115,6 +135,7 @@ class Projects::BlobController < Projects::ApplicationController @id = params[:id] @ref, @path = extract_ref(@id) + rescue InvalidPathError not_found! end @@ -124,8 +145,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 @target_branch.present? - namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @path)) + elsif sanitized_new_branch_name.present? + namespace_project_blob_path(@project.namespace, @project, File.join(sanitized_new_branch_name, @path)) else namespace_project_blob_path(@project.namespace, @project, @id) end @@ -139,25 +160,4 @@ 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 d9b3adae95b..c5f085c236f 100644 --- a/app/controllers/projects/compare_controller.rb +++ b/app/controllers/projects/compare_controller.rb @@ -13,8 +13,13 @@ 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(@project, head_ref, @project, base_ref) + compare_result = CompareService.new.execute( + current_user, + @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 f3054881daf..d1265198318 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -1,7 +1,9 @@ +require 'gitlab/satellite/satellite' + class Projects::MergeRequestsController < Projects::ApplicationController before_action :module_enabled before_action :merge_request, only: [ - :edit, :update, :show, :diffs, :commits, :merge, :merge_check, + :edit, :update, :show, :diffs, :commits, :automerge, :automerge_check, :ci_status, :toggle_subscription ] before_action :closes_issues, only: [:edit, :update, :show, :diffs, :commits] @@ -135,7 +137,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController end end - def merge_check + def automerge_check if @merge_request.unchecked? @merge_request.check_if_can_be_merged end @@ -145,11 +147,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController render partial: "projects/merge_requests/widget/show.html.haml", layout: false end - def merge + def automerge return access_denied! unless @merge_request.can_be_merged_by?(current_user) - if @merge_request.mergeable? - MergeWorker.perform_async(@merge_request.id, current_user.id, params) + if @merge_request.automergeable? + AutoMergeWorker.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 f8169b4f288..45ee4fe4135 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -61,14 +61,4 @@ 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/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 525a46291f6..ab9b068de05 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -231,37 +231,20 @@ module ProjectsHelper end end + def readme_path(project) + filename_path(project, :readme) + end + def changelog_path(project) - if project && changelog = project.repository.changelog - namespace_project_blob_path( - project.namespace, - project, - tree_join(project.default_branch, - changelog.name) - ) - end + filename_path(project, :changelog) end def license_path(project) - if project && license = project.repository.license - namespace_project_blob_path( - project.namespace, - project, - tree_join(project.default_branch, - license.name) - ) - end + filename_path(project, :license) end def version_path(project) - if project && version = project.repository.version - namespace_project_blob_path( - project.namespace, - project, - tree_join(project.default_branch, - version.name) - ) - end + filename_path(project, :version) end def hidden_pass_url(original_url) @@ -331,4 +314,17 @@ module ProjectsHelper count end end + + private + + def filename_path(project, filename) + if project && blob = project.repository.send(filename) + namespace_project_blob_path( + project.namespace, + project, + tree_join(project.default_branch, + blob.name) + ) + end + end end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 467b90861f9..324d1795ab4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -41,6 +41,8 @@ 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 @@ -55,7 +57,7 @@ class MergeRequest < ActiveRecord::Base transition [:reopened, :opened] => :closed end - event :mark_as_merged do + event :merge do transition [:reopened, :opened, :locked] => :merged end @@ -203,10 +205,7 @@ class MergeRequest < ActiveRecord::Base end def check_if_can_be_merged - can_be_merged = - project.repository.can_be_merged?(source_sha, target_branch) - - if can_be_merged + if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? mark_as_mergeable else mark_as_unmergeable @@ -221,6 +220,18 @@ 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 @@ -229,11 +240,11 @@ class MergeRequest < ActiveRecord::Base title =~ /\A\[?WIP\]?:? /i end - def mergeable? + def automergeable? open? && !work_in_progress? && can_be_merged? end - def gitlab_merge_status + def automerge_status if work_in_progress? "work_in_progress" else @@ -260,14 +271,14 @@ class MergeRequest < ActiveRecord::Base # # see "git diff" def to_diff(current_user) - target_project.repository.diff_text(target_branch, source_sha) + Gitlab::Satellite::MergeAction.new(current_user, self).diff_in_satellite end # Returns the commit as a series of email patches. # # see "git format-patch" def to_patch(current_user) - target_project.repository.format_patch(target_branch, source_sha) + Gitlab::Satellite::MergeAction.new(current_user, self).format_patch end def hook_attrs @@ -418,30 +429,4 @@ 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 e317c8eac4d..df1c2b78758 100644 --- a/app/models/merge_request_diff.rb +++ b/app/models/merge_request_diff.rb @@ -16,8 +16,9 @@ require Rails.root.join("app/models/commit") class MergeRequestDiff < ActiveRecord::Base include Sortable - # Prevent store of diff if commits amount more then 500 - COMMITS_SAFE_SIZE = 500 + # Prevent store of diff + # if commits amount more then 200 + COMMITS_SAFE_SIZE = 200 attr_reader :commits, :diffs @@ -123,12 +124,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.first[Commit::DIFF_HARD_LIMIT_LINES] + new_diffs = [] 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.first[Commit::DIFF_HARD_LIMIT_LINES] + new_diffs = [] end end @@ -159,21 +160,12 @@ class MergeRequestDiff < ActiveRecord::Base private def compare_result - @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 + @compare_result ||= CompareService.new.execute( + merge_request.author, + merge_request.source_project, + merge_request.source_branch, + merge_request.target_project, + merge_request.target_branch, + ) end end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 161a16ca61c..30ffacadded 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -118,11 +118,12 @@ 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 - # send update instructions to users. + # If repositories moved successfully we need to remove old satellites + # and 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 4628f478ca6..3dc1729e812 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -520,6 +520,14 @@ 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 @@ -589,11 +597,14 @@ 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 send update instructions to users. + # If repository moved successfully we need to remove old satellite + # and 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 @@ -691,6 +702,7 @@ 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 ecdcd48ae60..5aaa4e85cbc 100644 --- a/app/models/project_services/gitlab_ci_service.rb +++ b/app/models/project_services/gitlab_ci_service.rb @@ -74,8 +74,6 @@ class GitlabCiService < CiService else :error end - rescue Errno::ECONNREFUSED - :error end def fork_registration(new_project, private_token) @@ -105,8 +103,6 @@ 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 46efbede2a2..0a62980f93a 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -364,83 +364,6 @@ 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}) @@ -474,11 +397,6 @@ 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 f00ec7408b6..6d9ed345914 100644 --- a/app/services/base_service.rb +++ b/app/services/base_service.rb @@ -31,10 +31,6 @@ 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 70f642baaaa..6aa9df4b194 100644 --- a/app/services/compare_service.rb +++ b/app/services/compare_service.rb @@ -1,28 +1,27 @@ -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(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" + 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, + ) ) - end - - Gitlab::CompareResult.new( - Gitlab::Git::Compare.new( - target_project.repository.raw_repository, + else + Gitlab::Satellite::CompareAction.new( + current_user, + target_project, target_branch, - source_sha, - ) - ) + source_project, + source_branch + ).result + end end end diff --git a/app/services/files/base_service.rb b/app/services/files/base_service.rb index d7b40ee8906..bd245100955 100644 --- a/app/services/files/base_service.rb +++ b/app/services/files/base_service.rb @@ -1,80 +1,17 @@ module Files class BaseService < ::BaseService - class ValidationError < StandardError; end + attr_reader :ref, :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) + def initialize(project, user, params, ref, path = nil) + @project, @current_user, @params = project, user, params.dup + @ref = ref + @path = path end private - 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 + def repository + project.repository end end end diff --git a/app/services/files/create_service.rb b/app/services/files/create_service.rb index 91d715b2d63..23833aa78ec 100644 --- a/app/services/files/create_service.rb +++ b/app/services/files/create_service.rb @@ -1,30 +1,52 @@ require_relative "base_service" module Files - class CreateService < Files::BaseService - def commit - repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch) - end + class CreateService < BaseService + def execute + allowed = Gitlab::GitAccess.new(current_user, project).can_push_to_branch?(ref) - def validate - super + unless allowed + return error("You are not allowed to create file in this branch") + end - file_name = File.basename(@file_path) + file_name = File.basename(path) + file_path = path unless file_name =~ Gitlab::Regex.file_name_regex - raise_error( + return error( 'Your changes could not be committed, because the file name ' + Gitlab::Regex.file_name_regex_message ) end - unless project.empty_repo? - blob = repository.blob_at_branch(@current_branch, @file_path) + 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) if blob - raise_error("Your changes could not be committed, because file with such name exists") + return 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 27c881c3430..1497a0f883b 100644 --- a/app/services/files/delete_service.rb +++ b/app/services/files/delete_service.rb @@ -1,9 +1,36 @@ require_relative "base_service" module Files - class DeleteService < Files::BaseService - def commit - repository.remove_file(current_user, @file_path, @commit_message, @target_branch) + 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 end end end diff --git a/app/services/files/update_service.rb b/app/services/files/update_service.rb index a20903c6f02..0724d3ae634 100644 --- a/app/services/files/update_service.rb +++ b/app/services/files/update_service.rb @@ -1,9 +1,39 @@ require_relative "base_service" module Files - class UpdateService < Files::BaseService - def commit - repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch) + 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) end end end diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 81535450ac1..5a2c97b08af 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -10,14 +10,16 @@ class GitPushService # # Next, this method: # 1. Creates the push event - # 2. Updates merge requests - # 3. Recognizes cross-references from commit messages - # 4. Executes the project's web hooks - # 5. Executes the project's services + # 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 # 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) @@ -131,8 +133,7 @@ class GitPushService end def is_default_branch?(ref) - Gitlab::Git.branch_ref?(ref) && - (Gitlab::Git.ref_name(ref) == project.default_branch || project.default_branch.nil?) + Gitlab::Git.branch_ref?(ref) && Gitlab::Git.ref_name(ref) == project.default_branch 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 new file mode 100644 index 00000000000..cdedf48b0c0 --- /dev/null +++ b/app/services/merge_requests/auto_merge_service.rb @@ -0,0 +1,30 @@ +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 new file mode 100644 index 00000000000..9579573adf9 --- /dev/null +++ b/app/services/merge_requests/base_merge_service.rb @@ -0,0 +1,10 @@ +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 a9b29f9654d..956480938c3 100644 --- a/app/services/merge_requests/build_service.rb +++ b/app/services/merge_requests/build_service.rb @@ -12,16 +12,12 @@ module MergeRequests merge_request.target_project ||= (project.forked_from_project || project) merge_request.target_branch ||= merge_request.target_project.default_branch - 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) + unless merge_request.target_branch && merge_request.source_branch + return build_failed(merge_request, nil) end compare_result = CompareService.new.execute( + current_user, merge_request.source_project, merge_request.source_branch, merge_request.target_project, @@ -44,6 +40,7 @@ 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 @@ -62,6 +59,9 @@ 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 2107529a21a..327ead4ff3f 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -1,57 +1,22 @@ module MergeRequests # MergeService class # - # 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 - + # 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 def execute(merge_request, commit_message) - @commit_message = commit_message - @merge_request = merge_request + 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 + create_merge_event(merge_request, current_user) + create_note(merge_request) + notification_service.merge_mr(merge_request, current_user) + execute_hooks(merge_request, 'merge') - def after_merge - MergeRequests::PostMergeService.new(project, current_user).execute(merge_request) + true + rescue + false end end end diff --git a/app/services/merge_requests/post_merge_service.rb b/app/services/merge_requests/post_merge_service.rb deleted file mode 100644 index aceb8cb9021..00000000000 --- a/app/services/merge_requests/post_merge_service.rb +++ /dev/null @@ -1,22 +0,0 @@ -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 e903e48e3cd..d0648da049b 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::PostMergeService. + MergeRequests::MergeService. new(merge_request.target_project, @current_user). - execute(merge_request) + execute(merge_request, nil) end end diff --git a/app/services/post_commit_service.rb b/app/services/post_commit_service.rb deleted file mode 100644 index 8592c8d238b..00000000000 --- a/app/services/post_commit_service.rb +++ /dev/null @@ -1,71 +0,0 @@ -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 28872c89259..403f419ec50 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -27,6 +27,7 @@ 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 550ed6897dd..f43c0ef70e9 100644 --- a/app/services/projects/transfer_service.rb +++ b/app/services/projects/transfer_service.rb @@ -33,6 +33,9 @@ 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! @@ -48,6 +51,9 @@ 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/import/base/create.js.haml b/app/views/import/base/create.js.haml index 90a6f5f9d2d..9529f16c128 100644 --- a/app/views/import/base/create.js.haml +++ b/app/views/import/base/create.js.haml @@ -14,12 +14,16 @@ :plain job = $("tr#repo_#{@repo_id}") job.find(".import-actions").html("<p class='alert alert-danger'>Access denied! Please verify you can add deploy keys to this repository.</p>") -- else +- elsif @project.persisted? :plain job = $("tr#repo_#{@repo_id}") job.attr("id", "project_#{@project.id}") target_field = job.find(".import-target") target_field.empty() - target_field.append('<strong>#{link_to @project.path_with_namespace, [@project.namespace.becomes(Namespace), @project]}</strong>') + target_field.append('<strong>#{link_to @project.path_with_namespace, namespace_project_path(@project.namespace, @project)}</strong>') $("table.import-jobs tbody").prepend(job) job.addClass("active").find(".import-actions").html("<i class='fa fa-spinner fa-spin'></i> started") +- else + :plain + job = $("tr#repo_#{@repo_id}") + job.find(".import-actions").html("<p class='alert alert-danger'>Error saving project: #{escape_javascript(@project.errors.messages.to_s)}</p>") diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index 98ae509096e..777eb482714 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -61,7 +61,7 @@ rather than Git. Please convert = link_to "them to Git,", "https://www.atlassian.com/git/tutorials/migrating-overview" and go through the - = link_to "import flow", status_import_bitbucket_path + = link_to "import flow", status_import_bitbucket_path, "data-no-turbolink" => "true" again. diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index 9c3e1703c89..96f188e4aa7 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 7c2a4fece94..dac984f8c31 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -6,12 +6,11 @@ = render 'shared/commit_message_container', params: params, placeholder: 'Add new file' - - 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" + .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/empty.html.haml b/app/views/projects/empty.html.haml index dfe45a3802d..e577d35d560 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -43,6 +43,8 @@ cd existing_folder git init git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')} + git add . + git commit git push -u origin master - if can? current_user, :remove_project, @project diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml index 7709330611a..ff9c0cdb283 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. Please try again or select different branches. + %p We can't compare selected branches. It may be because of huge diff or satellite timeout. 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 76f44211dac..633a54f3620 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.active + %li.diffs-tab = 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.active + #diffs.diffs.tab-pane - 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 2662e3aff6b..c57eee14143 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -6,25 +6,40 @@ = render "projects/merge_requests/show/mr_box" %hr .append-bottom-20 - - 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)} + .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} %span into - %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" + %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} = render "projects/merge_requests/show/how_to_merge" = render "projects/merge_requests/widget/show.html.haml" diff --git a/app/views/projects/merge_requests/merge.js.haml b/app/views/projects/merge_requests/automerge.js.haml index 33321651e32..33321651e32 100644 --- a/app/views/projects/merge_requests/merge.js.haml +++ b/app/views/projects/merge_requests/automerge.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 a71b181a6a5..3b7f283daf0 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.project += render "projects/commits/commits", project: @merge_request.source_project diff --git a/app/views/projects/merge_requests/show/_diffs.html.haml b/app/views/projects/merge_requests/show/_diffs.html.haml index 626970f39be..786b5f39063 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.project + = render "projects/diffs/diffs", diffs: @merge_request.diffs, project: @merge_request.source_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 db1575f899a..22f601ac99e 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,45 +3,42 @@ .modal-content .modal-header %a.close{href: "#", "data-dismiss" => "modal"} × - %h3 Check out, review and merge locally + %h3 How to merge .modal-body - %p - %strong Step 1. - Fetch and check out the branch for this merge request - %pre.dark - - if @merge_request.for_fork? + - 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 :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 - - else - :preserve - git fetch origin - git checkout -b #{@merge_request.source_branch} origin/#{@merge_request.source_branch} - %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? + %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} - - else + 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 + :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 :preserve git checkout #{@merge_request.target_branch} git merge --no-ff #{@merge_request.source_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. + git push origin #{@merge_request.target_branch} :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 f3cc0e7e8a1..b5704c502c8 100644 --- a/app/views/projects/merge_requests/widget/_closed.html.haml +++ b/app/views/projects/merge_requests/widget/_closed.html.haml @@ -6,7 +6,4 @@ - 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 - = succeed '.' do - The changes were not merged into - %span.label-branch= @merge_request.target_branch + %p Changes were not merged into 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 4d4e2f68f61..f04eac0e3bb 100644 --- a/app/views/projects/merge_requests/widget/_heading.html.haml +++ b/app/views/projects/merge_requests/widget/_heading.html.haml @@ -1,28 +1,49 @@ - if @merge_request.has_ci? .mr-widget-heading - - [:success, :skipped, :canceled, :failed, :running, :pending].each do |status| + .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| .ci_widget{class: "ci-#{status}", style: "display:none"} - - if status == :success - - status = "passed" - = icon("check-circle") - - else - = icon("circle") + = icon("clock-o") %span CI build #{status} for #{@merge_request.last_commit_short_sha}. - %span.ci-coverage - = link_to "View build details", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" + = link_to "View build page", ci_build_details_path(@merge_request), :"data-no-turbolink" => "data-no-turbolink" .ci_widget = icon("spinner spin") - Checking CI status for #{@merge_request.last_commit_short_sha}… + Checking for CI status for #{@merge_request.last_commit_short_sha} .ci_widget.ci-not_found{style: "display:none"} - = icon("times-circle") - Could not find CI status for #{@merge_request.last_commit_short_sha}. + = 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" .ci_widget.ci-error{style: "display:none"} - = icon("times-circle") - Could not connect to the CI server. Please check your settings and try again. + = icon("times") + %span Cannot 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 78d0783cba0..13ec278847b 100644 --- a/app/views/projects/merge_requests/widget/_locked.html.haml +++ b/app/views/projects/merge_requests/widget/_locked.html.haml @@ -2,8 +2,7 @@ = render 'projects/merge_requests/widget/heading' .mr-widget-body %h4 - = icon("spinner spin") - Merge in progress… + Merge in progress... %p - This merge request is in the process of being merged, during which time it is locked and cannot be closed. + Merging is in progress. While merging this request 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 d22dfa085b8..a3b13140810 100644 --- a/app/views/projects/merge_requests/widget/_merged.html.haml +++ b/app/views/projects/merge_requests/widget/_merged.html.haml @@ -7,31 +7,23 @@ by #{link_to_member(@project, @merge_request.merge_event.author, avatar: true)} #{time_ago_with_tooltip(@merge_request.merge_event.created_at)} %div - - 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. + - if @source_branch.blank? + Source branch has been removed - - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) + - elsif can_remove_branch?(@merge_request.source_project, @merge_request.source_branch) && @merge_request.merged? .remove_source_branch_widget - %p - = succeed '.' do - The changes were merged into - %span.label-branch= @merge_request.target_branch - You can remove the source branch now. + %p Changes merged into #{@merge_request.target_branch}. You can remove 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 - %p - Failed to remove source branch '#{@merge_request.source_branch}'. + Failed to remove source branch '#{@merge_request.source_branch}' .remove_source_branch_in_progress.hide - %p - = icon('spinner spin') - Removing source branch '#{@merge_request.source_branch}'. Please wait. This page will be automatically reload. + %i.fa.fa-spinner.fa-spin + + Removing source branch '#{@merge_request.source_branch}'. Please wait. Page will be automatically reloaded. :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 0aad9bb3e88..bb794912f8f 100644 --- a/app/views/projects/merge_requests/widget/_open.html.haml +++ b/app/views/projects/merge_requests/widget/_open.html.haml @@ -3,6 +3,8 @@ .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? @@ -22,6 +24,6 @@ .mr-widget-footer %span %i.fa.fa-check - Accepting this merge request will close #{"issue".pluralize(@closes_issues.size)} + Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'} = 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 a489d4f9b24..263cab7a9e8 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: "#{merge_check_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}", + url_to_automerge_check: "#{automerge_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.gitlab_merge_status}", + current_status: "#{@merge_request.automerge_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 e1525f6aeb7..f5bacaf280a 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 [:merge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f| += form_for [:automerge, @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,16 +8,22 @@ .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" do - = icon('edit') + = link_to "#", class: "modify-merge-commit-link js-toggle-button", title: "Modify merge commit message" do + %i.fa.fa-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 ab30fa6b243..eaf113ee568 100644 --- a/app/views/projects/merge_requests/widget/open/_archived.html.haml +++ b/app/views/projects/merge_requests/widget/open/_archived.html.haml @@ -1,4 +1,2 @@ -%h4 - Project is archived %p - This merge request cannot be merged because archived projects cannot be written to. + %strong Archived projects do not provide commit access. 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 b6b8974297e..e775447cb75 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 - = icon("spinner spin") - Checking ability to merge automatically… + %i.fa.fa-spinner.fa-spin + Checking automatic merge… :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 e6c089fefb2..7dc3b4eb2cc 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 @@ -%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. +- 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. 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 c9f07629493..1c565bae80a 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 @@ -- 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. +%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. 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 new file mode 100644 index 00000000000..3718cfd8333 --- /dev/null +++ b/app/views/projects/merge_requests/widget/open/_no_satellite.html.haml @@ -0,0 +1,3 @@ +%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 a8145558ca8..82f6ffd8fcb 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,4 +1,2 @@ -%h4 - Ready to be merged automatically -%p - Ask someone with write access to this repository to merge this request. +%strong This request can be merged automatically. +Only those with write access to this repository can merge merge requests. 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 35626b624b7..4d526576bc2 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 - = icon("exclamation-triangle") - Nothing to merge from - %span.label-branch= source_branch_with_namespace(@merge_request) - into - %span.label-branch= @merge_request.target_branch +%h4 Nothing to merge %p - Please push new commits to the source branch or use a different target branch. + 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. 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 acfc31725eb..5787f6efea4 100644 --- a/app/views/projects/merge_requests/widget/open/_reload.html.haml +++ b/app/views/projects/merge_requests/widget/open/_reload.html.haml @@ -1,6 +1 @@ -%h4 - = icon("exclamation-triangle") - This merge request failed to be merged automatically - -%p - Please reload the page to find out the reason. +This merge request cannot be merged. Try to reload the page. 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 0cf16542cc1..4ce3ab31278 100644 --- a/app/views/projects/merge_requests/widget/open/_wip.html.haml +++ b/app/views/projects/merge_requests/widget/open/_wip.html.haml @@ -1,5 +1,13 @@ -%h4 - This merge request is currently a Work In Progress +- if @merge_request.can_be_merged_by?(current_user) + %h4 + This merge request cannot be accepted because it is marked as Work In Progress. -%p - When this merge request is ready, remove the "WIP" prefix from the title to allow it to be merged. + %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. diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index d49eacb30dd..d25fe68242b 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -40,7 +40,7 @@ - if bitbucket_import_enabled? - = link_to status_import_bitbucket_path, class: 'btn' do + = link_to status_import_bitbucket_path, class: 'btn', "data-no-turbolink" => "true" do %i.fa.fa-bitbucket Bitbucket - else diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 4577b84ab89..ebbd3e477fc 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -23,18 +23,21 @@ = link_to namespace_project_tags_path(@project.namespace, @project) do = pluralize(number_with_delimiter(@repository.tag_names.count), 'tag') + - if !prefer_readme? && @repository.readme + %li + = link_to 'Readme', readme_path(@project) + - if @repository.changelog %li - = link_to changelog_path(@project) do - Changelog + = link_to 'Changelog', changelog_path(@project) + - if @repository.license %li - = link_to license_path(@project) do - License + = link_to 'License', license_path(@project) + - if @repository.contribution_guide %li - = link_to contribution_guide_path(@project) do - Contribution guide + = link_to 'Contribution guide', contribution_guide_path(@project) - if current_user && can_push_branch?(@project, @project.default_branch) - unless @repository.changelog diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index 3489bf3f191..ac8c1936c9e 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 merged when it's ready. + <strong>Work In Progress</strong> merge request to be accepted 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 merged before it's ready. + <strong>Work In Progress</strong> merge request from being accepted 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 new file mode 100644 index 00000000000..a6dd73eee5f --- /dev/null +++ b/app/workers/auto_merge_worker.rb @@ -0,0 +1,13 @@ +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 deleted file mode 100644 index 6a8665c179a..00000000000 --- a/app/workers/merge_worker.rb +++ /dev/null @@ -1,19 +0,0 @@ -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 b546f8777e1..94832872d13 100644 --- a/app/workers/repository_import_worker.rb +++ b/app/workers/repository_import_worker.rb @@ -27,6 +27,7 @@ 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 |