Commit 9a1c5456 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 927cfbfe
...@@ -10,8 +10,10 @@ schedule:package-and-qa:notify-success: ...@@ -10,8 +10,10 @@ schedule:package-and-qa:notify-success:
extends: extends:
- .only-canonical-schedules - .only-canonical-schedules
- .notify - .notify
before_script:
- export COMMIT_NOTES_URL="https://$CI_SERVER_HOST/$CI_PROJECT_PATH/commit/$CI_COMMIT_SHA#notes-list"
script: script:
- 'scripts/notify-slack qa-master ":tada: Scheduled QA against master passed! :tada: See $CI_PIPELINE_URL." ci_passing' - 'scripts/notify-slack qa-master ":tada: Scheduled QA against master passed! :tada: See $CI_PIPELINE_URL. For downstream pipelines, see $COMMIT_NOTES_URL" ci_passing'
needs: ["schedule:package-and-qa"] needs: ["schedule:package-and-qa"]
when: on_success when: on_success
...@@ -19,7 +21,9 @@ schedule:package-and-qa:notify-failure: ...@@ -19,7 +21,9 @@ schedule:package-and-qa:notify-failure:
extends: extends:
- .only-canonical-schedules - .only-canonical-schedules
- .notify - .notify
before_script:
- export COMMIT_NOTES_URL="https://$CI_SERVER_HOST/$CI_PROJECT_PATH/commit/$CI_COMMIT_SHA#notes-list"
script: script:
- 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See $CI_PIPELINE_URL." ci_failing' - 'scripts/notify-slack qa-master ":skull_and_crossbones: Scheduled QA against master failed! :skull_and_crossbones: See $CI_PIPELINE_URL. For downstream pipelines, see $COMMIT_NOTES_URL" ci_failing'
needs: ["schedule:package-and-qa"] needs: ["schedule:package-and-qa"]
when: on_failure when: on_failure
# frozen_string_literal: true
module Git
module ChangeParams
private
%i[oldrev newrev ref].each do |method|
define_method method do
change[method]
end
end
def change
@change ||= params.fetch(:change, {})
end
end
end
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
module Git module Git
class BaseHooksService < ::BaseService class BaseHooksService < ::BaseService
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include ChangeParams
# The N most recent commits to process in a single push payload. # The N most recent commits to process in a single push payload.
PROCESS_COMMIT_LIMIT = 100 PROCESS_COMMIT_LIMIT = 100
...@@ -77,20 +78,20 @@ module Git ...@@ -77,20 +78,20 @@ module Git
def pipeline_params def pipeline_params
{ {
before: params[:oldrev], before: oldrev,
after: params[:newrev], after: newrev,
ref: params[:ref], ref: ref,
push_options: params[:push_options] || {}, push_options: params[:push_options] || {},
checkout_sha: Gitlab::DataBuilder::Push.checkout_sha( checkout_sha: Gitlab::DataBuilder::Push.checkout_sha(
project.repository, params[:newrev], params[:ref]) project.repository, newrev, ref)
} }
end end
def push_data_params(commits:, with_changed_files: true) def push_data_params(commits:, with_changed_files: true)
{ {
oldrev: params[:oldrev], oldrev: oldrev,
newrev: params[:newrev], newrev: newrev,
ref: params[:ref], ref: ref,
project: project, project: project,
user: current_user, user: current_user,
commits: commits, commits: commits,
......
...@@ -20,15 +20,15 @@ module Git ...@@ -20,15 +20,15 @@ module Git
strong_memoize(:commits) do strong_memoize(:commits) do
if creating_default_branch? if creating_default_branch?
# The most recent PROCESS_COMMIT_LIMIT commits in the default branch # The most recent PROCESS_COMMIT_LIMIT commits in the default branch
project.repository.commits(params[:newrev], limit: PROCESS_COMMIT_LIMIT) project.repository.commits(newrev, limit: PROCESS_COMMIT_LIMIT)
elsif creating_branch? elsif creating_branch?
# Use the pushed commits that aren't reachable by the default branch # Use the pushed commits that aren't reachable by the default branch
# as a heuristic. This may include more commits than are actually # as a heuristic. This may include more commits than are actually
# pushed, but that shouldn't matter because we check for existing # pushed, but that shouldn't matter because we check for existing
# cross-references later. # cross-references later.
project.repository.commits_between(project.default_branch, params[:newrev]) project.repository.commits_between(project.default_branch, newrev)
elsif updating_branch? elsif updating_branch?
project.repository.commits_between(params[:oldrev], params[:newrev]) project.repository.commits_between(oldrev, newrev)
else # removing branch else # removing branch
[] []
end end
...@@ -70,7 +70,7 @@ module Git ...@@ -70,7 +70,7 @@ module Git
def branch_update_hooks def branch_update_hooks
# Update the bare repositories info/attributes file using the contents of # Update the bare repositories info/attributes file using the contents of
# the default branch's .gitattributes file # the default branch's .gitattributes file
project.repository.copy_gitattributes(params[:ref]) if default_branch? project.repository.copy_gitattributes(ref) if default_branch?
end end
def branch_change_hooks def branch_change_hooks
...@@ -118,7 +118,7 @@ module Git ...@@ -118,7 +118,7 @@ module Git
# https://gitlab.com/gitlab-org/gitlab-foss/issues/59257 # https://gitlab.com/gitlab-org/gitlab-foss/issues/59257
def creating_branch? def creating_branch?
strong_memoize(:creating_branch) do strong_memoize(:creating_branch) do
Gitlab::Git.blank_ref?(params[:oldrev]) || Gitlab::Git.blank_ref?(oldrev) ||
!project.repository.branch_exists?(branch_name) !project.repository.branch_exists?(branch_name)
end end
end end
...@@ -128,7 +128,7 @@ module Git ...@@ -128,7 +128,7 @@ module Git
end end
def removing_branch? def removing_branch?
Gitlab::Git.blank_ref?(params[:newrev]) Gitlab::Git.blank_ref?(newrev)
end end
def creating_default_branch? def creating_default_branch?
...@@ -137,7 +137,7 @@ module Git ...@@ -137,7 +137,7 @@ module Git
def count_commits_in_branch def count_commits_in_branch
strong_memoize(:count_commits_in_branch) do strong_memoize(:count_commits_in_branch) do
project.repository.commit_count_for_ref(params[:ref]) project.repository.commit_count_for_ref(ref)
end end
end end
...@@ -148,7 +148,7 @@ module Git ...@@ -148,7 +148,7 @@ module Git
end end
def branch_name def branch_name
strong_memoize(:branch_name) { Gitlab::Git.ref_name(params[:ref]) } strong_memoize(:branch_name) { Gitlab::Git.ref_name(ref) }
end end
def upstream_commit_ids(commits) def upstream_commit_ids(commits)
......
...@@ -4,6 +4,7 @@ module Git ...@@ -4,6 +4,7 @@ module Git
class BranchPushService < ::BaseService class BranchPushService < ::BaseService
include Gitlab::Access include Gitlab::Access
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
include ChangeParams
# This method will be called after each git update # This method will be called after each git update
# and only if the provided user and project are present in GitLab. # and only if the provided user and project are present in GitLab.
...@@ -19,7 +20,7 @@ module Git ...@@ -19,7 +20,7 @@ module Git
# 6. Checks if the project's main language has changed # 6. Checks if the project's main language has changed
# #
def execute def execute
return unless Gitlab::Git.branch_ref?(params[:ref]) return unless Gitlab::Git.branch_ref?(ref)
enqueue_update_mrs enqueue_update_mrs
enqueue_detect_repository_languages enqueue_detect_repository_languages
...@@ -38,9 +39,9 @@ module Git ...@@ -38,9 +39,9 @@ module Git
UpdateMergeRequestsWorker.perform_async( UpdateMergeRequestsWorker.perform_async(
project.id, project.id,
current_user.id, current_user.id,
params[:oldrev], oldrev,
params[:newrev], newrev,
params[:ref] ref
) )
end end
...@@ -69,11 +70,11 @@ module Git ...@@ -69,11 +70,11 @@ module Git
end end
def removing_branch? def removing_branch?
Gitlab::Git.blank_ref?(params[:newrev]) Gitlab::Git.blank_ref?(newrev)
end end
def branch_name def branch_name
strong_memoize(:branch_name) { Gitlab::Git.ref_name(params[:ref]) } strong_memoize(:branch_name) { Gitlab::Git.ref_name(ref) }
end end
def default_branch? def default_branch?
......
...@@ -18,12 +18,12 @@ module Git ...@@ -18,12 +18,12 @@ module Git
def tag def tag
strong_memoize(:tag) do strong_memoize(:tag) do
next if Gitlab::Git.blank_ref?(params[:newrev]) next if Gitlab::Git.blank_ref?(newrev)
tag_name = Gitlab::Git.ref_name(params[:ref]) tag_name = Gitlab::Git.ref_name(ref)
tag = project.repository.find_tag(tag_name) tag = project.repository.find_tag(tag_name)
tag if tag && tag.target == params[:newrev] tag if tag && tag.target == newrev
end end
end end
......
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
module Git module Git
class TagPushService < ::BaseService class TagPushService < ::BaseService
include ChangeParams
def execute def execute
return unless Gitlab::Git.tag_ref?(params[:ref]) return unless Gitlab::Git.tag_ref?(ref)
project.repository.before_push_tag project.repository.before_push_tag
TagHooksService.new(project, current_user, params).execute TagHooksService.new(project, current_user, params).execute
......
...@@ -4,7 +4,7 @@ module Issues ...@@ -4,7 +4,7 @@ module Issues
class CloseService < Issues::BaseService class CloseService < Issues::BaseService
# Closes the supplied issue if the current user is able to do so. # Closes the supplied issue if the current user is able to do so.
def execute(issue, commit: nil, notifications: true, system_note: true) def execute(issue, commit: nil, notifications: true, system_note: true)
return issue unless can?(current_user, :update_issue, issue) return issue unless can?(current_user, :update_issue, issue) || issue.is_a?(ExternalIssue)
close_issue(issue, close_issue(issue,
closed_via: commit, closed_via: commit,
......
...@@ -29,9 +29,7 @@ module MergeRequests ...@@ -29,9 +29,7 @@ module MergeRequests
closed_issues = merge_request.visible_closing_issues_for(current_user) closed_issues = merge_request.visible_closing_issues_for(current_user)
closed_issues.each do |issue| closed_issues.each do |issue|
if can?(current_user, :update_issue, issue) Issues::CloseService.new(project, current_user).execute(issue, commit: merge_request)
Issues::CloseService.new(project, current_user, {}).execute(issue, commit: merge_request)
end
end end
end end
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project. Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.
To set up CA, you must first define a production environment by setting up your CI and then deploy to production. To set up CA, you must first define a production environment by setting up your CI and then deploy to production.
%p %p
%a.btn{ href: help_page_path('user/project/cycle_analytics'), target: '_blank' } Read more %a.btn{ href: help_page_path('user/analytics/cycle_analytics.md'), target: '_blank' } Read more
.col-md-6.overview-image .col-md-6.overview-image
%span.overview-icon %span.overview-icon
= custom_icon ('icon_cycle_analytics_overview') = custom_icon ('icon_cycle_analytics_overview')
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#cycle-analytics{ "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } } #cycle-analytics{ "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data - if @cycle_analytics_no_data
%banner{ "v-if" => "!isOverviewDialogDismissed", %banner{ "v-if" => "!isOverviewDialogDismissed",
"documentation-link": help_page_path('user/project/cycle_analytics'), "documentation-link": help_page_path('user/analytics/cycle_analytics.md'),
"v-on:dismiss-overview-dialog" => "dismissOverviewDialog()" } "v-on:dismiss-overview-dialog" => "dismissOverviewDialog()" }
= icon("spinner spin", "v-show" => "isLoading") = icon("spinner spin", "v-show" => "isLoading")
.wrapper{ "v-show" => "!isLoading && !hasError" } .wrapper{ "v-show" => "!isLoading && !hasError" }
......
...@@ -37,41 +37,22 @@ class PostReceive ...@@ -37,41 +37,22 @@ class PostReceive
end end
def process_project_changes(post_received) def process_project_changes(post_received)
changes = []
refs = Set.new
user = identify_user(post_received) user = identify_user(post_received)
return false unless user return false unless user
project = post_received.project
push_options = post_received.push_options
changes = post_received.changes
# We only need to expire certain caches once per push # We only need to expire certain caches once per push
expire_caches(post_received, post_received.project.repository) expire_caches(post_received, post_received.project.repository)
enqueue_repository_cache_update(post_received) enqueue_repository_cache_update(post_received)
post_received.enum_for(:changes_refs).with_index do |(oldrev, newrev, ref), index| process_changes(Git::BranchPushService, project, user, push_options, changes.branch_changes)
service_klass = process_changes(Git::TagPushService, project, user, push_options, changes.tag_changes)
if Gitlab::Git.tag_ref?(ref)
Git::TagPushService
elsif Gitlab::Git.branch_ref?(ref)
Git::BranchPushService
end
if service_klass
service_klass.new(
post_received.project,
user,
oldrev: oldrev,
newrev: newrev,
ref: ref,
push_options: post_received.push_options,
create_pipelines: index < PIPELINE_PROCESS_LIMIT || Feature.enabled?(:git_push_create_all_pipelines, post_received.project)
).execute
end
changes << Gitlab::DataBuilder::Repository.single_change(oldrev, newrev, ref)
refs << ref
end
update_remote_mirrors(post_received) update_remote_mirrors(post_received)
after_project_changes_hooks(post_received, user, refs.to_a, changes) after_project_changes_hooks(project, user, changes.refs, changes.repository_data)
end end
# Expire the repository status, branch, and tag cache once per push. # Expire the repository status, branch, and tag cache once per push.
...@@ -94,6 +75,20 @@ class PostReceive ...@@ -94,6 +75,20 @@ class PostReceive
) )
end end
def process_changes(service_class, project, user, push_options, changes)
return if changes.empty?
changes.each do |change|
service_class.new(
project,
user,
change: change,
push_options: push_options,
create_pipelines: change[:index] < PIPELINE_PROCESS_LIMIT || Feature.enabled?(:git_push_create_all_pipelines, project)
).execute
end
end
def update_remote_mirrors(post_received) def update_remote_mirrors(post_received)
return unless post_received.includes_branches? || post_received.includes_tags? return unless post_received.includes_branches? || post_received.includes_tags?
...@@ -104,9 +99,9 @@ class PostReceive ...@@ -104,9 +99,9 @@ class PostReceive
project.update_remote_mirrors project.update_remote_mirrors
end end
def after_project_changes_hooks(post_received, user, refs, changes) def after_project_changes_hooks(project, user, refs, changes)
hook_data = Gitlab::DataBuilder::Repository.update(post_received.project, user, changes, refs) repository_update_hook_data = Gitlab::DataBuilder::Repository.update(project, user, changes, refs)
SystemHooksService.new.execute_hooks(hook_data, :repository_update_hooks) SystemHooksService.new.execute_hooks(repository_update_hook_data, :repository_update_hooks)
Gitlab::UsageDataCounters::SourceCodeCounter.count(:pushes) Gitlab::UsageDataCounters::SourceCodeCounter.count(:pushes)
end end
...@@ -121,7 +116,7 @@ class PostReceive ...@@ -121,7 +116,7 @@ class PostReceive
# We only need to expire certain caches once per push # We only need to expire certain caches once per push
expire_caches(post_received, post_received.project.wiki.repository) expire_caches(post_received, post_received.project.wiki.repository)
::Git::WikiPushService.new(post_received.project, user, changes: post_received.enum_for(:changes_refs)).execute ::Git::WikiPushService.new(post_received.project, user, changes: post_received.changes).execute
end end
def log(message) def log(message)
......
---
title: 'Merge Request: Close JIRA issues when issues are disabled'
merge_request: 17743
author:
type: fixed
---
title: Allow intra-project MR dependencies
merge_request: 16799
author:
type: changed
...@@ -150,9 +150,11 @@ class Gitlab::Seeder::CycleAnalytics ...@@ -150,9 +150,11 @@ class Gitlab::Seeder::CycleAnalytics
::Git::BranchPushService.new( ::Git::BranchPushService.new(
issue.project, issue.project,
@user, @user,
oldrev: issue.project.repository.commit("master").sha, change: {
newrev: commit_sha, oldrev: issue.project.repository.commit("master").sha,
ref: 'refs/heads/master' newrev: commit_sha,
ref: 'refs/heads/master'
}
).execute ).execute
branch_name branch_name
......
...@@ -102,6 +102,9 @@ Example response: ...@@ -102,6 +102,9 @@ Example response:
## Liveness ## Liveness
DANGER: **Warning:**
In Gitlab [12.4](https://about.gitlab.com/upcoming-releases/) the response body of the Liveness check will change to match the example below.
The liveness probe checks whether the application server is alive. Unlike the [`health`](#health) check, this check hits the database. The liveness probe checks whether the application server is alive. Unlike the [`health`](#health) check, this check hits the database.
```text ```text
......
...@@ -47,7 +47,7 @@ With **[GitLab Enterprise Edition][ee]**, you can also: ...@@ -47,7 +47,7 @@ With **[GitLab Enterprise Edition][ee]**, you can also:
- Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **(ULTIMATE)** - Analyze your dependencies for vulnerabilities with [Dependency Scanning](../../application_security/dependency_scanning/index.md) **(ULTIMATE)**
- Analyze your Docker images for vulnerabilities with [Container Scanning](../../application_security/container_scanning/index.md) **(ULTIMATE)** - Analyze your Docker images for vulnerabilities with [Container Scanning](../../application_security/container_scanning/index.md) **(ULTIMATE)**
- Determine the performance impact of changes with [Browser Performance Testing](#browser-performance-testing-premium) **(PREMIUM)** - Determine the performance impact of changes with [Browser Performance Testing](#browser-performance-testing-premium) **(PREMIUM)**
- Specify merge order dependencies with [Cross-project Merge Request Dependencies](#cross-project-merge-request-dependencies-premium) **(PREMIUM)** - Specify merge order dependencies with [Merge Request Dependencies](#merge-request-dependencies-premium) **(PREMIUM)**
## Use cases ## Use cases
...@@ -509,7 +509,7 @@ GitLab runs the [Sitespeed.io container][sitespeed-container] and displays the d ...@@ -509,7 +509,7 @@ GitLab runs the [Sitespeed.io container][sitespeed-container] and displays the d
[Read more about Browser Performance Testing.](browser_performance_testing.md) [Read more about Browser Performance Testing.](browser_performance_testing.md)
## Cross-project Merge Request Dependencies **(PREMIUM)** ## Merge Request Dependencies **(PREMIUM)**
> Introduced in [GitLab Premium][products] 12.2. > Introduced in [GitLab Premium][products] 12.2.
...@@ -522,7 +522,7 @@ this relationship in place, the merge request cannot be merged until all of its ...@@ -522,7 +522,7 @@ this relationship in place, the merge request cannot be merged until all of its
dependencies have also been merged, helping to maintain the consistency of a dependencies have also been merged, helping to maintain the consistency of a
single logical change. single logical change.
[Read more about cross-project merge request dependencies.](merge_request_dependencies.md) [Read more about merge request dependencies.](merge_request_dependencies.md)
## Security reports **(ULTIMATE)** ## Security reports **(ULTIMATE)**
......
...@@ -2,14 +2,13 @@ ...@@ -2,14 +2,13 @@
type: reference, concepts type: reference, concepts
--- ---
# Cross-project Merge Request dependencies **(PREMIUM)** # Merge Request dependencies **(PREMIUM)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9688) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/9688) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
Cross-project merge request dependencies allows a required order of merging Merge request dependencies allows a required order of merging
between merge requests in different projects to be expressed. If a between merge requests to be expressed. If a merge request "depends on" another,
merge request "depends on" another, then it cannot be merged until its then it cannot be merged until its dependency is itself merged.
dependency is itself merged.
NOTE: **Note:** NOTE: **Note:**
Merge requests dependencies are a **PREMIUM** feature, but this restriction is Merge requests dependencies are a **PREMIUM** feature, but this restriction is
...@@ -58,20 +57,20 @@ instead. ...@@ -58,20 +57,20 @@ instead.
To continue the above example, you can configure a dependency when creating the To continue the above example, you can configure a dependency when creating the
new merge request in `awesome-project` (or by editing it, if it already exists). new merge request in `awesome-project` (or by editing it, if it already exists).
The dependency needs to be configured on the **dependent** merge The dependency needs to be configured on the **dependent** merge
request. There is a "Cross-project dependencies" section in the form: request. There is a **Merge request dependencies** section in the form:
![Cross-project dependencies form control](img/cross_project_dependencies_edit_v12_2.png) ![Merge request dependencies form control](img/dependencies_edit_v12_4.png)
Anyone who can edit a merge request can change the list of dependencies. Anyone who can edit a merge request can change the list of dependencies.
New dependencies can be added by reference, or by URL. To remove a dependency, New dependencies can be added by reference, or by URL. To remove a dependency,
press the **X** by its reference. press the **X** by its reference.
As dependencies are specified across projects, it's possible that someone else As dependencies can be specified across projects, it's possible that someone else
has added a dependency for a merge request in a project you don't have access to. has added a dependency for a merge request in a project you don't have access to.
These are shown as a simple count: These are shown as a simple count:
![Cross-project dependencies form control with inaccessible merge requests](img/cross_project_dependencies_edit_inaccessible_v12_2.png) ![Merge request dependencies form control with inaccessible merge requests](img/dependencies_edit_inaccessible_v12_4.png)
If necessary, you can remove all the dependencies like this by pressing the If necessary, you can remove all the dependencies like this by pressing the
**X**, just as you would for a single, visible dependency. **X**, just as you would for a single, visible dependency.
...@@ -82,7 +81,7 @@ or **Cancel** to return without making any changes. ...@@ -82,7 +81,7 @@ or **Cancel** to return without making any changes.
The list of configured dependencies, and the status of each one, is shown in the The list of configured dependencies, and the status of each one, is shown in the
merge request widget: merge request widget:
![Cross-project dependencies in merge request widget](img/cross_project_dependencies_view_v12_2.png) ![Dependencies in merge request widget](img/dependencies_view_v12_2.png)
Until all dependencies have, themselves, been merged, the **Merge** Until all dependencies have, themselves, been merged, the **Merge**
button will be disabled for the dependent merge request. In button will be disabled for the dependent merge request. In
......
# frozen_string_literal: true
module Gitlab
module Git
class Changes
include Enumerable
attr_reader :repository_data
def initialize
@refs = Set.new
@items = []
@branches_index = []
@tags_index = []
@repository_data = []
end
def includes_branches?
branches_index.any?
end
def includes_tags?
tags_index.any?
end
def add_branch_change(change)
@branches_index << add_change(change)
self
end
def add_tag_change(change)
@tags_index << add_change(change)
self
end
def each
items.each do |item|
yield item
end
end
def refs
@refs.to_a
end
def branch_changes
items.values_at(*branches_index)
end
def tag_changes
items.values_at(*tags_index)
end
private
attr_reader :items, :branches_index, :tags_index
def add_change(change)
# refs and repository_data are being cached when a change is added to
# the collection to remove the need to iterate through changes multiple
# times.
@refs << change[:ref]
@repository_data << build_change_repository_data(change)
@items << change
@items.size - 1
end
def build_change_repository_data(change)
DataBuilder::Repository.single_change(change[:oldrev], change[:newrev], change[:ref])
end
end
end
end
...@@ -8,7 +8,7 @@ module Gitlab ...@@ -8,7 +8,7 @@ module Gitlab
def initialize(project, identifier, changes, push_options = {}) def initialize(project, identifier, changes, push_options = {})
@project = project @project = project
@identifier = identifier @identifier = identifier
@changes = deserialize_changes(changes) @changes = parse_changes(changes)
@push_options = push_options @push_options = push_options
end end
...@@ -16,27 +16,12 @@ module Gitlab ...@@ -16,27 +16,12 @@ module Gitlab
super(identifier) super(identifier)
end end
def changes_refs
return changes unless block_given?
changes.each do |change|
change.strip!
oldrev, newrev, ref = change.split(' ')
yield oldrev, newrev, ref
end
end
def includes_branches? def includes_branches?
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref| changes.includes_branches?
Gitlab::Git.branch_ref?(ref)
end
end end
def includes_tags? def includes_tags?
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref| changes.includes_tags?
Gitlab::Git.tag_ref?(ref)
end
end end
def includes_default_branch? def includes_default_branch?
...@@ -44,16 +29,28 @@ module Gitlab ...@@ -44,16 +29,28 @@ module Gitlab
# first branch pushed will be the default. # first branch pushed will be the default.
return true unless project.default_branch.present? return true unless project.default_branch.present?
enum_for(:changes_refs).any? do |_oldrev, _newrev, ref| changes.branch_changes.any? do |change|
Gitlab::Git.branch_ref?(ref) && Gitlab::Git.branch_name(change[:ref]) == project.default_branch
Gitlab::Git.branch_name(ref) == project.default_branch
end end
end end
private private
def deserialize_changes(changes) def parse_changes(changes)
utf8_encode_changes(changes).each_line deserialized_changes = utf8_encode_changes(changes).each_line
Git::Changes.new.tap do |collection|
deserialized_changes.each_with_index do |raw_change, index|
oldrev, newrev, ref = raw_change.strip.split(' ')
change = { index: index, oldrev: oldrev, newrev: newrev, ref: ref }
if Git.branch_ref?(ref)
collection.add_branch_change(change)
elsif Git.tag_ref?(ref)
collection.add_tag_change(change)
end
end
end
end end
def utf8_encode_changes(changes) def utf8_encode_changes(changes)
......
...@@ -42,6 +42,9 @@ module Gitlab ...@@ -42,6 +42,9 @@ module Gitlab
# Initialize gon.features with any flags that should be # Initialize gon.features with any flags that should be
# made globally available to the frontend # made globally available to the frontend
push_frontend_feature_flag(:suppress_ajax_navigation_errors, default_enabled: true) push_frontend_feature_flag(:suppress_ajax_navigation_errors, default_enabled: true)
# Flag controls a GFM feature used across many routes.
push_frontend_feature_flag(:gfm_grafana_integration)
end end
# Exposes the state of a feature flag to the frontend code. # Exposes the state of a feature flag to the frontend code.
......
...@@ -1260,9 +1260,6 @@ msgstr "" ...@@ -1260,9 +1260,6 @@ msgstr ""
msgid "All changes are committed" msgid "All changes are committed"
msgstr "" msgstr ""
msgid "All cross-project dependencies have merged"
msgstr ""
msgid "All email addresses will be used to identify your commits." msgid "All email addresses will be used to identify your commits."
msgstr "" msgstr ""
...@@ -1278,6 +1275,9 @@ msgstr "" ...@@ -1278,6 +1275,9 @@ msgstr ""
msgid "All merge conflicts were resolved. The merge request can now be merged." msgid "All merge conflicts were resolved. The merge request can now be merged."
msgstr "" msgstr ""
msgid "All merge request dependencies have been merged"
msgstr ""
msgid "All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URL%{relative_url_link_end}." msgid "All paths are relative to the GitLab URL. Do not include %{relative_url_link_start}relative URL%{relative_url_link_end}."
msgstr "" msgstr ""
...@@ -4606,9 +4606,6 @@ msgstr "" ...@@ -4606,9 +4606,6 @@ msgstr ""
msgid "Cron syntax" msgid "Cron syntax"
msgstr "" msgstr ""
msgid "Cross-project dependencies"
msgstr ""
msgid "Current Branch" msgid "Current Branch"
msgstr "" msgstr ""
...@@ -9839,6 +9836,9 @@ msgstr "" ...@@ -9839,6 +9836,9 @@ msgstr ""
msgid "Merge request approvals allow you to set the number of necessary approvals and predefine a list of approvers that will need to approve every merge request in a project." msgid "Merge request approvals allow you to set the number of necessary approvals and predefine a list of approvers that will need to approve every merge request in a project."
msgstr "" msgstr ""
msgid "Merge request dependencies"
msgstr ""
msgid "Merge requests" msgid "Merge requests"
msgstr "" msgstr ""
...@@ -18696,9 +18696,6 @@ msgstr "" ...@@ -18696,9 +18696,6 @@ msgstr ""
msgid "cannot be enabled unless all domains have TLS certificates" msgid "cannot be enabled unless all domains have TLS certificates"
msgstr "" msgstr ""
msgid "cannot be in the same project"
msgstr ""
msgid "cannot be modified" msgid "cannot be modified"
msgstr "" msgstr ""
......
...@@ -44,7 +44,7 @@ function rspec_simple_job() { ...@@ -44,7 +44,7 @@ function rspec_simple_job() {
scripts/gitaly-test-spawn scripts/gitaly-test-spawn
bin/rspec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml "${rspec_opts}" bin/rspec --color --format documentation --format RspecJunitFormatter --out junit_rspec.xml ${rspec_opts}
} }
function rspec_paralellized_job() { function rspec_paralellized_job() {
......
...@@ -304,9 +304,11 @@ describe 'Environment' do ...@@ -304,9 +304,11 @@ describe 'Environment' do
# #
def remove_branch_with_hooks(project, user, branch) def remove_branch_with_hooks(project, user, branch)
params = { params = {
oldrev: project.commit(branch).id, change: {
newrev: Gitlab::Git::BLANK_SHA, oldrev: project.commit(branch).id,
ref: "refs/heads/#{branch}" newrev: Gitlab::Git::BLANK_SHA,
ref: "refs/heads/#{branch}"
}
} }
yield yield
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Git::Changes do
let(:changes) { described_class.new }
describe '#includes_branches?' do
subject { changes.includes_branches? }
context 'has changes for branches' do
before do
changes.add_branch_change(oldrev: 'abc123', newrev: 'def456', ref: 'branch')
end
it { is_expected.to be_truthy }
end
context 'has no changes for branches' do
before do
changes.add_tag_change(oldrev: 'abc123', newrev: 'def456', ref: 'tag')
end
it { is_expected.to be_falsey }
end
end
describe '#includes_tags?' do
subject { changes.includes_tags? }
context 'has changes for tags' do
before do
changes.add_tag_change(oldrev: 'abc123', newrev: 'def456', ref: 'tag')
end
it { is_expected.to be_truthy }
end
context 'has no changes for tags' do
before do
changes.add_branch_change(oldrev: 'abc123', newrev: 'def456', ref: 'branch')
end
it { is_expected.to be_falsey }
end
end
describe '#add_branch_change' do
let(:change) { { oldrev: 'abc123', newrev: 'def456', ref: 'branch' } }
subject { changes.add_branch_change(change) }
it 'adds the branch change to the collection' do
expect(subject).to include(change)
expect(subject.refs).to include(change[:ref])
expect(subject.repository_data).to include(before: change[:oldrev], after: change[:newrev], ref: change[:ref])
expect(subject.branch_changes).to include(change)
end
it 'does not add the change as a tag change' do
expect(subject.tag_changes).not_to include(change)
end
end
describe '#add_tag_change' do
let(:change) { { oldrev: 'abc123', newrev: 'def456', ref: 'tag' } }
subject { changes.add_tag_change(change) }
it 'adds the tag change to the collection' do
expect(subject).to include(change)
expect(subject.refs).to include(change[:ref])
expect(subject.repository_data).to include(before: change[:oldrev], after: change[:newrev], ref: change[:ref])
expect(subject.tag_changes).to include(change)
end
it 'does not add the change as a branch change' do
expect(subject.branch_changes).not_to include(change)
end
end
end
...@@ -8,7 +8,6 @@ describe Git::BaseHooksService do ...@@ -8,7 +8,6 @@ describe Git::BaseHooksService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:service) { described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) }
let(:oldrev) { Gitlab::Git::BLANK_SHA } let(:oldrev) { Gitlab::Git::BLANK_SHA }
let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0
...@@ -27,7 +26,7 @@ describe Git::BaseHooksService do ...@@ -27,7 +26,7 @@ describe Git::BaseHooksService do
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
subject { TestService.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) } subject { TestService.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }) }
context '#execute_hooks' do context '#execute_hooks' do
before do before do
......
...@@ -16,7 +16,7 @@ describe Git::BranchHooksService do ...@@ -16,7 +16,7 @@ describe Git::BranchHooksService do
let(:newrev) { commit.id } let(:newrev) { commit.id }
let(:service) do let(:service) do
described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) described_class.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref })
end end
describe "Git Push Data" do describe "Git Push Data" do
...@@ -350,7 +350,7 @@ describe Git::BranchHooksService do ...@@ -350,7 +350,7 @@ describe Git::BranchHooksService do
let(:forked_project) { fork_project(upstream_project, user, repository: true) } let(:forked_project) { fork_project(upstream_project, user, repository: true) }
let!(:forked_service) do let!(:forked_service) do
described_class.new(forked_project, user, oldrev: oldrev, newrev: newrev, ref: ref) described_class.new(forked_project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref })
end end
context 'when commits already exists in the upstream project' do context 'when commits already exists in the upstream project' do
......
...@@ -15,7 +15,7 @@ describe Git::TagHooksService, :service do ...@@ -15,7 +15,7 @@ describe Git::TagHooksService, :service do
let(:commit) { tag.dereferenced_target } let(:commit) { tag.dereferenced_target }
let(:service) do let(:service) do
described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) described_class.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref })
end end
describe 'System hooks' do describe 'System hooks' do
......
...@@ -8,7 +8,7 @@ describe Git::TagPushService do ...@@ -8,7 +8,7 @@ describe Git::TagPushService do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :repository) } let(:project) { create(:project, :repository) }
let(:service) { described_class.new(project, user, oldrev: oldrev, newrev: newrev, ref: ref) } let(:service) { described_class.new(project, user, change: { oldrev: oldrev, newrev: newrev, ref: ref }) }
let(:oldrev) { Gitlab::Git::BLANK_SHA } let(:oldrev) { Gitlab::Git::BLANK_SHA }
let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0 let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0
......
...@@ -8,6 +8,7 @@ describe Issues::CloseService do ...@@ -8,6 +8,7 @@ describe Issues::CloseService do
let(:user2) { create(:user, email: "user2@example.com") } let(:user2) { create(:user, email: "user2@example.com") }
let(:guest) { create(:user) } let(:guest) { create(:user) }
let(:issue) { create(:issue, title: "My issue", project: project, assignees: [user2], author: create(:user)) } let(:issue) { create(:issue, title: "My issue", project: project, assignees: [user2], author: create(:user)) }
let(:external_issue) { ExternalIssue.new('JIRA-123', project) }
let(:closing_merge_request) { create(:merge_request, source_project: project) } let(:closing_merge_request) { create(:merge_request, source_project: project) }
let(:closing_commit) { create(:commit, project: project) } let(:closing_commit) { create(:commit, project: project) }
let!(:todo) { create(:todo, :assigned, user: user, project: project, target: issue, author: user2) } let!(:todo) { create(:todo, :assigned, user: user, project: project, target: issue, author: user2) }
...@@ -36,6 +37,16 @@ describe Issues::CloseService do ...@@ -36,6 +37,16 @@ describe Issues::CloseService do
expect(service.execute(issue)).to eq(issue) expect(service.execute(issue)).to eq(issue)
end end
it 'closes the external issue even when the user is not authorized to do so' do
allow(service).to receive(:can?).with(user, :update_issue, external_issue)
.and_return(false)
expect(service).to receive(:close_issue)
.with(external_issue, closed_via: nil, notifications: true, system_note: true)
service.execute(external_issue)
end
it 'closes the issue when the user is authorized to do so' do it 'closes the issue when the user is authorized to do so' do
allow(service).to receive(:can?).with(user, :update_issue, issue) allow(service).to receive(:can?).with(user, :update_issue, issue)
.and_return(true) .and_return(true)
......
...@@ -56,9 +56,11 @@ describe MergeRequests::PostMergeService do ...@@ -56,9 +56,11 @@ describe MergeRequests::PostMergeService do
issue = create(:issue, project: project) issue = create(:issue, project: project)
allow(merge_request).to receive(:visible_closing_issues_for).and_return([issue]) allow(merge_request).to receive(:visible_closing_issues_for).and_return([issue])
allow_any_instance_of(Issues::CloseService).to receive(:execute).with(issue, commit: merge_request).and_raise expect_next_instance_of(Issues::CloseService) do |service|
allow(service).to receive(:execute).with(issue, commit: merge_request).and_raise(RuntimeError)
end
expect { described_class.new(project, user, {}).execute(merge_request) }.to raise_error expect { described_class.new(project, user).execute(merge_request) }.to raise_error(RuntimeError)
expect(merge_request.reload).to be_merged expect(merge_request.reload).to be_merged
end end
......
...@@ -25,11 +25,15 @@ module CycleAnalyticsHelpers ...@@ -25,11 +25,15 @@ module CycleAnalyticsHelpers
return if skip_push_handler return if skip_push_handler
Git::BranchPushService.new(project, Git::BranchPushService.new(
user, project,
oldrev: oldrev, user,
newrev: commit_shas.last, change: {
ref: 'refs/heads/master').execute oldrev: oldrev,
newrev: commit_shas.last,
ref: 'refs/heads/master'
}
).execute
end end
def create_cycle(user, project, issue, mr, milestone, pipeline) def create_cycle(user, project, issue, mr, milestone, pipeline)
......
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