Commit bc97513a authored by Douwe Maan's avatar Douwe Maan

Merge branch 'ce-to-ee-2017-07-07' into 'master'

CE upstream: Friday

See merge request !2376
parents 5c864443 4fd2dc3e
9.3.0-pre 9.4.0-pre
...@@ -105,9 +105,9 @@ ...@@ -105,9 +105,9 @@
this.measurements = measurements.small; this.measurements = measurements.small;
} }
this.data = query.result[0].values; this.data = query.result[0].values;
this.unitOfDisplay = query.unit || 'N/A'; this.unitOfDisplay = query.unit || '';
this.yAxisLabel = this.columnData.y_label || 'Values'; this.yAxisLabel = this.columnData.y_label || 'Values';
this.legendTitle = query.legend || 'Average'; this.legendTitle = query.label || 'Average';
this.graphWidth = this.$refs.baseSvg.clientWidth - this.graphWidth = this.$refs.baseSvg.clientWidth -
this.margin.left - this.margin.right; this.margin.left - this.margin.right;
this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom; this.graphHeight = this.graphHeight - this.margin.top - this.margin.bottom;
......
...@@ -731,11 +731,11 @@ ...@@ -731,11 +731,11 @@
.merge-request-tabs-holder { .merge-request-tabs-holder {
top: $header-height; top: $header-height;
z-index: 100; z-index: 200;
background-color: $white-light; background-color: $white-light;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
@media(min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
position: sticky; position: sticky;
position: -webkit-sticky; position: -webkit-sticky;
} }
...@@ -770,6 +770,12 @@ ...@@ -770,6 +770,12 @@
max-width: $limited-layout-width; max-width: $limited-layout-width;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
.inner-page-scroll-tabs {
background-color: $white-light;
margin-left: -$gl-padding;
padding-left: $gl-padding;
}
} }
} }
......
...@@ -47,7 +47,7 @@ module IssuableCollections ...@@ -47,7 +47,7 @@ module IssuableCollections
end end
def merge_requests_collection def merge_requests_collection
merge_requests_finder.execute.preload(:source_project, :target_project, :author, :assignee, :labels, :milestone, :merge_request_diff, :head_pipeline, target_project: :namespace) merge_requests_finder.execute.preload(:source_project, :target_project, :author, :assignee, :labels, :milestone, :head_pipeline, target_project: :namespace, merge_request_diff: :merge_request_diff_commits)
end end
def issues_finder def issues_finder
......
...@@ -10,5 +10,11 @@ module BlobViewer ...@@ -10,5 +10,11 @@ module BlobViewer
def visible_to?(current_user) def visible_to?(current_user)
can?(current_user, :read_wiki, project) can?(current_user, :read_wiki, project)
end end
def render_error
return if project.has_external_wiki? || (project.wiki_enabled? && project.wiki.has_home_page?)
:no_wiki
end
end end
end end
...@@ -222,7 +222,7 @@ module Ci ...@@ -222,7 +222,7 @@ module Ci
.reorder(iid: :desc) .reorder(iid: :desc)
merge_requests.find do |merge_request| merge_requests.find do |merge_request|
merge_request.commits_sha.include?(pipeline.sha) merge_request.commit_shas.include?(pipeline.sha)
end end
end end
end end
......
...@@ -34,7 +34,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -34,7 +34,7 @@ class MergeRequest < ActiveRecord::Base
after_create :ensure_merge_request_diff, unless: :importing? after_create :ensure_merge_request_diff, unless: :importing?
after_update :reload_diff_if_branch_changed after_update :reload_diff_if_branch_changed
delegate :commits, :real_size, :commits_sha, :commits_count, delegate :commits, :real_size, :commit_shas, :commits_count,
to: :merge_request_diff, prefix: nil to: :merge_request_diff, prefix: nil
delegate :codeclimate_artifact, to: :head_pipeline, prefix: :head, allow_nil: true delegate :codeclimate_artifact, to: :head_pipeline, prefix: :head, allow_nil: true
...@@ -542,7 +542,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -542,7 +542,7 @@ class MergeRequest < ActiveRecord::Base
def related_notes def related_notes
# Fetch comments only from last 100 commits # Fetch comments only from last 100 commits
commits_for_notes_limit = 100 commits_for_notes_limit = 100
commit_ids = commits.last(commits_for_notes_limit).map(&:id) commit_ids = commit_shas.take(commits_for_notes_limit)
Note.where( Note.where(
"(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" + "(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" +
...@@ -865,15 +865,15 @@ class MergeRequest < ActiveRecord::Base ...@@ -865,15 +865,15 @@ class MergeRequest < ActiveRecord::Base
return Ci::Pipeline.none unless source_project return Ci::Pipeline.none unless source_project
@all_pipelines ||= source_project.pipelines @all_pipelines ||= source_project.pipelines
.where(sha: all_commits_sha, ref: source_branch) .where(sha: all_commit_shas, ref: source_branch)
.order(id: :desc) .order(id: :desc)
end end
# Note that this could also return SHA from now dangling commits # Note that this could also return SHA from now dangling commits
# #
def all_commits_sha def all_commit_shas
if persisted? if persisted?
merge_request_diffs.flat_map(&:commits_sha).uniq merge_request_diffs.preload(:merge_request_diff_commits).flat_map(&:commit_shas).uniq
elsif compare_commits elsif compare_commits
compare_commits.to_a.reverse.map(&:id) compare_commits.to_a.reverse.map(&:id)
else else
......
...@@ -11,6 +11,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -11,6 +11,7 @@ class MergeRequestDiff < ActiveRecord::Base
belongs_to :merge_request belongs_to :merge_request
has_many :merge_request_diff_files, -> { order(:merge_request_diff_id, :relative_order) } has_many :merge_request_diff_files, -> { order(:merge_request_diff_id, :relative_order) }
has_many :merge_request_diff_commits, -> { order(:merge_request_diff_id, :relative_order) }
serialize :st_commits # rubocop:disable Cop/ActiveRecordSerialize serialize :st_commits # rubocop:disable Cop/ActiveRecordSerialize
serialize :st_diffs # rubocop:disable Cop/ActiveRecordSerialize serialize :st_diffs # rubocop:disable Cop/ActiveRecordSerialize
...@@ -47,14 +48,13 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -47,14 +48,13 @@ class MergeRequestDiff < ActiveRecord::Base
# Collect information about commits and diff from repository # Collect information about commits and diff from repository
# and save it to the database as serialized data # and save it to the database as serialized data
def save_git_content def save_git_content
ensure_commits_sha ensure_commit_shas
save_commits save_commits
reload_commits
save_diffs save_diffs
keep_around_commits keep_around_commits
end end
def ensure_commits_sha def ensure_commit_shas
merge_request.fetch_ref merge_request.fetch_ref
self.start_commit_sha ||= merge_request.target_branch_sha self.start_commit_sha ||= merge_request.target_branch_sha
self.head_commit_sha ||= merge_request.source_branch_sha self.head_commit_sha ||= merge_request.source_branch_sha
...@@ -66,7 +66,7 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -66,7 +66,7 @@ class MergeRequestDiff < ActiveRecord::Base
# created before version 8.4 that does not store head_commit_sha in separate db field. # created before version 8.4 that does not store head_commit_sha in separate db field.
def head_commit_sha def head_commit_sha
if persisted? && super.nil? if persisted? && super.nil?
last_commit.try(:sha) last_commit_sha
else else
super super
end end
...@@ -97,16 +97,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -97,16 +97,11 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def commits def commits
@commits ||= load_commits(st_commits) @commits ||= load_commits
end end
def reload_commits def last_commit_sha
@commits = nil commit_shas.first
commits
end
def last_commit
commits.first
end end
def first_commit def first_commit
...@@ -131,8 +126,12 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -131,8 +126,12 @@ class MergeRequestDiff < ActiveRecord::Base
project.commit(head_commit_sha) project.commit(head_commit_sha)
end end
def commits_sha def commit_shas
if st_commits.present?
st_commits.map { |commit| commit[:id] } st_commits.map { |commit| commit[:id] }
else
merge_request_diff_commits.map(&:sha)
end
end end
def diff_refs=(new_diff_refs) def diff_refs=(new_diff_refs)
...@@ -207,7 +206,11 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -207,7 +206,11 @@ class MergeRequestDiff < ActiveRecord::Base
end end
def commits_count def commits_count
st_commits.count if st_commits.present?
st_commits.size
else
merge_request_diff_commits.size
end
end end
def utf8_st_diffs def utf8_st_diffs
...@@ -231,29 +234,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -231,29 +234,6 @@ class MergeRequestDiff < ActiveRecord::Base
raw.any? { |element| VALID_CLASSES.include?(element.class) } raw.any? { |element| VALID_CLASSES.include?(element.class) }
end end
def dump_commits(commits)
commits.map(&:to_hash)
end
def load_commits(array)
array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash), merge_request.source_project) }
end
# Load all commits related to current merge request diff from repo
# and save it as array of hashes in st_commits db field
def save_commits
new_attributes = {}
commits = compare.commits
if commits.present?
commits = Commit.decorate(commits, merge_request.source_project).reverse
new_attributes[:st_commits] = dump_commits(commits)
end
update_columns_serialized(new_attributes)
end
def create_merge_request_diff_files(diffs) def create_merge_request_diff_files(diffs)
rows = diffs.map.with_index do |diff, index| rows = diffs.map.with_index do |diff, index|
diff.to_hash.merge( diff.to_hash.merge(
...@@ -294,12 +274,18 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -294,12 +274,18 @@ class MergeRequestDiff < ActiveRecord::Base
end end
end end
# Load diffs between branches related to current merge request diff from repo def load_commits
# and save it as array of hashes in st_diffs db field commits = st_commits.presence || merge_request_diff_commits
commits.map do |commit|
Commit.new(Gitlab::Git::Commit.new(commit.to_hash), merge_request.source_project)
end
end
def save_diffs def save_diffs
new_attributes = {} new_attributes = {}
if commits.size.zero? if compare.commits.size.zero?
new_attributes[:state] = :empty new_attributes[:state] = :empty
else else
diff_collection = compare.diffs(Commit.max_diff_options) diff_collection = compare.diffs(Commit.max_diff_options)
...@@ -319,7 +305,13 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -319,7 +305,13 @@ class MergeRequestDiff < ActiveRecord::Base
new_attributes[:state] = :overflow if diff_collection.overflow? new_attributes[:state] = :overflow if diff_collection.overflow?
end end
update_columns_serialized(new_attributes) update(new_attributes)
end
def save_commits
MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse)
merge_request_diff_commits.reload
end end
def repository def repository
...@@ -332,29 +324,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -332,29 +324,6 @@ class MergeRequestDiff < ActiveRecord::Base
project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha) project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha)
end end
#
# #save or #update_attributes providing changes on serialized attributes do a lot of
# serialization and deserialization calls resulting in bad performance.
# Using #update_columns solves the problem with just one YAML.dump per serialized attribute that we provide.
# As a tradeoff we need to reload the current instance to properly manage time objects on those serialized
# attributes. So to keep the same behaviour as the attribute assignment we reload the instance.
# The difference is in the usage of
# #write_attribute= (#update_attributes) and #raw_write_attribute= (#update_columns)
#
# Ex:
#
# new_attributes[:st_commits].first.slice(:committed_date)
# => {:committed_date=>2014-02-27 11:01:38 +0200}
# YAML.load(YAML.dump(new_attributes[:st_commits].first.slice(:committed_date)))
# => {:committed_date=>2014-02-27 10:01:38 +0100}
#
def update_columns_serialized(new_attributes)
return unless new_attributes.any?
update_columns(new_attributes.merge(updated_at: current_time_from_proper_timezone))
reload
end
def keep_around_commits def keep_around_commits
[repository, merge_request.source_project.repository].each do |repo| [repository, merge_request.source_project.repository].each do |repo|
repo.keep_around(start_commit_sha) repo.keep_around(start_commit_sha)
......
class MergeRequestDiffCommit < ActiveRecord::Base
include ShaAttribute
belongs_to :merge_request_diff
sha_attribute :sha
alias_attribute :id, :sha
def self.create_bulk(merge_request_diff_id, commits)
sha_attribute = Gitlab::Database::ShaAttribute.new
rows = commits.map.with_index do |commit, index|
# See #parent_ids.
commit_hash = commit.to_hash.except(:parent_ids)
sha = commit_hash.delete(:id)
commit_hash.merge(
merge_request_diff_id: merge_request_diff_id,
relative_order: index,
sha: sha_attribute.type_cast_for_database(sha)
)
end
Gitlab::Database.bulk_insert(self.table_name, rows)
end
def to_hash
Gitlab::Git::Commit::SERIALIZE_KEYS.each_with_object({}) do |key, hash|
hash[key] = public_send(key)
end
end
# We don't save these, because they would need a table or a serialised
# field. They aren't used anywhere, so just pretend the commit has no parents.
def parent_ids
[]
end
end
...@@ -70,6 +70,10 @@ class ProjectWiki ...@@ -70,6 +70,10 @@ class ProjectWiki
!!repository.exists? !!repository.exists?
end end
def has_home_page?
!!find_page('home')
end
# Returns an Array of Gitlab WikiPage instances or an # Returns an Array of Gitlab WikiPage instances or an
# empty Array if this Wiki has no pages. # empty Array if this Wiki has no pages.
def pages def pages
......
...@@ -69,7 +69,7 @@ module MergeRequests ...@@ -69,7 +69,7 @@ module MergeRequests
if merge_request.source_branch == @branch_name || force_push? if merge_request.source_branch == @branch_name || force_push?
merge_request.reload_diff(current_user) merge_request.reload_diff(current_user)
else else
mr_commit_ids = merge_request.commits_sha mr_commit_ids = merge_request.commit_shas
push_commit_ids = @commits.map(&:id) push_commit_ids = @commits.map(&:id)
matches = mr_commit_ids & push_commit_ids matches = mr_commit_ids & push_commit_ids
merge_request.reload_diff(current_user) if matches.any? merge_request.reload_diff(current_user) if matches.any?
...@@ -145,7 +145,7 @@ module MergeRequests ...@@ -145,7 +145,7 @@ module MergeRequests
return unless @commits.present? return unless @commits.present?
merge_requests_for_source_branch.each do |merge_request| merge_requests_for_source_branch.each do |merge_request|
mr_commit_ids = Set.new(merge_request.commits_sha) mr_commit_ids = Set.new(merge_request.commit_shas)
new_commits, existing_commits = @commits.partition do |commit| new_commits, existing_commits = @commits.partition do |commit|
mr_commit_ids.include?(commit.id) mr_commit_ids.include?(commit.id)
...@@ -161,7 +161,7 @@ module MergeRequests ...@@ -161,7 +161,7 @@ module MergeRequests
return unless @commits.present? return unless @commits.present?
merge_requests_for_source_branch.each do |merge_request| merge_requests_for_source_branch.each do |merge_request|
commit_shas = merge_request.commits_sha commit_shas = merge_request.commit_shas
wip_commit = @commits.detect do |commit| wip_commit = @commits.detect do |commit|
commit.work_in_progress? && commit_shas.include?(commit.sha) commit.work_in_progress? && commit_shas.include?(commit.sha)
......
= icon('info-circle fw') = icon('info-circle fw')
= succeed '.' do = succeed '.' do
To learn more about this project, read To learn more about this project, read
= link_to "the wiki", project_wikis_path(viewer.project) = link_to "the wiki", get_project_wiki_path(viewer.project)
.panel.panel-default
.panel-heading
Group members with access to
%strong= @group.name
%span.badge= members.size
- if can?(current_user, :admin_group_member, @group)
.controls
= link_to 'Manage group members',
group_group_members_path(@group),
class: 'btn'
%ul.content-list
= render partial: 'shared/members/member',
collection: members.limit(20),
as: :member,
locals: { show_controls: false }
- if members.size > 20
%li
and #{members.count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(@group)}
.row.prepend-top-default .row.prepend-top-default
.col-lg-4.settings-sidebar .col-lg-12
%h4.prepend-top-0 %h4
Project members Project members
- if can?(current_user, :admin_project_member, @project) - if can?(current_user, :admin_project_member, @project)
%p %p
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
%i Masters %i Masters
or or
%i Owners %i Owners
.col-lg-8
.light .light
- if can?(current_user, :admin_project_member, @project) && !membership_locked? - if can?(current_user, :admin_project_member, @project) && !membership_locked?
%ul.nav-links.project-member-tabs{ role: 'tablist' } %ul.nav-links.project-member-tabs{ role: 'tablist' }
......
- @project_group_links.each do |group_links|
- shared_group = group_links.group
- shared_group_members = shared_group.members
- shared_group_users_count = shared_group_members.size
.panel.panel-default
.panel-heading
Shared with
%strong= shared_group.name
group, members with
%strong= group_links.human_access
role (#{shared_group_users_count})
- if can?(current_user, :admin_group, shared_group)
.panel-head-actions
= link_to group_group_members_path(shared_group), class: 'btn btn-sm' do
%i.fa.fa-pencil-square-o
Edit group members
%ul.content-list
= render partial: 'shared/members/member',
collection: shared_group_members.order(access_level: :desc).limit(20),
as: :member,
locals: { show_controls: false, show_roles: false }
- if shared_group_users_count > 20
%li
and #{shared_group_users_count - 20} more. For full list visit #{link_to 'group members page', group_group_members_path(shared_group)}
---
title: Improve the performance of the project list API
merge_request: 12679
author:
---
title: Fixed the chart legend not being set correctly
merge_request: 12628
author:
---
title: Remove two columned layout from project member settings
merge_request:
author:
---
title: Don't show auxiliary blob viewer for README when there is no wiki
merge_request:
author:
---
title: Upgrade GitLab Workhorse to v2.3.0
merge_request: 12676
author:
...@@ -175,8 +175,9 @@ module Gitlab ...@@ -175,8 +175,9 @@ module Gitlab
config.after_initialize do config.after_initialize do
Rails.application.reload_routes! Rails.application.reload_routes!
named_routes_set = Gitlab::Application.routes.named_routes
project_url_helpers = Module.new do project_url_helpers = Module.new do
Gitlab::Application.routes.named_routes.helper_names.each do |name| named_routes_set.helper_names.each do |name|
next unless name.include?('namespace_project') next unless name.include?('namespace_project')
define_method(name.sub('namespace_project', 'project')) do |project, *args| define_method(name.sub('namespace_project', 'project')) do |project, *args|
...@@ -185,6 +186,9 @@ module Gitlab ...@@ -185,6 +186,9 @@ module Gitlab
end end
end end
named_routes_set.url_helpers_module.include project_url_helpers
named_routes_set.url_helpers_module.extend project_url_helpers
Gitlab::Routing.url_helpers.include project_url_helpers Gitlab::Routing.url_helpers.include project_url_helpers
Gitlab::Routing.url_helpers.extend project_url_helpers Gitlab::Routing.url_helpers.extend project_url_helpers
......
resources :builds, only: [:index, :show], constraints: { id: /\d+/ } do
collection do
resources :artifacts, only: [], controller: 'build_artifacts' do
collection do
get :latest_succeeded,
path: '*ref_name_and_path',
format: false
end
end
end
member do
get :raw
end
resource :artifacts, only: [], controller: 'build_artifacts' do
get :download
get :browse, path: 'browse(/*path)', format: false
get :file, path: 'file/*path', format: false
get :raw, path: 'raw/*path', format: false
end
end
require 'constraints/project_url_constrainer' require 'constraints/project_url_constrainer'
require 'gitlab/routes/legacy_builds'
resources :projects, only: [:index, :new, :create] resources :projects, only: [:index, :new, :create]
...@@ -288,7 +287,7 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -288,7 +287,7 @@ constraints(ProjectUrlConstrainer.new) do
end end
end end
Gitlab::Routes::LegacyBuilds.new(self).draw draw :legacy_builds
resources :hooks, only: [:index, :create, :edit, :update, :destroy], constraints: { id: /\d+/ } do resources :hooks, only: [:index, :create, :edit, :update, :destroy], constraints: { id: /\d+/ } do
member do member do
......
class CreateMergeRequestDiffCommits < ActiveRecord::Migration
DOWNTIME = false
def change
create_table :merge_request_diff_commits, id: false do |t|
t.datetime_with_timezone :authored_date
t.datetime_with_timezone :committed_date
t.belongs_to :merge_request_diff, null: false, foreign_key: { on_delete: :cascade }
t.integer :relative_order, null: false
t.binary :sha, null: false, limit: 20
t.text :author_name
t.text :author_email
t.text :committer_name
t.text :committer_email
t.text :message
t.index [:merge_request_diff_id, :relative_order], name: 'index_merge_request_diff_commits_on_mr_diff_id_and_order', unique: true
end
end
end
...@@ -884,6 +884,21 @@ ActiveRecord::Schema.define(version: 20170706121518) do ...@@ -884,6 +884,21 @@ ActiveRecord::Schema.define(version: 20170706121518) do
add_index "members", ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree add_index "members", ["source_id", "source_type"], name: "index_members_on_source_id_and_source_type", using: :btree
add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree add_index "members", ["user_id"], name: "index_members_on_user_id", using: :btree
create_table "merge_request_diff_commits", id: false, force: :cascade do |t|
t.datetime "authored_date"
t.datetime "committed_date"
t.integer "merge_request_diff_id", null: false
t.integer "relative_order", null: false
t.binary "sha", null: false
t.text "author_name"
t.text "author_email"
t.text "committer_name"
t.text "committer_email"
t.text "message"
end
add_index "merge_request_diff_commits", ["merge_request_diff_id", "relative_order"], name: "index_merge_request_diff_commits_on_mr_diff_id_and_order", unique: true, using: :btree
create_table "merge_request_diff_files", id: false, force: :cascade do |t| create_table "merge_request_diff_files", id: false, force: :cascade do |t|
t.integer "merge_request_diff_id", null: false t.integer "merge_request_diff_id", null: false
t.integer "relative_order", null: false t.integer "relative_order", null: false
...@@ -1895,6 +1910,7 @@ ActiveRecord::Schema.define(version: 20170706121518) do ...@@ -1895,6 +1910,7 @@ ActiveRecord::Schema.define(version: 20170706121518) do
add_foreign_key "labels", "projects", name: "fk_7de4989a69", on_delete: :cascade add_foreign_key "labels", "projects", name: "fk_7de4989a69", on_delete: :cascade
add_foreign_key "lists", "boards", name: "fk_0d3f677137", on_delete: :cascade add_foreign_key "lists", "boards", name: "fk_0d3f677137", on_delete: :cascade
add_foreign_key "lists", "labels", name: "fk_7a5553d60f", on_delete: :cascade add_foreign_key "lists", "labels", name: "fk_7a5553d60f", on_delete: :cascade
add_foreign_key "merge_request_diff_commits", "merge_request_diffs", on_delete: :cascade
add_foreign_key "merge_request_diff_files", "merge_request_diffs", on_delete: :cascade add_foreign_key "merge_request_diff_files", "merge_request_diffs", on_delete: :cascade
add_foreign_key "merge_request_diffs", "merge_requests", name: "fk_8483f3258f", on_delete: :cascade add_foreign_key "merge_request_diffs", "merge_requests", name: "fk_8483f3258f", on_delete: :cascade
add_foreign_key "merge_request_metrics", "ci_pipelines", column: "pipeline_id", on_delete: :cascade add_foreign_key "merge_request_metrics", "ci_pipelines", column: "pipeline_id", on_delete: :cascade
......
...@@ -30,6 +30,8 @@ module Banzai ...@@ -30,6 +30,8 @@ module Banzai
attributes = attributes.reject { |_, v| v.nil? } attributes = attributes.reject { |_, v| v.nil? }
attributes[:reference_type] ||= self.class.reference_type attributes[:reference_type] ||= self.class.reference_type
attributes[:container] ||= 'body'
attributes[:placement] ||= 'bottom'
attributes.delete(:original) if context[:no_original_data] attributes.delete(:original) if context[:no_original_data]
attributes.map do |key, value| attributes.map do |key, value|
%Q(data-#{key.to_s.dasherize}="#{escape_once(value)}") %Q(data-#{key.to_s.dasherize}="#{escape_once(value)}")
......
...@@ -13,6 +13,10 @@ module Gitlab ...@@ -13,6 +13,10 @@ module Gitlab
MergeRequestDiff.arel_table MergeRequestDiff.arel_table
end end
def mr_diff_commits_table
MergeRequestDiffCommit.arel_table
end
def mr_closing_issues_table def mr_closing_issues_table
MergeRequestsClosingIssues.arel_table MergeRequestsClosingIssues.arel_table
end end
......
...@@ -2,40 +2,59 @@ module Gitlab ...@@ -2,40 +2,59 @@ module Gitlab
module CycleAnalytics module CycleAnalytics
class PlanEventFetcher < BaseEventFetcher class PlanEventFetcher < BaseEventFetcher
def initialize(*args) def initialize(*args)
@projections = [mr_diff_table[:st_commits].as('commits'), @projections = [mr_diff_table[:id],
mr_diff_table[:st_commits],
issue_metrics_table[:first_mentioned_in_commit_at]] issue_metrics_table[:first_mentioned_in_commit_at]]
super(*args) super(*args)
end end
def events_query def events_query
base_query.join(mr_diff_table).on(mr_diff_table[:merge_request_id].eq(mr_table[:id])) base_query
.join(mr_diff_table)
.on(mr_diff_table[:merge_request_id].eq(mr_table[:id]))
super super
end end
private private
def merge_request_diff_commits
@merge_request_diff_commits ||=
MergeRequestDiffCommit
.where(merge_request_diff_id: event_result.map { |event| event['id'] })
.group_by(&:merge_request_diff_id)
end
def serialize(event) def serialize(event)
st_commit = first_time_reference_commit(event.delete('commits'), event) commit = first_time_reference_commit(event)
return unless commit
serialize_commit(event, commit, query)
end
return unless st_commit def first_time_reference_commit(event)
return nil unless event && merge_request_diff_commits
serialize_commit(event, st_commit, query) commits =
if event['st_commits'].present?
YAML.load(event['st_commits'])
else
merge_request_diff_commits[event['id'].to_i]
end end
def first_time_reference_commit(commits, event)
return nil if commits.blank? return nil if commits.blank?
YAML.load(commits).find do |commit| commits.find do |commit|
next unless commit[:committed_date] && event['first_mentioned_in_commit_at'] next unless commit[:committed_date] && event['first_mentioned_in_commit_at']
commit[:committed_date].to_i == DateTime.parse(event['first_mentioned_in_commit_at'].to_s).to_i commit[:committed_date].to_i == DateTime.parse(event['first_mentioned_in_commit_at'].to_s).to_i
end end
end end
def serialize_commit(event, st_commit, query) def serialize_commit(event, commit, query)
commit = Commit.new(Gitlab::Git::Commit.new(st_commit), @project) commit = Commit.new(Gitlab::Git::Commit.new(commit.to_hash), @project)
AnalyticsCommitSerializer.new(project: @project, total_time: event['total_time']).represent(commit) AnalyticsCommitSerializer.new(project: @project, total_time: event['total_time']).represent(commit)
end end
......
...@@ -27,6 +27,7 @@ project_tree: ...@@ -27,6 +27,7 @@ project_tree:
- :author - :author
- :events - :events
- merge_request_diff: - merge_request_diff:
- :merge_request_diff_commits
- :merge_request_diff_files - :merge_request_diff_files
- :events - :events
- :timelogs - :timelogs
......
module Gitlab
module Routes
class LegacyBuilds
def initialize(map)
@map = map
end
def draw
@map.instance_eval do
resources :builds, only: [:index, :show], constraints: { id: /\d+/ } do
collection do
resources :artifacts, only: [], controller: 'build_artifacts' do
collection do
get :latest_succeeded,
path: '*ref_name_and_path',
format: false
end
end
end
member do
get :raw
end
resource :artifacts, only: [], controller: 'build_artifacts' do
get :download
get :browse, path: 'browse(/*path)', format: false
get :file, path: 'file/*path', format: false
get :raw, path: 'raw/*path', format: false
end
end
end
end
end
end
end
...@@ -2481,6 +2481,7 @@ export const singleRowMetrics = [ ...@@ -2481,6 +2481,7 @@ export const singleRowMetrics = [
'queries': [ 'queries': [
{ {
'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100', 'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100',
'label': 'Container CPU',
'result': [ 'result': [
{ {
'metric': { 'metric': {
......
...@@ -95,7 +95,7 @@ describe('MonitoringColumn', () => { ...@@ -95,7 +95,7 @@ describe('MonitoringColumn', () => {
}); });
}); });
it('has a title for the y-axis that comes from the backend', () => { it('has a title for the y-axis and the chart legend that comes from the backend', () => {
const component = createComponent({ const component = createComponent({
columnData: singleRowMetrics[0], columnData: singleRowMetrics[0],
classType: 'col-md-6', classType: 'col-md-6',
...@@ -104,5 +104,6 @@ describe('MonitoringColumn', () => { ...@@ -104,5 +104,6 @@ describe('MonitoringColumn', () => {
}); });
expect(component.yAxisLabel).toEqual(component.columnData.y_label); expect(component.yAxisLabel).toEqual(component.columnData.y_label);
expect(component.legendTitle).toEqual(component.columnData.queries[0].label);
}); });
}); });
...@@ -92,7 +92,10 @@ merge_requests: ...@@ -92,7 +92,10 @@ merge_requests:
- head_pipeline - head_pipeline
merge_request_diff: merge_request_diff:
- merge_request - merge_request
- merge_request_diff_commits
- merge_request_diff_files - merge_request_diff_files
merge_request_diff_commits:
- merge_request_diff
merge_request_diff_files: merge_request_diff_files:
- merge_request_diff - merge_request_diff
pipelines: pipelines:
......
...@@ -2741,13 +2741,12 @@ ...@@ -2741,13 +2741,12 @@
"merge_request_diff": { "merge_request_diff": {
"id": 27, "id": 27,
"state": "collected", "state": "collected",
"st_commits": [ "merge_request_diff_commits": [
{ {
"id": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc", "merge_request_diff_id": 27,
"relative_order": 0,
"sha": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc",
"message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
"parent_ids": [
"5937ac0a7beb003549fc5fd26fc247adbce4a52e"
],
"authored_date": "2014-08-06T08:35:52.000+02:00", "authored_date": "2014-08-06T08:35:52.000+02:00",
"author_name": "Dmitriy Zaporozhets", "author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com", "author_email": "dmitriy.zaporozhets@gmail.com",
...@@ -2756,11 +2755,10 @@ ...@@ -2756,11 +2755,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com" "committer_email": "dmitriy.zaporozhets@gmail.com"
}, },
{ {
"id": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", "merge_request_diff_id": 27,
"relative_order": 1,
"sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e",
"message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
"parent_ids": [
"570e7b2abdd848b95f2f578043fc23bd6f6fd24d"
],
"authored_date": "2014-02-27T10:01:38.000+01:00", "authored_date": "2014-02-27T10:01:38.000+01:00",
"author_name": "Dmitriy Zaporozhets", "author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com", "author_email": "dmitriy.zaporozhets@gmail.com",
...@@ -2769,11 +2767,10 @@ ...@@ -2769,11 +2767,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com" "committer_email": "dmitriy.zaporozhets@gmail.com"
}, },
{ {
"id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", "merge_request_diff_id": 27,
"relative_order": 2,
"sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d",
"message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
"parent_ids": [
"6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9"
],
"authored_date": "2014-02-27T09:57:31.000+01:00", "authored_date": "2014-02-27T09:57:31.000+01:00",
"author_name": "Dmitriy Zaporozhets", "author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com", "author_email": "dmitriy.zaporozhets@gmail.com",
...@@ -2782,11 +2779,10 @@ ...@@ -2782,11 +2779,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com" "committer_email": "dmitriy.zaporozhets@gmail.com"
}, },
{ {
"id": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9", "merge_request_diff_id": 27,
"relative_order": 3,
"sha": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9",
"message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
"parent_ids": [
"d14d6c0abdd253381df51a723d58691b2ee1ab08"
],
"authored_date": "2014-02-27T09:54:21.000+01:00", "authored_date": "2014-02-27T09:54:21.000+01:00",
"author_name": "Dmitriy Zaporozhets", "author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com", "author_email": "dmitriy.zaporozhets@gmail.com",
...@@ -2795,11 +2791,10 @@ ...@@ -2795,11 +2791,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com" "committer_email": "dmitriy.zaporozhets@gmail.com"
}, },
{ {
"id": "d14d6c0abdd253381df51a723d58691b2ee1ab08", "merge_request_diff_id": 27,
"relative_order": 4,
"sha": "d14d6c0abdd253381df51a723d58691b2ee1ab08",
"message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
"parent_ids": [
"c1acaa58bbcbc3eafe538cb8274ba387047b69f8"
],
"authored_date": "2014-02-27T09:49:50.000+01:00", "authored_date": "2014-02-27T09:49:50.000+01:00",
"author_name": "Dmitriy Zaporozhets", "author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com", "author_email": "dmitriy.zaporozhets@gmail.com",
...@@ -2808,11 +2803,10 @@ ...@@ -2808,11 +2803,10 @@
"committer_email": "dmitriy.zaporozhets@gmail.com" "committer_email": "dmitriy.zaporozhets@gmail.com"
}, },
{ {
"id": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8", "merge_request_diff_id": 27,
"relative_order": 5,
"sha": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8",
"message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n",
"parent_ids": [
"ae73cb07c9eeaf35924a10f713b364d32b2dd34f"
],
"authored_date": "2014-02-27T09:48:32.000+01:00", "authored_date": "2014-02-27T09:48:32.000+01:00",
"author_name": "Dmitriy Zaporozhets", "author_name": "Dmitriy Zaporozhets",
"author_email": "dmitriy.zaporozhets@gmail.com", "author_email": "dmitriy.zaporozhets@gmail.com",
......
...@@ -95,6 +95,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do ...@@ -95,6 +95,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(MergeRequestDiffFile.where.not(diff: nil).count).to eq(9) expect(MergeRequestDiffFile.where.not(diff: nil).count).to eq(9)
end end
it 'has the correct data for merge request diff commits in serialised and table formats' do
expect(MergeRequestDiff.where.not(st_commits: nil).count).to eq(7)
expect(MergeRequestDiffCommit.count).to eq(6)
end
it 'has the correct time for merge request st_commits' do it 'has the correct time for merge request st_commits' do
st_commits = MergeRequestDiff.where.not(st_commits: nil).first.st_commits st_commits = MergeRequestDiff.where.not(st_commits: nil).first.st_commits
......
...@@ -87,6 +87,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do ...@@ -87,6 +87,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_files']).not_to be_empty expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_files']).not_to be_empty
end end
it 'has merge request diff commits' do
expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_commits']).not_to be_empty
end
it 'has merge requests comments' do it 'has merge requests comments' do
expect(saved_project_json['merge_requests'].first['notes']).not_to be_empty expect(saved_project_json['merge_requests'].first['notes']).not_to be_empty
end end
......
...@@ -176,6 +176,17 @@ MergeRequestDiff: ...@@ -176,6 +176,17 @@ MergeRequestDiff:
- real_size - real_size
- head_commit_sha - head_commit_sha
- start_commit_sha - start_commit_sha
MergeRequestDiffCommit:
- merge_request_diff_id
- relative_order
- sha
- authored_date
- committed_date
- author_name
- author_email
- committer_name
- committer_email
- message
MergeRequestDiffFile: MergeRequestDiffFile:
- merge_request_diff_id - merge_request_diff_id
- relative_order - relative_order
......
require 'spec_helper'
describe BlobViewer::Readme, model: true do
include FakeBlobHelpers
let(:project) { create(:project, :repository) }
let(:blob) { fake_blob(path: 'README.md') }
subject { described_class.new(blob) }
describe '#render_error' do
context 'when there is no wiki' do
it 'returns :no_wiki' do
expect(subject.render_error).to eq(:no_wiki)
end
end
context 'when there is an external wiki' do
before do
project.has_external_wiki = true
end
it 'returns nil' do
expect(subject.render_error).to be_nil
end
end
context 'when there is a local wiki' do
before do
project.wiki_enabled = true
end
context 'when the wiki is empty' do
it 'returns :no_wiki' do
expect(subject.render_error).to eq(:no_wiki)
end
end
context 'when the wiki is not empty' do
before do
WikiPages::CreateService.new(project, project.owner, title: 'home', content: 'Home page').execute
end
it 'returns nil' do
expect(subject.render_error).to be_nil
end
end
end
end
end
...@@ -882,7 +882,7 @@ describe Ci::Build, :models do ...@@ -882,7 +882,7 @@ describe Ci::Build, :models do
pipeline2 = create(:ci_pipeline, project: project) pipeline2 = create(:ci_pipeline, project: project)
@build2 = create(:ci_build, pipeline: pipeline2) @build2 = create(:ci_build, pipeline: pipeline2)
allow(@merge_request).to receive(:commits_sha) allow(@merge_request).to receive(:commit_shas)
.and_return([pipeline.sha, pipeline2.sha]) .and_return([pipeline.sha, pipeline2.sha])
allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request]) allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request])
end end
......
require 'rails_helper'
describe MergeRequestDiffCommit, type: :model do
let(:merge_request) { create(:merge_request) }
subject { merge_request.commits.first }
describe '#to_hash' do
it 'returns the same results as Commit#to_hash, except for parent_ids' do
commit_from_repo = merge_request.project.repository.commit(subject.sha)
commit_from_repo_hash = commit_from_repo.to_hash.merge(parent_ids: [])
expect(subject.to_hash).to eq(commit_from_repo_hash)
end
end
end
...@@ -98,7 +98,7 @@ describe MergeRequestDiff, models: true do ...@@ -98,7 +98,7 @@ describe MergeRequestDiff, models: true do
end end
it 'saves empty state' do it 'saves empty state' do
allow_any_instance_of(MergeRequestDiff).to receive(:commits) allow_any_instance_of(MergeRequestDiff).to receive_message_chain(:compare, :commits)
.and_return([]) .and_return([])
mr_diff = create(:merge_request).merge_request_diff mr_diff = create(:merge_request).merge_request_diff
...@@ -107,14 +107,14 @@ describe MergeRequestDiff, models: true do ...@@ -107,14 +107,14 @@ describe MergeRequestDiff, models: true do
end end
end end
describe '#commits_sha' do describe '#commit_shas' do
it 'returns all commits SHA using serialized commits' do it 'returns all commits SHA using serialized commits' do
subject.st_commits = [ subject.st_commits = [
{ id: 'sha1' }, { id: 'sha1' },
{ id: 'sha2' } { id: 'sha2' }
] ]
expect(subject.commits_sha).to eq(%w(sha1 sha2)) expect(subject.commit_shas).to eq(%w(sha1 sha2))
end end
end end
......
...@@ -928,14 +928,14 @@ describe MergeRequest, models: true do ...@@ -928,14 +928,14 @@ describe MergeRequest, models: true do
subject { create :merge_request, :simple } subject { create :merge_request, :simple }
end end
describe '#commits_sha' do describe '#commit_shas' do
before do before do
allow(subject.merge_request_diff).to receive(:commits_sha) allow(subject.merge_request_diff).to receive(:commit_shas)
.and_return(['sha1']) .and_return(['sha1'])
end end
it 'delegates to merge request diff' do it 'delegates to merge request diff' do
expect(subject.commits_sha).to eq ['sha1'] expect(subject.commit_shas).to eq ['sha1']
end end
end end
...@@ -960,7 +960,7 @@ describe MergeRequest, models: true do ...@@ -960,7 +960,7 @@ describe MergeRequest, models: true do
describe '#all_pipelines' do describe '#all_pipelines' do
shared_examples 'returning pipelines with proper ordering' do shared_examples 'returning pipelines with proper ordering' do
let!(:all_pipelines) do let!(:all_pipelines) do
subject.all_commits_sha.map do |sha| subject.all_commit_shas.map do |sha|
create(:ci_empty_pipeline, create(:ci_empty_pipeline,
project: subject.source_project, project: subject.source_project,
sha: sha, sha: sha,
...@@ -1002,16 +1002,16 @@ describe MergeRequest, models: true do ...@@ -1002,16 +1002,16 @@ describe MergeRequest, models: true do
end end
end end
describe '#all_commits_sha' do describe '#all_commit_shas' do
context 'when merge request is persisted' do context 'when merge request is persisted' do
let(:all_commits_sha) do let(:all_commit_shas) do
subject.merge_request_diffs.flat_map(&:commits).map(&:sha).uniq subject.merge_request_diffs.flat_map(&:commits).map(&:sha).uniq
end end
shared_examples 'returning all SHA' do shared_examples 'returning all SHA' do
it 'returns all SHA from all merge_request_diffs' do it 'returns all SHA from all merge_request_diffs' do
expect(subject.merge_request_diffs.size).to eq(2) expect(subject.merge_request_diffs.size).to eq(2)
expect(subject.all_commits_sha).to eq(all_commits_sha) expect(subject.all_commit_shas).to eq(all_commit_shas)
end end
end end
...@@ -1042,7 +1042,7 @@ describe MergeRequest, models: true do ...@@ -1042,7 +1042,7 @@ describe MergeRequest, models: true do
end end
it 'returns commits from compare commits temporary data' do it 'returns commits from compare commits temporary data' do
expect(subject.all_commits_sha).to eq [commit, commit] expect(subject.all_commit_shas).to eq [commit, commit]
end end
end end
...@@ -1050,7 +1050,7 @@ describe MergeRequest, models: true do ...@@ -1050,7 +1050,7 @@ describe MergeRequest, models: true do
subject { build(:merge_request) } subject { build(:merge_request) }
it 'returns array with diff head sha element only' do it 'returns array with diff head sha element only' do
expect(subject.all_commits_sha).to eq [subject.diff_head_sha] expect(subject.all_commit_shas).to eq [subject.diff_head_sha]
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment