Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Release Tools Bot <delivery-team+release-tools@gitlab.com>2023-09-28 18:25:30 +0300
committerGitLab Release Tools Bot <delivery-team+release-tools@gitlab.com>2023-09-28 18:25:30 +0300
commit8b7cfdd3397edb18f0e0d4f1c71d6b9282f68aef (patch)
treeda9f75c7a333910cc22842293a7a7b9b98101998
parente11473abda8f2f224f77a066691dc90744ef0925 (diff)
parente6801ed8d4470b43705026fffb85e2a8248fbea8 (diff)
Merge remote-tracking branch 'dev/16-4-stable' into 16-4-stable
-rw-r--r--CHANGELOG.md20
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--GITLAB_PAGES_VERSION2
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/behaviors/markdown/render_math.js21
-rw-r--r--app/assets/stylesheets/framework/markdown_area.scss10
-rw-r--r--app/controllers/projects/error_tracking/projects_controller.rb2
-rw-r--r--app/controllers/projects/ml/candidates_controller.rb4
-rw-r--r--app/helpers/merge_requests_helper.rb2
-rw-r--r--app/helpers/projects/ml/experiments_helper.rb8
-rw-r--r--app/models/project.rb1
-rw-r--r--app/models/project_team.rb6
-rw-r--r--app/policies/project_policy.rb2
-rw-r--r--app/presenters/ml/candidate_details_presenter.rb7
-rw-r--r--app/services/ci/list_config_variables_service.rb3
-rw-r--r--app/services/error_tracking/list_projects_service.rb2
-rw-r--r--app/services/groups/destroy_service.rb18
-rw-r--r--app/views/projects/ml/candidates/show.html.haml2
-rw-r--r--app/views/projects/ml/experiments/show.html.haml2
-rw-r--r--config/sidekiq_queues.yml2
-rw-r--r--doc/operations/error_tracking.md2
-rw-r--r--lib/api/commits.rb2
-rw-r--r--lib/api/projects.rb2
-rw-r--r--lib/banzai/filter/asset_proxy_filter.rb8
-rw-r--r--lib/gitlab/checks/tag_check.rb4
-rw-r--r--lib/gitlab/ci/lint.rb4
-rw-r--r--lib/gitlab/ci/yaml_processor.rb31
-rw-r--r--lib/gitlab/import_export/project/import_export.yml2
-rw-r--r--lib/gitlab/import_export/project/relation_factory.rb35
-rw-r--r--locale/gitlab.pot6
-rw-r--r--spec/controllers/projects/error_tracking/projects_controller_spec.rb2
-rw-r--r--spec/features/markdown/math_spec.rb104
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson17
-rw-r--r--spec/fixtures/lib/gitlab/import_export/complex/tree/project/merge_requests.ndjson4
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb39
-rw-r--r--spec/helpers/projects/ml/experiments_helper_spec.rb14
-rw-r--r--spec/lib/banzai/filter/asset_proxy_filter_spec.rb27
-rw-r--r--spec/lib/gitlab/checks/tag_check_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/lint_spec.rb56
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb82
-rw-r--r--spec/lib/gitlab/import_export/project/relation_factory_spec.rb36
-rw-r--r--spec/lib/gitlab/import_export/project/tree_restorer_spec.rb70
-rw-r--r--spec/lib/gitlab/import_export/project/tree_saver_spec.rb13
-rw-r--r--spec/models/blob_viewer/gitlab_ci_yml_spec.rb36
-rw-r--r--spec/models/group_spec.rb39
-rw-r--r--spec/models/project_spec.rb60
-rw-r--r--spec/presenters/ml/candidate_details_presenter_spec.rb14
-rw-r--r--spec/requests/api/commits_spec.rb56
-rw-r--r--spec/requests/api/projects_spec.rb20
-rw-r--r--spec/requests/projects/ml/candidates_controller_spec.rb26
-rw-r--r--spec/services/ci/list_config_variables_service_spec.rb45
-rw-r--r--spec/services/error_tracking/list_projects_service_spec.rb12
-rw-r--r--spec/support/shared_contexts/ci/yaml_processor_shared_context.rb22
53 files changed, 880 insertions, 134 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b010bab400f..65a1df824a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,26 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
+## 16.4.1 (2023-09-28)
+
+### Security (15 changes)
+
+- [Mark any CI builds that are not complete as canceled when imported](gitlab-org/security/gitlab@2b3246c076dd7b6505945b6e19d3787fc8698b6f) ([merge request](gitlab-org/security/gitlab!3597))
+- [Destroy group service accounts when removing group](gitlab-org/security/gitlab@5135447afe579babb040e7f40192ac330d663aee) ([merge request](gitlab-org/security/gitlab!3602))
+- [Fix SSO Enforcement for shared groups and projects](gitlab-org/security/gitlab@bdcbc1561c60b8039763bf85f0b00e34e6771cc0) ([merge request](gitlab-org/security/gitlab!3603))
+- [Prevents Ci::Build data from being rendered](gitlab-org/security/gitlab@d53320b0ad9b5c6f517971072a073f985d35facb) ([merge request](gitlab-org/security/gitlab!3604))
+- [Allow only one membership for security policy bots](gitlab-org/security/gitlab@0427e9ce8496fd587f4c971d8df710ab37d4a104) ([merge request](gitlab-org/security/gitlab!3611))
+- [Reset all approvals when target branch changes](gitlab-org/security/gitlab@d3cd8f60d73ce2feecd034383bf2e17789f6fe43) ([merge request](gitlab-org/security/gitlab!3607))
+- [Default to using the asset proxy](gitlab-org/security/gitlab@524aebbbaa746b3745506ce642eba67b668f9872) ([merge request](gitlab-org/security/gitlab!3587))
+- [Restrict Project Fork Linking to Owners and Admins](gitlab-org/security/gitlab@3132e578fcd0fc093d732a9891dd72a37341cfab) ([merge request](gitlab-org/security/gitlab!3605))
+- [Prevent math hijacking page elements](gitlab-org/security/gitlab@c8c813dc3fc8b26e3975392758328c97568e6eb4) ([merge request](gitlab-org/security/gitlab!3591))
+- [Delete of member branch protection rules cascadingly](gitlab-org/security/gitlab@4635a97c527fbe81bb4d93502460d7147262c2a6) ([merge request](gitlab-org/security/gitlab!3594))
+- [Prevent collaboration across forks when author cannot push](gitlab-org/security/gitlab@d9b21a60fe0ff6f7e5cbecbcaf2a70ac33aa4acd) ([merge request](gitlab-org/security/gitlab!3586))
+- [Allow Maintainer+ to list Sentry projects](gitlab-org/security/gitlab@a8ad5be6dea95c30d498770d8eb58182b51c7f44) ([merge request](gitlab-org/security/gitlab!3553))
+- [Fix leaking source code of restricted project through a fork](gitlab-org/security/gitlab@a44af43b779df34712bd04dc01bf0da4fa7fc994) ([merge request](gitlab-org/security/gitlab!3593))
+- [Prevent leaking CI variables via fork MRs](gitlab-org/security/gitlab@1ba8ef7d453bc3b9299b98e066d4d2756c7edb2e) ([merge request](gitlab-org/security/gitlab!3588))
+- [Pipelines will have no access to protected vars and may fail with tags](gitlab-org/security/gitlab@5db5e98acb966bd80105ee74127fef228e6edab5) ([merge request](gitlab-org/security/gitlab!3583))
+
## 16.4.0 (2023-09-21)
### Added (179 changes)
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index b21be527a69..4b8dba5f3e3 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-16.4.0 \ No newline at end of file
+16.4.1 \ No newline at end of file
diff --git a/GITLAB_PAGES_VERSION b/GITLAB_PAGES_VERSION
index b21be527a69..4b8dba5f3e3 100644
--- a/GITLAB_PAGES_VERSION
+++ b/GITLAB_PAGES_VERSION
@@ -1 +1 @@
-16.4.0 \ No newline at end of file
+16.4.1 \ No newline at end of file
diff --git a/VERSION b/VERSION
index b21be527a69..4b8dba5f3e3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-16.4.0 \ No newline at end of file
+16.4.1 \ No newline at end of file
diff --git a/app/assets/javascripts/behaviors/markdown/render_math.js b/app/assets/javascripts/behaviors/markdown/render_math.js
index b2348cf0bad..7525fc76d16 100644
--- a/app/assets/javascripts/behaviors/markdown/render_math.js
+++ b/app/assets/javascripts/behaviors/markdown/render_math.js
@@ -66,16 +66,12 @@ class SafeMathRenderer {
el.removeAttribute('style');
if (!forceRender && (this.totalMS >= MAX_RENDER_TIME_MS || text.length > MAX_MATH_CHARS)) {
// Show unrendered math code
- const wrapperElement = document.createElement('div');
const codeElement = document.createElement('pre');
codeElement.className = 'code';
codeElement.textContent = el.textContent;
codeElement.dataset.mathStyle = el.dataset.mathStyle;
- const { parentNode } = el;
- parentNode.replaceChild(wrapperElement, el);
-
let message;
if (text.length > MAX_MATH_CHARS) {
message = sprintf(
@@ -103,11 +99,11 @@ class SafeMathRenderer {
</div>
`;
- if (!wrapperElement.classList.contains('lazy-alert-shown')) {
+ if (!el.classList.contains('lazy-alert-shown')) {
// eslint-disable-next-line no-unsanitized/property
- wrapperElement.innerHTML = html;
- wrapperElement.append(codeElement);
- wrapperElement.classList.add('lazy-alert-shown');
+ el.innerHTML = html;
+ el.append(codeElement);
+ el.classList.add('lazy-alert-shown');
}
// Render the next math
@@ -125,6 +121,12 @@ class SafeMathRenderer {
}
try {
+ if (displayContainer.dataset.mathStyle === 'inline') {
+ displayContainer.classList.add('math-content-inline');
+ } else {
+ displayContainer.classList.add('math-content-display');
+ }
+
// eslint-disable-next-line no-unsanitized/property
displayContainer.innerHTML = this.katex.renderToString(text, {
displayMode: el.dataset.mathStyle === 'display',
@@ -169,8 +171,7 @@ class SafeMathRenderer {
render() {
// Replace math blocks with a placeholder so they aren't rendered twice
this.elements.forEach((el) => {
- const placeholder = document.createElement('span');
- placeholder.style.display = 'none';
+ const placeholder = document.createElement('div');
placeholder.dataset.mathStyle = el.dataset.mathStyle;
placeholder.textContent = el.textContent;
el.parentNode.replaceChild(placeholder, el);
diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss
index b87fd3e67d4..62782de5402 100644
--- a/app/assets/stylesheets/framework/markdown_area.scss
+++ b/app/assets/stylesheets/framework/markdown_area.scss
@@ -137,6 +137,16 @@
border-radius: $border-radius-default $border-radius-default 0 0;
}
+.math-content-inline {
+ overflow: auto;
+ display: inline-flex;
+}
+
+.math-content-display {
+ overflow: auto;
+ display: block;
+}
+
@include media-breakpoint-down(xs) {
.referenced-users {
margin-right: 0;
diff --git a/app/controllers/projects/error_tracking/projects_controller.rb b/app/controllers/projects/error_tracking/projects_controller.rb
index 531bd327e43..372fbfdc183 100644
--- a/app/controllers/projects/error_tracking/projects_controller.rb
+++ b/app/controllers/projects/error_tracking/projects_controller.rb
@@ -5,7 +5,7 @@ module Projects
class ProjectsController < Projects::ApplicationController
respond_to :json
- before_action :authorize_read_sentry_issue!
+ before_action :authorize_admin_sentry!
feature_category :error_tracking
urgency :low
diff --git a/app/controllers/projects/ml/candidates_controller.rb b/app/controllers/projects/ml/candidates_controller.rb
index 9905e454acb..12111c45fde 100644
--- a/app/controllers/projects/ml/candidates_controller.rb
+++ b/app/controllers/projects/ml/candidates_controller.rb
@@ -9,7 +9,9 @@ module Projects
feature_category :mlops
- def show; end
+ def show
+ @include_ci_info = @candidate.from_ci? && can?(current_user, :read_build, @candidate.ci_build)
+ end
def destroy
@experiment = @candidate.experiment
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index a90a16e120c..06eb3fcc233 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -133,6 +133,8 @@ module MergeRequestsHelper
_('Not available for private projects')
elsif ProtectedBranch.protected?(merge_request.source_project, merge_request.source_branch)
_('Not available for protected branches')
+ elsif !merge_request.author.can?(:push_code, merge_request.source_project)
+ _('Merge request author cannot push to target project')
end
end
diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb
index 7aef208447a..d5b2c3cd36a 100644
--- a/app/helpers/projects/ml/experiments_helper.rb
+++ b/app/helpers/projects/ml/experiments_helper.rb
@@ -14,12 +14,12 @@ module Projects
Gitlab::Json.generate(data)
end
- def candidates_table_items(candidates)
+ def candidates_table_items(candidates, user)
items = candidates.map do |candidate|
{
**candidate.params.to_h { |p| [p.name, p.value] },
**candidate.latest_metrics.to_h { |m| [m.name, number_with_precision(m.value, precision: 4)] },
- ci_job: job_info(candidate),
+ ci_job: job_info(candidate, user),
artifact: link_to_artifact(candidate),
details: link_to_details(candidate),
name: candidate.name,
@@ -72,8 +72,8 @@ module Projects
project_ml_candidate_path(candidate.project, candidate.iid)
end
- def job_info(candidate)
- return unless candidate.from_ci?
+ def job_info(candidate, user)
+ return unless candidate.from_ci? && can?(user, :read_build, candidate.ci_build)
build = candidate.ci_build
diff --git a/app/models/project.rb b/app/models/project.rb
index 68196f0a757..5989584ce43 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -3456,6 +3456,7 @@ class Project < ApplicationRecord
# Issue for N+1: https://gitlab.com/gitlab-org/gitlab-foss/issues/49322
Gitlab::GitalyClient.allow_n_plus_1_calls do
merge_requests_allowing_collaboration(branch_name).any? do |merge_request|
+ merge_request.author.can?(:push_code, self) &&
merge_request.can_be_merged_by?(user, skip_collaboration_check: true)
end
end
diff --git a/app/models/project_team.rb b/app/models/project_team.rb
index 34754f4fc95..38521ae6090 100644
--- a/app/models/project_team.rb
+++ b/app/models/project_team.rb
@@ -121,7 +121,7 @@ class ProjectTeam
def import(source_project, current_user)
target_project = project
- source_members = source_project.project_members.to_a
+ source_members = source_members_for_import(source_project)
target_user_ids = target_project.project_members.pluck_user_ids
importer_access_level = max_member_access(current_user.id)
@@ -242,6 +242,10 @@ class ProjectTeam
def member_user_ids
Member.on_project_and_ancestors(project).select(:user_id)
end
+
+ def source_members_for_import(source_project)
+ source_project.project_members.to_a
+ end
end
ProjectTeam.prepend_mod_with('ProjectTeam')
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 38e6360f81d..a57b6f8daf7 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -289,6 +289,7 @@ class ProjectPolicy < BasePolicy
enable :change_visibility_level
enable :remove_project
enable :archive_project
+ enable :link_forked_project
enable :remove_fork_project
enable :destroy_merge_request
enable :destroy_issue
@@ -545,6 +546,7 @@ class ProjectPolicy < BasePolicy
enable :destroy_release
enable :destroy_artifacts
enable :admin_operations
+ enable :admin_sentry
enable :read_deploy_token
enable :create_deploy_token
enable :destroy_deploy_token
diff --git a/app/presenters/ml/candidate_details_presenter.rb b/app/presenters/ml/candidate_details_presenter.rb
index 7f0bd9d6c11..29d4617903f 100644
--- a/app/presenters/ml/candidate_details_presenter.rb
+++ b/app/presenters/ml/candidate_details_presenter.rb
@@ -4,8 +4,9 @@ module Ml
class CandidateDetailsPresenter
include Rails.application.routes.url_helpers
- def initialize(candidate)
+ def initialize(candidate, include_ci_job = false)
@candidate = candidate
+ @include_ci_job = include_ci_job
end
def present
@@ -32,10 +33,10 @@ module Ml
private
- attr_reader :candidate
+ attr_reader :candidate, :include_ci_job
def job_info
- return unless candidate.from_ci?
+ return unless include_ci_job && candidate.from_ci?
build = candidate.ci_build
diff --git a/app/services/ci/list_config_variables_service.rb b/app/services/ci/list_config_variables_service.rb
index 1020e98f463..e028d7252ae 100644
--- a/app/services/ci/list_config_variables_service.rb
+++ b/app/services/ci/list_config_variables_service.rb
@@ -32,7 +32,8 @@ module Ci
config.content,
project: project,
user: current_user,
- sha: sha
+ sha: sha,
+ verify_project_sha: true
).execute
result.valid? ? result.root_variables_with_prefill_data : {}
diff --git a/app/services/error_tracking/list_projects_service.rb b/app/services/error_tracking/list_projects_service.rb
index 1539e24df9d..67d690d64e7 100644
--- a/app/services/error_tracking/list_projects_service.rb
+++ b/app/services/error_tracking/list_projects_service.rb
@@ -5,6 +5,8 @@ module ErrorTracking
private
def perform
+ return error('Access denied', :unauthorized) unless can?(current_user, :admin_sentry, project)
+
unless project_error_tracking_setting.valid?
return error(project_error_tracking_setting.errors.full_messages.join(', '), :bad_request)
end
diff --git a/app/services/groups/destroy_service.rb b/app/services/groups/destroy_service.rb
index a896ca5cabc..aeab2667737 100644
--- a/app/services/groups/destroy_service.rb
+++ b/app/services/groups/destroy_service.rb
@@ -33,7 +33,7 @@ module Groups
user_ids_for_project_authorizations_refresh = obtain_user_ids_for_project_authorizations_refresh
- destroy_group_bots
+ destroy_associated_users
group.destroy
@@ -80,12 +80,9 @@ module Groups
end
# rubocop:disable CodeReuse/ActiveRecord
- def destroy_group_bots
- bot_ids = group.members_and_requesters.joins(:user)
- .merge(User.project_bot)
- .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422405')
- .pluck(:user_id)
+ def destroy_associated_users
current_user_id = current_user.id
+ bot_ids = users_to_destroy
group.run_after_commit do
bot_ids.each do |user_id|
@@ -95,6 +92,15 @@ module Groups
end
# rubocop:enable CodeReuse/ActiveRecord
+ # rubocop:disable CodeReuse/ActiveRecord
+ def users_to_destroy
+ group.members_and_requesters.joins(:user)
+ .merge(User.project_bot)
+ .allow_cross_joins_across_databases(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/422405')
+ .pluck(:user_id)
+ end
+ # rubocop:enable CodeReuse/ActiveRecord
+
def publish_event
event = Groups::GroupDeletedEvent.new(
data: {
diff --git a/app/views/projects/ml/candidates/show.html.haml b/app/views/projects/ml/candidates/show.html.haml
index 5d5059551d3..979bc107fd2 100644
--- a/app/views/projects/ml/candidates/show.html.haml
+++ b/app/views/projects/ml/candidates/show.html.haml
@@ -3,6 +3,6 @@
- add_to_breadcrumbs experiment.name, project_ml_experiment_path(@project, experiment.iid)
- breadcrumb_title "Candidate #{@candidate.iid}"
- add_page_specific_style 'page_bundles/ml_experiment_tracking'
-- presenter = ::Ml::CandidateDetailsPresenter.new(@candidate)
+- presenter = ::Ml::CandidateDetailsPresenter.new(@candidate, @include_ci_info)
#js-show-ml-candidate{ data: { view_model: presenter.present } }
diff --git a/app/views/projects/ml/experiments/show.html.haml b/app/views/projects/ml/experiments/show.html.haml
index d4a05b613c9..85f3f85fd8b 100644
--- a/app/views/projects/ml/experiments/show.html.haml
+++ b/app/views/projects/ml/experiments/show.html.haml
@@ -4,7 +4,7 @@
- add_page_specific_style 'page_bundles/ml_experiment_tracking'
- experiment = experiment_as_data(@experiment)
-- items = candidates_table_items(@candidates)
+- items = candidates_table_items(@candidates, current_user)
- metrics = unique_logged_names(@candidates, &:latest_metrics)
- params = unique_logged_names(@candidates, &:params)
- page_info = formatted_page_info(@page_info)
diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml
index d14c20426df..05626a2b8b8 100644
--- a/config/sidekiq_queues.yml
+++ b/config/sidekiq_queues.yml
@@ -389,6 +389,8 @@
- 2
- - mailers
- 2
+- - members_destroyer_clean_up_group_protected_branch_rules
+ - 1
- - members_expiring_email_notification
- 1
- - merge
diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md
index 82982a03016..1ebbb047c01 100644
--- a/doc/operations/error_tracking.md
+++ b/doc/operations/error_tracking.md
@@ -161,7 +161,7 @@ GitLab provides a way to connect Sentry to your project.
Prerequisites:
-- You must have at least the Developer role for the project.
+- You must have at least the Maintainer role for the project.
To enable the Sentry integration:
diff --git a/lib/api/commits.rb b/lib/api/commits.rb
index 069d117db17..c0222539c98 100644
--- a/lib/api/commits.rb
+++ b/lib/api/commits.rb
@@ -219,7 +219,7 @@ module API
if params[:start_project]
start_project = find_project!(params[:start_project])
- unless user_project.forked_from?(start_project)
+ unless can?(current_user, :read_code, start_project) && user_project.forked_from?(start_project)
forbidden!("Project is not included in the fork network for #{start_project.full_name}")
end
end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 6d13512aad6..ac28effea43 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -701,7 +701,7 @@ module API
requires :forked_from_id, type: String, desc: 'The ID of the project it was forked from', documentation: { example: 'gitlab' }
end
post ":id/fork/:forked_from_id", feature_category: :source_code_management do
- authorize! :admin_project, user_project
+ authorize! :link_forked_project, user_project
fork_from_project = find_project!(params[:forked_from_id])
diff --git a/lib/banzai/filter/asset_proxy_filter.rb b/lib/banzai/filter/asset_proxy_filter.rb
index 00ffdd3d809..512c55381ec 100644
--- a/lib/banzai/filter/asset_proxy_filter.rb
+++ b/lib/banzai/filter/asset_proxy_filter.rb
@@ -22,13 +22,13 @@ module Banzai
begin
uri = URI.parse(original_src)
+
+ next if uri.host.nil? && !original_src.start_with?('///')
+ next if asset_host_allowed?(uri.host)
rescue StandardError
- next
+ # Ignored
end
- next if uri.host.nil? && !original_src.start_with?('///')
- next if asset_host_allowed?(uri.host)
-
element['src'] = asset_proxy_url(original_src)
element['data-canonical-src'] = original_src
end
diff --git a/lib/gitlab/checks/tag_check.rb b/lib/gitlab/checks/tag_check.rb
index 5c43ca946b5..4505bcb5411 100644
--- a/lib/gitlab/checks/tag_check.rb
+++ b/lib/gitlab/checks/tag_check.rb
@@ -39,6 +39,10 @@ module Gitlab
def prohibited_tag_checks
return if deletion?
+ unless Gitlab::GitRefValidator.validate(tag_name)
+ raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name]
+ end
+
if tag_name.start_with?("refs/tags/") # rubocop: disable Style/GuardClause
raise GitAccess::ForbiddenError, ERROR_MESSAGES[:prohibited_tag_name]
end
diff --git a/lib/gitlab/ci/lint.rb b/lib/gitlab/ci/lint.rb
index e0112a1b1c2..54861e2769e 100644
--- a/lib/gitlab/ci/lint.rb
+++ b/lib/gitlab/ci/lint.rb
@@ -28,6 +28,9 @@ module Gitlab
def initialize(project:, current_user:, sha: nil)
@project = project
@current_user = current_user
+ # If the `sha` is not provided, the default is the project's head commit (or nil). In such case, we
+ # don't need to call `YamlProcessor.verify_project_sha!`, which prevents redundant calls to Gitaly.
+ @verify_project_sha = sha.present?
@sha = sha || project&.repository&.commit&.sha
end
@@ -77,6 +80,7 @@ module Gitlab
Gitlab::Ci::YamlProcessor.new(content, project: @project,
user: @current_user,
sha: @sha,
+ verify_project_sha: @verify_project_sha,
logger: logger).execute
end
end
diff --git a/lib/gitlab/ci/yaml_processor.rb b/lib/gitlab/ci/yaml_processor.rb
index 3a0173d1548..289f41b4ec7 100644
--- a/lib/gitlab/ci/yaml_processor.rb
+++ b/lib/gitlab/ci/yaml_processor.rb
@@ -8,6 +8,8 @@
module Gitlab
module Ci
class YamlProcessor
+ include Gitlab::Utils::StrongMemoize
+
ValidationError = Class.new(StandardError)
def initialize(config_content, opts = {})
@@ -28,6 +30,8 @@ module Gitlab
return Result.new(errors: ['Please provide content of .gitlab-ci.yml'])
end
+ verify_project_sha! if verify_project_sha?
+
@ci_config = Gitlab::Ci::Config.new(@config_content, **@opts)
unless @ci_config.valid?
@@ -47,6 +51,15 @@ module Gitlab
@opts[:project]
end
+ def sha
+ @opts[:sha]
+ end
+
+ def verify_project_sha?
+ @opts.delete(:verify_project_sha) || false
+ end
+ strong_memoize_attr :verify_project_sha?
+
def run_logical_validations!
@stages = @ci_config.stages
@jobs = @ci_config.normalized_jobs
@@ -191,6 +204,24 @@ module Gitlab
def error!(message)
raise ValidationError, message
end
+
+ def verify_project_sha!
+ return unless project && sha && project.repository_exists? && project.commit(sha)
+
+ unless project_ref_contains_sha?
+ error!('Could not validate configuration. Config originates from external project')
+ end
+ end
+
+ def project_ref_contains_sha?
+ # A 5-minute cache TTL is sufficient to prevent Gitaly load issues while also mitigating rare
+ # use cases concerning stale data. For example, when an external commit gets merged into the
+ # project, there may be at most a 5-minute window where the `sha` is still considered external.
+ Rails.cache.fetch(['project', project.id, 'ref/contains/sha', sha], expires_in: 5.minutes) do
+ repo = project.repository
+ repo.branch_names_contains(sha, limit: 1).any? || repo.tag_names_contains(sha, limit: 1).any?
+ end
+ end
end
end
end
diff --git a/lib/gitlab/import_export/project/import_export.yml b/lib/gitlab/import_export/project/import_export.yml
index 1b04e55e0c7..7130fd8d7d6 100644
--- a/lib/gitlab/import_export/project/import_export.yml
+++ b/lib/gitlab/import_export/project/import_export.yml
@@ -169,7 +169,6 @@ included_attributes:
- :cron_timezone
- :description
- :next_run_at
- - :owner_id
- :project_id
- :ref
- :updated_at
@@ -373,7 +372,6 @@ included_attributes:
- :updated_by_id
- :merge_error
- :merge_params
- - :merge_when_pipeline_succeeds
- :merge_user_id
- :merge_commit_sha
- :squash_commit_sha
diff --git a/lib/gitlab/import_export/project/relation_factory.rb b/lib/gitlab/import_export/project/relation_factory.rb
index 840621a94a2..78d0735bbb5 100644
--- a/lib/gitlab/import_export/project/relation_factory.rb
+++ b/lib/gitlab/import_export/project/relation_factory.rb
@@ -98,6 +98,7 @@ module Gitlab
when :'ProtectedBranch::PushAccessLevel' then setup_protected_branch_access_level
when :ApprovalProjectRulesProtectedBranch then setup_merge_approval_protected_branch
when :releases then setup_release
+ when :merge_requests, :MergeRequest, :merge_request then setup_merge_request
end
update_project_references
@@ -148,22 +149,30 @@ module Gitlab
end
def setup_pipeline
+ @relation_hash['status'] = transform_status(@relation_hash['status'])
+
@relation_hash.fetch('stages', []).each do |stage|
+ stage.status = transform_status(stage.status)
+
# old export files have statuses
- stage.statuses.each do |status|
- status.pipeline = imported_object
+ stage.statuses.each do |job|
+ job.status = transform_status(job.status)
+ job.pipeline = imported_object
end
- stage.builds.each do |status|
- status.pipeline = imported_object
+ stage.builds.each do |job|
+ job.status = transform_status(job.status)
+ job.pipeline = imported_object
end
- stage.bridges.each do |status|
- status.pipeline = imported_object
+ stage.bridges.each do |job|
+ job.status = transform_status(job.status)
+ job.pipeline = imported_object
end
- stage.generic_commit_statuses.each do |status|
- status.pipeline = imported_object
+ stage.generic_commit_statuses.each do |job|
+ job.status = transform_status(job.status)
+ job.pipeline = imported_object
end
end
end
@@ -187,6 +196,10 @@ module Gitlab
@relation_hash['active'] = false
end
+ def setup_merge_request
+ @relation_hash['merge_when_pipeline_succeeds'] = false
+ end
+
def setup_protected_branch_access_level
return if root_group_owner?
return if @relation_hash['access_level'] == Gitlab::Access::NO_ACCESS
@@ -226,6 +239,12 @@ module Gitlab
@relation_name == :'Ci::Trigger' && @relation_hash['owner_id'].nil?
end
+ def transform_status(status)
+ return 'canceled' if ::Ci::HasStatus::COMPLETED_STATUSES.exclude?(status)
+
+ status
+ end
+
def preload_keys(object, references, value)
return object unless value
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index bf468a3b209..e5a755f12b5 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -29344,6 +29344,9 @@ msgstr ""
msgid "Merge request approvals"
msgstr ""
+msgid "Merge request author cannot push to target project"
+msgstr ""
+
msgid "Merge request change summary"
msgstr ""
@@ -57085,6 +57088,9 @@ msgstr[1] ""
msgid "security Reports|There was an error creating the merge request"
msgstr ""
+msgid "security policy bot users cannot be added to other projects"
+msgstr ""
+
msgid "selective_code_owner_removals can only be enabled when retain_approvals_on_push is enabled"
msgstr ""
diff --git a/spec/controllers/projects/error_tracking/projects_controller_spec.rb b/spec/controllers/projects/error_tracking/projects_controller_spec.rb
index 7529c701b2b..63346faccbf 100644
--- a/spec/controllers/projects/error_tracking/projects_controller_spec.rb
+++ b/spec/controllers/projects/error_tracking/projects_controller_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Projects::ErrorTracking::ProjectsController do
let(:user) { create(:user) }
it 'returns 404' do
- project.add_guest(user)
+ project.add_developer(user)
get :index, params: list_projects_params
diff --git a/spec/features/markdown/math_spec.rb b/spec/features/markdown/math_spec.rb
index 25459494a0c..0bc8f2146e9 100644
--- a/spec/features/markdown/math_spec.rb
+++ b/spec/features/markdown/math_spec.rb
@@ -24,9 +24,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
```
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
+ create_and_visit_issue_with_description(description)
expect(page).to have_selector('.katex .mord.mathnormal', text: 'b')
expect(page).to have_selector('.katex-display .mord.mathnormal', text: 'b')
@@ -40,9 +38,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
This link is valid $`\\href{https://gitlab.com}{Gitlab}`$.
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
+ create_and_visit_issue_with_description(description)
page.within '.description > .md' do
# unfortunately there is no class selector for KaTeX's "unsupported command"
@@ -59,9 +55,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
```
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
+ create_and_visit_issue_with_description(description)
page.within '.description > .md' do
expect(page).to have_selector('.js-lazy-render-math-container', text: /math block exceeds 1000 characters/)
@@ -75,11 +69,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
```
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
-
- wait_for_requests
+ create_and_visit_issue_with_description(description)
page.within '.description > .md' do
expect(page).not_to have_selector('.katex-error')
@@ -93,11 +83,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
```
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
-
- wait_for_requests
+ create_and_visit_issue_with_description(description)
page.within '.description > .md' do
click_button 'Display anyway'
@@ -113,11 +99,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
```
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
-
- wait_for_requests
+ create_and_visit_issue_with_description(description)
page.within '.description > .md' do
expect(page).to have_selector('.katex-error',
@@ -132,11 +114,7 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
```
MATH
- issue = create(:issue, project: project, description: description)
-
- visit project_issue_path(project, issue)
-
- wait_for_requests
+ create_and_visit_issue_with_description(description)
page.within '.description > .md' do
expect(page).to have_selector('.katex-error', text: /&amp;lt;script&amp;gt;/)
@@ -162,4 +140,72 @@ RSpec.describe 'Math rendering', :js, feature_category: :team_planning do
expect(page).not_to have_selector('.js-lazy-render-math')
end
end
+
+ it 'uses math-content-display for display math', :js do
+ description = <<~MATH
+ ```math
+ 1 + 2
+ ```
+ MATH
+
+ create_and_visit_issue_with_description(description)
+
+ page.within '.description > .md' do
+ expect(page).to have_selector('.math-content-display')
+ end
+ end
+
+ it 'uses math-content-inline for inline math', :js do
+ description = 'one $`1 + 2`$ two'
+
+ create_and_visit_issue_with_description(description)
+
+ page.within '.description > .md' do
+ expect(page).to have_selector('.math-content-inline')
+ end
+ end
+
+ context 'when math tries to cover other elements on the page' do
+ it 'prevents hijacking for display math', :js do
+ description = <<~MATH
+ [test link](#)
+
+ ```math
+ \\hskip{-200pt}\\href{https://example.com}{\\smash{\\raisebox{20em}{$\\smash{\\raisebox{20em}{$\\phantom{\\underset{\\underset{\\underset{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}}{\\underset{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}}}{\\underset{\\underset{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}}{}}}$}}$}}}
+ ```
+ MATH
+
+ issue = create_and_visit_issue_with_description(description)
+
+ page.within '.description > .md' do
+ click_link 'test link'
+
+ expect(page).to have_current_path(project_issue_path(project, issue))
+ end
+ end
+
+ it 'prevents hijacking for inline math', :js do
+ description = <<~MATH
+ [test link](#) $`\\hskip{-200pt}\\href{https://example.com}{\\smash{\\raisebox{20em}{$\\smash{\\raisebox{20em}{$\\phantom{\\underset{\\underset{\\underset{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}}{\\underset{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}}}{\\underset{\\underset{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}{\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}\\rule{20em}{20em}}}{}}}$}}$}}}`$
+ MATH
+
+ issue = create_and_visit_issue_with_description(description)
+
+ page.within '.description > .md' do
+ click_link 'test link'
+
+ expect(page).to have_current_path(project_issue_path(project, issue))
+ end
+ end
+ end
+
+ def create_and_visit_issue_with_description(description)
+ issue = create(:issue, project: project, description: description)
+
+ visit project_issue_path(project, issue)
+
+ wait_for_requests
+
+ issue
+ end
end
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson
index 348a01372ab..8e08ca3efd2 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/ci_pipelines.ndjson
@@ -1,7 +1,10 @@
-{"id":19,"project_id":5,"ref":"master","sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":24,"project_id":5,"pipeline_id":40,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":79,"project_id":5,"status":"failed","finished_at":"2016-03-29T06:28:12.695Z","trace":"Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.","created_at":"2016-03-22T15:20:35.950Z","updated_at":"2016-03-29T06:28:12.696Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":80,"project_id":5,"status":"success","finished_at":null,"trace":"Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.","created_at":"2016-03-22T15:20:35.966Z","updated_at":"2016-03-22T15:20:35.966Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
-{"id":20,"project_id":5,"ref":"master","sha":"ce84140e8b878ce6e7c4d298c7202ff38170e3ac","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[],"source":"external_pull_request_event","external_pull_request":{"id":3,"pull_request_iid":4,"source_branch":"feature","target_branch":"master","source_repository":"the-repository","target_repository":"the-repository","source_sha":"ce84140e8b878ce6e7c4d298c7202ff38170e3ac","target_sha":"a09386439ca39abe575675ffd4b89ae824fec22f","status":"open","created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z"}}
-{"id":26,"project_id":5,"ref":"master","sha":"048721d90c449b244b7b4c53a9186b04330174ec","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.757Z","updated_at":"2016-03-22T15:20:35.757Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"source":"merge_request_event","merge_request_id":27,"stages":[{"id":21,"project_id":5,"pipeline_id":37,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":74,"project_id":5,"status":"success","finished_at":null,"trace":"Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.","created_at":"2016-03-22T15:20:35.846Z","updated_at":"2016-03-22T15:20:35.846Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":73,"project_id":5,"status":"canceled","finished_at":null,"trace":null,"created_at":"2016-03-22T15:20:35.842Z","updated_at":"2016-03-22T15:20:35.842Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}],"merge_request":{"id":27,"target_branch":"feature","source_branch":"feature_conflict","source_project_id":2147483547,"author_id":1,"assignee_id":null,"title":"MR1","created_at":"2016-06-14T15:02:36.568Z","updated_at":"2016-06-14T15:02:56.815Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":9,"description":null,"position":0,"updated_by_id":null,"merge_error":null,"diff_head_sha":"HEAD","source_branch_sha":"ABCD","target_branch_sha":"DCBA","merge_params":{"force_remove_source_branch":null}}}
-{"id":36,"project_id":5,"ref":null,"sha":"sha-notes","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.755Z","updated_at":"2016-03-22T15:20:35.755Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"user_id":2147483547,"duration":null,"source":"push","merge_request_id":null,"pipeline_metadata": {"id": 2, "project_id": 5, "pipeline_id": 36, "name": "Build pipeline"},"notes":[{"id":2147483547,"note":"Natus rerum qui dolorem dolorum voluptas.","noteable_type":"Commit","author_id":1,"created_at":"2016-03-22T15:19:59.469Z","updated_at":"2016-03-22T15:19:59.469Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":"be93687618e4b132087f430a4d8fc3a609c9b77c","noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"}}],"stages":[{"id":11,"project_id":5,"pipeline_id":36,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":71,"project_id":5,"status":"failed","finished_at":"2016-03-29T06:28:12.630Z","trace":null,"created_at":"2016-03-22T15:20:35.772Z","updated_at":"2016-03-29T06:28:12.634Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":{"image":"busybox:latest"},"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"stage_id":11,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null,"type":"Ci::Build","token":"abcd","artifacts_file_store":1,"artifacts_metadata_store":1,"artifacts_size":10}],"bridges":[{"id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}], "generic_commit_statuses": [{"id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]},{"id":12,"project_id":5,"pipeline_id":36,"name":"deploy","status":2,"created_at":"2016-03-22T15:45:45.772Z","updated_at":"2016-03-29T06:45:45.634Z"}]}
-{"id":38,"iid":1,"project_id":5,"ref":"master","sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.759Z","updated_at":"2016-03-22T15:20:35.759Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":22,"project_id":5,"pipeline_id":38,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":76,"project_id":5,"status":"success","finished_at":null,"trace":"Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.","created_at":"2016-03-22T15:20:35.882Z","updated_at":"2016-03-22T15:20:35.882Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":75,"project_id":5,"status":"failed","finished_at":null,"trace":"Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.","created_at":"2016-03-22T15:20:35.864Z","updated_at":"2016-03-22T15:20:35.864Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
-{"id":39,"project_id":5,"ref":"master","sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.761Z","updated_at":"2016-03-22T15:20:35.761Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":23,"project_id":5,"pipeline_id":39,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":78,"project_id":5,"status":"success","finished_at":null,"trace":"Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.","created_at":"2016-03-22T15:20:35.927Z","updated_at":"2016-03-22T15:20:35.927Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":77,"project_id":5,"status":"failed","finished_at":null,"trace":"Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.","created_at":"2016-03-22T15:20:35.905Z","updated_at":"2016-03-22T15:20:35.905Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
-{"id":41,"project_id":5,"ref":"master","sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[]}
+{"id":19,"project_id":5,"ref":"master","sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"waiting_for_resource","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":24,"project_id":5,"pipeline_id":40,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","statuses":[{"id":79,"project_id":5,"status":"running","finished_at":"2016-03-29T06:28:12.695Z","trace":"Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.","created_at":"2016-03-22T15:20:35.950Z","updated_at":"2016-03-29T06:28:12.696Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":80,"project_id":5,"status":"success","finished_at":null,"trace":"Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.","created_at":"2016-03-22T15:20:35.966Z","updated_at":"2016-03-22T15:20:35.966Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
+{"id":20,"project_id":5,"ref":"master","sha":"ce84140e8b878ce6e7c4d298c7202ff38170e3ac","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"preparing","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":90,"project_id":5,"status":10,"finished_at":"2016-03-29T06:28:12.695Z","trace":"foo","created_at":"2016-03-22T15:20:35.950Z","updated_at":"2016-03-29T06:28:12.696Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":40,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}],"source":"external_pull_request_event","external_pull_request":{"id":3,"pull_request_iid":4,"source_branch":"feature","target_branch":"master","source_repository":"the-repository","target_repository":"the-repository","source_sha":"ce84140e8b878ce6e7c4d298c7202ff38170e3ac","target_sha":"a09386439ca39abe575675ffd4b89ae824fec22f","status":"open","created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z"}}
+{"id":26,"project_id":5,"ref":"master","sha":"048721d90c449b244b7b4c53a9186b04330174ec","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.757Z","updated_at":"2016-03-22T15:20:35.757Z","tag":false,"yaml_errors":null,"committed_at":null,"status":"pending","started_at":null,"finished_at":null,"duration":null,"source":"merge_request_event","merge_request_id":27,"stages":[{"id":21,"project_id":5,"pipeline_id":37,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":74,"project_id":5,"status":"success","finished_at":null,"trace":"Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.","created_at":"2016-03-22T15:20:35.846Z","updated_at":"2016-03-22T15:20:35.846Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":73,"project_id":5,"status":"canceled","finished_at":null,"trace":null,"created_at":"2016-03-22T15:20:35.842Z","updated_at":"2016-03-22T15:20:35.842Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":37,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}],"merge_request":{"id":27,"merge_when_pipeline_succeeds":true,"target_branch":"feature","source_branch":"feature_conflict","source_project_id":2147483547,"author_id":1,"assignee_id":null,"title":"MR1","created_at":"2016-06-14T15:02:36.568Z","updated_at":"2016-06-14T15:02:56.815Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":9,"description":null,"position":0,"updated_by_id":null,"merge_error":null,"diff_head_sha":"HEAD","source_branch_sha":"ABCD","target_branch_sha":"DCBA","merge_params":{"force_remove_source_branch":null}}}
+{"id":36,"project_id":5,"ref":null,"sha":"sha-notes","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.755Z","updated_at":"2016-03-22T15:20:35.755Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"running","started_at":null,"finished_at":null,"user_id":2147483547,"duration":null,"source":"push","merge_request_id":null,"pipeline_metadata": {"id": 2, "project_id": 5, "pipeline_id": 36, "name": "Build pipeline"},"notes":[{"id":2147483547,"note":"Natus rerum qui dolorem dolorum voluptas.","noteable_type":"Commit","author_id":1,"created_at":"2016-03-22T15:19:59.469Z","updated_at":"2016-03-22T15:19:59.469Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":"be93687618e4b132087f430a4d8fc3a609c9b77c","noteable_id":36,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"}}],"stages":[{"id":11,"project_id":5,"pipeline_id":36,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":71,"project_id":5,"status":"failed","finished_at":"2016-03-29T06:28:12.630Z","trace":null,"created_at":"2016-03-22T15:20:35.772Z","updated_at":"2016-03-29T06:28:12.634Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":{"image":"busybox:latest"},"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"stage_id":11,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null,"type":"Ci::Build","token":"abcd","artifacts_file_store":1,"artifacts_metadata_store":1,"artifacts_size":10}],"bridges":[{",id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}], "generic_commit_statuses": [{"id":72,"project_id":5,"status":"success","finished_at":null,"trace":"Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]},{"id":12,"project_id":5,"pipeline_id":36,"name":"deploy","status":2,"created_at":"2016-03-22T15:45:45.772Z","updated_at":"2016-03-29T06:45:45.634Z"}]}
+{"id":38,"iid":1,"project_id":5,"ref":"master","sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.759Z","updated_at":"2016-03-22T15:20:35.759Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"created","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":22,"project_id":5,"pipeline_id":38,"name":"test","status":3,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":76,"project_id":5,"status":"success","finished_at":null,"trace":"Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.","created_at":"2016-03-22T15:20:35.882Z","updated_at":"2016-03-22T15:20:35.882Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":75,"project_id":5,"status":"failed","finished_at":null,"trace":"Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.","created_at":"2016-03-22T15:20:35.864Z","updated_at":"2016-03-22T15:20:35.864Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":38,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
+{"id":39,"project_id":5,"ref":"master","sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.761Z","updated_at":"2016-03-22T15:20:35.761Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"scheduled","started_at":null,"finished_at":null,"duration":null,"stages":[{"id":23,"project_id":5,"pipeline_id":39,"name":"test","status":1,"created_at":"2016-03-22T15:44:44.772Z","updated_at":"2016-03-29T06:44:44.634Z","builds":[{"id":78,"project_id":5,"status":"pending","finished_at":null,"trace":"Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.","created_at":"2016-03-22T15:20:35.927Z","updated_at":"2016-03-22T15:20:35.927Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":77,"project_id":5,"status":"running","finished_at":null,"trace":"Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.","created_at":"2016-03-22T15:20:35.905Z","updated_at":"2016-03-22T15:20:35.905Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":39,"commands":"$ build command","job_id":null,"name":"test build 1","deploy":false,"options":null,"allow_failure":false,"stage":"test","trigger_request_id":null,"stage_idx":1,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}],"bridges":[{"id":73,"project_id":5,"status":"pending","finished_at":null,"trace":"123","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":75,"project_id":5,"status":"waiting_for_resource","finished_at":null,"trace":"1234","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":76,"project_id":5,"status":"running","finished_at":null,"trace":"12345","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":77,"project_id":5,"status":"scheduled","finished_at":null,"trace":"123456","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}],"generic_commit_statuses": [{"id":73,"project_id":5,"status":"pending","finished_at":null,"trace":"123","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null},{"id":74,"project_id":5,"status":"running","finished_at":null,"trace":"123","created_at":"2016-03-22T15:20:35.777Z","updated_at":"2016-03-22T15:20:35.777Z","started_at":null,"runner_id":null,"coverage":null,"commit_id":36,"commands":"$ deploy command","job_id":null,"name":"test build 2","deploy":false,"options":null,"allow_failure":false,"stage":"deploy","trigger_request_id":null,"stage_idx":1,"stage_id":12,"tag":null,"ref":"master","user_id":null,"target_url":null,"description":null,"erased_by_id":null,"erased_at":null}]}]}
+{"id":41,"project_id":5,"ref":"master","sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"success","started_at":null,"finished_at":null,"duration":null,"stages":[]}
+{"id":42,"project_id":5,"ref":"master","sha":"1b6c4f044c63217d1ed06e514c84d22871bed912","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"failed","started_at":null,"finished_at":null,"duration":null,"stages":[]}
+{"id":43,"project_id":5,"ref":"master","sha":"ded178474ef2ba1f80a9964ba15da3ddb3cf664b","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"canceled","started_at":null,"finished_at":null,"duration":null,"stages":[]}
+{"id":44,"project_id":5,"ref":"master","sha":"fd459e5c514d70dc525c5e70990ca5e0debb3105","before_sha":null,"push_data":null,"created_at":"2016-03-22T15:20:35.763Z","updated_at":"2016-03-22T15:20:35.763Z","tag":null,"yaml_errors":null,"committed_at":null,"status":"skipped","started_at":null,"finished_at":null,"duration":null,"stages":[]}
diff --git a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/merge_requests.ndjson b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/merge_requests.ndjson
index 887d7ab658b..60d9f96151c 100644
--- a/spec/fixtures/lib/gitlab/import_export/complex/tree/project/merge_requests.ndjson
+++ b/spec/fixtures/lib/gitlab/import_export/complex/tree/project/merge_requests.ndjson
@@ -5,5 +5,5 @@
{"id":13,"target_branch":"improve/awesome","source_branch":"test-8","source_project_id":5,"author_id":16,"assignee_id":25,"title":"Voluptates consequatur eius nemo amet libero animi illum delectus tempore.","created_at":"2016-06-14T15:02:24.415Z","updated_at":"2016-06-14T15:02:59.958Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":5,"description":"Est eaque quasi qui qui. Similique voluptatem impedit iusto ratione reprehenderit. Itaque est illum ut nulla aut.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":false,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":793,"note":"In illum maxime aperiam nulla est aspernatur.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:02:59.782Z","updated_at":"2016-06-14T15:02:59.782Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[{"merge_request_diff_id":14,"id":529,"target_type":"Note","target_id":793,"project_id":4,"created_at":"2016-07-07T14:35:12.128Z","updated_at":"2016-07-07T14:35:12.128Z","action":6,"author_id":1}]},{"id":794,"note":"Enim quia perferendis cum distinctio tenetur optio voluptas veniam.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:02:59.807Z","updated_at":"2016-06-14T15:02:59.807Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":795,"note":"Dolor ad quia quis pariatur ducimus.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:02:59.831Z","updated_at":"2016-06-14T15:02:59.831Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":796,"note":"Et a odio voluptate aut.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:02:59.854Z","updated_at":"2016-06-14T15:02:59.854Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":797,"note":"Quis nihil temporibus voluptatum modi minima a ut.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:02:59.879Z","updated_at":"2016-06-14T15:02:59.879Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":798,"note":"Ut alias consequatur in nostrum.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:02:59.904Z","updated_at":"2016-06-14T15:02:59.904Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":799,"note":"Voluptatibus aperiam assumenda et neque sint libero.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:02:59.926Z","updated_at":"2016-06-14T15:02:59.926Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":800,"note":"Veritatis voluptatem dolor dolores magni quo ut ipsa fuga.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:02:59.956Z","updated_at":"2016-06-14T15:02:59.956Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":13,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":13,"state":"collected","merge_request_diff_commits":[{"merge_request_diff_id":13,"relative_order":0,"sha":"0bfedc29d30280c7e8564e19f654584b459e5868","message":"fixes #10\n","authored_date":"2016-01-19T15:25:23.000+01:00","committed_date":"2016-01-19T15:25:23.000+01:00","commit_author":{"name":"James Lopez","email":"james@jameslopez.es"},"committer":{"name":"James Lopez","email":"james@jameslopez.es"}},{"merge_request_diff_id":13,"relative_order":1,"sha":"be93687618e4b132087f430a4d8fc3a609c9b77c","message":"Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6","authored_date":"2015-12-07T12:52:12.000+01:00","committed_date":"2015-12-07T12:52:12.000+01:00","commit_author":{"name":"Marin Jankovski","email":"marin@gitlab.com"},"committer":{"name":"Marin Jankovski","email":"marin@gitlab.com"}},{"merge_request_diff_id":13,"relative_order":2,"sha":"048721d90c449b244b7b4c53a9186b04330174ec","message":"LFS object pointer.\n","authored_date":"2015-12-07T11:54:28.000+01:00","committed_date":"2015-12-07T11:54:28.000+01:00","commit_author":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"},"committer":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"}},{"merge_request_diff_id":13,"relative_order":3,"sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","message":"GitLab currently doesn't support patches that involve a merge commit: add a commit here\n","authored_date":"2015-11-13T16:27:12.000+01:00","committed_date":"2015-11-13T16:27:12.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":13,"relative_order":4,"sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","message":"Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5","authored_date":"2015-11-13T08:50:17.000+01:00","committed_date":"2015-11-13T08:50:17.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":13,"relative_order":5,"sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","message":"Add GitLab SVG\n","authored_date":"2015-11-13T08:39:43.000+01:00","committed_date":"2015-11-13T08:39:43.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":13,"relative_order":6,"sha":"59e29889be61e6e0e5e223bfa9ac2721d31605b8","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4","authored_date":"2015-11-13T07:21:40.000+01:00","committed_date":"2015-11-13T07:21:40.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":13,"relative_order":7,"sha":"66eceea0db202bb39c4e445e8ca28689645366c5","message":"add spaces in whitespace file\n","authored_date":"2015-11-13T06:01:27.000+01:00","committed_date":"2015-11-13T06:01:27.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":13,"relative_order":8,"sha":"08f22f255f082689c0d7d39d19205085311542bc","message":"remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n","authored_date":"2015-11-13T06:00:16.000+01:00","committed_date":"2015-11-13T06:00:16.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":13,"relative_order":9,"sha":"19e2e9b4ef76b422ce1154af39a91323ccc57434","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3","authored_date":"2015-11-13T05:23:14.000+01:00","committed_date":"2015-11-13T05:23:14.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":13,"relative_order":10,"sha":"c642fe9b8b9f28f9225d7ea953fe14e74748d53b","message":"add whitespace in empty\n","authored_date":"2015-11-13T05:08:45.000+01:00","committed_date":"2015-11-13T05:08:45.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":13,"relative_order":11,"sha":"9a944d90955aaf45f6d0c88f30e27f8d2c41cec0","message":"add empty file\n","authored_date":"2015-11-13T05:08:04.000+01:00","committed_date":"2015-11-13T05:08:04.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":13,"relative_order":12,"sha":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd","message":"Add ISO-8859 test file\n","authored_date":"2015-08-25T17:53:12.000+02:00","committed_date":"2015-08-25T17:53:12.000+02:00","commit_author":{"name":"Stan Hu","email":"stanhu@packetzoom.com"},"committer":{"name":"Stan Hu","email":"stanhu@packetzoom.com"}},{"merge_request_diff_id":13,"relative_order":13,"sha":"e56497bb5f03a90a51293fc6d516788730953899","message":"Merge branch 'tree_helper_spec' into 'master'\n\nAdd directory structure for tree_helper spec\n\nThis directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module\n\nSee [merge request #275](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/275#note_732774)\n\nSee merge request !2\n","authored_date":"2015-01-10T22:23:29.000+01:00","committed_date":"2015-01-10T22:23:29.000+01:00","commit_author":{"name":"Sytse Sijbrandij","email":"sytse@gitlab.com"},"committer":{"name":"Sytse Sijbrandij","email":"sytse@gitlab.com"}},{"merge_request_diff_id":13,"relative_order":14,"sha":"4cd80ccab63c82b4bad16faa5193fbd2aa06df40","message":"add directory structure for tree_helper spec\n","authored_date":"2015-01-10T21:28:18.000+01:00","committed_date":"2015-01-10T21:28:18.000+01:00","commit_author":{"name":"marmis85","email":"marmis85@gmail.com"},"committer":{"name":"marmis85","email":"marmis85@gmail.com"}}],"merge_request_diff_files":[{"merge_request_diff_id":13,"relative_order":0,"utf8_diff":"--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n","new_path":"CHANGELOG","old_path":"CHANGELOG","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":13,"relative_order":1,"utf8_diff":"--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n","new_path":"encoding/iso8859.txt","old_path":"encoding/iso8859.txt","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":13,"relative_order":2,"utf8_diff":"--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n","new_path":"files/images/wm.svg","old_path":"files/images/wm.svg","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":13,"relative_order":3,"utf8_diff":"--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n","new_path":"files/lfs/lfs_object.iso","old_path":"files/lfs/lfs_object.iso","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":13,"relative_order":4,"utf8_diff":"--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n","new_path":"files/whitespace","old_path":"files/whitespace","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":13,"relative_order":5,"utf8_diff":"--- /dev/null\n+++ b/foo/bar/.gitkeep\n","new_path":"foo/bar/.gitkeep","old_path":"foo/bar/.gitkeep","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":13,"relative_order":6,"utf8_diff":"--- /dev/null\n+++ b/test\n","new_path":"test","old_path":"test","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false}],"merge_request_id":13,"created_at":"2016-06-14T15:02:24.420Z","updated_at":"2016-06-14T15:02:24.561Z","base_commit_sha":"5937ac0a7beb003549fc5fd26fc247adbce4a52e","real_size":"7"},"events":[{"id":225,"target_type":"MergeRequest","target_id":13,"project_id":36,"created_at":"2016-06-14T15:02:24.636Z","updated_at":"2016-06-14T15:02:24.636Z","action":1,"author_id":16},{"id":173,"target_type":"MergeRequest","target_id":13,"project_id":5,"created_at":"2016-06-14T15:02:24.636Z","updated_at":"2016-06-14T15:02:24.636Z","action":1,"author_id":16}]}
{"id":12,"target_branch":"flatten-dirs","source_branch":"test-2","source_project_id":5,"author_id":1,"assignee_id":22,"title":"In a rerum harum nihil accusamus aut quia nobis non.","created_at":"2016-06-14T15:02:24.000Z","updated_at":"2016-06-14T15:03:00.225Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":4,"description":"Nam magnam odit velit rerum. Sapiente dolore sunt saepe debitis. Culpa maiores ut ad dolores dolorem et.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":false,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":801,"note":"Nihil dicta molestias expedita atque.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:03:00.001Z","updated_at":"2016-06-14T15:03:00.001Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":802,"note":"Illum culpa voluptas enim accusantium deserunt.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:03:00.034Z","updated_at":"2016-06-14T15:03:00.034Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":803,"note":"Dicta esse aliquam laboriosam unde alias.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:03:00.065Z","updated_at":"2016-06-14T15:03:00.065Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":804,"note":"Dicta autem et sed molestiae ut quae.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:03:00.097Z","updated_at":"2016-06-14T15:03:00.097Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":805,"note":"Ut ut temporibus voluptas dolore quia velit.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:03:00.129Z","updated_at":"2016-06-14T15:03:00.129Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":806,"note":"Dolores similique sint pariatur error id quia fugit aut.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:03:00.162Z","updated_at":"2016-06-14T15:03:00.162Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":807,"note":"Quisquam provident nihil aperiam voluptatem.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:03:00.193Z","updated_at":"2016-06-14T15:03:00.193Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":808,"note":"Similique quo vero expedita deserunt ipsam earum.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:03:00.224Z","updated_at":"2016-06-14T15:03:00.224Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":12,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":12,"state":"collected","merge_request_diff_commits":[{"merge_request_diff_id":12,"relative_order":0,"sha":"97a0df9696e2aebf10c31b3016f40214e0e8f243","message":"fixes #10\n","authored_date":"2016-01-19T14:08:21.000+01:00","committed_date":"2016-01-19T14:08:21.000+01:00","commit_author":{"name":"James Lopez","email":"james@jameslopez.es"},"committer":{"name":"James Lopez","email":"james@jameslopez.es"}},{"merge_request_diff_id":12,"relative_order":1,"sha":"be93687618e4b132087f430a4d8fc3a609c9b77c","message":"Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6","authored_date":"2015-12-07T12:52:12.000+01:00","committed_date":"2015-12-07T12:52:12.000+01:00","commit_author":{"name":"Marin Jankovski","email":"marin@gitlab.com"},"committer":{"name":"Marin Jankovski","email":"marin@gitlab.com"}},{"merge_request_diff_id":12,"relative_order":2,"sha":"048721d90c449b244b7b4c53a9186b04330174ec","message":"LFS object pointer.\n","authored_date":"2015-12-07T11:54:28.000+01:00","committed_date":"2015-12-07T11:54:28.000+01:00","commit_author":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"},"committer":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"}},{"merge_request_diff_id":12,"relative_order":3,"sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","message":"GitLab currently doesn't support patches that involve a merge commit: add a commit here\n","authored_date":"2015-11-13T16:27:12.000+01:00","committed_date":"2015-11-13T16:27:12.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":12,"relative_order":4,"sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","message":"Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5","authored_date":"2015-11-13T08:50:17.000+01:00","committed_date":"2015-11-13T08:50:17.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":12,"relative_order":5,"sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","message":"Add GitLab SVG\n","authored_date":"2015-11-13T08:39:43.000+01:00","committed_date":"2015-11-13T08:39:43.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":12,"relative_order":6,"sha":"59e29889be61e6e0e5e223bfa9ac2721d31605b8","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4","authored_date":"2015-11-13T07:21:40.000+01:00","committed_date":"2015-11-13T07:21:40.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":12,"relative_order":7,"sha":"66eceea0db202bb39c4e445e8ca28689645366c5","message":"add spaces in whitespace file\n","authored_date":"2015-11-13T06:01:27.000+01:00","committed_date":"2015-11-13T06:01:27.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":12,"relative_order":8,"sha":"08f22f255f082689c0d7d39d19205085311542bc","message":"remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n","authored_date":"2015-11-13T06:00:16.000+01:00","committed_date":"2015-11-13T06:00:16.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":12,"relative_order":9,"sha":"19e2e9b4ef76b422ce1154af39a91323ccc57434","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3","authored_date":"2015-11-13T05:23:14.000+01:00","committed_date":"2015-11-13T05:23:14.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":12,"relative_order":10,"sha":"c642fe9b8b9f28f9225d7ea953fe14e74748d53b","message":"add whitespace in empty\n","authored_date":"2015-11-13T05:08:45.000+01:00","committed_date":"2015-11-13T05:08:45.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":12,"relative_order":11,"sha":"9a944d90955aaf45f6d0c88f30e27f8d2c41cec0","message":"add empty file\n","authored_date":"2015-11-13T05:08:04.000+01:00","committed_date":"2015-11-13T05:08:04.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":12,"relative_order":12,"sha":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd","message":"Add ISO-8859 test file\n","authored_date":"2015-08-25T17:53:12.000+02:00","committed_date":"2015-08-25T17:53:12.000+02:00","commit_author":{"name":"Stan Hu","email":"stanhu@packetzoom.com"},"committer":{"name":"Stan Hu","email":"stanhu@packetzoom.com"}}],"merge_request_diff_files":[{"merge_request_diff_id":12,"relative_order":0,"utf8_diff":"--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n","new_path":"CHANGELOG","old_path":"CHANGELOG","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":12,"relative_order":1,"utf8_diff":"--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n","new_path":"encoding/iso8859.txt","old_path":"encoding/iso8859.txt","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":12,"relative_order":2,"utf8_diff":"--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n","new_path":"files/images/wm.svg","old_path":"files/images/wm.svg","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":12,"relative_order":3,"utf8_diff":"--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n","new_path":"files/lfs/lfs_object.iso","old_path":"files/lfs/lfs_object.iso","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":12,"relative_order":4,"utf8_diff":"--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n","new_path":"files/whitespace","old_path":"files/whitespace","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":12,"relative_order":5,"utf8_diff":"--- /dev/null\n+++ b/test\n","new_path":"test","old_path":"test","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false}],"merge_request_id":12,"created_at":"2016-06-14T15:02:24.006Z","updated_at":"2016-06-14T15:02:24.169Z","base_commit_sha":"e56497bb5f03a90a51293fc6d516788730953899","real_size":"6"},"events":[{"id":226,"target_type":"MergeRequest","target_id":12,"project_id":36,"created_at":"2016-06-14T15:02:24.253Z","updated_at":"2016-06-14T15:02:24.253Z","action":1,"author_id":1},{"id":172,"target_type":"MergeRequest","target_id":12,"project_id":5,"created_at":"2016-06-14T15:02:24.253Z","updated_at":"2016-06-14T15:02:24.253Z","action":1,"author_id":1}]}
{"id":11,"target_branch":"test-15","source_branch":"'test'","source_project_id":5,"author_id":16,"assignee_id":16,"title":"Corporis provident similique perspiciatis dolores eos animi.","created_at":"2016-06-14T15:02:23.767Z","updated_at":"2016-06-14T15:03:00.475Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":3,"description":"Libero nesciunt mollitia quis odit eos vero quasi. Iure voluptatem ut sint pariatur voluptates ut aut. Laborum possimus unde illum ipsum eum.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":false,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":809,"note":"Omnis ratione laboriosam dolores qui.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:03:00.260Z","updated_at":"2016-06-14T15:03:00.260Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":810,"note":"Voluptas voluptates pariatur dolores maxime est voluptas.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:03:00.290Z","updated_at":"2016-06-14T15:03:00.290Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":811,"note":"Sit perspiciatis facilis ipsum consequatur.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:03:00.323Z","updated_at":"2016-06-14T15:03:00.323Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":812,"note":"Ut neque aliquam nam et est.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:03:00.349Z","updated_at":"2016-06-14T15:03:00.349Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":813,"note":"Et debitis rerum minima sit aut dolorem.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:03:00.374Z","updated_at":"2016-06-14T15:03:00.374Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":814,"note":"Ea nisi earum fugit iste aperiam consequatur.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:03:00.397Z","updated_at":"2016-06-14T15:03:00.397Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":815,"note":"Amet ratione consequatur laudantium rerum voluptas est nobis.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:03:00.450Z","updated_at":"2016-06-14T15:03:00.450Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":816,"note":"Ab ducimus cumque quia dolorem vitae sint beatae rerum.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:03:00.474Z","updated_at":"2016-06-14T15:03:00.474Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":11,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":11,"state":"empty","merge_request_diff_commits":[],"merge_request_diff_files":[],"merge_request_id":11,"created_at":"2016-06-14T15:02:23.772Z","updated_at":"2016-06-14T15:02:23.833Z","base_commit_sha":"e56497bb5f03a90a51293fc6d516788730953899","real_size":null},"events":[{"id":227,"target_type":"MergeRequest","target_id":11,"project_id":36,"created_at":"2016-06-14T15:02:23.865Z","updated_at":"2016-06-14T15:02:23.865Z","action":1,"author_id":16},{"id":171,"target_type":"MergeRequest","target_id":11,"project_id":5,"created_at":"2016-06-14T15:02:23.865Z","updated_at":"2016-06-14T15:02:23.865Z","action":1,"author_id":16}]}
-{"id":10,"target_branch":"feature","source_branch":"test-5","source_project_id":5,"author_id":20,"assignee_id":25,"title":"Eligendi reprehenderit doloribus quia et sit id.","created_at":"2016-06-14T15:02:23.014Z","updated_at":"2016-06-14T15:03:00.685Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":2,"description":"Ut dolor quia aliquid dolore et nisi. Est minus suscipit enim quaerat sapiente consequatur rerum. Eveniet provident consequatur dolor accusantium reiciendis.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":false,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":817,"note":"Recusandae et voluptas enim qui et.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:03:00.510Z","updated_at":"2016-06-14T15:03:00.510Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":818,"note":"Asperiores dolorem rerum ipsum totam.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:03:00.538Z","updated_at":"2016-06-14T15:03:00.538Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":819,"note":"Qui quam et iure quasi provident cumque itaque sequi.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:03:00.562Z","updated_at":"2016-06-14T15:03:00.562Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":820,"note":"Sint accusantium aliquid iste qui iusto minus vel.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:03:00.585Z","updated_at":"2016-06-14T15:03:00.585Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":821,"note":"Dolor corrupti dolorem blanditiis voluptas.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:03:00.610Z","updated_at":"2016-06-14T15:03:00.610Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":822,"note":"Est perferendis assumenda aliquam aliquid sit ipsum ullam aut.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:03:00.635Z","updated_at":"2016-06-14T15:03:00.635Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":823,"note":"Hic neque reiciendis quaerat maiores.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:03:00.659Z","updated_at":"2016-06-14T15:03:00.659Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":824,"note":"Sequi architecto doloribus ut vel autem.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:03:00.683Z","updated_at":"2016-06-14T15:03:00.683Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":10,"state":"collected","merge_request_diff_commits":[{"merge_request_diff_id":10,"relative_order":0,"sha":"f998ac87ac9244f15e9c15109a6f4e62a54b779d","message":"fixes #10\n","authored_date":"2016-01-19T14:43:23.000+01:00","committed_date":"2016-01-19T14:43:23.000+01:00","commit_author":{"name":"James Lopez","email":"james@jameslopez.es"},"committer":{"name":"James Lopez","email":"james@jameslopez.es"}},{"merge_request_diff_id":10,"relative_order":1,"sha":"be93687618e4b132087f430a4d8fc3a609c9b77c","message":"Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6","authored_date":"2015-12-07T12:52:12.000+01:00","committed_date":"2015-12-07T12:52:12.000+01:00","commit_author":{"name":"Marin Jankovski","email":"marin@gitlab.com"},"committer":{"name":"Marin Jankovski","email":"marin@gitlab.com"}},{"merge_request_diff_id":10,"relative_order":2,"sha":"048721d90c449b244b7b4c53a9186b04330174ec","message":"LFS object pointer.\n","authored_date":"2015-12-07T11:54:28.000+01:00","committed_date":"2015-12-07T11:54:28.000+01:00","commit_author":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"},"committer":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"}},{"merge_request_diff_id":10,"relative_order":3,"sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","message":"GitLab currently doesn't support patches that involve a merge commit: add a commit here\n","authored_date":"2015-11-13T16:27:12.000+01:00","committed_date":"2015-11-13T16:27:12.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":4,"sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","message":"Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5","authored_date":"2015-11-13T08:50:17.000+01:00","committed_date":"2015-11-13T08:50:17.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":5,"sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","message":"Add GitLab SVG\n","authored_date":"2015-11-13T08:39:43.000+01:00","committed_date":"2015-11-13T08:39:43.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":6,"sha":"59e29889be61e6e0e5e223bfa9ac2721d31605b8","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4","authored_date":"2015-11-13T07:21:40.000+01:00","committed_date":"2015-11-13T07:21:40.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":7,"sha":"66eceea0db202bb39c4e445e8ca28689645366c5","message":"add spaces in whitespace file\n","authored_date":"2015-11-13T06:01:27.000+01:00","committed_date":"2015-11-13T06:01:27.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":8,"sha":"08f22f255f082689c0d7d39d19205085311542bc","message":"remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n","authored_date":"2015-11-13T06:00:16.000+01:00","committed_date":"2015-11-13T06:00:16.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":9,"sha":"19e2e9b4ef76b422ce1154af39a91323ccc57434","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3","authored_date":"2015-11-13T05:23:14.000+01:00","committed_date":"2015-11-13T05:23:14.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":10,"sha":"c642fe9b8b9f28f9225d7ea953fe14e74748d53b","message":"add whitespace in empty\n","authored_date":"2015-11-13T05:08:45.000+01:00","committed_date":"2015-11-13T05:08:45.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":11,"sha":"9a944d90955aaf45f6d0c88f30e27f8d2c41cec0","message":"add empty file\n","authored_date":"2015-11-13T05:08:04.000+01:00","committed_date":"2015-11-13T05:08:04.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":12,"sha":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd","message":"Add ISO-8859 test file\n","authored_date":"2015-08-25T17:53:12.000+02:00","committed_date":"2015-08-25T17:53:12.000+02:00","commit_author":{"name":"Stan Hu","email":"stanhu@packetzoom.com"},"committer":{"name":"Stan Hu","email":"stanhu@packetzoom.com"}},{"merge_request_diff_id":10,"relative_order":13,"sha":"e56497bb5f03a90a51293fc6d516788730953899","message":"Merge branch 'tree_helper_spec' into 'master'\n\nAdd directory structure for tree_helper spec\n\nThis directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module\n\nSee [merge request #275](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/275#note_732774)\n\nSee merge request !2\n","authored_date":"2015-01-10T22:23:29.000+01:00","committed_date":"2015-01-10T22:23:29.000+01:00","commit_author":{"name":"Sytse Sijbrandij","email":"sytse@gitlab.com"},"committer":{"name":"Sytse Sijbrandij","email":"sytse@gitlab.com"}},{"merge_request_diff_id":10,"relative_order":14,"sha":"4cd80ccab63c82b4bad16faa5193fbd2aa06df40","message":"add directory structure for tree_helper spec\n","authored_date":"2015-01-10T21:28:18.000+01:00","committed_date":"2015-01-10T21:28:18.000+01:00","commit_author":{"name":"marmis85","email":"marmis85@gmail.com"},"committer":{"name":"marmis85","email":"marmis85@gmail.com"}},{"merge_request_diff_id":10,"relative_order":16,"sha":"5937ac0a7beb003549fc5fd26fc247adbce4a52e","message":"Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T10:01:38.000+01:00","committed_date":"2014-02-27T10:01:38.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":17,"sha":"570e7b2abdd848b95f2f578043fc23bd6f6fd24d","message":"Change some files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:57:31.000+01:00","committed_date":"2014-02-27T09:57:31.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":18,"sha":"6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9","message":"More submodules\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:54:21.000+01:00","committed_date":"2014-02-27T09:54:21.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":19,"sha":"d14d6c0abdd253381df51a723d58691b2ee1ab08","message":"Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:49:50.000+01:00","committed_date":"2014-02-27T09:49:50.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":20,"sha":"c1acaa58bbcbc3eafe538cb8274ba387047b69f8","message":"Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:48:32.000+01:00","committed_date":"2014-02-27T09:48:32.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}}],"merge_request_diff_files":[{"merge_request_diff_id":10,"relative_order":0,"utf8_diff":"Binary files a/.DS_Store and /dev/null differ\n","new_path":".DS_Store","old_path":".DS_Store","a_mode":"100644","b_mode":"0","new_file":false,"renamed_file":false,"deleted_file":true,"too_large":false},{"merge_request_diff_id":10,"relative_order":1,"utf8_diff":"--- a/.gitignore\n+++ b/.gitignore\n@@ -17,3 +17,4 @@ rerun.txt\n pickle-email-*.html\n .project\n config/initializers/secret_token.rb\n+.DS_Store\n","new_path":".gitignore","old_path":".gitignore","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":2,"utf8_diff":"--- a/.gitmodules\n+++ b/.gitmodules\n@@ -1,3 +1,9 @@\n [submodule \"six\"]\n \tpath = six\n \turl = git://github.com/randx/six.git\n+[submodule \"gitlab-shell\"]\n+\tpath = gitlab-shell\n+\turl = https://github.com/gitlabhq/gitlab-shell.git\n+[submodule \"gitlab-grack\"]\n+\tpath = gitlab-grack\n+\turl = https://gitlab.com/gitlab-org/gitlab-grack.git\n","new_path":".gitmodules","old_path":".gitmodules","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":3,"utf8_diff":"--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n","new_path":"CHANGELOG","old_path":"CHANGELOG","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":4,"utf8_diff":"--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n","new_path":"encoding/iso8859.txt","old_path":"encoding/iso8859.txt","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":5,"utf8_diff":"Binary files a/files/.DS_Store and /dev/null differ\n","new_path":"files/.DS_Store","old_path":"files/.DS_Store","a_mode":"100644","b_mode":"0","new_file":false,"renamed_file":false,"deleted_file":true,"too_large":false},{"merge_request_diff_id":10,"relative_order":6,"utf8_diff":"--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n","new_path":"files/images/wm.svg","old_path":"files/images/wm.svg","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":7,"utf8_diff":"--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n","new_path":"files/lfs/lfs_object.iso","old_path":"files/lfs/lfs_object.iso","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":8,"utf8_diff":"--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" => path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" => path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output << stdout.read\n @cmd_output << stderr.read\n","new_path":"files/ruby/popen.rb","old_path":"files/ruby/popen.rb","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":9,"utf8_diff":"--- a/files/ruby/regex.rb\n+++ b/files/ruby/regex.rb\n@@ -19,14 +19,12 @@ module Gitlab\n end\n \n def archive_formats_regex\n- #|zip|tar| tar.gz | tar.bz2 |\n- /(zip|tar|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n+ /(zip|tar|7z|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n end\n \n def git_reference_regex\n # Valid git ref regex, see:\n # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html\n-\n %r{\n (?!\n (?# doesn't begins with)\n","new_path":"files/ruby/regex.rb","old_path":"files/ruby/regex.rb","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":10,"utf8_diff":"--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n","new_path":"files/whitespace","old_path":"files/whitespace","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":11,"utf8_diff":"--- /dev/null\n+++ b/foo/bar/.gitkeep\n","new_path":"foo/bar/.gitkeep","old_path":"foo/bar/.gitkeep","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":12,"utf8_diff":"--- /dev/null\n+++ b/gitlab-grack\n@@ -0,0 +1 @@\n+Subproject commit 645f6c4c82fd3f5e06f67134450a570b795e55a6\n","new_path":"gitlab-grack","old_path":"gitlab-grack","a_mode":"0","b_mode":"160000","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":13,"utf8_diff":"--- /dev/null\n+++ b/gitlab-shell\n@@ -0,0 +1 @@\n+Subproject commit 79bceae69cb5750d6567b223597999bfa91cb3b9\n","new_path":"gitlab-shell","old_path":"gitlab-shell","a_mode":"0","b_mode":"160000","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":14,"utf8_diff":"--- /dev/null\n+++ b/test\n","new_path":"test","old_path":"test","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false}],"merge_request_id":10,"created_at":"2016-06-14T15:02:23.019Z","updated_at":"2016-06-14T15:02:23.493Z","base_commit_sha":"ae73cb07c9eeaf35924a10f713b364d32b2dd34f","real_size":"15"},"events":[{"id":228,"target_type":"MergeRequest","target_id":10,"project_id":36,"created_at":"2016-06-14T15:02:23.660Z","updated_at":"2016-06-14T15:02:23.660Z","action":1,"author_id":1},{"id":170,"target_type":"MergeRequest","target_id":10,"project_id":5,"created_at":"2016-06-14T15:02:23.660Z","updated_at":"2016-06-14T15:02:23.660Z","action":1,"author_id":20}]}
-{"id":9,"target_branch":"test-6","source_branch":"test-12","source_project_id":5,"author_id":16,"assignee_id":6,"title":"Et ipsam voluptas velit sequi illum ut.","created_at":"2016-06-14T15:02:22.825Z","updated_at":"2016-06-14T15:03:00.904Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":1,"description":"Eveniet nihil ratione veniam similique qui aut sapiente tempora. Sed praesentium iusto dignissimos possimus id repudiandae quo nihil. Qui doloremque autem et iure fugit.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":false,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":825,"note":"Aliquid voluptatem consequatur voluptas ex perspiciatis.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:03:00.722Z","updated_at":"2016-06-14T15:03:00.722Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":826,"note":"Itaque optio voluptatem praesentium voluptas.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:03:00.745Z","updated_at":"2016-06-14T15:03:00.745Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":827,"note":"Ut est corporis fuga asperiores delectus excepturi aperiam.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:03:00.771Z","updated_at":"2016-06-14T15:03:00.771Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":828,"note":"Similique ea dolore officiis temporibus.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:03:00.798Z","updated_at":"2016-06-14T15:03:00.798Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":829,"note":"Qui laudantium qui quae quis.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:03:00.828Z","updated_at":"2016-06-14T15:03:00.828Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":830,"note":"Et vel voluptas amet laborum qui soluta.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:03:00.850Z","updated_at":"2016-06-14T15:03:00.850Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":831,"note":"Enim ad consequuntur assumenda provident voluptatem similique deleniti.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:03:00.876Z","updated_at":"2016-06-14T15:03:00.876Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":832,"note":"Officiis sequi commodi pariatur totam fugiat voluptas corporis dignissimos.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:03:00.902Z","updated_at":"2016-06-14T15:03:00.902Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":9,"state":"collected","merge_request_diff_commits":[{"merge_request_diff_id":9,"relative_order":0,"sha":"a4e5dfebf42e34596526acb8611bc7ed80e4eb3f","message":"fixes #10\n","authored_date":"2016-01-19T15:44:02.000+01:00","committed_date":"2016-01-19T15:44:02.000+01:00","commit_author":{"name":"James Lopez","email":"james@jameslopez.es"},"committer":{"name":"James Lopez","email":"james@jameslopez.es"}}],"merge_request_diff_files":[{"merge_request_diff_id":9,"relative_order":0,"utf8_diff":"--- /dev/null\n+++ b/test\n","new_path":"test","old_path":"test","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false}],"merge_request_id":9,"created_at":"2016-06-14T15:02:22.829Z","updated_at":"2016-06-14T15:02:22.900Z","base_commit_sha":"be93687618e4b132087f430a4d8fc3a609c9b77c","real_size":"1"},"events":[{"id":229,"target_type":"MergeRequest","target_id":9,"project_id":36,"created_at":"2016-06-14T15:02:22.927Z","updated_at":"2016-06-14T15:02:22.927Z","action":1,"author_id":16},{"id":169,"target_type":"MergeRequest","target_id":9,"project_id":5,"created_at":"2016-06-14T15:02:22.927Z","updated_at":"2016-06-14T15:02:22.927Z","action":1,"author_id":16}]}
+{"id":10,"target_branch":"feature","source_branch":"test-5","source_project_id":5,"author_id":20,"assignee_id":25,"title":"Eligendi reprehenderit doloribus quia et sit id.","created_at":"2016-06-14T15:02:23.014Z","updated_at":"2016-06-14T15:03:00.685Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":2,"description":"Ut dolor quia aliquid dolore et nisi. Est minus suscipit enim quaerat sapiente consequatur rerum. Eveniet provident consequatur dolor accusantium reiciendis.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":true,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":817,"note":"Recusandae et voluptas enim qui et.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:03:00.510Z","updated_at":"2016-06-14T15:03:00.510Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":818,"note":"Asperiores dolorem rerum ipsum totam.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:03:00.538Z","updated_at":"2016-06-14T15:03:00.538Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":819,"note":"Qui quam et iure quasi provident cumque itaque sequi.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:03:00.562Z","updated_at":"2016-06-14T15:03:00.562Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":820,"note":"Sint accusantium aliquid iste qui iusto minus vel.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:03:00.585Z","updated_at":"2016-06-14T15:03:00.585Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":821,"note":"Dolor corrupti dolorem blanditiis voluptas.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:03:00.610Z","updated_at":"2016-06-14T15:03:00.610Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":822,"note":"Est perferendis assumenda aliquam aliquid sit ipsum ullam aut.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:03:00.635Z","updated_at":"2016-06-14T15:03:00.635Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":823,"note":"Hic neque reiciendis quaerat maiores.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:03:00.659Z","updated_at":"2016-06-14T15:03:00.659Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":824,"note":"Sequi architecto doloribus ut vel autem.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:03:00.683Z","updated_at":"2016-06-14T15:03:00.683Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":10,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":10,"state":"collected","merge_request_diff_commits":[{"merge_request_diff_id":10,"relative_order":0,"sha":"f998ac87ac9244f15e9c15109a6f4e62a54b779d","message":"fixes #10\n","authored_date":"2016-01-19T14:43:23.000+01:00","committed_date":"2016-01-19T14:43:23.000+01:00","commit_author":{"name":"James Lopez","email":"james@jameslopez.es"},"committer":{"name":"James Lopez","email":"james@jameslopez.es"}},{"merge_request_diff_id":10,"relative_order":1,"sha":"be93687618e4b132087f430a4d8fc3a609c9b77c","message":"Merge branch 'master' into 'master'\r\n\r\nLFS object pointer.\r\n\r\n\r\n\r\nSee merge request !6","authored_date":"2015-12-07T12:52:12.000+01:00","committed_date":"2015-12-07T12:52:12.000+01:00","commit_author":{"name":"Marin Jankovski","email":"marin@gitlab.com"},"committer":{"name":"Marin Jankovski","email":"marin@gitlab.com"}},{"merge_request_diff_id":10,"relative_order":2,"sha":"048721d90c449b244b7b4c53a9186b04330174ec","message":"LFS object pointer.\n","authored_date":"2015-12-07T11:54:28.000+01:00","committed_date":"2015-12-07T11:54:28.000+01:00","commit_author":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"},"committer":{"name":"Marin Jankovski","email":"maxlazio@gmail.com"}},{"merge_request_diff_id":10,"relative_order":3,"sha":"5f923865dde3436854e9ceb9cdb7815618d4e849","message":"GitLab currently doesn't support patches that involve a merge commit: add a commit here\n","authored_date":"2015-11-13T16:27:12.000+01:00","committed_date":"2015-11-13T16:27:12.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":4,"sha":"d2d430676773caa88cdaf7c55944073b2fd5561a","message":"Merge branch 'add-svg' into 'master'\r\n\r\nAdd GitLab SVG\r\n\r\nAdded to test preview of sanitized SVG images\r\n\r\nSee merge request !5","authored_date":"2015-11-13T08:50:17.000+01:00","committed_date":"2015-11-13T08:50:17.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":5,"sha":"2ea1f3dec713d940208fb5ce4a38765ecb5d3f73","message":"Add GitLab SVG\n","authored_date":"2015-11-13T08:39:43.000+01:00","committed_date":"2015-11-13T08:39:43.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":6,"sha":"59e29889be61e6e0e5e223bfa9ac2721d31605b8","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd whitespace test file\r\n\r\nSorry, I did a mistake.\r\nGit ignore empty files.\r\nSo I add a new whitespace test file.\r\n\r\nSee merge request !4","authored_date":"2015-11-13T07:21:40.000+01:00","committed_date":"2015-11-13T07:21:40.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":7,"sha":"66eceea0db202bb39c4e445e8ca28689645366c5","message":"add spaces in whitespace file\n","authored_date":"2015-11-13T06:01:27.000+01:00","committed_date":"2015-11-13T06:01:27.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":8,"sha":"08f22f255f082689c0d7d39d19205085311542bc","message":"remove empty file.(beacase git ignore empty file)\nadd whitespace test file.\n","authored_date":"2015-11-13T06:00:16.000+01:00","committed_date":"2015-11-13T06:00:16.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":9,"sha":"19e2e9b4ef76b422ce1154af39a91323ccc57434","message":"Merge branch 'whitespace' into 'master'\r\n\r\nadd spaces\r\n\r\nTo test this pull request.(https://github.com/gitlabhq/gitlabhq/pull/9757)\r\nJust add whitespaces.\r\n\r\nSee merge request !3","authored_date":"2015-11-13T05:23:14.000+01:00","committed_date":"2015-11-13T05:23:14.000+01:00","commit_author":{"name":"Stan Hu","email":"stanhu@gmail.com"},"committer":{"name":"Stan Hu","email":"stanhu@gmail.com"}},{"merge_request_diff_id":10,"relative_order":10,"sha":"c642fe9b8b9f28f9225d7ea953fe14e74748d53b","message":"add whitespace in empty\n","authored_date":"2015-11-13T05:08:45.000+01:00","committed_date":"2015-11-13T05:08:45.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":11,"sha":"9a944d90955aaf45f6d0c88f30e27f8d2c41cec0","message":"add empty file\n","authored_date":"2015-11-13T05:08:04.000+01:00","committed_date":"2015-11-13T05:08:04.000+01:00","commit_author":{"name":"윤민식","email":"minsik.yoon@samsung.com"},"committer":{"name":"윤민식","email":"minsik.yoon@samsung.com"}},{"merge_request_diff_id":10,"relative_order":12,"sha":"c7fbe50c7c7419d9701eebe64b1fdacc3df5b9dd","message":"Add ISO-8859 test file\n","authored_date":"2015-08-25T17:53:12.000+02:00","committed_date":"2015-08-25T17:53:12.000+02:00","commit_author":{"name":"Stan Hu","email":"stanhu@packetzoom.com"},"committer":{"name":"Stan Hu","email":"stanhu@packetzoom.com"}},{"merge_request_diff_id":10,"relative_order":13,"sha":"e56497bb5f03a90a51293fc6d516788730953899","message":"Merge branch 'tree_helper_spec' into 'master'\n\nAdd directory structure for tree_helper spec\n\nThis directory structure is needed for a testing the method flatten_tree(tree) in the TreeHelper module\n\nSee [merge request #275](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/275#note_732774)\n\nSee merge request !2\n","authored_date":"2015-01-10T22:23:29.000+01:00","committed_date":"2015-01-10T22:23:29.000+01:00","commit_author":{"name":"Sytse Sijbrandij","email":"sytse@gitlab.com"},"committer":{"name":"Sytse Sijbrandij","email":"sytse@gitlab.com"}},{"merge_request_diff_id":10,"relative_order":14,"sha":"4cd80ccab63c82b4bad16faa5193fbd2aa06df40","message":"add directory structure for tree_helper spec\n","authored_date":"2015-01-10T21:28:18.000+01:00","committed_date":"2015-01-10T21:28:18.000+01:00","commit_author":{"name":"marmis85","email":"marmis85@gmail.com"},"committer":{"name":"marmis85","email":"marmis85@gmail.com"}},{"merge_request_diff_id":10,"relative_order":16,"sha":"5937ac0a7beb003549fc5fd26fc247adbce4a52e","message":"Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T10:01:38.000+01:00","committed_date":"2014-02-27T10:01:38.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":17,"sha":"570e7b2abdd848b95f2f578043fc23bd6f6fd24d","message":"Change some files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:57:31.000+01:00","committed_date":"2014-02-27T09:57:31.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":18,"sha":"6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9","message":"More submodules\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:54:21.000+01:00","committed_date":"2014-02-27T09:54:21.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":19,"sha":"d14d6c0abdd253381df51a723d58691b2ee1ab08","message":"Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:49:50.000+01:00","committed_date":"2014-02-27T09:49:50.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}},{"merge_request_diff_id":10,"relative_order":20,"sha":"c1acaa58bbcbc3eafe538cb8274ba387047b69f8","message":"Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n","authored_date":"2014-02-27T09:48:32.000+01:00","committed_date":"2014-02-27T09:48:32.000+01:00","commit_author":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"},"committer":{"name":"Dmitriy Zaporozhets","email":"dmitriy.zaporozhets@gmail.com"}}],"merge_request_diff_files":[{"merge_request_diff_id":10,"relative_order":0,"utf8_diff":"Binary files a/.DS_Store and /dev/null differ\n","new_path":".DS_Store","old_path":".DS_Store","a_mode":"100644","b_mode":"0","new_file":false,"renamed_file":false,"deleted_file":true,"too_large":false},{"merge_request_diff_id":10,"relative_order":1,"utf8_diff":"--- a/.gitignore\n+++ b/.gitignore\n@@ -17,3 +17,4 @@ rerun.txt\n pickle-email-*.html\n .project\n config/initializers/secret_token.rb\n+.DS_Store\n","new_path":".gitignore","old_path":".gitignore","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":2,"utf8_diff":"--- a/.gitmodules\n+++ b/.gitmodules\n@@ -1,3 +1,9 @@\n [submodule \"six\"]\n \tpath = six\n \turl = git://github.com/randx/six.git\n+[submodule \"gitlab-shell\"]\n+\tpath = gitlab-shell\n+\turl = https://github.com/gitlabhq/gitlab-shell.git\n+[submodule \"gitlab-grack\"]\n+\tpath = gitlab-grack\n+\turl = https://gitlab.com/gitlab-org/gitlab-grack.git\n","new_path":".gitmodules","old_path":".gitmodules","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":3,"utf8_diff":"--- a/CHANGELOG\n+++ b/CHANGELOG\n@@ -1,4 +1,6 @@\n-v 6.7.0\n+v6.8.0\n+\n+v6.7.0\n - Add support for Gemnasium as a Project Service (Olivier Gonzalez)\n - Add edit file button to MergeRequest diff\n - Public groups (Jason Hollingsworth)\n","new_path":"CHANGELOG","old_path":"CHANGELOG","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":4,"utf8_diff":"--- /dev/null\n+++ b/encoding/iso8859.txt\n@@ -0,0 +1 @@\n+Äü\n","new_path":"encoding/iso8859.txt","old_path":"encoding/iso8859.txt","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":5,"utf8_diff":"Binary files a/files/.DS_Store and /dev/null differ\n","new_path":"files/.DS_Store","old_path":"files/.DS_Store","a_mode":"100644","b_mode":"0","new_file":false,"renamed_file":false,"deleted_file":true,"too_large":false},{"merge_request_diff_id":10,"relative_order":6,"utf8_diff":"--- /dev/null\n+++ b/files/images/wm.svg\n@@ -0,0 +1,78 @@\n+<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n+<svg width=\"1300px\" height=\"680px\" viewBox=\"0 0 1300 680\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:sketch=\"http://www.bohemiancoding.com/sketch/ns\">\n+ <!-- Generator: Sketch 3.2.2 (9983) - http://www.bohemiancoding.com/sketch -->\n+ <title>wm</title>\n+ <desc>Created with Sketch.</desc>\n+ <defs>\n+ <path id=\"path-1\" d=\"M-69.8,1023.54607 L1675.19996,1023.54607 L1675.19996,0 L-69.8,0 L-69.8,1023.54607 L-69.8,1023.54607 Z\"></path>\n+ </defs>\n+ <g id=\"Page-1\" stroke=\"none\" stroke-width=\"1\" fill=\"none\" fill-rule=\"evenodd\" sketch:type=\"MSPage\">\n+ <path d=\"M1300,680 L0,680 L0,0 L1300,0 L1300,680 L1300,680 Z\" id=\"bg\" fill=\"#30353E\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"gitlab_logo\" sketch:type=\"MSLayerGroup\" transform=\"translate(-262.000000, -172.000000)\">\n+ <g id=\"g10\" transform=\"translate(872.500000, 512.354581) scale(1, -1) translate(-872.500000, -512.354581) translate(0.000000, 0.290751)\">\n+ <g id=\"g12\" transform=\"translate(1218.022652, 440.744871)\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\">\n+ <path d=\"M-50.0233338,141.900706 L-69.07059,141.900706 L-69.0100967,0.155858152 L8.04444805,0.155858152 L8.04444805,17.6840847 L-49.9628405,17.6840847 L-50.0233338,141.900706 L-50.0233338,141.900706 Z\" id=\"path14\"></path>\n+ </g>\n+ <g id=\"g16\">\n+ <g id=\"g18-Clipped\">\n+ <mask id=\"mask-2\" sketch:name=\"path22\" fill=\"white\">\n+ <use xlink:href=\"#path-1\"></use>\n+ </mask>\n+ <g id=\"path22\"></g>\n+ <g id=\"g18\" mask=\"url(#mask-2)\">\n+ <g transform=\"translate(382.736659, 312.879425)\">\n+ <g id=\"g24\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(852.718192, 124.992771)\">\n+ <path d=\"M63.9833317,27.9148929 C59.2218085,22.9379001 51.2134221,17.9597442 40.3909323,17.9597442 C25.8888194,17.9597442 20.0453962,25.1013043 20.0453962,34.4074318 C20.0453962,48.4730484 29.7848226,55.1819277 50.5642821,55.1819277 C54.4602853,55.1819277 60.7364685,54.7492469 63.9833317,54.1002256 L63.9833317,27.9148929 L63.9833317,27.9148929 Z M44.2869356,113.827628 C28.9053426,113.827628 14.7975996,108.376082 3.78897657,99.301416 L10.5211864,87.6422957 C18.3131929,92.1866076 27.8374026,96.7320827 41.4728323,96.7320827 C57.0568452,96.7320827 63.9833317,88.7239978 63.9833317,75.3074024 L63.9833317,68.3821827 C60.9528485,69.0312039 54.6766653,69.4650479 50.7806621,69.4650479 C17.4476729,69.4650479 0.565379986,57.7791759 0.565379986,33.3245665 C0.565379986,11.4683685 13.9844297,0.43151772 34.3299658,0.43151772 C48.0351955,0.43151772 61.1692285,6.70771614 65.7143717,16.8780421 L69.1776149,3.02876588 L82.5978279,3.02876588 L82.5978279,75.5237428 C82.5978279,98.462806 72.6408582,113.827628 44.2869356,113.827628 L44.2869356,113.827628 Z\" id=\"path26\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g28\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(959.546624, 124.857151)\">\n+ <path d=\"M37.2266657,17.4468081 C30.0837992,17.4468081 23.8064527,18.3121698 19.0449295,20.4767371 L19.0449295,79.2306079 L19.0449295,86.0464943 C25.538656,91.457331 33.5470425,95.3526217 43.7203922,95.3526217 C62.1173451,95.3526217 69.2602116,82.3687072 69.2602116,61.3767077 C69.2602116,31.5135879 57.7885819,17.4468081 37.2266657,17.4468081 M45.2315622,113.963713 C28.208506,113.963713 19.0449295,102.384849 19.0449295,102.384849 L19.0449295,120.67143 L18.9844362,144.908535 L10.3967097,144.908535 L0.371103324,144.908535 L0.431596656,6.62629771 C9.73826309,2.73100702 22.5081728,0.567602823 36.3611458,0.567602823 C71.8579349,0.567602823 88.9566078,23.2891625 88.9566078,62.4584098 C88.9566078,93.4043948 73.1527248,113.963713 45.2315622,113.963713\" id=\"path30\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g32\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(509.576747, 125.294950)\">\n+ <path d=\"M68.636665,129.10638 C85.5189579,129.10638 96.3414476,123.480366 103.484314,117.853189 L111.669527,132.029302 C100.513161,141.811145 85.5073245,147.06845 69.5021849,147.06845 C29.0274926,147.06845 0.673569983,122.3975 0.673569983,72.6252464 C0.673569983,20.4709215 31.2622559,0.12910638 66.2553217,0.12910638 C83.7879179,0.12910638 98.7227909,4.24073748 108.462217,8.35236859 L108.063194,64.0763105 L108.063194,70.6502677 L108.063194,81.6057001 L56.1168719,81.6057001 L56.1168719,64.0763105 L89.2323178,64.0763105 L89.6313411,21.7701271 C85.3025779,19.6055598 77.7269514,17.8748364 67.554765,17.8748364 C39.4172223,17.8748364 20.5863462,35.5717154 20.5863462,72.8415868 C20.5863462,110.711628 40.0663623,129.10638 68.636665,129.10638\" id=\"path34\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g36\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(692.388992, 124.376085)\">\n+ <path d=\"M19.7766662,145.390067 L1.16216997,145.390067 L1.2226633,121.585642 L1.2226633,111.846834 L1.2226633,106.170806 L1.2226633,96.2656714 L1.2226633,39.5681976 L1.2226633,39.3518572 C1.2226633,16.4127939 11.1796331,1.04797161 39.5335557,1.04797161 C43.4504989,1.04797161 47.2836822,1.40388649 51.0051854,2.07965952 L51.0051854,18.7925385 C48.3109055,18.3796307 45.4351455,18.1446804 42.3476589,18.1446804 C26.763646,18.1446804 19.8371595,26.1516022 19.8371595,39.5681976 L19.8371595,96.2656714 L51.0051854,96.2656714 L51.0051854,111.846834 L19.8371595,111.846834 L19.7766662,145.390067 L19.7766662,145.390067 Z\" id=\"path38\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <path d=\"M646.318899,128.021188 L664.933395,128.021188 L664.933395,236.223966 L646.318899,236.223966 L646.318899,128.021188 L646.318899,128.021188 Z\" id=\"path40\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <path d=\"M646.318899,251.154944 L664.933395,251.154944 L664.933395,269.766036 L646.318899,269.766036 L646.318899,251.154944 L646.318899,251.154944 Z\" id=\"path42\" fill=\"#8C929D\" sketch:type=\"MSShapeGroup\"></path>\n+ <g id=\"g44\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.464170, 0.676006)\">\n+ <path d=\"M429.269989,169.815599 L405.225053,243.802859 L357.571431,390.440955 C355.120288,397.984955 344.444378,397.984955 341.992071,390.440955 L294.337286,243.802859 L136.094873,243.802859 L88.4389245,390.440955 C85.9877812,397.984955 75.3118715,397.984955 72.8595648,390.440955 L25.2059427,243.802859 L1.16216997,169.815599 C-1.03187664,163.067173 1.37156997,155.674379 7.11261982,151.503429 L215.215498,0.336141836 L423.319539,151.503429 C429.060589,155.674379 431.462873,163.067173 429.269989,169.815599\" id=\"path46\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g48\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(135.410135, 1.012147)\">\n+ <path d=\"M80.269998,0 L80.269998,0 L159.391786,243.466717 L1.14820997,243.466717 L80.269998,0 L80.269998,0 Z\" id=\"path50\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g52\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path54\"></g>\n+ </g>\n+ <g id=\"g56\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(24.893471, 1.012613)\">\n+ <path d=\"M190.786662,0 L111.664874,243.465554 L0.777106647,243.465554 L190.786662,0 L190.786662,0 Z\" id=\"path58\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g60\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <g id=\"path62\"></g>\n+ </g>\n+ <g id=\"g64\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(0.077245, 0.223203)\">\n+ <path d=\"M25.5933327,244.255313 L25.5933327,244.255313 L1.54839663,170.268052 C-0.644486651,163.519627 1.75779662,156.126833 7.50000981,151.957046 L215.602888,0.789758846 L25.5933327,244.255313 L25.5933327,244.255313 Z\" id=\"path66\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g68\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012147)\">\n+ <g id=\"path70\"></g>\n+ </g>\n+ <g id=\"g72\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(25.670578, 244.478283)\">\n+ <path d=\"M0,0 L110.887767,0 L63.2329818,146.638096 C60.7806751,154.183259 50.1047654,154.183259 47.6536221,146.638096 L0,0 L0,0 Z\" id=\"path74\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g76\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(215.680133, 1.012613)\">\n+ <path d=\"M0,0 L79.121788,243.465554 L190.009555,243.465554 L0,0 L0,0 Z\" id=\"path78\" fill=\"#FC6D26\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g80\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(214.902910, 0.223203)\">\n+ <path d=\"M190.786662,244.255313 L190.786662,244.255313 L214.831598,170.268052 C217.024481,163.519627 214.622198,156.126833 208.879985,151.957046 L0.777106647,0.789758846 L190.786662,244.255313 L190.786662,244.255313 Z\" id=\"path82\" fill=\"#FCA326\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ <g id=\"g84\" stroke-width=\"1\" fill=\"none\" sketch:type=\"MSLayerGroup\" transform=\"translate(294.009575, 244.478283)\">\n+ <path d=\"M111.679997,0 L0.79222998,0 L48.4470155,146.638096 C50.8993221,154.183259 61.5752318,154.183259 64.0263751,146.638096 L111.679997,0 L111.679997,0 Z\" id=\"path86\" fill=\"#E24329\" sketch:type=\"MSShapeGroup\"></path>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+ </g>\n+</svg>\n\\ No newline at end of file\n","new_path":"files/images/wm.svg","old_path":"files/images/wm.svg","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":7,"utf8_diff":"--- /dev/null\n+++ b/files/lfs/lfs_object.iso\n@@ -0,0 +1,4 @@\n+version https://git-lfs.github.com/spec/v1\n+oid sha256:91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897\n+size 1575078\n+\n","new_path":"files/lfs/lfs_object.iso","old_path":"files/lfs/lfs_object.iso","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":8,"utf8_diff":"--- a/files/ruby/popen.rb\n+++ b/files/ruby/popen.rb\n@@ -6,12 +6,18 @@ module Popen\n \n def popen(cmd, path=nil)\n unless cmd.is_a?(Array)\n- raise \"System commands must be given as an array of strings\"\n+ raise RuntimeError, \"System commands must be given as an array of strings\"\n end\n \n path ||= Dir.pwd\n- vars = { \"PWD\" => path }\n- options = { chdir: path }\n+\n+ vars = {\n+ \"PWD\" => path\n+ }\n+\n+ options = {\n+ chdir: path\n+ }\n \n unless File.directory?(path)\n FileUtils.mkdir_p(path)\n@@ -19,6 +25,7 @@ module Popen\n \n @cmd_output = \"\"\n @cmd_status = 0\n+\n Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr|\n @cmd_output << stdout.read\n @cmd_output << stderr.read\n","new_path":"files/ruby/popen.rb","old_path":"files/ruby/popen.rb","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":9,"utf8_diff":"--- a/files/ruby/regex.rb\n+++ b/files/ruby/regex.rb\n@@ -19,14 +19,12 @@ module Gitlab\n end\n \n def archive_formats_regex\n- #|zip|tar| tar.gz | tar.bz2 |\n- /(zip|tar|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n+ /(zip|tar|7z|tar\\.gz|tgz|gz|tar\\.bz2|tbz|tbz2|tb2|bz2)/\n end\n \n def git_reference_regex\n # Valid git ref regex, see:\n # https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html\n-\n %r{\n (?!\n (?# doesn't begins with)\n","new_path":"files/ruby/regex.rb","old_path":"files/ruby/regex.rb","a_mode":"100644","b_mode":"100644","new_file":false,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":10,"utf8_diff":"--- /dev/null\n+++ b/files/whitespace\n@@ -0,0 +1 @@\n+test \n","new_path":"files/whitespace","old_path":"files/whitespace","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":11,"utf8_diff":"--- /dev/null\n+++ b/foo/bar/.gitkeep\n","new_path":"foo/bar/.gitkeep","old_path":"foo/bar/.gitkeep","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":12,"utf8_diff":"--- /dev/null\n+++ b/gitlab-grack\n@@ -0,0 +1 @@\n+Subproject commit 645f6c4c82fd3f5e06f67134450a570b795e55a6\n","new_path":"gitlab-grack","old_path":"gitlab-grack","a_mode":"0","b_mode":"160000","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":13,"utf8_diff":"--- /dev/null\n+++ b/gitlab-shell\n@@ -0,0 +1 @@\n+Subproject commit 79bceae69cb5750d6567b223597999bfa91cb3b9\n","new_path":"gitlab-shell","old_path":"gitlab-shell","a_mode":"0","b_mode":"160000","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false},{"merge_request_diff_id":10,"relative_order":14,"utf8_diff":"--- /dev/null\n+++ b/test\n","new_path":"test","old_path":"test","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false}],"merge_request_id":10,"created_at":"2016-06-14T15:02:23.019Z","updated_at":"2016-06-14T15:02:23.493Z","base_commit_sha":"ae73cb07c9eeaf35924a10f713b364d32b2dd34f","real_size":"15"},"events":[{"id":228,"target_type":"MergeRequest","target_id":10,"project_id":36,"created_at":"2016-06-14T15:02:23.660Z","updated_at":"2016-06-14T15:02:23.660Z","action":1,"author_id":1},{"id":170,"target_type":"MergeRequest","target_id":10,"project_id":5,"created_at":"2016-06-14T15:02:23.660Z","updated_at":"2016-06-14T15:02:23.660Z","action":1,"author_id":20}]}
+{"id":9,"target_branch":"test-6","source_branch":"test-12","source_project_id":5,"author_id":16,"assignee_id":6,"title":"Et ipsam voluptas velit sequi illum ut.","created_at":"2016-06-14T15:02:22.825Z","updated_at":"2016-06-14T15:03:00.904Z","state":"opened","merge_status":"unchecked","target_project_id":5,"iid":1,"description":"Eveniet nihil ratione veniam similique qui aut sapiente tempora. Sed praesentium iusto dignissimos possimus id repudiandae quo nihil. Qui doloremque autem et iure fugit.","position":0,"updated_by_id":null,"merge_error":null,"merge_params":{"force_remove_source_branch":null},"merge_when_pipeline_succeeds":true,"merge_user_id":null,"merge_commit_sha":null,"notes":[{"id":825,"note":"Aliquid voluptatem consequatur voluptas ex perspiciatis.","noteable_type":"MergeRequest","author_id":26,"created_at":"2016-06-14T15:03:00.722Z","updated_at":"2016-06-14T15:03:00.722Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 4"},"events":[]},{"id":826,"note":"Itaque optio voluptatem praesentium voluptas.","noteable_type":"MergeRequest","author_id":25,"created_at":"2016-06-14T15:03:00.745Z","updated_at":"2016-06-14T15:03:00.745Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 3"},"events":[]},{"id":827,"note":"Ut est corporis fuga asperiores delectus excepturi aperiam.","noteable_type":"MergeRequest","author_id":22,"created_at":"2016-06-14T15:03:00.771Z","updated_at":"2016-06-14T15:03:00.771Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"User 0"},"events":[]},{"id":828,"note":"Similique ea dolore officiis temporibus.","noteable_type":"MergeRequest","author_id":20,"created_at":"2016-06-14T15:03:00.798Z","updated_at":"2016-06-14T15:03:00.798Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ottis Schuster II"},"events":[]},{"id":829,"note":"Qui laudantium qui quae quis.","noteable_type":"MergeRequest","author_id":16,"created_at":"2016-06-14T15:03:00.828Z","updated_at":"2016-06-14T15:03:00.828Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Rhett Emmerich IV"},"events":[]},{"id":830,"note":"Et vel voluptas amet laborum qui soluta.","noteable_type":"MergeRequest","author_id":15,"created_at":"2016-06-14T15:03:00.850Z","updated_at":"2016-06-14T15:03:00.850Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Burdette Bernier"},"events":[]},{"id":831,"note":"Enim ad consequuntur assumenda provident voluptatem similique deleniti.","noteable_type":"MergeRequest","author_id":6,"created_at":"2016-06-14T15:03:00.876Z","updated_at":"2016-06-14T15:03:00.876Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Ari Wintheiser"},"events":[]},{"id":832,"note":"Officiis sequi commodi pariatur totam fugiat voluptas corporis dignissimos.","noteable_type":"MergeRequest","author_id":1,"created_at":"2016-06-14T15:03:00.902Z","updated_at":"2016-06-14T15:03:00.902Z","project_id":5,"attachment":{"url":null},"line_code":null,"commit_id":null,"noteable_id":9,"system":false,"st_diff":null,"updated_by_id":null,"author":{"name":"Administrator"},"events":[]}],"merge_request_diff":{"id":9,"state":"collected","merge_request_diff_commits":[{"merge_request_diff_id":9,"relative_order":0,"sha":"a4e5dfebf42e34596526acb8611bc7ed80e4eb3f","message":"fixes #10\n","authored_date":"2016-01-19T15:44:02.000+01:00","committed_date":"2016-01-19T15:44:02.000+01:00","commit_author":{"name":"James Lopez","email":"james@jameslopez.es"},"committer":{"name":"James Lopez","email":"james@jameslopez.es"}}],"merge_request_diff_files":[{"merge_request_diff_id":9,"relative_order":0,"utf8_diff":"--- /dev/null\n+++ b/test\n","new_path":"test","old_path":"test","a_mode":"0","b_mode":"100644","new_file":true,"renamed_file":false,"deleted_file":false,"too_large":false}],"merge_request_id":9,"created_at":"2016-06-14T15:02:22.829Z","updated_at":"2016-06-14T15:02:22.900Z","base_commit_sha":"be93687618e4b132087f430a4d8fc3a609c9b77c","real_size":"1"},"events":[{"id":229,"target_type":"MergeRequest","target_id":9,"project_id":36,"created_at":"2016-06-14T15:02:22.927Z","updated_at":"2016-06-14T15:02:22.927Z","action":1,"author_id":16},{"id":169,"target_type":"MergeRequest","target_id":9,"project_id":5,"created_at":"2016-06-14T15:02:22.927Z","updated_at":"2016-06-14T15:02:22.927Z","action":1,"author_id":16}]}
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index b6c8653a563..3614cbe5011 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -234,4 +234,43 @@ RSpec.describe MergeRequestsHelper, feature_category: :code_review_workflow do
it { expect(tab_count_display(merge_request, '10')).to eq('10') }
end
end
+
+ describe '#allow_collaboration_unavailable_reason' do
+ subject { allow_collaboration_unavailable_reason(merge_request) }
+
+ let(:merge_request) do
+ create(:merge_request, author: author, source_project: project, source_branch: generate(:branch))
+ end
+
+ let_it_be(:public_project) { create(:project, :small_repo, :public) }
+ let(:project) { public_project }
+ let(:forked_project) { fork_project(project) }
+ let(:author) { project.creator }
+
+ context 'when the merge request allows collaboration for the user' do
+ before do
+ allow(merge_request).to receive(:can_allow_collaboration?).with(current_user).and_return(true)
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when the project is private' do
+ let(:project) { create(:project, :empty_repo, :private) }
+
+ it { is_expected.to eq(_('Not available for private projects')) }
+ end
+
+ context 'when the source branch is protected' do
+ let!(:protected_branch) { create(:protected_branch, project: project, name: merge_request.source_branch) }
+
+ it { is_expected.to eq(_('Not available for protected branches')) }
+ end
+
+ context 'when the merge request author cannot push to the source project' do
+ let(:author) { create(:user) }
+
+ it { is_expected.to eq(_('Merge request author cannot push to target project')) }
+ end
+ end
end
diff --git a/spec/helpers/projects/ml/experiments_helper_spec.rb b/spec/helpers/projects/ml/experiments_helper_spec.rb
index 021d518a329..569fd0f9ec5 100644
--- a/spec/helpers/projects/ml/experiments_helper_spec.rb
+++ b/spec/helpers/projects/ml/experiments_helper_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe Projects::Ml::ExperimentsHelper, feature_category: :mlops do
let_it_be(:candidates) { [candidate0, candidate1] }
describe '#candidates_table_items' do
- subject { Gitlab::Json.parse(helper.candidates_table_items(candidates)) }
+ subject { Gitlab::Json.parse(helper.candidates_table_items(candidates, project.creator)) }
it 'creates the correct model for the table', :aggregate_failures do
expected_values = [
@@ -72,6 +72,18 @@ RSpec.describe Projects::Ml::ExperimentsHelper, feature_category: :mlops do
expect(subject[0]['user']).to be_nil
end
end
+
+ context 'when user is not allowed to read the project' do
+ before do
+ allow(Ability).to receive(:allowed?)
+ .with(project.creator, :read_build, build)
+ .and_return(false)
+ end
+
+ it 'does not include ci info' do
+ expect(subject[0]['ci_job']).to be_nil
+ end
+ end
end
describe '#unique_logged_names' do
diff --git a/spec/lib/banzai/filter/asset_proxy_filter_spec.rb b/spec/lib/banzai/filter/asset_proxy_filter_spec.rb
index dc6ac52a8c2..7a34bf13c8f 100644
--- a/spec/lib/banzai/filter/asset_proxy_filter_spec.rb
+++ b/spec/lib/banzai/filter/asset_proxy_filter_spec.rb
@@ -89,6 +89,33 @@ RSpec.describe Banzai::Filter::AssetProxyFilter, feature_category: :team_plannin
expect(doc.at_css('img')['data-canonical-src']).to eq src
end
+ it 'replaces by default, even strings that do not look like URLs' do
+ src = 'oigjsie8787%$**(#(%0'
+ new_src = 'https://assets.example.com/1b893f9a71d66c99437f27e19b9a061a6f5d9391/6f69676a7369653837383725242a2a2823282530'
+ doc = filter(image(src), @context)
+
+ expect(doc.at_css('img')['src']).to eq new_src
+ expect(doc.at_css('img')['data-canonical-src']).to eq src
+ end
+
+ it 'replaces URL with non-ASCII characters' do
+ src = 'https://example.com/x?¬'
+ new_src = 'https://assets.example.com/2f29a8c7f13f3ae14dc18c154dbbd657d703e75f/68747470733a2f2f6578616d706c652e636f6d2f783fc2ac'
+ doc = filter(image(src), @context)
+
+ expect(doc.at_css('img')['src']).to eq new_src
+ expect(doc.at_css('img')['data-canonical-src']).to eq src
+ end
+
+ it 'replaces out-of-spec URL that would still be rendered in the browser' do
+ src = 'https://example.com/##'
+ new_src = 'https://assets.example.com/d7d0c845cc553d9430804c07e9456545ef3e6fe6/68747470733a2f2f6578616d706c652e636f6d2f2323'
+ doc = filter(image(src), @context)
+
+ expect(doc.at_css('img')['src']).to eq new_src
+ expect(doc.at_css('img')['data-canonical-src']).to eq src
+ end
+
it 'skips internal images' do
src = "#{Gitlab.config.gitlab.url}/test.png"
doc = filter(image(src), @context)
diff --git a/spec/lib/gitlab/checks/tag_check_spec.rb b/spec/lib/gitlab/checks/tag_check_spec.rb
index e75b0459337..60d3eb4bfb3 100644
--- a/spec/lib/gitlab/checks/tag_check_spec.rb
+++ b/spec/lib/gitlab/checks/tag_check_spec.rb
@@ -15,6 +15,12 @@ RSpec.describe Gitlab::Checks::TagCheck, feature_category: :source_code_manageme
end
context "prohibited tags check" do
+ it 'prohibits tags name that include refs/heads at the head' do
+ allow(subject).to receive(:tag_name).and_return("refs/heads/foo")
+
+ expect { subject.validate! }.to raise_error(Gitlab::GitAccess::ForbiddenError, "You cannot create a tag with a prohibited pattern.")
+ end
+
it "prohibits tag names that include refs/tags/ at the head" do
allow(subject).to receive(:tag_name).and_return("refs/tags/foo")
diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb
index b238e9161eb..4196aad2db4 100644
--- a/spec/lib/gitlab/ci/lint_spec.rb
+++ b/spec/lib/gitlab/ci/lint_spec.rb
@@ -6,8 +6,9 @@ RSpec.describe Gitlab::Ci::Lint, feature_category: :pipeline_composition do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user) }
- let(:lint) { described_class.new(project: project, current_user: user) }
+ let(:sha) { nil }
let(:ref) { project.default_branch }
+ let(:lint) { described_class.new(project: project, current_user: user, sha: sha) }
describe '#validate' do
subject { lint.validate(content, dry_run: dry_run, ref: ref) }
@@ -250,6 +251,59 @@ RSpec.describe Gitlab::Ci::Lint, feature_category: :pipeline_composition do
subject
end
+
+ context 'when sha is provided' do
+ let(:sha) { project.commit.sha }
+
+ it 'runs YamlProcessor with verify_project_sha: true' do
+ expect(Gitlab::Ci::YamlProcessor)
+ .to receive(:new)
+ .with(content, a_hash_including(verify_project_sha: true))
+ .and_call_original
+
+ subject
+ end
+
+ it_behaves_like 'content is valid'
+
+ context 'when the sha is invalid' do
+ let(:sha) { 'invalid-sha' }
+
+ it_behaves_like 'content is valid'
+ end
+
+ context 'when the sha is from a fork' do
+ include_context 'when a project repository contains a forked commit'
+
+ let(:sha) { forked_commit_sha }
+
+ context 'when a project ref contains the sha' do
+ before do
+ mock_branch_contains_forked_commit_sha
+ end
+
+ it_behaves_like 'content is valid'
+ end
+
+ context 'when a project ref does not contain the sha' do
+ it 'returns an error' do
+ expect(subject).not_to be_valid
+ expect(subject.errors).to include(/Could not validate configuration/)
+ end
+ end
+ end
+ end
+
+ context 'when sha is not provided' do
+ it 'runs YamlProcessor with verify_project_sha: false' do
+ expect(Gitlab::Ci::YamlProcessor)
+ .to receive(:new)
+ .with(content, a_hash_including(verify_project_sha: false))
+ .and_call_original
+
+ subject
+ end
+ end
end
context 'when using dry run mode' do
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index c09c0b31e97..5cfd8d9b9fb 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -3607,6 +3607,88 @@ module Gitlab
end
end
end
+
+ describe 'verify project sha', :use_clean_rails_redis_caching do
+ include_context 'when a project repository contains a forked commit'
+
+ let(:config) { YAML.dump(job: { script: 'echo' }) }
+ let(:verify_project_sha) { true }
+ let(:sha) { forked_commit_sha }
+
+ let(:processor) { described_class.new(config, project: project, sha: sha, verify_project_sha: verify_project_sha) }
+
+ subject { processor.execute }
+
+ shared_examples 'when the processor is executed twice consecutively' do |branch_names_contains_sha = false|
+ it 'calls Gitaly only once for each ref type' do
+ expect(repository).to receive(:branch_names_contains).once.and_call_original
+ expect(repository).to receive(:tag_names_contains).once.and_call_original unless branch_names_contains_sha
+
+ 2.times { processor.execute }
+ end
+ end
+
+ context 'when a project branch contains the forked commit sha' do
+ before_all do
+ repository.add_branch(project.owner, 'branch1', forked_commit_sha)
+ end
+
+ after(:all) do
+ repository.rm_branch(project.owner, 'branch1')
+ end
+
+ it { is_expected.to be_valid }
+
+ it_behaves_like 'when the processor is executed twice consecutively', true
+ end
+
+ context 'when a project tag contains the forked commit sha' do
+ before_all do
+ repository.add_tag(project.owner, 'tag1', forked_commit_sha)
+ end
+
+ after(:all) do
+ repository.rm_tag(project.owner, 'tag1')
+ end
+
+ it { is_expected.to be_valid }
+
+ it_behaves_like 'when the processor is executed twice consecutively'
+ end
+
+ context 'when a project ref does not contain the forked commit sha' do
+ it 'returns an error' do
+ is_expected.not_to be_valid
+ expect(subject.errors).to include(/Could not validate configuration/)
+ end
+
+ it_behaves_like 'when the processor is executed twice consecutively'
+ end
+
+ context 'when verify_project_sha option is false' do
+ let(:verify_project_sha) { false }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when project is not provided' do
+ let(:project) { nil }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when sha is not provided' do
+ let(:sha) { nil }
+
+ it { is_expected.to be_valid }
+ end
+
+ context 'when sha is invalid' do
+ let(:sha) { 'invalid-sha' }
+
+ it { is_expected.to be_valid }
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
index 7252457849e..5e9fed32c4e 100644
--- a/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
+++ b/spec/lib/gitlab/import_export/project/relation_factory_spec.rb
@@ -172,6 +172,10 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
it 'has preloaded target project' do
expect(created_object.target_project).to equal(project)
end
+
+ it 'has MWPS set to false' do
+ expect(created_object.merge_when_pipeline_succeeds).to eq(false)
+ end
end
context 'issue object' do
@@ -297,6 +301,38 @@ RSpec.describe Gitlab::ImportExport::Project::RelationFactory, :use_clean_rails_
end
end
+ context 'pipeline setup' do
+ let(:relation_sym) { :ci_pipelines }
+ let(:relation_hash) do
+ {
+ "id" => 1,
+ "status" => status
+ }
+ end
+
+ subject { created_object }
+
+ ::Ci::HasStatus::COMPLETED_STATUSES.each do |status|
+ context "when relation_hash has a completed status of #{status}}" do
+ let(:status) { status }
+
+ it "does not change the created object status" do
+ expect(created_object.status).to eq(status)
+ end
+ end
+ end
+
+ ::Ci::HasStatus::CANCELABLE_STATUSES.each do |status|
+ context "when relation_hash has cancelable status of #{status}}" do
+ let(:status) { status }
+
+ it "sets the created object status to canceled" do
+ expect(created_object.status).to eq('canceled')
+ end
+ end
+ end
+ end
+
context 'pipeline_schedule' do
let(:relation_sym) { :pipeline_schedules }
let(:relation_hash) do
diff --git a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
index c83cfb0e2f5..b0bc31e366e 100644
--- a/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_restorer_spec.rb
@@ -135,6 +135,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
expect(pipeline.merge_request.id).to be > 0
expect(pipeline.merge_request.target_branch).to eq('feature')
expect(pipeline.merge_request.source_branch).to eq('feature_conflict')
+ expect(pipeline.merge_request.merge_when_pipeline_succeeds).to eq(false)
end
it 'restores pipelines based on ascending id order' do
@@ -146,6 +147,9 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
5f923865dde3436854e9ceb9cdb7815618d4e849
d2d430676773caa88cdaf7c55944073b2fd5561a
2ea1f3dec713d940208fb5ce4a38765ecb5d3f73
+ 1b6c4f044c63217d1ed06e514c84d22871bed912
+ ded178474ef2ba1f80a9964ba15da3ddb3cf664b
+ fd459e5c514d70dc525c5e70990ca5e0debb3105
]
project = Project.find_by_path('project')
@@ -297,6 +301,12 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
end
end
+ it 'sets MWPS to false for all merge requests' do
+ MergeRequest.find_each do |merge_request|
+ expect(merge_request.merge_when_pipeline_succeeds).to eq(false)
+ end
+ end
+
it 'has multiple merge request assignees' do
expect(MergeRequest.find_by(title: 'MR1').assignees).to contain_exactly(@user, *@existing_members)
expect(MergeRequest.find_by(title: 'MR2').assignees).to be_empty
@@ -545,9 +555,9 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
end
it 'has the correct number of pipelines and statuses' do
- expect(@project.ci_pipelines.size).to eq(7)
+ expect(@project.ci_pipelines.size).to eq(10)
- @project.ci_pipelines.order(:id).zip([2, 0, 2, 3, 2, 2, 0])
+ @project.ci_pipelines.order(:id).zip([2, 0, 2, 3, 2, 8, 0, 0, 0, 0])
.each do |(pipeline, expected_status_size)|
expect(pipeline.statuses.size).to eq(expected_status_size)
end
@@ -555,28 +565,58 @@ RSpec.describe Gitlab::ImportExport::Project::TreeRestorer, feature_category: :i
end
context 'when restoring hierarchy of pipeline, stages and jobs' do
- it 'restores pipelines' do
- expect(Ci::Pipeline.all.count).to be 7
- end
+ context 'pipelines' do
+ it 'restores pipelines' do
+ expect(Ci::Pipeline.all.count).to be 10
+ end
- it 'restores pipeline stages' do
- expect(Ci::Stage.all.count).to be 6
+ it 'marks cancelable pipelines as canceled' do
+ expect(Ci::Pipeline.where(status: 'canceled').count).to eq 7
+ end
end
- it 'correctly restores association between stage and a pipeline' do
- expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0))
+ context 'stages' do
+ it 'restores pipeline stages' do
+ expect(Ci::Stage.all.count).to be 7
+ end
+
+ it 'marks cancelable stages as canceled' do
+ expect(Ci::Stage.where(status: 'canceled').count).to eq 6
+ end
+
+ it 'correctly restores association between stage and a pipeline' do
+ expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0))
+ end
end
- it 'restores builds' do
- expect(Ci::Build.all.count).to be 7
+ context 'builds' do
+ it 'restores builds' do
+ expect(Ci::Build.all.count).to be 7
+ end
+
+ it 'marks cancelable builds as canceled' do
+ expect(Ci::Build.where(status: 'canceled').count).to eq 3
+ end
end
- it 'restores bridges' do
- expect(Ci::Bridge.all.count).to be 1
+ context 'bridges' do
+ it 'restores bridges' do
+ expect(Ci::Bridge.all.count).to be 5
+ end
+
+ it 'marks cancelable bridges as canceled' do
+ expect(Ci::Bridge.where(status: 'canceled').count).to eq 4
+ end
end
- it 'restores generic commit statuses' do
- expect(GenericCommitStatus.all.count).to be 1
+ context 'generic commit statuses' do
+ it 'restores generic commit statuses' do
+ expect(GenericCommitStatus.all.count).to be 3
+ end
+
+ it 'marks cancelable generic commit statuses as canceled' do
+ expect(GenericCommitStatus.where(status: 'canceled').count).to eq 2
+ end
end
it 'correctly restores association between a stage and a job' do
diff --git a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
index aa8290d7a05..abb781b277b 100644
--- a/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project/tree_saver_spec.rb
@@ -127,6 +127,10 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_
expect(system_notes.size).to eq(1)
expect(system_notes.first['note']).to eq('merged')
end
+
+ it 'has no merge_when_pipeline_succeeds' do
+ expect(subject.first['merge_when_pipeline_succeeds']).to be_nil
+ end
end
context 'with snippets' do
@@ -301,6 +305,14 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_
it { is_expected.not_to be_empty }
end
+
+ context 'with pipeline schedules' do
+ let(:relation_name) { :pipeline_schedules }
+
+ it 'has no owner_id' do
+ expect(subject.first['owner_id']).to be_nil
+ end
+ end
end
describe '#saves project tree' do
@@ -535,6 +547,7 @@ RSpec.describe Gitlab::ImportExport::Project::TreeSaver, :with_license, feature_
design = create(:design, :with_file, versions_count: 2, issue: issue)
create(:diff_note_on_design, noteable: design, project: project, author: user)
+ create(:ci_pipeline_schedule, project: project, owner: user)
project
end
diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
index 803614d90a5..36b75e5338a 100644
--- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
+++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe BlobViewer::GitlabCiYml do
+RSpec.describe BlobViewer::GitlabCiYml, feature_category: :source_code_management do
include FakeBlobHelpers
include RepoHelpers
@@ -13,18 +13,20 @@ RSpec.describe BlobViewer::GitlabCiYml do
let(:blob) { fake_blob(path: '.gitlab-ci.yml', data: data) }
let(:sha) { sample_commit.id }
- subject { described_class.new(blob) }
+ subject(:blob_viewer) { described_class.new(blob) }
describe '#validation_message' do
+ subject(:validation_message) { blob_viewer.validation_message(project: project, sha: sha, user: user) }
+
it 'calls prepare! on the viewer' do
- expect(subject).to receive(:prepare!)
+ expect(blob_viewer).to receive(:prepare!)
- subject.validation_message(project: project, sha: sha, user: user)
+ validation_message
end
context 'when the configuration is valid' do
it 'returns nil' do
- expect(subject.validation_message(project: project, sha: sha, user: user)).to be_nil
+ expect(validation_message).to be_nil
end
end
@@ -32,7 +34,29 @@ RSpec.describe BlobViewer::GitlabCiYml do
let(:data) { 'oof' }
it 'returns the error message' do
- expect(subject.validation_message(project: project, sha: sha, user: user)).to eq('Invalid configuration format')
+ expect(validation_message).to eq('Invalid configuration format')
+ end
+ end
+
+ context 'when the sha is from a fork' do
+ include_context 'when a project repository contains a forked commit'
+
+ let(:sha) { forked_commit_sha }
+
+ context 'when a project ref contains the sha' do
+ before do
+ mock_branch_contains_forked_commit_sha
+ end
+
+ it 'returns nil' do
+ expect(validation_message).to be_nil
+ end
+ end
+
+ context 'when a project ref does not contain the sha' do
+ it 'returns an error' do
+ expect(validation_message).to match(/Could not validate configuration/)
+ end
end
end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 3f671fc3f70..ddeab16908d 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -1511,6 +1511,45 @@ RSpec.describe Group, feature_category: :groups_and_projects do
it { expect(subject.parent).to be_kind_of(described_class) }
end
+ describe '#member?' do
+ let_it_be(:group) { create(:group) }
+ let_it_be(:user) { create(:user) }
+
+ before_all do
+ group.add_developer(user)
+ end
+
+ subject { group.member?(user) }
+
+ context 'when user is a developer' do
+ it 'returns true' do
+ expect(group.member?(user)).to be_truthy
+ end
+
+ it 'returns false with maintainer as min_access_level param' do
+ expect(group.member?(user, Gitlab::Access::MAINTAINER)).to be_falsey
+ end
+ end
+
+ context 'in shared group' do
+ let(:shared_group) { create(:group) }
+ let(:member_shared) { create(:user) }
+
+ before do
+ create(:group_group_link, shared_group: group, shared_with_group: shared_group)
+ shared_group.add_developer(member_shared)
+ end
+
+ it 'return true for shared group member' do
+ expect(group.member?(member_shared)).to be_truthy
+ end
+
+ it 'returns false with maintainer as min_access_level param' do
+ expect(group.member?(member_shared, Gitlab::Access::MAINTAINER)).to be_falsey
+ end
+ end
+ end
+
describe '#max_member_access_for_user' do
let_it_be(:group_user) { create(:user) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index aedfc7fca53..46bf80b1e8f 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -6438,6 +6438,8 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
let!(:merge_request) do
create(
:merge_request,
+ author: author,
+ state_id: state_id,
target_project: target_project,
target_branch: 'target-branch',
source_project: project,
@@ -6446,6 +6448,9 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
)
end
+ let(:author) { project.creator }
+ let(:state_id) { MergeRequest.available_states[:opened] }
+
before do
target_project.add_developer(user)
end
@@ -6455,10 +6460,12 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
expect(project.merge_requests_allowing_push_to_user(user)).to include(merge_request)
end
- it 'does not include closed merge requests' do
- merge_request.close
+ context 'when the merge requests are closed' do
+ let(:state_id) { MergeRequest.available_states[:closed] }
- expect(project.merge_requests_allowing_push_to_user(user)).to be_empty
+ it 'does not include closed merge requests' do
+ expect(project.merge_requests_allowing_push_to_user(user)).to be_empty
+ end
end
it 'does not include merge requests for guest users' do
@@ -6480,16 +6487,38 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
end
describe '#any_branch_allows_collaboration?' do
- it 'allows access when there are merge requests open allowing collaboration', :sidekiq_might_not_need_inline do
- expect(project.any_branch_allows_collaboration?(user))
- .to be_truthy
- end
+ context 'when there is an open merge request allowing collaboration' do
+ it 'allows access', :sidekiq_might_not_need_inline do
+ expect(project.any_branch_allows_collaboration?(user))
+ .to be_truthy
+ end
+
+ context 'when the merge request author is not allowed to push_code' do
+ let(:author) { create(:user) }
- it 'does not allow access when there are no merge requests open allowing collaboration' do
- merge_request.close!
+ it 'returns false' do
+ expect(project.any_branch_allows_collaboration?(user))
+ .to be_falsey
+ end
+ end
- expect(project.any_branch_allows_collaboration?(user))
- .to be_falsey
+ context 'when the merge request is closed' do
+ let(:state_id) { MergeRequest.available_states[:closed] }
+
+ it 'returns false' do
+ expect(project.any_branch_allows_collaboration?(user))
+ .to be_falsey
+ end
+ end
+
+ context 'when the merge request is merged' do
+ let(:state_id) { MergeRequest.available_states[:merged] }
+
+ it 'returns false' do
+ expect(project.any_branch_allows_collaboration?(user))
+ .to be_falsey
+ end
+ end
end
end
@@ -6537,6 +6566,15 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
.not_to exceed_query_limit(control).with_threshold(2)
end
end
+
+ context 'when the merge request author is not allowed to push_code' do
+ let(:author) { create(:user) }
+
+ it 'returns false' do
+ expect(project.branch_allows_collaboration?(user, 'awesome-feature-1'))
+ .to be_falsey
+ end
+ end
end
end
diff --git a/spec/presenters/ml/candidate_details_presenter_spec.rb b/spec/presenters/ml/candidate_details_presenter_spec.rb
index 9d1f6f634e4..0ecf80b683e 100644
--- a/spec/presenters/ml/candidate_details_presenter_spec.rb
+++ b/spec/presenters/ml/candidate_details_presenter_spec.rb
@@ -25,7 +25,9 @@ RSpec.describe ::Ml::CandidateDetailsPresenter, feature_category: :mlops do
]
end
- subject { Gitlab::Json.parse(described_class.new(candidate).present)['candidate'] }
+ let(:include_ci_job) { true }
+
+ subject { Gitlab::Json.parse(described_class.new(candidate, include_ci_job).present)['candidate'] }
before do
allow(candidate).to receive(:latest_metrics).and_return(metrics)
@@ -68,6 +70,8 @@ RSpec.describe ::Ml::CandidateDetailsPresenter, feature_category: :mlops do
let_it_be(:pipeline) { build_stubbed(:ci_pipeline, project: project, user: user) }
let_it_be(:build) { candidate.ci_build = build_stubbed(:ci_build, pipeline: pipeline, user: user) }
+ let(:can_read_build) { true }
+
it 'generates the correct ci' do
expected_info = {
'path' => "/#{project.full_path}/-/jobs/#{build.id}",
@@ -109,6 +113,14 @@ RSpec.describe ::Ml::CandidateDetailsPresenter, feature_category: :mlops do
expect(subject.dig('info', 'ci_job', 'merge_request')).to include(expected_info)
end
end
+
+ context 'when ci job is not to be added' do
+ let(:include_ci_job) { false }
+
+ it 'ci_job is nil' do
+ expect(subject.dig('info', 'ci_job')).to be_nil
+ end
+ end
end
end
end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 8b9ac7cd588..90595c2d7f9 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -774,6 +774,62 @@ RSpec.describe API::Commits, feature_category: :source_code_management do
end
end
+ context 'when project repository access becomes restricted after being forked' do
+ let!(:fork_owner) { create(:user) }
+ let!(:forked_project) { fork_project(public_project, fork_owner, namespace: fork_owner.namespace, repository: true) }
+ let(:url) { "/projects/#{forked_project.id}/repository/commits" }
+
+ before do
+ # Restrict repository visibility of the public project
+ public_project.merge_requests_access_level = 'private'
+ public_project.builds_access_level = 'private'
+ public_project.repository_access_level = 'private'
+ public_project.save!
+
+ valid_c_params[:start_branch] = 'master'
+ valid_c_params[:branch] = 'patch'
+ valid_c_params[:start_project] = public_project.id
+ end
+
+ after do
+ # Reopen repository visibility of the public project
+ public_project.merge_requests_access_level = 'enabled'
+ public_project.repository_access_level = 'enabled'
+ public_project.builds_access_level = 'enabled'
+ public_project.save!
+ end
+
+ it 'returns a 403' do
+ post api(url, fork_owner), params: valid_c_params
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'when fork owner has no more access to a private repository' do
+ let_it_be(:private_project) { create(:project, :private, :repository) }
+ let_it_be(:fork_owner) { create(:user) }
+ let_it_be(:fork_owner_membership) { private_project.add_developer(fork_owner) }
+ let_it_be(:forked_project) { fork_project(private_project, fork_owner, namespace: fork_owner.namespace, repository: true) }
+ let(:url) { "/projects/#{forked_project.id}/repository/commits" }
+
+ before do
+ # Restrict user from repository
+ Members::DestroyService.new(private_project.owner).execute(fork_owner_membership)
+ Sidekiq::Worker.drain_all
+
+ valid_c_params[:start_branch] = 'master'
+ valid_c_params[:branch] = 'patch'
+ valid_c_params[:start_project] = private_project.id
+ end
+
+ it 'returns a 402' do
+ post api(url, fork_owner), params: valid_c_params
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
context 'when the target project is not part of the fork network of start_project' do
let(:unrelated_project) { create(:project, :public, :repository, creator: guest) }
let(:url) { "/projects/#{unrelated_project.id}/repository/commits" }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index e3e8df79a1d..12898060e22 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -3292,6 +3292,10 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
let(:failed_status_code) { :not_found }
end
+ it 'refreshes the forks count cache' do
+ expect(project_fork_source.forks_count).to be_zero
+ end
+
context 'user is a developer' do
before do
project_fork_target.add_developer(user)
@@ -3304,15 +3308,23 @@ RSpec.describe API::Projects, :aggregate_failures, feature_category: :groups_and
end
end
- it 'refreshes the forks count cache' do
- expect(project_fork_source.forks_count).to be_zero
- end
-
context 'user is maintainer' do
before do
project_fork_target.add_maintainer(user)
end
+ it 'denies project to be forked from an existing project' do
+ post api(path, user)
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
+
+ context 'user is owner' do
+ before do
+ project_fork_target.add_owner(user)
+ end
+
context 'and user is a reporter of target group' do
let_it_be_with_reload(:target_group) { create(:group, project_creation_level: ::Gitlab::Access::DEVELOPER_MAINTAINER_PROJECT_ACCESS) }
let_it_be_with_reload(:project_fork_target) { create(:project, namespace: target_group) }
diff --git a/spec/requests/projects/ml/candidates_controller_spec.rb b/spec/requests/projects/ml/candidates_controller_spec.rb
index 4c7491970e1..78f31be26d1 100644
--- a/spec/requests/projects/ml/candidates_controller_spec.rb
+++ b/spec/requests/projects/ml/candidates_controller_spec.rb
@@ -6,7 +6,11 @@ RSpec.describe Projects::Ml::CandidatesController, feature_category: :mlops do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { project.first_owner }
let_it_be(:experiment) { create(:ml_experiments, project: project, user: user) }
- let_it_be(:candidate) { create(:ml_candidates, experiment: experiment, user: user, project: project) }
+ let_it_be(:candidate) do
+ create(:ml_candidates, experiment: experiment, user: user, project: project).tap do |c|
+ c.update!(ci_build: create(:ci_build))
+ end
+ end
let(:ff_value) { true }
let(:candidate_iid) { candidate.iid }
@@ -47,7 +51,13 @@ RSpec.describe Projects::Ml::CandidatesController, feature_category: :mlops do
end
describe 'GET show' do
+ let(:can_read_build) { true }
+
before do
+ allow(Ability).to receive(:allowed?)
+ .with(user, :read_build, candidate.ci_build)
+ .and_return(can_read_build)
+
show_candidate
end
@@ -64,6 +74,20 @@ RSpec.describe Projects::Ml::CandidatesController, feature_category: :mlops do
expect { show_candidate }.not_to exceed_all_query_limit(control_count)
end
+ context 'when user has permission to read the build' do
+ it 'includes ci build info' do
+ expect(assigns[:include_ci_info]).to eq(true)
+ end
+ end
+
+ context 'when user has no permission to read the build' do
+ let(:can_read_build) { false }
+
+ it 'sets include_ci_job to false' do
+ expect(assigns[:include_ci_info]).to eq(false)
+ end
+ end
+
it_behaves_like '404 if candidate does not exist'
it_behaves_like 'requires read_model_experiments'
end
diff --git a/spec/services/ci/list_config_variables_service_spec.rb b/spec/services/ci/list_config_variables_service_spec.rb
index 07c9085b83a..ccc8b77f6b2 100644
--- a/spec/services/ci/list_config_variables_service_spec.rb
+++ b/spec/services/ci/list_config_variables_service_spec.rb
@@ -32,15 +32,50 @@ RSpec.describe Ci::ListConfigVariablesService,
}
end
+ let(:expected_result) do
+ {
+ 'KEY1' => { value: 'val 1', description: 'description 1' },
+ 'KEY2' => { value: 'val 2', description: '' },
+ 'KEY3' => { value: 'val 3' },
+ 'KEY4' => { value: 'val 4' }
+ }
+ end
+
before do
synchronous_reactive_cache(service)
end
- it 'returns variable list' do
- expect(result['KEY1']).to eq({ value: 'val 1', description: 'description 1' })
- expect(result['KEY2']).to eq({ value: 'val 2', description: '' })
- expect(result['KEY3']).to eq({ value: 'val 3' })
- expect(result['KEY4']).to eq({ value: 'val 4' })
+ it 'returns variables list' do
+ expect(result).to eq(expected_result)
+ end
+
+ context 'when the ref is a sha from a fork' do
+ include_context 'when a project repository contains a forked commit'
+
+ before do
+ allow_next_instance_of(Gitlab::Ci::ProjectConfig) do |instance|
+ allow(instance).to receive(:exists?).and_return(true)
+ allow(instance).to receive(:content).and_return(YAML.dump(ci_config))
+ end
+ end
+
+ let(:ref) { forked_commit_sha }
+
+ context 'when a project ref contains the sha' do
+ before do
+ mock_branch_contains_forked_commit_sha
+ end
+
+ it 'returns variables list' do
+ expect(result).to eq(expected_result)
+ end
+ end
+
+ context 'when a project ref does not contain the sha' do
+ it 'returns empty response' do
+ expect(result).to eq({})
+ end
+ end
end
end
diff --git a/spec/services/error_tracking/list_projects_service_spec.rb b/spec/services/error_tracking/list_projects_service_spec.rb
index d91808edc8d..53dbbfd8c71 100644
--- a/spec/services/error_tracking/list_projects_service_spec.rb
+++ b/spec/services/error_tracking/list_projects_service_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe ErrorTracking::ListProjectsService, feature_category: :integratio
subject { described_class.new(project, user, params) }
before do
- project.add_reporter(user)
+ project.add_maintainer(user)
end
describe '#execute' do
@@ -137,6 +137,16 @@ RSpec.describe ErrorTracking::ListProjectsService, feature_category: :integratio
end
end
+ context 'with user with insufficient permissions' do
+ before do
+ project.add_developer(user)
+ end
+
+ it 'returns error' do
+ expect(result).to include(status: :error, message: 'Access denied', http_status: :unauthorized)
+ end
+ end
+
context 'with error tracking disabled' do
before do
expect(project).to receive(:error_tracking_setting).at_least(:once)
diff --git a/spec/support/shared_contexts/ci/yaml_processor_shared_context.rb b/spec/support/shared_contexts/ci/yaml_processor_shared_context.rb
new file mode 100644
index 00000000000..3b4d6fcef6f
--- /dev/null
+++ b/spec/support/shared_contexts/ci/yaml_processor_shared_context.rb
@@ -0,0 +1,22 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'when a project repository contains a forked commit' do
+ include ProjectForksHelper
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:repository) { project.repository }
+ let_it_be(:forked_project) { fork_project(project, project.owner, repository: true) }
+
+ let_it_be(:forked_commit_sha) do
+ forked_project.repository.create_file(project.owner, 'file.txt', 'file', message: 'test', branch_name: 'master')
+ end
+
+ before_all do
+ # Creating this MR moves the forked commit to the project repository
+ create(:merge_request, source_project: forked_project, target_project: project)
+ end
+
+ def mock_branch_contains_forked_commit_sha
+ allow(repository).to receive(:branch_names_contains).with(forked_commit_sha, limit: 1).and_return(['branch1'])
+ end
+end