Commit bf6f4d65 authored by Mike Greiling's avatar Mike Greiling

Merge branch 'master' into go-go-gadget-webpack-ee

* master: (54 commits)
  Move project services to new location under Integrations
  Move webhooks to new a location under Integrations
  Fix documentation link in doc/user/project/pages/index.md
  Fixed merge request widget tests
  Small documentation changes and fixes for Geo
  Remove ‘EE-specific’ comments related to Pages feature
  Update specs with new method signatures
  rm_tag now takes a user argument
  Use GitOperationService instead
  Merge remote-tracking branch 'ce/fix-git-hooks-when-creating-file' into master-ce
  Mentioned pages to CE port in project/pages/index.md
  Fixed merge request environment not displaying
  Update guidance on handling shared secrets in HA setup
  Pull EE specific Gitlab::Auth code in to its own module
  Use `add_$role` helper in snippets specs
  Check public snippets for spam
  Keep snippet visibility on error
  Add info on using both push/pull repository mirroring
  Properly read approvalPending from dataset.
  Fix data attr spacing.
  ...
parents d0663b4f d3c1f030
Please view this file on the master branch, on stable branches it's out of date.
## 8.16.3 (2017-01-27)
- Fix sidekiq cluster mishandling of queue names. !1117
## 8.16.2 (2017-01-25)
- Track Mattermost usage in usage ping. !1071
......
......@@ -2,6 +2,17 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 8.16.3 (2017-01-27)
- Add caching of droplab ajax requests. !8725
- Fix access to the wiki code via HTTP when repository feature disabled. !8758
- Revert 3f17f29a. !8785
- Fix race conditions for AuthorizedProjectsWorker.
- Fix autocomplete initial undefined state.
- Fix Error 500 when repositories contain annotated tags pointing to blobs.
- Fix /explore sorting.
- Fixed label dropdown toggle text not correctly updating.
## 8.16.2 (2017-01-25)
- allow issue filter bar to be operated with mouse only. !8681
......
......@@ -43,7 +43,6 @@ require('./smart_interval');
// ci_status_url - String, URL to use to check CI status
//
this.opts = opts;
this.$widgetBody = $('.mr-widget-body');
$('#modal_merge_info').modal({
show: false
});
......@@ -108,7 +107,7 @@ require('./smart_interval');
urlSuffix = deleteSourceBranch ? '?deleted_source_branch=true' : '';
return window.location.href = window.location.pathname + urlSuffix;
} else if (data.merge_error) {
return _this.$widgetBody.html("<h4>" + data.merge_error + "</h4>");
return $('.mr-widget-body').html("<h4>" + data.merge_error + "</h4>");
} else {
callback = function() {
return merge_request_widget.mergeInProgress(deleteSourceBranch);
......@@ -146,8 +145,9 @@ require('./smart_interval');
MergeRequestWidget.prototype.getMergeStatus = function() {
return $.get(this.opts.merge_check_url, function(data) {
var $html = $(data);
$('.mr-widget-body').replaceWith($html.find('.mr-widget-body'));
$('.mr-widget-footer:not(.mr-approvals-footer)').replaceWith($html.find('.mr-widget-footer:not(.mr-approvals-footer)'));
$('.mr-widget-footer').replaceWith($html.find('.mr-widget-footer'));
});
};
......@@ -227,7 +227,7 @@ require('./smart_interval');
environment.ci_success_icon = this.$ciSuccessIcon;
const templateString = _.unescape($template[0].outerHTML);
const template = _.template(templateString)(environment);
this.$widgetBody.before(template);
$('.mr-widget-body').before(template);
}
};
......
......@@ -46,7 +46,10 @@
.on('click', '.js-rebase-button', () => {
$('.js-rebase-button').html("<i class='fa fa-spinner fa-spin'></i> Rebase in progress");
});
} else {
} else if (!$('.mr-approvals-footer').length) {
// getMergeStatus replaces the MR widget with new, updated HTML, which means any persistent
// event management gets clobbered. When the MR is approvable, MR status is already managed
// and breaks when the DOM is clobbered.
merge_request_widget.getMergeStatus();
}
});
......
......@@ -23,7 +23,7 @@ require('./approvals/approvals_store');
initWidgetState() {
this.assignToData('showApprovals', false);
this.assignToData('disableAcceptance', Boolean(this.rootEl.dataset.approvalPending));
this.assignToData('disableAcceptance', this.rootEl.dataset.approvalPending === 'true');
}
initApprovals() {
......
......@@ -56,15 +56,24 @@
&.right {
float: right;
padding-right: 0;
}
a {
.modify-merge-commit-link {
color: $gl-text-color;
}
}
.remove_source_checkbox {
.merge-param-checkbox {
margin: 0;
}
a .fa-question-circle {
color: $gl-text-color-secondary;
&:hover,
&:focus {
color: $link-hover-color;
}
}
}
}
......
......@@ -118,6 +118,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:plantuml_url,
:max_artifacts_size,
:max_attachment_size,
:max_pages_size,
:metrics_enabled,
:metrics_host,
:metrics_method_call_threshold,
......@@ -158,7 +159,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def application_setting_params_ee
[
:help_text,
:max_pages_size,
:elasticsearch_host,
:elasticsearch_indexing,
:elasticsearch_port,
......
......@@ -4,13 +4,15 @@ module CreatesCommit
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
set_commit_variables
start_branch = @mr_target_branch unless initial_commit?
commit_params = @commit_params.merge(
source_project: @project,
source_branch: @ref,
target_branch: @target_branch
start_project: @mr_target_project,
start_branch: start_branch,
target_branch: @mr_source_branch
)
result = service.new(@tree_edit_project, current_user, commit_params).execute
result = service.new(
@mr_source_project, current_user, commit_params).execute
if result[:status] == :success
update_flash_notice(success_notice)
......@@ -89,20 +91,18 @@ module CreatesCommit
@mr_source_project != @mr_target_project
end
def different_branch?
@mr_source_branch != @mr_target_branch || different_project?
end
def create_merge_request?
params[:create_merge_request].present? && different_branch?
# XXX: Even if the field is set, if we're checking the same branch
# as the target branch in the same project,
# we don't want to create a merge request.
params[:create_merge_request].present? &&
(different_project? || @ref != @target_branch)
end
# TODO: We should really clean this up
def set_commit_variables
@mr_source_branch ||= @target_branch
if can?(current_user, :push_code, @project)
# Edit file in this project
@tree_edit_project = @project
@mr_source_project = @project
if @project.forked?
......@@ -112,15 +112,34 @@ module CreatesCommit
else
# Merge request to this project
@mr_target_project = @project
@mr_target_branch ||= @ref
@mr_target_branch = @ref || @target_branch
end
else
# Edit file in fork
@tree_edit_project = current_user.fork_of(@project)
# Merge request from fork to this project
@mr_source_project = @tree_edit_project
@mr_source_project = current_user.fork_of(@project)
@mr_target_project = @project
@mr_target_branch ||= @ref
@mr_target_branch = @ref || @target_branch
end
@mr_source_branch = guess_mr_source_branch
end
def initial_commit?
@mr_target_branch.nil? ||
!@mr_target_project.repository.branch_exists?(@mr_target_branch)
end
def guess_mr_source_branch
# XXX: Happens when viewing a commit without a branch. In this case,
# @target_branch would be the default branch for @mr_source_project,
# however we want a generated new branch here. Thus we can't use
# @target_branch, but should pass nil to indicate that we want a new
# branch instead of @target_branch.
return if
create_merge_request? &&
# XXX: Don't understand why rubocop prefers this indention
@mr_source_project.repository.branch_exists?(@target_branch)
@target_branch
end
end
......@@ -7,7 +7,7 @@ module SpammableActions
def mark_as_spam
if SpamService.new(spammable).mark_as_spam!
redirect_to spammable, notice: "#{spammable.class} was submitted to Akismet successfully."
redirect_to spammable, notice: "#{spammable.spammable_entity_type.titlecase} was submitted to Akismet successfully."
else
redirect_to spammable, alert: 'Error with Akismet. Please check the logs for more info.'
end
......
......@@ -39,7 +39,7 @@ class Projects::CommitController < Projects::ApplicationController
end
def revert
assign_change_commit_vars(@commit.revert_branch_name)
assign_change_commit_vars
return render_404 if @target_branch.blank?
......@@ -48,7 +48,7 @@ class Projects::CommitController < Projects::ApplicationController
end
def cherry_pick
assign_change_commit_vars(@commit.cherry_pick_branch_name)
assign_change_commit_vars
return render_404 if @target_branch.blank?
......@@ -105,11 +105,9 @@ class Projects::CommitController < Projects::ApplicationController
}
end
def assign_change_commit_vars(mr_source_branch)
def assign_change_commit_vars
@commit = project.commit(params[:id])
@target_branch = params[:target_branch]
@mr_source_branch = mr_source_branch
@mr_target_branch = @target_branch
@commit_params = {
commit: @commit,
create_merge_request: params[:create_merge_request].present? || different_project?
......
......@@ -46,7 +46,8 @@ class Projects::CompareController < Projects::ApplicationController
end
def define_diff_vars
@compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref)
@compare = CompareService.new(@project, @head_ref)
.execute(@project, @start_ref)
if @compare
@commits = @compare.commits
......
......@@ -338,7 +338,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
return
end
@merge_request.update(merge_error: nil)
@merge_request.update(merge_error: nil, squash: merge_params[:squash])
if params[:merge_when_build_succeeds].present?
unless @merge_request.head_pipeline
......@@ -699,6 +699,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
approvals_before_merge
approver_group_ids
approver_ids
squash
]
end
......@@ -716,7 +717,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def merge_params
params.permit(:should_remove_source_branch, :commit_message)
params.permit(:should_remove_source_branch, :commit_message, :squash)
end
# Make sure merge requests created before 8.0
......
class Projects::SnippetsController < Projects::ApplicationController
include ToggleAwardEmoji
include SpammableActions
before_action :module_enabled
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji]
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
# Allow read any snippet
before_action :authorize_read_project_snippet!, except: [:new, :create, :index]
......@@ -36,8 +37,8 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def create
@snippet = CreateSnippetService.new(@project, current_user,
snippet_params).execute
create_params = snippet_params.merge(request: request)
@snippet = CreateSnippetService.new(@project, current_user, create_params).execute
if @snippet.valid?
respond_with(@snippet,
......@@ -88,6 +89,7 @@ class Projects::SnippetsController < Projects::ApplicationController
@snippet ||= @project.snippets.find(params[:id])
end
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def authorize_read_project_snippet!
return render_404 unless can?(current_user, :read_project_snippet, @snippet)
......
class SnippetsController < ApplicationController
include ToggleAwardEmoji
include SpammableActions
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :download]
......@@ -40,8 +41,8 @@ class SnippetsController < ApplicationController
end
def create
@snippet = CreateSnippetService.new(nil, current_user,
snippet_params).execute
create_params = snippet_params.merge(request: request)
@snippet = CreateSnippetService.new(nil, current_user, create_params).execute
respond_with @snippet.becomes(Snippet)
end
......@@ -96,6 +97,7 @@ class SnippetsController < ApplicationController
end
end
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def authorize_read_snippet!
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
......
......@@ -181,4 +181,16 @@ module MergeRequestsHelper
def different_base?(version1, version2)
version1 && version2 && version1.base_commit_sha != version2.base_commit_sha
end
def merge_params(merge_request)
{
merge_when_build_succeeds: true,
should_remove_source_branch: true,
sha: merge_request.diff_head_sha
}.merge(merge_params_ee(merge_request))
end
def merge_params_ee(merge_request)
{ squash: merge_request.squash }
end
end
......@@ -64,7 +64,7 @@ module SearchHelper
{ category: "Help", label: "Rake Tasks Help", url: help_page_path("raketasks/README") },
{ category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") },
{ category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks/system_hooks") },
{ category: "Help", label: "Webhooks Help", url: help_page_path("web_hooks/web_hooks") },
{ category: "Help", label: "Webhooks Help", url: help_page_path("user/project/integrations/webhooks") },
{ category: "Help", label: "Workflow Help", url: help_page_path("workflow/README") },
]
end
......
......@@ -93,10 +93,6 @@ module VisibilityLevelHelper
current_application_settings.default_project_visibility
end
def default_snippet_visibility
current_application_settings.default_snippet_visibility
end
def default_group_visibility
current_application_settings.default_group_visibility
end
......
......@@ -34,7 +34,13 @@ module Spammable
end
def check_for_spam
self.errors.add(:base, "Your #{self.class.name.underscore} has been recognized as spam and has been discarded.") if spam?
if spam?
self.errors.add(:base, "Your #{spammable_entity_type} has been recognized as spam and has been discarded.")
end
end
def spammable_entity_type
self.class.name.underscore
end
def spam_title
......
......@@ -812,6 +812,10 @@ class MergeRequest < ActiveRecord::Base
File.join(Gitlab.config.shared.path, 'tmp/rebase', source_project.id.to_s, id.to_s).to_s
end
def squash_dir_path
File.join(Gitlab.config.shared.path, 'tmp/squash', source_project.id.to_s, id.to_s).to_s
end
def rebase_in_progress?
# The source project can be deleted
return false unless source_project
......@@ -820,14 +824,26 @@ class MergeRequest < ActiveRecord::Base
end
def clean_stuck_rebase
expiration_time = Time.now - 15.minutes
if File.new(rebase_dir_path).mtime < expiration_time
if File.mtime(rebase_dir_path) < 15.minutes.ago
FileUtils.rm_rf(rebase_dir_path)
true
end
end
def squash_in_progress?
# The source project can be deleted
return false unless source_project
File.exist?(squash_dir_path) && !clean_stuck_squash
end
def clean_stuck_squash
if File.mtime(squash_dir_path) < 15.minutes.ago
FileUtils.rm_rf(squash_dir_path)
true
end
end
def diverged_commits_count
cache = Rails.cache.read(:"merge_request_#{id}_diverged_commits")
......
......@@ -169,7 +169,8 @@ class MergeRequestDiff < ActiveRecord::Base
# When compare merge request versions we want diff A..B instead of A...B
# so we handle cases when user does squash and rebase of the commits between versions.
# For this reason we set straight to true by default.
CompareService.new.execute(project, head_commit_sha, project, sha, straight: straight)
CompareService.new(project, head_commit_sha)
.execute(project, sha, straight: straight)
end
def commits_count
......
......@@ -3,9 +3,10 @@ class JenkinsService < CiService
prop_accessor :jenkins_url, :project_name, :username, :password
before_update :reset_password
validates :username,
presence: true,
if: ->(service) { service.activated? && service.password_touched? }
validates :jenkins_url, presence: true, url: true, if: :activated?
validates :project_name, presence: true, if: :activated?
validates :username, presence: true, if: ->(service) { service.activated? && service.password_touched? }
default_value_for :push_events, true
default_value_for :merge_requests_events, false
......@@ -43,13 +44,12 @@ class JenkinsService < CiService
{ success: true, result: message }
end
def auth
require 'base64'
Base64.urlsafe_encode64("#{username}:#{password}")
end
def hook_url
File.join(jenkins_url, "project/#{project_name}").to_s
url = URI.parse(jenkins_url)
url.path = File.join(url.path || '/', "project/#{project_name}")
url.user = ERB::Util.url_encode(username) unless username.blank?
url.password = ERB::Util.url_encode(password) unless password.blank?
url.to_s
end
def self.supported_events
......
......@@ -14,4 +14,8 @@ class ProjectSnippet < Snippet
participant :author
participant :notes_with_associations
def check_for_spam?
super && project.public?
end
end
This diff is collapsed.
......@@ -8,6 +8,7 @@ class Snippet < ActiveRecord::Base
include Elastic::SnippetsSearch
include Awardable
include Mentionable
include Spammable
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :content
......@@ -18,7 +19,7 @@ class Snippet < ActiveRecord::Base
default_content_html_invalidator || file_name_changed?
end
default_value_for :visibility_level, Snippet::PRIVATE
default_value_for(:visibility_level) { current_application_settings.default_snippet_visibility }
belongs_to :author, class_name: 'User'
belongs_to :project
......@@ -47,6 +48,9 @@ class Snippet < ActiveRecord::Base
participant :author
participant :notes_with_associations
attr_spammable :title, spam_title: true
attr_spammable :content, spam_description: true
def self.reference_prefix
'$'
end
......@@ -128,6 +132,14 @@ class Snippet < ActiveRecord::Base
notes.includes(:author)
end
def check_for_spam?
public?
end
def spammable_entity_type
'snippet'
end
class << self
# Searches for snippets with a matching title or file name.
#
......
......@@ -117,12 +117,12 @@ class ProjectPolicy < BasePolicy
can! :admin_pipeline
can! :admin_environment
can! :admin_deployment
# EE-only
can! :admin_path_locks
can! :admin_pages
can! :read_pages
can! :update_pages
# EE-only
can! :admin_path_locks
end
def public_access!
......@@ -149,8 +149,6 @@ class ProjectPolicy < BasePolicy
can! :remove_fork_project
can! :destroy_merge_request
can! :destroy_issue
# EE-only
can! :remove_pages
end
......
......@@ -4,7 +4,8 @@ module Commits
class ChangeError < StandardError; end
def execute
@source_project = params[:source_project] || @project
@start_project = params[:start_project] || @project
@start_branch = params[:start_branch]
@target_branch = params[:target_branch]
@commit = params[:commit]
@create_merge_request = params[:create_merge_request].present?
......@@ -25,13 +26,28 @@ module Commits
def commit_change(action)
raise NotImplementedError unless repository.respond_to?(action)
into = @create_merge_request ? @commit.public_send("#{action}_branch_name") : @target_branch
tree_id = repository.public_send("check_#{action}_content", @commit, @target_branch)
if @create_merge_request
into = @commit.public_send("#{action}_branch_name")
tree_branch = @start_branch
else
into = tree_branch = @target_branch
end
tree_id = repository.public_send(
"check_#{action}_content", @commit, tree_branch)
if tree_id
create_target_branch(into) if @create_merge_request
validate_target_branch(into) if @create_merge_request
repository.public_send(
action,
current_user,
@commit,
into,
tree_id,
start_project: @start_project,
start_branch_name: @start_branch)
repository.public_send(action, current_user, @commit, into, tree_id)
success
else
error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title(current_user)} automatically.
......@@ -50,12 +66,12 @@ module Commits
true
end
def create_target_branch(new_branch)
def validate_target_branch(new_branch)
# Temporary branch exists and contains the change commit
return success if repository.find_branch(new_branch)
return if repository.find_branch(new_branch)
result = CreateBranchService.new(@project, current_user)
.execute(new_branch, @target_branch, source_project: @source_project)
result = ValidateNewBranchService.new(@project, current_user)
.execute(new_branch)
if result[:status] == :error
raise ChangeError, "There was an error creating the source branch: #{result[:message]}"
......
......@@ -3,23 +3,27 @@ require 'securerandom'
# Compare 2 branches for one repo or between repositories
# and return Gitlab::Git::Compare object that responds to commits and diffs
class CompareService
def execute(source_project, source_branch, target_project, target_branch, straight: false)
source_commit = source_project.commit(source_branch)
return unless source_commit
attr_reader :start_project, :start_branch_name
source_sha = source_commit.sha
def initialize(new_start_project, new_start_branch_name)
@start_project = new_start_project
@start_branch_name = new_start_branch_name
end
def execute(target_project, target_branch, straight: false)
# If compare with other project we need to fetch ref first
unless target_project == source_project
random_string = SecureRandom.hex
target_project.repository.with_repo_branch_commit(
start_project.repository,
start_branch_name) do |commit|
break unless commit
target_project.repository.fetch_ref(
source_project.repository.path_to_repo,
"refs/heads/#{source_branch}",
"refs/tmp/#{random_string}/head"
)
compare(commit.sha, target_project, target_branch, straight)
end
end
private
def compare(source_sha, target_project, target_branch, straight)
raw_compare = Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
......
class CreateBranchService < BaseService
def execute(branch_name, ref, source_project: @project)
valid_branch = Gitlab::GitRefValidator.validate(branch_name)
def execute(branch_name, ref)
result = ValidateNewBranchService.new(project, current_user)
.execute(branch_name)
unless valid_branch
return error('Branch name is invalid')
end
repository = project.repository
existing_branch = repository.find_branch(branch_name)
if existing_branch
return error('Branch already exists')
end
return result if result[:status] == :error
new_branch = if source_project != @project
repository.fetch_ref(
source_project.repository.path_to_repo,
"refs/heads/#{ref}",
"refs/heads/#{branch_name}"
)
repository.after_create_branch
repository.find_branch(branch_name)
else
repository.add_branch(current_user, branch_name, ref)
end
new_branch = repository.add_branch(current_user, branch_name, ref)
if new_branch
success(new_branch)
......
class CreateSnippetService < BaseService
def execute
request = params.delete(:request)
api = params.delete(:api)
snippet = if project
project.snippets.build(params)
else
......@@ -12,8 +15,12 @@ class CreateSnippetService < BaseService
end
snippet.author = current_user
snippet.spam = SpamService.new(snippet, request).check(api)
if snippet.save
UserAgentDetailService.new(snippet, request).create
end
snippet.save
snippet
end
end
......@@ -7,7 +7,7 @@ class DeleteTagService < BaseService
return error('No such tag', 404)
end
if repository.rm_tag(tag_name)
if repository.rm_tag(current_user, tag_name)
release = project.releases.find_by(tag: tag_name)
release.destroy if release
......
......@@ -3,8 +3,8 @@ module Files
class ValidationError < StandardError; end
def execute
@source_project = params[:source_project] || @project
@source_branch = params[:source_branch]
@start_project = params[:start_project] || @project
@start_branch = params[:start_branch]
@target_branch = params[:target_branch]
@commit_message = params[:commit_message]
......@@ -22,10 +22,8 @@ module Files
# Validate parameters
validate
# Create new branch if it different from source_branch
if different_branch?
create_target_branch
end
# Create new branch if it different from start_branch
validate_target_branch if different_branch?
result = commit
if result
......@@ -40,7 +38,7 @@ module Files
private
def different_branch?
@source_branch != @target_branch || @source_project != @project
@start_branch != @target_branch || @start_project != @project
end
def file_has_changed?
......@@ -65,22 +63,23 @@ module Files
end
unless project.empty_repo?
unless @source_project.repository.branch_names.include?(@source_branch)
unless @start_project.repository.branch_exists?(@start_branch)
raise_error('You can only create or edit files when you are on a branch')
end
if different_branch?
if repository.branch_names.include?(@target_branch)
if repository.branch_exists?(@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, @source_branch, source_project: @source_project)
def validate_target_branch
result = ValidateNewBranchService.new(project, current_user).
execute(@target_branch)
unless result[:status] == :success
if result[:status] == :error
raise_error("Something went wrong when we tried to create #{@target_branch} for you: #{result[:message]}")
end
end
......
module Files
class CreateDirService < Files::BaseService
def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch, author_email: @author_email, author_name: @author_name)
repository.commit_dir(
current_user,
@file_path,
message: @commit_message,
branch_name: @target_branch,
author_email: @author_email,
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
def validate
......
module Files
class CreateService < Files::BaseService
def commit
repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch, false, author_email: @author_email, author_name: @author_name)
repository.commit_file(
current_user,
@file_path,
@file_content,
message: @commit_message,
branch_name: @target_branch,
update: false,
author_email: @author_email,
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
def validate
......@@ -24,7 +34,7 @@ module Files
unless project.empty_repo?
@file_path.slice!(0) if @file_path.start_with?('/')
blob = repository.blob_at_branch(@source_branch, @file_path)
blob = repository.blob_at_branch(@start_branch, @file_path)
if blob
raise_error('Your changes could not be committed because a file with the same name already exists')
......
module Files
class DeleteService < Files::BaseService
def commit
repository.remove_file(current_user, @file_path, @commit_message, @target_branch, author_email: @author_email, author_name: @author_name)
repository.remove_file(
current_user,
@file_path,
message: @commit_message,
branch_name: @target_branch,
author_email: @author_email,
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
end
end
......@@ -5,11 +5,13 @@ module Files
def commit
repository.multi_action(
user: current_user,
branch: @target_branch,
message: @commit_message,
branch_name: @target_branch,
actions: params[:actions],
author_email: @author_email,
author_name: @author_name
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch
)
end
......@@ -61,7 +63,7 @@ module Files
end
def last_commit
Gitlab::Git::Commit.last_for_path(repository, @source_branch, @file_path)
Gitlab::Git::Commit.last_for_path(repository, @start_branch, @file_path)
end
def regex_check(file)
......
......@@ -4,11 +4,13 @@ module Files
def commit
repository.update_file(current_user, @file_path, @file_content,
branch: @target_branch,
previous_path: @previous_path,
message: @commit_message,
branch_name: @target_branch,
previous_path: @previous_path,
author_email: @author_email,
author_name: @author_name)
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
private
......@@ -23,7 +25,7 @@ module Files
def last_commit
@last_commit ||= Gitlab::Git::Commit.
last_for_path(@source_project.repository, @source_branch, @file_path)
last_for_path(@start_project.repository, @start_branch, @file_path)
end
end
end
......@@ -18,10 +18,10 @@ class GitHooksService
end
end
yield self
yield(self).tap do
run_hook('post-receive')
end
end
private
......
class GitOperationService
attr_reader :user, :repository
def initialize(new_user, new_repository)
@user = new_user
@repository = new_repository
end
def add_branch(branch_name, newrev)
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
oldrev = Gitlab::Git::BLANK_SHA
update_ref_in_hooks(ref, newrev, oldrev)
end
def rm_branch(branch)
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch.name
oldrev = branch.target
newrev = Gitlab::Git::BLANK_SHA
update_ref_in_hooks(ref, newrev, oldrev)
end
def add_tag(tag_name, newrev, options = {})
ref = Gitlab::Git::TAG_REF_PREFIX + tag_name
oldrev = Gitlab::Git::BLANK_SHA
with_hooks(ref, newrev, oldrev) do |service|
# We want to pass the OID of the tag object to the hooks. For an
# annotated tag we don't know that OID until after the tag object
# (raw_tag) is created in the repository. That is why we have to
# update the value after creating the tag object. Only the
# "post-receive" hook will receive the correct value in this case.
raw_tag = repository.rugged.tags.create(tag_name, newrev, options)
service.newrev = raw_tag.target_id
end
end
def rm_tag(tag)
ref = Gitlab::Git::TAG_REF_PREFIX + tag.name
oldrev = tag.target
newrev = Gitlab::Git::BLANK_SHA
update_ref_in_hooks(ref, newrev, oldrev) do
repository.rugged.tags.delete(tag_name)
end
end
# Whenever `start_branch_name` is passed, if `branch_name` doesn't exist,
# it would be created from `start_branch_name`.
# If `start_project` is passed, and the branch doesn't exist,
# it would try to find the commits from it instead of current repository.
def with_branch(
branch_name,
start_branch_name: nil,
start_project: repository.project,
&block)
check_with_branch_arguments!(
branch_name, start_branch_name, start_project)
update_branch_with_hooks(branch_name) do
repository.with_repo_branch_commit(
start_project.repository,
start_branch_name || branch_name,
&block)
end
end
private
def update_branch_with_hooks(branch_name)
update_autocrlf_option
was_empty = repository.empty?
# Make commit
newrev = yield
unless newrev
raise Repository::CommitError.new('Failed to create commit')
end
branch = repository.find_branch(branch_name)
oldrev = find_oldrev_from_branch(newrev, branch)
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
update_ref_in_hooks(ref, newrev, oldrev)
# If repo was empty expire cache
repository.after_create if was_empty
repository.after_create_branch if
was_empty || Gitlab::Git.blank_ref?(oldrev)
newrev
end
def find_oldrev_from_branch(newrev, branch)
return Gitlab::Git::BLANK_SHA unless branch
oldrev = branch.target
if oldrev == repository.rugged.merge_base(newrev, branch.target)
oldrev
else
raise Repository::CommitError.new('Branch diverged')
end
end
def update_ref_in_hooks(ref, newrev, oldrev)
with_hooks(ref, newrev, oldrev) do
update_ref(ref, newrev, oldrev)
end
end
def with_hooks(ref, newrev, oldrev)
GitHooksService.new.execute(
user,
repository.path_to_repo,
oldrev,
newrev,
ref) do |service|
yield(service)
end
end
def update_ref(ref, newrev, oldrev)
# We use 'git update-ref' because libgit2/rugged currently does not
# offer 'compare and swap' ref updates. Without compare-and-swap we can
# (and have!) accidentally reset the ref to an earlier state, clobbering
# commits. See also https://github.com/libgit2/libgit2/issues/1534.
command = %W[#{Gitlab.config.git.bin_path} update-ref --stdin -z]
_, status = Gitlab::Popen.popen(
command,
repository.path_to_repo) do |stdin|
stdin.write("update #{ref}\x00#{newrev}\x00#{oldrev}\x00")
end
unless status.zero?
raise Repository::CommitError.new(
"Could not update branch #{Gitlab::Git.branch_name(ref)}." \
" Please refresh and try again.")
end
end
def update_autocrlf_option
if repository.raw_repository.autocrlf != :input
repository.raw_repository.autocrlf = :input
end
end
def check_with_branch_arguments!(
branch_name, start_branch_name, start_project)
return if repository.branch_exists?(branch_name)
if repository.project != start_project
unless start_branch_name
raise ArgumentError,
'Should also pass :start_branch_name if' +
' :start_project is different from current project'
end
unless start_project.repository.branch_exists?(start_branch_name)
raise ArgumentError,
"Cannot find branch #{branch_name} nor" \
" #{start_branch_name} from" \
" #{start_project.path_with_namespace}"
end
elsif start_branch_name
unless repository.branch_exists?(start_branch_name)
raise ArgumentError,
"Cannot find branch #{branch_name} nor" \
" #{start_branch_name} from" \
" #{repository.project.path_with_namespace}"
end
end
end
end
......@@ -16,11 +16,12 @@ module MergeRequests
messages = validate_branches(merge_request)
return build_failed(merge_request, messages) unless messages.empty?
compare = CompareService.new.execute(
compare = CompareService.new(
merge_request.source_project,
merge_request.source_branch,
merge_request.source_branch
).execute(
merge_request.target_project,
merge_request.target_branch,
merge_request.target_branch
)
merge_request.compare_commits = compare.commits
......
......@@ -10,7 +10,7 @@ module MergeRequests
def commit
repository.ff_merge(current_user,
merge_request.diff_head_sha,
source,
merge_request.target_branch,
merge_request: merge_request)
ensure
......
......@@ -6,7 +6,7 @@ module MergeRequests
# Executed when you do merge via GitLab UI
#
class MergeService < MergeRequests::BaseService
attr_reader :merge_request
attr_reader :merge_request, :source
def execute(merge_request)
if project.merge_requests_ff_only_enabled && !self.is_a?(FfMergeService)
......@@ -24,6 +24,10 @@ module MergeRequests
return error(message)
end
@source = find_merge_source
return log_merge_error('No source for merge', true) unless @source
merge_request.in_locked_state do
if commit
after_merge
......@@ -64,7 +68,7 @@ module MergeRequests
committer: committer
}
commit_id = repository.merge(current_user, merge_request, options)
commit_id = repository.merge(current_user, source, merge_request, options)
if commit_id
merge_request.update(merge_commit_sha: commit_id)
......@@ -103,9 +107,21 @@ module MergeRequests
end
def merge_request_info
project = merge_request.project
merge_request.to_reference(full: true)
end
def find_merge_source
return merge_request.diff_head_sha unless merge_request.squash
"#{project.to_reference}#{merge_request.to_reference}"
squash_result = SquashService.new(project, current_user, params).execute(merge_request)
if squash_result[:status] == :success
squash_result[:squash_sha]
else
log_merge_error("Squashing #{merge_request_info} failed")
nil
end
end
end
end
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 RebaseService < MergeRequests::BaseService
include Gitlab::Popen
attr_reader :merge_request
class RebaseService < MergeRequests::WorkingCopyBaseService
def execute(merge_request)
@merge_request = merge_request
......@@ -22,92 +12,53 @@ module MergeRequests
def rebase
if merge_request.rebase_in_progress?
log('Rebase task canceled: Another rebase is already in progress')
log_error('Rebase task canceled: Another rebase is already in progress')
return false
end
# Clone
output, status = popen(
%W(git clone -b #{merge_request.source_branch} -- #{source_project.repository.path_to_repo} #{tree_path}),
run_git_command(
%W(clone -b #{merge_request.source_branch} -- #{source_project.repository.path_to_repo} #{tree_path}),
nil,
git_env
git_env,
'clone repository for rebase'
)
unless status.zero?
log('Failed to clone repository for rebase:')
log(output)
return false
end
# Rebase
output, status = popen(
%W(git pull --rebase #{target_project.repository.path_to_repo} #{merge_request.target_branch}),
run_git_command(
%W(pull --rebase #{target_project.repository.path_to_repo} #{merge_request.target_branch}),
tree_path,
git_env
git_env,
'rebase branch'
)
unless status.zero?
log('Failed to rebase branch:')
log(output)
return false
end
output, status = popen(
%W(git rev-parse #{merge_request.source_branch}),
rebase_sha = run_git_command(
%W(rev-parse #{merge_request.source_branch}),
tree_path,
git_env
git_env,
'get SHA of rebased branch'
)
unless status.zero?
log('Failed to get SHA of rebased branch:')
log(output)
return false
end
merge_request.update_attributes(rebase_commit_sha: rebase_sha)
merge_request.update_attributes(rebase_commit_sha: output.chomp)
# Push
output, status = popen(
%W(git push -f origin #{merge_request.source_branch}),
run_git_command(
%W(push -f origin #{merge_request.source_branch}),
tree_path,
git_env
git_env,
'push rebased branch'
)
unless status.zero?
log('Failed to push rebased branch:')
log(output)
return false
end
true
rescue => ex
log('Failed to rebase branch:')
log(ex.message)
rescue GitCommandError
false
rescue => e
log_error('Failed to rebase branch:')
log_error(e)
false
ensure
clean_dir
end
def source_project
@source_project ||= merge_request.source_project
end
def target_project
@target_project ||= merge_request.target_project
end
def tree_path
@tree_path ||= merge_request.rebase_dir_path
end
def log(message)
Gitlab::GitLogger.error(message)
end
def clean_dir
FileUtils.rm_rf(tree_path) if File.exist?(tree_path)
end
def git_env
{ 'GL_ID' => Gitlab::GlId.gl_id(current_user), 'GL_PROTOCOL' => 'web' }
end
end
end
require 'securerandom'
module MergeRequests
class SquashService < MergeRequests::WorkingCopyBaseService
attr_reader :repository, :rugged
def execute(merge_request)
@merge_request = merge_request
@repository = target_project.repository
@rugged = repository.rugged
squash || error('Failed to squash. Should be done manually')
end
def squash
if merge_request.commits_count <= 1
return success(squash_sha: merge_request.diff_head_sha)
end
if merge_request.squash_in_progress?
log_error('Squash task canceled: Another squash is already in progress')
return false
end
run_git_command(
%W(worktree add #{tree_path} #{merge_request.target_branch} --detach),
repository.path_to_repo,
git_env,
'add worktree for squash'
)
run_git_command(%w(apply --cached), tree_path, git_env, 'apply patch') do |stdin|
stdin.puts(merge_request_to_patch)
end
run_git_command(
%W(commit -C #{merge_request.diff_head_sha}),
tree_path,
git_env.merge('GIT_COMMITTER_NAME' => current_user.name, 'GIT_COMMITTER_EMAIL' => current_user.email),
'commit squashed changes'
)
squash_sha = run_git_command(
%w(rev-parse HEAD),
tree_path,
git_env,
'get SHA of squashed commit'
)
success(squash_sha: squash_sha)
rescue GitCommandError
false
rescue => e
log_error("Failed to squash merge request #{merge_request.to_reference(full: true)}:")
log_error(e.message)
false
ensure
clean_dir
end
def tree_path
@tree_path ||= merge_request.squash_dir_path
end
def merge_request_to_patch
@merge_request_to_patch ||= rugged.diff(merge_request.diff_base_sha, merge_request.diff_head_sha).patch
end
end
end
module MergeRequests
class WorkingCopyBaseService < MergeRequests::BaseService
class GitCommandError < StandardError; end
include Gitlab::Popen
attr_reader :merge_request
def run_git_command(command, path, env, message = nil, &block)
git_command = [Gitlab.config.git.bin_path] + command
output, status = popen(git_command, path, env, &block)
unless status.zero?
if message
log_error("Failed to #{message} with `#{git_command.join(' ')}`:")
else
log_error("`#{git_command.join(' ')}` failed:")
end
log_error(output)
raise GitCommandError
end
output.chomp
end
def source_project
@source_project ||= merge_request.source_project
end
def target_project
@target_project ||= merge_request.target_project
end
def log_error(message)
Gitlab::GitLogger.error(message)
end
def clean_dir
FileUtils.rm_rf(tree_path) if File.exist?(tree_path)
end
def git_env
{ 'GL_ID' => Gitlab::GlId.gl_id(current_user), 'GL_PROTOCOL' => 'web' }
end
# Don't try to print expensive instance variables.
def inspect
"#<#{self.class} #{merge_request.to_reference(full: true)}>"
end
end
end
require_relative 'base_service'
class ValidateNewBranchService < BaseService
def execute(branch_name)
valid_branch = Gitlab::GitRefValidator.validate(branch_name)
unless valid_branch
return error('Branch name is invalid')
end
repository = project.repository
existing_branch = repository.find_branch(branch_name)
if existing_branch
return error('Branch already exists')
end
success
rescue GitHooksService::PreReceiveError => ex
error(ex.message)
end
end
......@@ -194,6 +194,8 @@
%li Build traces and artifacts
%li LFS objects
%li Container registry images
%li CI variables
%li Any encrypted tokens
%hr
- if can? current_user, :archive_project, @project
.row.prepend-top-default
......
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('mr_widget_ee')
- approval_pending = @merge_request.requires_approve? && !@merge_request.approved?
#merge-request-widget-app.mr-state-widget{ 'data-endpoint'=> merge_request_path(@merge_request), 'data-approval-pending' => approval_pending }
#merge-request-widget-app.mr-state-widget{ 'data-endpoint'=> merge_request_path(@merge_request), 'data-approval-pending' => (!@merge_request.approved?).to_s }
= render 'projects/merge_requests/widget/heading'
.mr-widget-body
-# After conflicts are resolved, the user is redirected back to the MR page.
......
......@@ -11,10 +11,10 @@
.accept-action
- if @pipeline && @pipeline.active?
%span.btn-group
= button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds" do
= button_tag class: "btn btn-create js-merge-button merge_when_build_succeeds", disabled: !@merge_request.approved?, ":disabled" => "disableAcceptance" do
Merge When Pipeline Succeeds
- unless @project.only_allow_merge_if_build_succeeds?
= button_tag class: "btn btn-success dropdown-toggle", 'data-toggle' => 'dropdown' do
= button_tag class: "btn btn-success dropdown-toggle", 'data-toggle' => 'dropdown', disabled: !@merge_request.approved?, ":disabled" => "disableAcceptance" do
= icon('caret-down')
%span.sr-only
Select Merge Moment
......@@ -28,18 +28,24 @@
= icon('warning fw')
Merge Immediately
- else
= f.button class: "btn btn-create btn-grouped js-merge-button accept_merge_request #{status_class}", ':disabled' => 'disableAcceptance' do
= f.button class: "btn btn-create btn-grouped js-merge-button accept_merge_request #{status_class}", disabled: !@merge_request.approved?, ":disabled" => "disableAcceptance" do
Accept Merge Request
- if @merge_request.force_remove_source_branch?
.accept-control
The source branch will be removed.
- elsif @merge_request.can_remove_source_branch?(current_user)
.accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= label_tag :should_remove_source_branch, class: "merge-param-checkbox" do
= check_box_tag :should_remove_source_branch
Remove source branch
.accept-control.checkbox
= label_tag :squash, class: 'merge-param-checkbox' do
= hidden_field_tag :squash, '0', id: nil
= check_box_tag :squash, '1', @merge_request.squash
Squash commits
= link_to icon('question-circle'), help_page_path('user/project/merge_requests/squash_and_merge'), title: 'About this feature', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'}
.accept-control.right
.accept-control
- if @project.merge_requests_ff_only_enabled
Fast-forward merge without a merge commit
- else
......
......@@ -7,10 +7,12 @@
%div
%p
= succeed '.' do
The changes will be
- if @merge_request.squash
squashed and
- if @project.merge_requests_ff_only_enabled
The changes will be fast-forward merged into
- else
The changes will be merged into
fast-forward
merged into
%span.label-branch= @merge_request.target_branch
- if @merge_request.remove_source_branch?
The source branch will be removed.
......@@ -22,7 +24,7 @@
- if remove_source_branch_button || user_can_cancel_automatic_merge
.clearfix.prepend-top-10
- if remove_source_branch_button
= link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_when_build_succeeds: true, should_remove_source_branch: true, sha: @merge_request.diff_head_sha), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do
= link_to merge_namespace_project_merge_request_path(@merge_request.target_project.namespace, @merge_request.target_project, @merge_request, merge_params(@merge_request)), remote: true, method: :post, class: "btn btn-grouped btn-primary btn-sm remove_source_branch" do
= icon('times')
Remove Source Branch When Merged
......
......@@ -21,7 +21,9 @@
= hidden_field_tag :authenticity_token, form_authenticity_token
.accept-merge-holder.clearfix.js-toggle-container
.accept-action
= f.button class: "btn btn-reopen js-rebase-button" do
= f.button class: "btn btn-reopen js-rebase-button", disabled: !@merge_request.approved?, ":disabled" => "disableAcceptance" do
Rebase onto #{@merge_request.target_branch}
.accept-control
Fast-forward merge is not possible. Rebase the source branch onto the target branch or merge target branch into source branch to allow this merge request to be merged.
- if @merge_request.requires_approve?
%b{ "v-show" => "disableAcceptance" } (Rebasing is disabled until merge request has been approved)
......@@ -8,6 +8,8 @@
- if can?(current_user, :create_project_snippet, @project)
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-inverted btn-create', title: "New snippet" do
New snippet
- if @snippet.submittable_as_spam? && current_user.admin?
= link_to 'Submit as spam', mark_as_spam_namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :post, class: 'btn btn-grouped btn-spam', title: 'Submit as spam'
- if can?(current_user, :create_project_snippet, @project) || can?(current_user, :update_project_snippet, @snippet)
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
......@@ -27,3 +29,6 @@
%li
= link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
Edit
- if @snippet.submittable_as_spam? && current_user.admin?
%li
= link_to 'Submit as spam', mark_as_spam_namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :post
......@@ -3,4 +3,4 @@
%h3.page-title
Edit Snippet
%hr
= render "shared/snippets/form", url: namespace_project_snippet_path(@project.namespace, @project, @snippet), visibility_level: @snippet.visibility_level
= render "shared/snippets/form", url: namespace_project_snippet_path(@project.namespace, @project, @snippet)
......@@ -3,4 +3,4 @@
%h3.page-title
New Snippet
%hr
= render "shared/snippets/form", url: namespace_project_snippets_path(@project.namespace, @project, @snippet), visibility_level: default_snippet_visibility
= render "shared/snippets/form", url: namespace_project_snippets_path(@project.namespace, @project, @snippet)
......@@ -45,6 +45,8 @@
= render 'shared/issuable/form/branch_chooser', issuable: issuable, form: form
= render 'shared/issuable/form/merge_params', issuable: issuable
- if @merge_request_for_resolving_discussions
.form-group
.col-sm-10.col-sm-offset-2
......
......@@ -19,12 +19,3 @@
- if issuable.new_record?
&nbsp;
= link_to 'Change branches', mr_change_branches_path(issuable)
- if issuable.can_remove_source_branch?(current_user)
.form-group
.col-sm-10.col-sm-offset-2
.checkbox
= label_tag 'merge_request[force_remove_source_branch]' do
= hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil
= check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?
Remove source branch when merge request is accepted.
- issuable = local_assigns.fetch(:issuable)
- return unless issuable.is_a?(MergeRequest)
- return if issuable.closed_without_fork?
.form-group
.col-sm-10.col-sm-offset-2
- if issuable.can_remove_source_branch?(current_user)
.checkbox
= label_tag 'merge_request[force_remove_source_branch]' do
= hidden_field_tag 'merge_request[force_remove_source_branch]', '0', id: nil
= check_box_tag 'merge_request[force_remove_source_branch]', '1', issuable.force_remove_source_branch?
Remove source branch when merge request is accepted.
.checkbox
= label_tag 'merge_request[squash]' do
= hidden_field_tag 'merge_request[squash]', '0', id: nil
= check_box_tag 'merge_request[squash]', '1', issuable.squash
Squash commits when merge request is accepted.
= link_to 'About this feature', help_page_path('user/project/merge_requests/squash_and_merge')
......@@ -11,7 +11,7 @@
.col-sm-10
= f.text_field :title, class: 'form-control', required: true, autofocus: true
= render 'shared/visibility_level', f: f, visibility_level: visibility_level, can_change_visibility_level: true, form_model: @snippet
= render 'shared/visibility_level', f: f, visibility_level: @snippet.visibility_level, can_change_visibility_level: true, form_model: @snippet
.file-editor
.form-group
......
......@@ -5,8 +5,7 @@
%h4.prepend-top-0
= page_title
%p
#{link_to "Webhooks", help_page_path("web_hooks/web_hooks")} can be
used for binding events when something is happening within the #{context_title}.
#{link_to "Webhooks", help_page_path("user/project/integrations/webhooks")} can be
.col-lg-9.append-bottom-default
= form_for hook, as: :hook, url: polymorphic_path(url_components + [:hooks]) do |f|
= form_errors(hook)
......
......@@ -8,6 +8,8 @@
- if current_user
= link_to new_snippet_path, class: "btn btn-grouped btn-inverted btn-create", title: "New snippet" do
New snippet
- if @snippet.submittable_as_spam? && current_user.admin?
= link_to 'Submit as spam', mark_as_spam_snippet_path(@snippet), method: :post, class: 'btn btn-grouped btn-spam', title: 'Submit as spam'
- if current_user
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
......@@ -26,3 +28,6 @@
%li
= link_to edit_snippet_path(@snippet) do
Edit
- if @snippet.submittable_as_spam? && current_user.admin?
%li
= link_to 'Submit as spam', mark_as_spam_snippet_path(@snippet), method: :post
......@@ -2,4 +2,4 @@
%h3.page-title
Edit Snippet
%hr
= render 'shared/snippets/form', url: snippet_path(@snippet), visibility_level: @snippet.visibility_level
= render 'shared/snippets/form', url: snippet_path(@snippet)
......@@ -2,4 +2,4 @@
%h3.page-title
New Snippet
%hr
= render "shared/snippets/form", url: snippets_path(@snippet), visibility_level: default_snippet_visibility
= render "shared/snippets/form", url: snippets_path(@snippet)
......@@ -33,13 +33,15 @@ class EmailsOnPushWorker
reverse_compare = false
if action == :push
compare = CompareService.new.execute(project, after_sha, project, before_sha)
compare = CompareService.new(project, after_sha)
.execute(project, before_sha)
diff_refs = compare.diff_refs
return false if compare.same
if compare.commits.empty?
compare = CompareService.new.execute(project, before_sha, project, after_sha)
compare = CompareService.new(project, before_sha)
.execute(project, after_sha)
diff_refs = compare.diff_refs
reverse_compare = true
......
---
title: Disable all merge acceptance buttons pending MR approval.
merge_request: !1101
author:
---
title: Fix sidekiq cluster mishandling of queue names
merge_request: 1117
author:
---
title: Pull EE specific Gitlab::Auth code in to its own module
merge_request: 1112
author:
---
title: Fix autocomplete initial undefined state
title: Fixed merge request environment link not displaying
merge_request:
author:
---
title: Fix race conditions for AuthorizedProjectsWorker
title: Allow squashing merge requests into a single commit
merge_request:
author:
---
title: Add caching of droplab ajax requests
merge_request: 8725
author:
---
title: Fix access to the wiki code via HTTP when repository feature disabled
merge_request: 8758
author:
---
title: Ignore encrypted attributes in Import/Export
merge_request:
author:
---
title: Fixed label dropdown toggle text not correctly updating
merge_request:
author:
---
title: Revert 3f17f29a
merge_request: 8785
author:
---
title: Fix Error 500 when repositories contain annotated tags pointing to blobs
merge_request:
author:
---
title: Fix /explore sorting
title: Check public snippets for spam
merge_request:
author:
......@@ -39,11 +39,9 @@ constraints(ProjectUrlConstrainer.new) do
end
end
## EE-specific
resource :pages, only: [:show, :destroy] do
resources :domains, only: [:show, :new, :create, :destroy], controller: 'pages_domains', constraints: { id: /[^\/]+/ }
end
## EE-specific
resources :compare, only: [:index, :create] do
collection do
......@@ -70,6 +68,7 @@ constraints(ProjectUrlConstrainer.new) do
resources :snippets, concerns: :awardable, constraints: { id: /\d+/ } do
member do
get 'raw'
post :mark_as_spam
end
end
......
......@@ -2,6 +2,7 @@ resources :snippets, concerns: :awardable do
member do
get 'raw'
get 'download'
post :mark_as_spam
end
end
......
......@@ -50,8 +50,8 @@
- [reactive_caching, 1]
- [cronjob, 1]
- [default, 1]
# EE specific queues
- [pages, 1]
# EE specific queues
- [elasticsearch, 1]
- [geo, 1]
- [project_mirror, 1]
......
class AddSquashToMergeRequests < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
DOWNTIME = false
def up
add_column_with_default :merge_requests, :squash, :boolean, default: false, allow_null: false
end
def down
remove_column :merge_requests, :squash
end
end
......@@ -782,6 +782,7 @@ ActiveRecord::Schema.define(version: 20170121130655) do
t.text "title_html"
t.text "description_html"
t.integer "time_estimate"
t.boolean "squash", default: false, null: false
end
add_index "merge_requests", ["assignee_id"], name: "index_merge_requests_on_assignee_id", using: :btree
......
......@@ -21,11 +21,11 @@
- [Migrating from SVN](workflow/importing/migrating_from_svn.md) Convert a SVN repository to Git and GitLab.
- [Permissions](user/permissions.md) Learn what each role in a project (external/guest/reporter/developer/master/owner) can do.
- [Profile Settings](profile/README.md)
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
- [Project Services](user/project/integrations//project_services.md) Integrate a project with external services, such as CI and chat.
- [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects.
- [Analytics](analytics/README.md)
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
- [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Webhooks](user/project/integrations/webhooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
- [Git Attributes](user/project/git_attributes.md) Managing Git attributes using a `.gitattributes` file.
- [Git cheatsheet](https://gitlab.com/gitlab-com/marketing/raw/master/design/print/git-cheatsheet/print-pdf/git-cheatsheet.pdf) Download a PDF describing the most used Git operations.
......
......@@ -3,7 +3,7 @@
>
**Note:** Custom Git hooks must be configured on the filesystem of the GitLab
server. Only GitLab server administrators will be able to complete these tasks.
Please explore [webhooks](../web_hooks/web_hooks.md) as an option if you do not
Please explore [webhooks] as an option if you do not
have filesystem access. For a user configurable Git hook interface, please see
[GitLab Enterprise Edition Git Hooks](http://docs.gitlab.com/ee/git_hooks/git_hooks.html).
......@@ -80,5 +80,6 @@ STDERR takes precedence over STDOUT.
![Custom message from custom Git hook](img/custom_hooks_error_msg.png)
[hooks]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#Server-Side-Hooks
[webhooks]: ../user/project/integrations/webhooks.md
[5073]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5073
[93]: https://gitlab.com/gitlab-org/gitlab-shell/merge_requests/93
......@@ -95,16 +95,9 @@ Secondary GitLab servers (servers configured **after** the first GitLab server)
need some additional configuration.
1. Configure shared secrets. These values can be obtained from the primary
GitLab server in `/etc/gitlab/gitlab-secrets.json`. Add these to
`/etc/gitlab/gitlab.rb` **prior to** running the first `reconfigure` in
the steps above.
```ruby
gitlab_shell['secret_token'] = 'fbfb19c355066a9afb030992231c4a363357f77345edd0f2e772359e5be59b02538e1fa6cae8f93f7d23355341cea2b93600dab6d6c3edcdced558fc6d739860'
gitlab_rails['otp_key_base'] = 'b719fe119132c7810908bba18315259ed12888d4f5ee5430c42a776d840a396799b0a5ef0a801348c8a357f07aa72bbd58e25a84b8f247a25c72f539c7a6c5fa'
gitlab_rails['secret_key_base'] = '6e657410d57c71b4fc3ed0d694e7842b1895a8b401d812c17fe61caf95b48a6d703cb53c112bc01ebd197a85da81b18e29682040e99b4f26594772a4a2c98c6d'
gitlab_rails['db_key_base'] = 'bf2e47b68d6cafaef1d767e628b619365becf27571e10f196f98dc85e7771042b9203199d39aff91fcb6837c8ed83f2a912b278da50999bb11a2fbc0fba52964'
```
GitLab server in `/etc/gitlab/gitlab-secrets.json`. Copy this file to the
secondary servers **prior to** running the first `reconfigure` in the steps
above.
1. Run `touch /etc/gitlab/skip-auto-migrations` to prevent database migrations
from running on upgrade. Only the primary GitLab application server should
......
# Web terminals
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7690)
in GitLab 8.15. Only project masters and owners can access web terminals.
> [Introduced][ce-7690] in GitLab 8.15. Only project masters and owners can
access web terminals.
With the introduction of the [Kubernetes](../../project_services/kubernetes.md)
project service, GitLab gained the ability to store and use credentials for a
Kubernetes cluster. One of the things it uses these credentials for is providing
access to [web terminals](../../ci/environments.html#web-terminals)
for environments.
With the introduction of the [Kubernetes project service][kubservice], GitLab
gained the ability to store and use credentials for a Kubernetes cluster. One
of the things it uses these credentials for is providing access to
[web terminals](../../ci/environments.html#web-terminals) for environments.
## How it works
......@@ -71,3 +70,6 @@ by the above guides.
When these headers are not passed through, Workhorse will return a
`400 Bad Request` response to users attempting to use a web terminal. In turn,
they will receive a `Connection failed` message.
[ce-7690]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7690
[kubservice]: ../../user/project/integrations/kubernetes.md)
......@@ -75,6 +75,7 @@ Parameters:
"approvals_before_merge": null
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
]
......@@ -145,6 +146,7 @@ Parameters:
"approvals_before_merge": null
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
```
......@@ -251,6 +253,7 @@ Parameters:
"approvals_before_merge": null,
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1",
"changes": [
{
......@@ -287,6 +290,7 @@ POST /projects/:id/merge_requests
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
| `approvals_before_merge` | integer| no | Number of approvals required before this can be merged (see below) |
| `squash` | boolean| no | Squash commits into a single commit when merging |
If `approvals_before_merge` is not provided, it inherits the value from the
target project. If it is provided, then the following conditions must hold in
......@@ -349,6 +353,7 @@ order for it to take effect:
"approvals_before_merge": null
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
```
......@@ -374,6 +379,7 @@ PUT /projects/:id/merge_requests/:merge_request_id
| `labels` | string | no | Labels for MR as a comma-separated list |
| `milestone_id` | integer | no | The ID of a milestone |
| `remove_source_branch` | boolean | no | Flag indicating if a merge request should remove the source branch when merging |
| `squash` | boolean| no | Squash commits into a single commit when merging |
```json
{
......@@ -426,6 +432,7 @@ PUT /projects/:id/merge_requests/:merge_request_id
"approvals_before_merge": null
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
```
......@@ -471,7 +478,19 @@ Parameters:
- `merge_commit_message` (optional) - Custom merge commit message
- `should_remove_source_branch` (optional) - if `true` removes the source branch
- `merge_when_build_succeeds` (optional) - if `true` the MR is merged when the build succeeds
- `sha` (optional) - if present, then this SHA must match the HEAD of the source branch, otherwise the merge will fail
- `sha` (optional) - if present, then this SHA must
| Attribute | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `id` | string | yes | The ID of a project |
| `merge_request_id` | integer | yes | The ID of the merge request |
| `merge_commit_message` | string | no | Custom merge commit message |
| `should_remove_source_branch` | boolean | no | Remove the source branch after merge |
| `merge_when_build_succeeds` | boolean | no | Merge when build succeeds, rather than immediately |
| `sha` | string | no | If present, then this SHA must match the HEAD of the source branch, otherwise the merge will fail |
| `squash` | boolean | no | Squash the merge request into a single commit |
```json
{
......@@ -525,6 +544,7 @@ Parameters:
"approvals_before_merge": null
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
```
......@@ -698,6 +718,7 @@ Parameters:
"approvals_before_merge": null
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": false,
"web_url": "http://example.com/example/example/merge_requests/1"
}
```
......@@ -1021,6 +1042,7 @@ Example response:
"user_notes_count": 7,
"should_remove_source_branch": true,
"force_remove_source_branch": false,
"squash": true,
"web_url": "http://example.com/example/example/merge_requests/1"
},
"target_url": "https://gitlab.example.com/gitlab-org/gitlab-ci/merge_requests/7",
......
......@@ -808,6 +808,7 @@ Get JetBrains TeamCity CI service settings for a project.
GET /projects/:id/services/teamcity
```
<<<<<<< HEAD
## Jenkins CI
A continuous integration and build server
......@@ -879,5 +880,5 @@ Get Jenkins CI (Deprecated) service settings for a project.
GET /projects/:id/services/jenkins-deprecated
```
[jira-doc]: ../project_services/jira.md
[jira-doc]: ../user/project/integrations/jira.md
[old-jira-api]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-13-stable/doc/api/services.md#jira
......@@ -33,8 +33,9 @@ enable [Kubernetes service][kubernetes-service].
created automatically for you.
[mr-8135]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8135
[project-services]: ../../project_services/project_services.md
[project-settings]: https://docs.gitlab.com/ce/public_access/public_access.html
[project-services]: ../../user/project/integrations/project_services.md
[auto-deploy-templates]: https://gitlab.com/gitlab-org/gitlab-ci-yml/tree/master/autodeploy
[kubernetes-service]: ../../project_services/kubernetes.md
[kubernetes-service]: ../../user/project/integrations/kubernetes.md
[docker-in-docker]: ../docker/using_docker_build.md#use-docker-in-docker-executor
[review-app]: ../review_apps/index.md
# Introduction to environments and deployments
>**Note:**
Introduced in GitLab 8.9.
> Introduced in GitLab 8.9.
During the development of software, there can be many stages until it's ready
for public consumption. You sure want to first test your code and then deploy it
......@@ -242,7 +241,7 @@ Web terminals were added in GitLab 8.15 and are only available to project
masters and owners.
If you deploy to your environments with the help of a deployment service (e.g.,
the [Kubernetes](../project_services/kubernetes.md) service), GitLab can open
the [Kubernetes service][kubernetes-service], GitLab can open
a terminal session to your environment! This is a very powerful feature that
allows you to debug issues without leaving the comfort of your web browser. To
enable it, just follow the instructions given in the service documentation.
......@@ -566,7 +565,7 @@ Below are some links you may find interesting:
[Pipelines]: pipelines.md
[jobs]: yaml/README.md#jobs
[yaml]: yaml/README.md
[kubernetes-service]: ../project_services/kubernetes.md]
[kubernetes-service]: ../user/project/integrations/kubernetes.md
[environments]: #environments
[deployments]: #deployments
[permissions]: ../user/permissions.md
......
......@@ -217,7 +217,7 @@ builds, you should explicitly enable the **Builds Emails** service under your
project's settings.
For more information read the
[Builds emails service documentation](../../project_services/builds_emails.md).
[Builds emails service documentation](../../user/project/integrations/builds_emails.md).
## Examples
......
......@@ -157,14 +157,14 @@ Once you set them, they will be available for all subsequent builds.
>**Note:**
This feature requires GitLab CI 8.15 or higher.
[Project services](../../project_services/project_services.md) that are
[Project services](../../user/project/integrations/project_services.md) that are
responsible for deployment configuration may define their own variables that
are set in the build environment. These variables are only defined for
[deployment builds](../environments.md). Please consult the documentation of
the project services that you are using to learn which variables they define.
An example project service that defines deployment variables is
[Kubernetes Service](../../project_services/kubernetes.md).
[Kubernetes Service](../../user/project/integrations/kubernetes.md).
## Debug tracing
......
......@@ -109,7 +109,7 @@ Dropdowns are used to allow users to choose one (or many) options from a list of
### Max size
The max height for dropdowns should target **10-15 items**. If the height of the dropdown is too large, the list becomes very hard to parse and it is easy to visually lose track of the item you are looking for. Usability also suffers as more mouse movement is required, and you have a larger area in which you hijack the scroll away from the page level. While it may initially seem counterintuitive to not show as many items as you can, it is actually quicker and easier to process the information when it is cropped at a reasonable height.
The max height for dropdowns should target **10-15** single line items, or **7-10** multi-line items. If the height of the dropdown is too large, the list becomes very hard to parse and it is easy to visually lose track of the item you are looking for. Usability also suffers as more mouse movement is required, and you have a larger area in which you hijack the scroll away from the page level. While it may initially seem counterintuitive to not show as many items as you can, it is actually quicker and easier to process the information when it is cropped at a reasonable height.
---
......
......@@ -102,6 +102,12 @@ When using the <kbd>Alt</kbd> keystrokes in Windows, use the numeric keypad, not
## Terminology
Only use the terms in the tables below.
### Projects and Groups
| Term | Use | :no_entry_sign: Don't |
| ---- | --- | ----- |
| Members | When discussing the people who are a part of a project or a group. | Don't use `users`. |
### Issues
#### Adjectives (states)
......@@ -117,7 +123,7 @@ Use `5 open issues` and don’t use `5 pending issues`.
#### Verbs (actions)
| Term | Use | Don’t |
| Term | Use | :no_entry_sign: Don’t |
| ---- | --- | --- |
| Add | Add an issue | Don’t use `create` or `new` |
| View | View an open or closed issue ||
......@@ -158,7 +164,7 @@ The form should be titled `Edit issue`. The submit button should be labeled `Sav
#### Verbs (actions)
| Term | Use | Don’t |
| Term | Use | :no_entry_sign: Don’t |
| ---- | --- | --- |
| Add | Add a merge request | Do not use `create` or `new` |
| View | View an open or merged merge request ||
......
......@@ -65,7 +65,7 @@ logins opened on all nodes as we will be moving back and forth.
sudo -i
```
1. Create a new SSH key pair for the primary node. Choose the default location
1. (Source install only): Create a new SSH key pair for the primary node. Choose the default location
and leave the password blank by hitting 'Enter' three times:
```bash
......@@ -74,7 +74,7 @@ logins opened on all nodes as we will be moving back and forth.
Read more in [additional info for SSH key pairs](#additional-information-for-the-ssh-key-pairs).
1. Get the contents of `id_rsa.pub` the was just created:
1. Get the contents of `id_rsa.pub` for the git user:
```
# Omnibus GitLab installations
......@@ -86,6 +86,7 @@ logins opened on all nodes as we will be moving back and forth.
1. Visit the primary node's **Admin Area ➔ Geo Nodes** (`/admin/geo_nodes`) in
your browser.
1. Add the primary node by providing its full URL and the public SSH key
you created previously. Make sure to check the box 'This is a primary node'
when adding it.
......
......@@ -32,11 +32,11 @@ and `secondary` as either `slave` or `standby` server (read-only).
The following guide assumes that:
- You are using PostgreSQL 9.1 or later which includes the
[`pg_basebackup` tool][pgback]. As of this writing, the latest Omnibus
packages (8.5) have version 9.2.
- You are using PostgreSQL 9.2 or later which includes the
[`pg_basebackup` tool][pgback]. If you are using Omnibus it includes the required
PostgreSQL version for Geo.
- You have a primary server already set up (the GitLab server you are
replicating from), running PostgreSQL 9.2.x, and you
replicating from), running Omnibus' PostgreSQL (or equivalent version), and you
have a new secondary server set up on the same OS and PostgreSQL version. If
you are using Omnibus, make sure the GitLab version is the same on all nodes.
- The IP of the primary server for our examples will be `1.2.3.4`, whereas the
......@@ -182,6 +182,7 @@ The following guide assumes that:
postgresql['max_wal_senders'] = 10
postgresql['wal_keep_segments'] = 10
postgresql['hot_standby'] = "on"
gitlab_rails['auto_migrate'] = false # prevents migrations to be executed on the secondary server
```
1. [Reconfigure GitLab][] for the changes to take effect.
......
......@@ -5,7 +5,7 @@ trackers and external authentication.
See the documentation below for details on how to configure these services.
- [JIRA](../project_services/jira.md) Integrate with the JIRA issue tracker
- [JIRA](../user/project/integrations/jira.md) Integrate with the JIRA issue tracker
- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
- [LDAP](ldap.md) Set up sign in via LDAP
- [Jenkins](jenkins.md) Integrate with the Jenkins CI
......@@ -20,17 +20,14 @@ See the documentation below for details on how to configure these services.
- [Koding](../administration/integration/koding.md) Configure Koding to use IDE integration
- [PlantUML](../administration/integration/plantuml.md) Configure PlantUML to use diagrams in AsciiDoc documents.
GitLab Enterprise Edition contains [advanced Jenkins support][jenkins].
[jenkins]: http://docs.gitlab.com/ee/integration/jenkins.html
> GitLab Enterprise Edition contains [advanced Jenkins support][jenkins].
## Project services
Integration with services such as Campfire, Flowdock, Gemnasium, HipChat,
Pivotal Tracker, and Slack are available in the form of a [Project Service][].
[Project Service]: ../project_services/project_services.md
[Project Service]: ../user/project/integrations/project_services.md
## SSL certificate errors
......@@ -66,3 +63,5 @@ After that restart GitLab with:
```bash
sudo gitlab-ctl restart
```
[jenkins]: http://docs.gitlab.com/ee/integration/jenkins.html
......@@ -18,9 +18,9 @@ The configuration is done via a project's **Services**.
To enable an external issue tracker you must configure the appropriate **Service**.
Visit the links below for details:
- [Redmine](../project_services/redmine.md)
- [Jira](../project_services/jira.md)
- [Bugzilla](../project_services/bugzilla.md)
- [Redmine](../user/project/integrations/redmine.md)
- [Jira](../user/project/integrations/jira.md)
- [Bugzilla](../user/project/integrations/bugzilla.md)
### Service Template
......@@ -28,4 +28,4 @@ To save you the hassle from configuring each project's service individually,
GitLab provides the ability to set Service Templates which can then be
overridden in each project's settings.
Read more on [Services Templates](../project_services/services_templates.md).
Read more on [Services Templates](../user/project/integrations/services_templates.md).
# GitLab JIRA integration
This document was moved to [project_services/jira](../project_services/jira.md).
This document was moved to [integrations/jira](../user/project/integrations/jira.md).
# Atlassian Bamboo CI Service
GitLab provides integration with Atlassian Bamboo for continuous integration.
When configured, pushes to a project will trigger a build in Bamboo automatically.
Merge requests will also display CI status showing whether the build is pending,
failed, or completed successfully. It also provides a link to the Bamboo build
page for more information.
Bamboo doesn't quite provide the same features as a traditional build system when
it comes to accepting webhooks and commit data. There are a few things that
need to be configured in a Bamboo build plan before GitLab can integrate.
## Setup
### Complete these steps in Bamboo:
1. Navigate to a Bamboo build plan and choose 'Configure plan' from the 'Actions'
dropdown.
1. Select the 'Triggers' tab.
1. Click 'Add trigger'.
1. Enter a description such as 'GitLab trigger'
1. Choose 'Repository triggers the build when changes are committed'
1. Check one or more repositories checkboxes
1. Enter the GitLab IP address in the 'Trigger IP addresses' box. This is a
whitelist of IP addresses that are allowed to trigger Bamboo builds.
1. Save the trigger.
1. In the left pane, select a build stage. If you have multiple build stages
you want to select the last stage that contains the git checkout task.
1. Select the 'Miscellaneous' tab.
1. Under 'Pattern Match Labelling' put '${bamboo.repository.revision.number}'
in the 'Labels' box.
1. Save
Bamboo is now ready to accept triggers from GitLab. Next, set up the Bamboo
service in GitLab
### Complete these steps in GitLab:
1. Navigate to the project you want to configure to trigger builds.
1. Select 'Settings' in the top navigation.
1. Select 'Services' in the left navigation.
1. Click 'Atlassian Bamboo CI'
1. Select the 'Active' checkbox.
1. Enter the base URL of your Bamboo server. 'https://bamboo.example.com'
1. Enter the build key from your Bamboo build plan. Build keys are a short,
all capital letter, identifier that is unique. It will be something like PR-BLD
1. If necessary, enter username and password for a Bamboo user that has
access to trigger the build plan. Leave these fields blank if you do not require
authentication.
1. Save or optionally click 'Test Settings'. Please note that 'Test Settings'
will actually trigger a build in Bamboo.
## Troubleshooting
If builds are not triggered, these are a couple of things to keep in mind.
1. Ensure you entered the right GitLab IP address in Bamboo under 'Trigger
IP addresses'.
1. Remember that GitLab only triggers builds on push events. A commit via the
web interface will not trigger CI currently.
This document was moved to [user/project/integrations/bamboo.md](../user/project/integrations/bamboo.md).
# Bugzilla Service
Go to your project's **Settings > Services > Bugzilla** and fill in the required
details as described in the table below.
| Field | Description |
| ----- | ----------- |
| `description` | A name for the issue tracker (to differentiate between instances, for example) |
| `project_url` | The URL to the project in Bugzilla which is being linked to this GitLab project. Note that the `project_url` requires PRODUCT_NAME to be updated with the product/project name in Bugzilla. |
| `issues_url` | The URL to the issue in Bugzilla project that is linked to this GitLab project. Note that the `issues_url` requires `:id` in the URL. This ID is used by GitLab as a placeholder to replace the issue number. |
| `new_issue_url` | This is the URL to create a new issue in Bugzilla for the project linked to this GitLab project. Note that the `new_issue_url` requires PRODUCT_NAME to be updated with the product/project name in Bugzilla. |
Once you have configured and enabled Bugzilla:
- the **Issues** link on the GitLab project pages takes you to the appropriate
Bugzilla product page
- clicking **New issue** on the project dashboard takes you to Bugzilla for entering a new issue
This document was moved to [user/project/integrations/bugzilla.md](../user/project/integrations/bugzilla.md).
## Enabling build emails
To receive e-mail notifications about the result status of your builds, visit
your project's **Settings > Services > Builds emails** and activate the service.
In the _Recipients_ area, provide a list of e-mails separated by comma.
Check the _Add pusher_ checkbox if you want the committer to also receive
e-mail notifications about each build's status.
If you enable the _Notify only broken builds_ option, e-mail notifications will
be sent only for failed builds.
---
![Builds emails service settings](img/builds_emails_service.png)
This document was moved to [user/project/integrations/builds_emails.md](../user/project/integrations/builds_emails.md).
## Enabling emails on push
To receive email notifications for every change that is pushed to the project, visit
your project's **Settings > Services > Emails on push** and activate the service.
In the _Recipients_ area, provide a list of emails separated by commas.
You can configure any of the following settings depending on your preference.
+ **Push events** - Email will be triggered when a push event is recieved
+ **Tag push events** - Email will be triggered when a tag is created and pushed
+ **Send from committer** - Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. `user@gitlab.com`).
+ **Disable code diffs** - Don't include possibly sensitive code diffs in notification body.
---
![Email on push service settings](img/emails_on_push_service.png)
This document was moved to [user/project/integrations/emails_on_push.md](../user/project/integrations/emails_on_push.md).
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment