Commit 51927b30 authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-09-19

# Conflicts:
#	config/initializers/0_post_deployment_migrations.rb
#	locale/gitlab.pot

[ci skip]
parents 998a4114 38cf0b67
...@@ -22,7 +22,7 @@ export default { ...@@ -22,7 +22,7 @@ export default {
type: Object, type: Object,
required: true, required: true,
}, },
position: { linePosition: {
type: String, type: String,
required: false, required: false,
default: '', default: '',
...@@ -81,7 +81,7 @@ export default { ...@@ -81,7 +81,7 @@ export default {
noteTargetLine: this.noteTargetLine, noteTargetLine: this.noteTargetLine,
diffViewType: this.diffViewType, diffViewType: this.diffViewType,
diffFile: selectedDiffFile, diffFile: selectedDiffFile,
linePosition: this.position, linePosition: this.linePosition,
}); });
this.saveNote(postData) this.saveNote(postData)
......
...@@ -92,7 +92,7 @@ export default { ...@@ -92,7 +92,7 @@ export default {
:diff-file-hash="diffFileHash" :diff-file-hash="diffFileHash"
:line="line.left" :line="line.left"
:note-target-line="line.left" :note-target-line="line.left"
position="left" line-position="left"
/> />
</td> </td>
<td class="notes_line new"></td> <td class="notes_line new"></td>
...@@ -111,7 +111,7 @@ export default { ...@@ -111,7 +111,7 @@ export default {
:diff-file-hash="diffFileHash" :diff-file-hash="diffFileHash"
:line="line.right" :line="line.right"
:note-target-line="line.right" :note-target-line="line.right"
position="right" line-position="right"
/> />
</td> </td>
</tr> </tr>
......
...@@ -7,6 +7,7 @@ export const CONTEXT_LINE_TYPE = 'context'; ...@@ -7,6 +7,7 @@ export const CONTEXT_LINE_TYPE = 'context';
export const EMPTY_CELL_TYPE = 'empty-cell'; export const EMPTY_CELL_TYPE = 'empty-cell';
export const COMMENT_FORM_TYPE = 'commentForm'; export const COMMENT_FORM_TYPE = 'commentForm';
export const DIFF_NOTE_TYPE = 'DiffNote'; export const DIFF_NOTE_TYPE = 'DiffNote';
export const LEGACY_DIFF_NOTE_TYPE = 'LegacyDiffNote';
export const NOTE_TYPE = 'Note'; export const NOTE_TYPE = 'Note';
export const NEW_LINE_TYPE = 'new'; export const NEW_LINE_TYPE = 'new';
export const OLD_LINE_TYPE = 'old'; export const OLD_LINE_TYPE = 'old';
......
...@@ -90,16 +90,18 @@ export default { ...@@ -90,16 +90,18 @@ export default {
const firstDiscussion = discussions[0]; const firstDiscussion = discussions[0];
const isDiffDiscussion = firstDiscussion.diff_discussion; const isDiffDiscussion = firstDiscussion.diff_discussion;
const hasLineCode = firstDiscussion.line_code; const hasLineCode = firstDiscussion.line_code;
const isResolvable = firstDiscussion.resolvable;
const diffPosition = diffPositionByLineCode[firstDiscussion.line_code]; const diffPosition = diffPositionByLineCode[firstDiscussion.line_code];
if ( if (
selectedFile && selectedFile &&
isDiffDiscussion && isDiffDiscussion &&
hasLineCode && hasLineCode &&
isResolvable &&
diffPosition && diffPosition &&
isDiscussionApplicableToLine(firstDiscussion, diffPosition) isDiscussionApplicableToLine({
discussion: firstDiscussion,
diffPosition,
latestDiff: state.latestDiff,
})
) { ) {
const targetLine = selectedFile.parallelDiffLines.find( const targetLine = selectedFile.parallelDiffLines.find(
line => line =>
......
...@@ -4,6 +4,7 @@ import { ...@@ -4,6 +4,7 @@ import {
LINE_POSITION_LEFT, LINE_POSITION_LEFT,
LINE_POSITION_RIGHT, LINE_POSITION_RIGHT,
TEXT_DIFF_POSITION_TYPE, TEXT_DIFF_POSITION_TYPE,
LEGACY_DIFF_NOTE_TYPE,
DIFF_NOTE_TYPE, DIFF_NOTE_TYPE,
NEW_LINE_TYPE, NEW_LINE_TYPE,
OLD_LINE_TYPE, OLD_LINE_TYPE,
...@@ -60,7 +61,10 @@ export function getNoteFormData(params) { ...@@ -60,7 +61,10 @@ export function getNoteFormData(params) {
noteable_type: noteableType, noteable_type: noteableType,
noteable_id: noteableData.id, noteable_id: noteableData.id,
commit_id: '', commit_id: '',
type: DIFF_NOTE_TYPE, type:
diffFile.diffRefs.startSha && diffFile.diffRefs.headSha
? DIFF_NOTE_TYPE
: LEGACY_DIFF_NOTE_TYPE,
line_code: noteTargetLine.lineCode, line_code: noteTargetLine.lineCode,
}, },
}; };
...@@ -230,7 +234,16 @@ export function getDiffPositionByLineCode(diffFiles) { ...@@ -230,7 +234,16 @@ export function getDiffPositionByLineCode(diffFiles) {
const { lineCode, oldLine, newLine } = line; const { lineCode, oldLine, newLine } = line;
if (lineCode) { if (lineCode) {
acc[lineCode] = { baseSha, headSha, startSha, newPath, oldPath, oldLine, newLine }; acc[lineCode] = {
baseSha,
headSha,
startSha,
newPath,
oldPath,
oldLine,
newLine,
lineCode,
};
} }
}); });
} }
...@@ -241,9 +254,15 @@ export function getDiffPositionByLineCode(diffFiles) { ...@@ -241,9 +254,15 @@ export function getDiffPositionByLineCode(diffFiles) {
// This method will check whether the discussion is still applicable // This method will check whether the discussion is still applicable
// to the diff line in question regarding different versions of the MR // to the diff line in question regarding different versions of the MR
export function isDiscussionApplicableToLine(discussion, diffPosition) { export function isDiscussionApplicableToLine({ discussion, diffPosition, latestDiff }) {
const originalRefs = convertObjectPropsToCamelCase(discussion.original_position.formatter); const { lineCode, ...diffPositionCopy } = diffPosition;
const refs = convertObjectPropsToCamelCase(discussion.position.formatter);
return _.isEqual(refs, diffPosition) || _.isEqual(originalRefs, diffPosition); if (discussion.original_position && discussion.position) {
const originalRefs = convertObjectPropsToCamelCase(discussion.original_position.formatter);
const refs = convertObjectPropsToCamelCase(discussion.position.formatter);
return _.isEqual(refs, diffPositionCopy) || _.isEqual(originalRefs, diffPositionCopy);
}
return latestDiff && discussion.active && lineCode === discussion.line_code;
} }
...@@ -27,7 +27,7 @@ export const getQuickActionText = note => { ...@@ -27,7 +27,7 @@ export const getQuickActionText = note => {
export const reduceDiscussionsToLineCodes = selectedDiscussions => export const reduceDiscussionsToLineCodes = selectedDiscussions =>
selectedDiscussions.reduce((acc, note) => { selectedDiscussions.reduce((acc, note) => {
if (note.diff_discussion && note.line_code && note.resolvable) { if (note.diff_discussion && note.line_code) {
// For context about line notes: there might be multiple notes with the same line code // For context about line notes: there might be multiple notes with the same line code
const items = acc[note.line_code] || []; const items = acc[note.line_code] || [];
items.push(note); items.push(note);
......
...@@ -131,7 +131,7 @@ class DiffNote < Note ...@@ -131,7 +131,7 @@ class DiffNote < Note
# As an extra benefit, the returned `diff_file` already # As an extra benefit, the returned `diff_file` already
# has `highlighted_diff_lines` data set from Redis on # has `highlighted_diff_lines` data set from Redis on
# `Diff::FileCollection::MergeRequestDiff`. # `Diff::FileCollection::MergeRequestDiff`.
noteable.diffs(paths: original_position.paths, expanded: true).diff_files.first noteable.diffs(original_position.diff_options).diff_files.first
else else
original_position.diff_file(self.project.repository) original_position.diff_file(self.project.repository)
end end
......
...@@ -31,7 +31,7 @@ module MergeRequests ...@@ -31,7 +31,7 @@ module MergeRequests
def clear_cache(new_diff) def clear_cache(new_diff)
# Executing the iteration we cache highlighted diffs for each diff file of # Executing the iteration we cache highlighted diffs for each diff file of
# MergeRequestDiff. # MergeRequestDiff.
new_diff.diffs_collection.write_cache cacheable_collection(new_diff).write_cache
# Remove cache for all diffs on this MR. Do not use the association on the # Remove cache for all diffs on this MR. Do not use the association on the
# model, as that will interfere with other actions happening when # model, as that will interfere with other actions happening when
...@@ -39,9 +39,15 @@ module MergeRequests ...@@ -39,9 +39,15 @@ module MergeRequests
MergeRequestDiff.where(merge_request: merge_request).each do |merge_request_diff| MergeRequestDiff.where(merge_request: merge_request).each do |merge_request_diff|
next if merge_request_diff == new_diff next if merge_request_diff == new_diff
merge_request_diff.diffs_collection.clear_cache cacheable_collection(merge_request_diff).clear_cache
end end
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def cacheable_collection(diff)
# There are scenarios where we don't need to request Diff Stats.
# Mainly when clearing / writing diff caches.
diff.diffs(include_stats: false)
end
end end
end end
...@@ -10,7 +10,7 @@ class NewMergeRequestWorker ...@@ -10,7 +10,7 @@ class NewMergeRequestWorker
EventCreateService.new.open_mr(issuable, user) EventCreateService.new.open_mr(issuable, user)
NotificationService.new.new_merge_request(issuable, user) NotificationService.new.new_merge_request(issuable, user)
issuable.diffs.write_cache issuable.diffs(include_stats: false).write_cache
issuable.create_cross_references!(user) issuable.create_cross_references!(user)
end end
......
---
title: Ensure the schema is loaded with post_migrations included
merge_request: 21689
author:
type: changed
---
title: Correctly show legacy diff notes in the merge request changes tab
merge_request: 21652
author:
type: fixed
---
title: Use stats RPC when comparing diffs
merge_request: 21778
author:
type: fixed
# Post deployment migrations are included by default. This file must be loaded # Post deployment migrations are included by default. This file must be loaded
# before other initializers as Rails may otherwise memoize a list of migrations # before other initializers as Rails may otherwise memoize a list of migrations
# excluding the post deployment migrations. # excluding the post deployment migrations.
<<<<<<< HEAD
unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS'] unless ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS']
Rails.application.config.paths['db'].each do |db_path| Rails.application.config.paths['db'].each do |db_path|
path = Rails.root.join(db_path, 'post_migrate').to_s path = Rails.root.join(db_path, 'post_migrate').to_s
...@@ -21,3 +22,6 @@ migrate_paths.each do |migrate_path| ...@@ -21,3 +22,6 @@ migrate_paths.each do |migrate_path|
Rails.application.config.paths['db/migrate'] << ee_migrate_path.to_s Rails.application.config.paths['db/migrate'] << ee_migrate_path.to_s
ActiveRecord::Migrator.migrations_paths << ee_migrate_path.to_s ActiveRecord::Migrator.migrations_paths << ee_migrate_path.to_s
end end
=======
Gitlab::Database.add_post_migrate_path_to_rails
>>>>>>> upstream/master
...@@ -261,5 +261,21 @@ module Gitlab ...@@ -261,5 +261,21 @@ module Gitlab
end end
private_class_method :database_version private_class_method :database_version
def self.add_post_migrate_path_to_rails(force: false)
return if ENV['SKIP_POST_DEPLOYMENT_MIGRATIONS'] && !force
Rails.application.config.paths['db'].each do |db_path|
path = Rails.root.join(db_path, 'post_migrate').to_s
unless Rails.application.config.paths['db/migrate'].include? path
Rails.application.config.paths['db/migrate'] << path
# Rails memoizes migrations at certain points where it won't read the above
# path just yet. As such we must also update the following list of paths.
ActiveRecord::Migrator.migrations_paths << path
end
end
end
end end
end end
...@@ -20,8 +20,9 @@ module Gitlab ...@@ -20,8 +20,9 @@ module Gitlab
DiffViewer::Image DiffViewer::Image
].sort_by { |v| v.binary? ? 0 : 1 }.freeze ].sort_by { |v| v.binary? ? 0 : 1 }.freeze
def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil) def initialize(diff, repository:, diff_refs: nil, fallback_diff_refs: nil, stats: nil)
@diff = diff @diff = diff
@stats = stats
@repository = repository @repository = repository
@diff_refs = diff_refs @diff_refs = diff_refs
@fallback_diff_refs = fallback_diff_refs @fallback_diff_refs = fallback_diff_refs
...@@ -165,11 +166,11 @@ module Gitlab ...@@ -165,11 +166,11 @@ module Gitlab
end end
def added_lines def added_lines
diff_lines.count(&:added?) @stats&.additions || diff_lines.count(&:added?)
end end
def removed_lines def removed_lines
diff_lines.count(&:removed?) @stats&.deletions || diff_lines.count(&:removed?)
end end
def file_identifier def file_identifier
......
...@@ -2,23 +2,27 @@ module Gitlab ...@@ -2,23 +2,27 @@ module Gitlab
module Diff module Diff
module FileCollection module FileCollection
class Base class Base
include Gitlab::Utils::StrongMemoize
attr_reader :project, :diff_options, :diff_refs, :fallback_diff_refs, :diffable attr_reader :project, :diff_options, :diff_refs, :fallback_diff_refs, :diffable
delegate :count, :size, :real_size, to: :diff_files delegate :count, :size, :real_size, to: :diff_files
def self.default_options def self.default_options
::Commit.max_diff_options.merge(ignore_whitespace_change: false, expanded: false) ::Commit.max_diff_options.merge(ignore_whitespace_change: false, expanded: false, include_stats: true)
end end
def initialize(diffable, project:, diff_options: nil, diff_refs: nil, fallback_diff_refs: nil) def initialize(diffable, project:, diff_options: nil, diff_refs: nil, fallback_diff_refs: nil)
diff_options = self.class.default_options.merge(diff_options || {}) diff_options = self.class.default_options.merge(diff_options || {})
@diffable = diffable @diffable = diffable
@include_stats = diff_options.delete(:include_stats)
@diffs = diffable.raw_diffs(diff_options) @diffs = diffable.raw_diffs(diff_options)
@project = project @project = project
@diff_options = diff_options @diff_options = diff_options
@diff_refs = diff_refs @diff_refs = diff_refs
@fallback_diff_refs = fallback_diff_refs @fallback_diff_refs = fallback_diff_refs
@repository = project.repository
end end
def diff_files def diff_files
...@@ -43,10 +47,27 @@ module Gitlab ...@@ -43,10 +47,27 @@ module Gitlab
private private
def diff_stats_collection
strong_memoize(:diff_stats) do
# There are scenarios where we don't need to request Diff Stats,
# when caching for instance.
next unless @include_stats
next unless diff_refs
@repository.diff_stats(diff_refs.base_sha, diff_refs.head_sha)
end
end
def decorate_diff!(diff) def decorate_diff!(diff)
return diff if diff.is_a?(File) return diff if diff.is_a?(File)
Gitlab::Diff::File.new(diff, repository: project.repository, diff_refs: diff_refs, fallback_diff_refs: fallback_diff_refs) stats = diff_stats_collection&.find_by_path(diff.new_path)
Gitlab::Diff::File.new(diff,
repository: project.repository,
diff_refs: diff_refs,
fallback_diff_refs: fallback_diff_refs,
stats: stats)
end end
end end
end end
......
...@@ -116,6 +116,10 @@ module Gitlab ...@@ -116,6 +116,10 @@ module Gitlab
end end
end end
def diff_options
{ paths: paths, expanded: true, include_stats: false }
end
def diff_line(repository) def diff_line(repository)
@diff_line ||= diff_file(repository)&.line_for_position(self) @diff_line ||= diff_file(repository)&.line_for_position(self)
end end
...@@ -130,7 +134,7 @@ module Gitlab ...@@ -130,7 +134,7 @@ module Gitlab
return unless diff_refs.complete? return unless diff_refs.complete?
return unless comparison = diff_refs.compare_in(repository.project) return unless comparison = diff_refs.compare_in(repository.project)
comparison.diffs(paths: paths, expanded: true).diff_files.first comparison.diffs(diff_options).diff_files.first
end end
def get_formatter_class(type) def get_formatter_class(type)
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
module Gitlab module Gitlab
module Git module Git
class DiffStatsCollection class DiffStatsCollection
include Gitlab::Utils::StrongMemoize
include Enumerable include Enumerable
def initialize(diff_stats) def initialize(diff_stats)
...@@ -12,6 +13,18 @@ module Gitlab ...@@ -12,6 +13,18 @@ module Gitlab
def each(&block) def each(&block)
@collection.each(&block) @collection.each(&block)
end end
def find_by_path(path)
indexed_by_path[path]
end
private
def indexed_by_path
strong_memoize(:indexed_by_path) do
index_by { |stats| stats.path }
end
end
end end
end end
end end
...@@ -444,7 +444,7 @@ module Gitlab ...@@ -444,7 +444,7 @@ module Gitlab
end end
Gitlab::Git::DiffStatsCollection.new(stats) Gitlab::Git::DiffStatsCollection.new(stats)
rescue CommandError rescue CommandError, TypeError
Gitlab::Git::DiffStatsCollection.new([]) Gitlab::Git::DiffStatsCollection.new([])
end end
......
...@@ -51,6 +51,8 @@ namespace :gitlab do ...@@ -51,6 +51,8 @@ namespace :gitlab do
if ActiveRecord::Base.connection.tables.count > 1 if ActiveRecord::Base.connection.tables.count > 1
Rake::Task['db:migrate'].invoke Rake::Task['db:migrate'].invoke
else else
# Add post-migrate paths to ensure we mark all migrations as up
Gitlab::Database.add_post_migrate_path_to_rails(force: true)
Rake::Task['db:schema:load'].invoke Rake::Task['db:schema:load'].invoke
Rake::Task['db:seed_fu'].invoke Rake::Task['db:seed_fu'].invoke
end end
......
...@@ -771,6 +771,7 @@ msgstr "" ...@@ -771,6 +771,7 @@ msgstr ""
msgid "Artifacts" msgid "Artifacts"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Ascending" msgid "Ascending"
msgstr "" msgstr ""
...@@ -778,6 +779,9 @@ msgid "Ask your group maintainer to set up a group Runner." ...@@ -778,6 +779,9 @@ msgid "Ask your group maintainer to set up a group Runner."
msgstr "" msgstr ""
msgid "Assertion consumer service URL" msgid "Assertion consumer service URL"
=======
msgid "Ask your group maintainer to set up a group Runner."
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "Assign custom color like #FF0000" msgid "Assign custom color like #FF0000"
...@@ -6773,9 +6777,12 @@ msgstr "" ...@@ -6773,9 +6777,12 @@ msgstr ""
msgid "Set up a specific Runner automatically" msgid "Set up a specific Runner automatically"
msgstr "" msgstr ""
<<<<<<< HEAD
msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}" msgid "Set up assertions/attributes/claims (email, first_name, last_name) and NameID according to %{docsLinkStart}the documentation %{icon}%{docsLinkEnd}"
msgstr "" msgstr ""
=======
>>>>>>> upstream/master
msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically." msgid "Set up your project to automatically push and/or pull changes to/from another repository. Branches, tags, and commits will be synced automatically."
msgstr "" msgstr ""
...@@ -8432,9 +8439,12 @@ msgid "You can resolve the merge conflict using either the Interactive mode, by ...@@ -8432,9 +8439,12 @@ msgid "You can resolve the merge conflict using either the Interactive mode, by
msgstr "" msgstr ""
msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas." msgid "You can set up jobs to only use Runners with specific tags. Separate tags with commas."
<<<<<<< HEAD
msgstr "" msgstr ""
msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead." msgid "You cannot write to a read-only secondary GitLab Geo instance. Please use %{link_to_primary_node} instead."
=======
>>>>>>> upstream/master
msgstr "" msgstr ""
msgid "You cannot write to this read-only GitLab instance." msgid "You cannot write to this read-only GitLab instance."
......
...@@ -6,7 +6,6 @@ module RuboCop ...@@ -6,7 +6,6 @@ module RuboCop
MSG = "Don't use ruby interpolation \#{} inside translated strings, instead use \%{}" MSG = "Don't use ruby interpolation \#{} inside translated strings, instead use \%{}"
TRANSLATION_METHODS = ':_ :s_ :N_ :n_' TRANSLATION_METHODS = ':_ :s_ :N_ :n_'
RUBY_INTERPOLATION_REGEX = /.*\#\{.*\}/
def_node_matcher :translation_method?, <<~PATTERN def_node_matcher :translation_method?, <<~PATTERN
(send nil? {#{TRANSLATION_METHODS}} $dstr ...) (send nil? {#{TRANSLATION_METHODS}} $dstr ...)
......
...@@ -200,23 +200,20 @@ describe 'Merge request > User posts diff notes', :js do ...@@ -200,23 +200,20 @@ describe 'Merge request > User posts diff notes', :js do
end end
context 'with a new line' do context 'with a new line' do
# TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034 it 'allows commenting' do
xit 'allows commenting' do should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]'))
should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9"]').find(:xpath, '..'))
end end
end end
context 'with an old line' do context 'with an old line' do
# TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034 it 'allows commenting' do
xit 'allows commenting' do should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]'))
should_allow_commenting(find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9_22_22"]').find(:xpath, '..'))
end end
end end
context 'with an unchanged line' do context 'with an unchanged line' do
# TODO: https://gitlab.com/gitlab-org/gitlab-ce/issues/48034 it 'allows commenting' do
xit 'allows commenting' do should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]'))
should_allow_commenting(find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7"]').find(:xpath, '..'))
end end
end end
......
...@@ -157,6 +157,7 @@ describe('DiffsStoreActions', () => { ...@@ -157,6 +157,7 @@ describe('DiffsStoreActions', () => {
newPath: 'file1', newPath: 'file1',
oldLine: 5, oldLine: 5,
oldPath: 'file2', oldPath: 'file2',
lineCode: 'ABC_1_1',
}, },
}, },
}, },
......
...@@ -162,6 +162,7 @@ describe('DiffsStoreMutations', () => { ...@@ -162,6 +162,7 @@ describe('DiffsStoreMutations', () => {
}; };
const state = { const state = {
latestDiff: true,
diffFiles: [ diffFiles: [
{ {
fileHash: 'ABC', fileHash: 'ABC',
...@@ -229,6 +230,76 @@ describe('DiffsStoreMutations', () => { ...@@ -229,6 +230,76 @@ describe('DiffsStoreMutations', () => {
expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2); expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2);
expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2); expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2);
}); });
it('should add legacy discussions to the given line', () => {
const diffPosition = {
baseSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
headSha: 'b921914f9a834ac47e6fd9420f78db0f83559130',
newLine: null,
newPath: '500-lines-4.txt',
oldLine: 5,
oldPath: '500-lines-4.txt',
startSha: 'ed13df29948c41ba367caa757ab3ec4892509910',
lineCode: 'ABC_1',
};
const state = {
latestDiff: true,
diffFiles: [
{
fileHash: 'ABC',
parallelDiffLines: [
{
left: {
lineCode: 'ABC_1',
discussions: [],
},
right: {
lineCode: 'ABC_1',
discussions: [],
},
},
],
highlightedDiffLines: [
{
lineCode: 'ABC_1',
discussions: [],
},
],
},
],
};
const discussions = [
{
id: 1,
line_code: 'ABC_1',
diff_discussion: true,
active: true,
},
{
id: 2,
line_code: 'ABC_1',
diff_discussion: true,
active: true,
},
];
const diffPositionByLineCode = {
ABC_1: diffPosition,
};
mutations[types.SET_LINE_DISCUSSIONS_FOR_FILE](state, {
fileHash: 'ABC',
discussions,
diffPositionByLineCode,
});
expect(state.diffFiles[0].parallelDiffLines[0].left.discussions.length).toEqual(2);
expect(state.diffFiles[0].parallelDiffLines[0].left.discussions[1].id).toEqual(2);
expect(state.diffFiles[0].highlightedDiffLines[0].discussions.length).toEqual(2);
expect(state.diffFiles[0].highlightedDiffLines[0].discussions[1].id).toEqual(2);
});
}); });
describe('REMOVE_LINE_DISCUSSIONS', () => { describe('REMOVE_LINE_DISCUSSIONS', () => {
......
...@@ -3,6 +3,7 @@ import { ...@@ -3,6 +3,7 @@ import {
LINE_POSITION_LEFT, LINE_POSITION_LEFT,
LINE_POSITION_RIGHT, LINE_POSITION_RIGHT,
TEXT_DIFF_POSITION_TYPE, TEXT_DIFF_POSITION_TYPE,
LEGACY_DIFF_NOTE_TYPE,
DIFF_NOTE_TYPE, DIFF_NOTE_TYPE,
NEW_LINE_TYPE, NEW_LINE_TYPE,
OLD_LINE_TYPE, OLD_LINE_TYPE,
...@@ -151,6 +152,64 @@ describe('DiffsStoreUtils', () => { ...@@ -151,6 +152,64 @@ describe('DiffsStoreUtils', () => {
data: postData, data: postData,
}); });
}); });
it('should create legacy note form data', () => {
const diffFile = getDiffFileMock();
delete diffFile.diffRefs.startSha;
delete diffFile.diffRefs.headSha;
noteableDataMock.targetType = MERGE_REQUEST_NOTEABLE_TYPE;
const options = {
note: 'Hello world!',
noteableData: noteableDataMock,
noteableType: MERGE_REQUEST_NOTEABLE_TYPE,
diffFile,
noteTargetLine: {
lineCode: '1c497fbb3a46b78edf04cc2a2fa33f67e3ffbe2a_1_3',
metaData: null,
newLine: 3,
oldLine: 1,
},
diffViewType: PARALLEL_DIFF_VIEW_TYPE,
linePosition: LINE_POSITION_LEFT,
};
const position = JSON.stringify({
base_sha: diffFile.diffRefs.baseSha,
start_sha: undefined,
head_sha: undefined,
old_path: diffFile.oldPath,
new_path: diffFile.newPath,
position_type: TEXT_DIFF_POSITION_TYPE,
old_line: options.noteTargetLine.oldLine,
new_line: options.noteTargetLine.newLine,
});
const postData = {
view: options.diffViewType,
line_type: options.linePosition === LINE_POSITION_RIGHT ? NEW_LINE_TYPE : OLD_LINE_TYPE,
merge_request_diff_head_sha: undefined,
in_reply_to_discussion_id: '',
note_project_id: '',
target_type: options.noteableType,
target_id: options.noteableData.id,
note: {
noteable_type: options.noteableType,
noteable_id: options.noteableData.id,
commit_id: '',
type: LEGACY_DIFF_NOTE_TYPE,
line_code: options.noteTargetLine.lineCode,
note: options.note,
position,
},
};
expect(utils.getNoteFormData(options)).toEqual({
endpoint: options.noteableData.create_note_path,
data: postData,
});
});
}); });
describe('addLineReferences', () => { describe('addLineReferences', () => {
...@@ -291,13 +350,72 @@ describe('DiffsStoreUtils', () => { ...@@ -291,13 +350,72 @@ describe('DiffsStoreUtils', () => {
it('returns true when the discussion is up to date', () => { it('returns true when the discussion is up to date', () => {
expect( expect(
utils.isDiscussionApplicableToLine(discussions.upToDateDiscussion1, diffPosition), utils.isDiscussionApplicableToLine({
discussion: discussions.upToDateDiscussion1,
diffPosition,
latestDiff: true,
}),
).toBe(true); ).toBe(true);
}); });
it('returns false when the discussion is not up to date', () => { it('returns false when the discussion is not up to date', () => {
expect( expect(
utils.isDiscussionApplicableToLine(discussions.outDatedDiscussion1, diffPosition), utils.isDiscussionApplicableToLine({
discussion: discussions.outDatedDiscussion1,
diffPosition,
latestDiff: true,
}),
).toBe(false);
});
it('returns true when line codes match and discussion does not contain position and is not active', () => {
const discussion = { ...discussions.outDatedDiscussion1, line_code: 'ABC_1', active: false };
delete discussion.original_position;
delete discussion.position;
expect(
utils.isDiscussionApplicableToLine({
discussion,
diffPosition: {
...diffPosition,
lineCode: 'ABC_1',
},
latestDiff: true,
}),
).toBe(false);
});
it('returns true when line codes match and discussion does not contain position and is active', () => {
const discussion = { ...discussions.outDatedDiscussion1, line_code: 'ABC_1', active: true };
delete discussion.original_position;
delete discussion.position;
expect(
utils.isDiscussionApplicableToLine({
discussion,
diffPosition: {
...diffPosition,
lineCode: 'ABC_1',
},
latestDiff: true,
}),
).toBe(true);
});
it('returns false when not latest diff', () => {
const discussion = { ...discussions.outDatedDiscussion1, line_code: 'ABC_1', active: true };
delete discussion.original_position;
delete discussion.position;
expect(
utils.isDiscussionApplicableToLine({
discussion,
diffPosition: {
...diffPosition,
lineCode: 'ABC_1',
},
latestDiff: false,
}),
).toBe(false); ).toBe(false);
}); });
}); });
......
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Diff::FileCollection::Commit do
let(:project) { create(:project, :repository) }
it_behaves_like 'diff statistics' do
let(:collection_default_args) do
{ diff_options: {} }
end
let(:diffable) { project.commit }
let(:stub_path) { 'bar/branch-test.txt' }
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Diff::FileCollection::Compare do
include RepoHelpers
let(:project) { create(:project, :repository) }
let(:commit) { project.commit }
let(:start_commit) { sample_image_commit }
let(:head_commit) { sample_commit }
let(:raw_compare) do
Gitlab::Git::Compare.new(project.repository.raw_repository,
start_commit.id,
head_commit.id)
end
it_behaves_like 'diff statistics' do
let(:collection_default_args) do
{
project: diffable.project,
diff_options: {},
diff_refs: diffable.diff_refs
}
end
let(:diffable) { Compare.new(raw_compare, project) }
let(:stub_path) { '.gitignore' }
end
end
...@@ -29,6 +29,14 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do ...@@ -29,6 +29,14 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
expect(mr_diff.cache_key).not_to eq(key) expect(mr_diff.cache_key).not_to eq(key)
end end
it_behaves_like 'diff statistics' do
let(:collection_default_args) do
{ diff_options: {} }
end
let(:diffable) { merge_request.merge_request_diff }
let(:stub_path) { '.gitignore' }
end
shared_examples 'initializes a DiffCollection' do shared_examples 'initializes a DiffCollection' do
it 'returns a valid instance of a DiffCollection' do it 'returns a valid instance of a DiffCollection' do
expect(diff_files).to be_a(Gitlab::Git::DiffCollection) expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
......
...@@ -186,6 +186,70 @@ describe Gitlab::Diff::File do ...@@ -186,6 +186,70 @@ describe Gitlab::Diff::File do
end end
end end
context 'diff file stats' do
let(:diff_file) do
described_class.new(diff,
diff_refs: commit.diff_refs,
repository: project.repository,
stats: stats)
end
let(:raw_diff) do
<<~EOS
--- a/files/ruby/popen.rb
+++ b/files/ruby/popen.rb
@@ -6,12 +6,18 @@ module Popen
def popen(cmd, path=nil)
unless cmd.is_a?(Array)
- raise "System commands must be given as an array of strings"
+ raise RuntimeError, "System commands must be given as an array of strings"
+ # foobar
end
EOS
end
describe '#added_lines' do
context 'when stats argument given' do
let(:stats) { double(Gitaly::DiffStats, additions: 10, deletions: 15) }
it 'returns added lines from stats' do
expect(diff_file.added_lines).to eq(stats.additions)
end
end
context 'when stats argument not given' do
let(:stats) { nil }
it 'returns added lines by parsing raw diff' do
allow(diff_file).to receive(:raw_diff) { raw_diff }
expect(diff_file.added_lines).to eq(2)
end
end
end
describe '#removed_lines' do
context 'when stats argument given' do
let(:stats) { double(Gitaly::DiffStats, additions: 10, deletions: 15) }
it 'returns removed lines from stats' do
expect(diff_file.removed_lines).to eq(stats.deletions)
end
end
context 'when stats argument not given' do
let(:stats) { nil }
it 'returns removed lines by parsing raw diff' do
allow(diff_file).to receive(:raw_diff) { raw_diff }
expect(diff_file.removed_lines).to eq(1)
end
end
end
end
describe '#simple_viewer' do describe '#simple_viewer' do
context 'when the file is not diffable' do context 'when the file is not diffable' do
before do before do
......
# frozen_string_literal: true
require "spec_helper"
describe Gitlab::Git::DiffStatsCollection do
let(:stats_a) do
double(Gitaly::DiffStats, additions: 10, deletions: 15, path: 'foo')
end
let(:stats_b) do
double(Gitaly::DiffStats, additions: 5, deletions: 1, path: 'bar')
end
let(:diff_stats) { [stats_a, stats_b] }
let(:collection) { described_class.new(diff_stats) }
describe '.find_by_path' do
it 'returns stats by path when found' do
expect(collection.find_by_path('foo')).to eq(stats_a)
end
it 'returns nil when stats is not found by path' do
expect(collection.find_by_path('no-file')).to be_nil
end
end
end
...@@ -1136,6 +1136,14 @@ describe Gitlab::Git::Repository, :seed_helper do ...@@ -1136,6 +1136,14 @@ describe Gitlab::Git::Repository, :seed_helper do
expect(collection).to be_a(Enumerable) expect(collection).to be_a(Enumerable)
expect(collection.to_a).to be_empty expect(collection.to_a).to be_empty
end end
it 'returns no Gitaly::DiffStats when there is a nil SHA' do
collection = repository.diff_stats(nil, 'master')
expect(collection).to be_a(Gitlab::Git::DiffStatsCollection)
expect(collection).to be_a(Enumerable)
expect(collection.to_a).to be_empty
end
end end
describe "#ls_files" do describe "#ls_files" do
......
# frozen_string_literal: true
shared_examples 'diff statistics' do |test_include_stats_flag: true|
def stub_stats_find_by_path(path, stats_mock)
expect_next_instance_of(Gitlab::Git::DiffStatsCollection) do |collection|
allow(collection).to receive(:find_by_path).and_call_original
expect(collection).to receive(:find_by_path).with(path).and_return(stats_mock)
end
end
context 'when should request diff stats' do
it 'Repository#diff_stats is called' do
subject = described_class.new(diffable, collection_default_args)
expect(diffable.project.repository)
.to receive(:diff_stats)
.with(diffable.diff_refs.base_sha, diffable.diff_refs.head_sha)
.and_call_original
subject.diff_files
end
it 'Gitlab::Diff::File is initialized with diff stats' do
subject = described_class.new(diffable, collection_default_args)
stats_mock = double(Gitaly::DiffStats, path: '.gitignore', additions: 758, deletions: 120)
stub_stats_find_by_path(stub_path, stats_mock)
diff_file = subject.diff_files.find { |file| file.new_path == stub_path }
expect(diff_file.added_lines).to eq(stats_mock.additions)
expect(diff_file.removed_lines).to eq(stats_mock.deletions)
end
end
context 'when should not request diff stats' do
it 'Repository#diff_stats is not called' do
collection_default_args[:diff_options][:include_stats] = false
subject = described_class.new(diffable, collection_default_args)
expect(diffable.project.repository).not_to receive(:diff_stats)
subject.diff_files
end
end
end
...@@ -61,6 +61,39 @@ describe 'gitlab:db namespace rake task' do ...@@ -61,6 +61,39 @@ describe 'gitlab:db namespace rake task' do
expect(Rake::Task['db:migrate']).not_to receive(:invoke) expect(Rake::Task['db:migrate']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error') expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error')
end end
context 'SKIP_POST_DEPLOYMENT_MIGRATIONS environment variable set' do
let(:rails_paths) { { 'db' => ['db'], 'db/migrate' => ['db/migrate'] } }
before do
allow(ENV).to receive(:[]).and_call_original
allow(ENV).to receive(:[]).with('SKIP_POST_DEPLOYMENT_MIGRATIONS').and_return true
# Our environment has already been loaded, so we need to pretend like post_migrations were not
allow(Rails.application.config).to receive(:paths).and_return(rails_paths)
allow(ActiveRecord::Migrator).to receive(:migrations_paths).and_return(rails_paths['db/migrate'].dup)
end
it 'adds post deployment migrations before schema load if the schema is not already loaded' do
allow(ActiveRecord::Base.connection).to receive(:tables).and_return([])
expect(Gitlab::Database).to receive(:add_post_migrate_path_to_rails).and_call_original
expect(Rake::Task['db:schema:load']).to receive(:invoke)
expect(Rake::Task['db:seed_fu']).to receive(:invoke)
expect(Rake::Task['db:migrate']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
expect(rails_paths['db/migrate'].include?(File.join(Rails.root, 'db', 'post_migrate'))).to be(true)
end
it 'ignores post deployment migrations when schema has already been loaded' do
allow(ActiveRecord::Base.connection).to receive(:tables).and_return(%w[table1 table2])
expect(Rake::Task['db:migrate']).to receive(:invoke)
expect(Gitlab::Database).not_to receive(:add_post_migrate_path_to_rails)
expect(Rake::Task['db:schema:load']).not_to receive(:invoke)
expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
expect(rails_paths['db/migrate'].include?(File.join(Rails.root, 'db', 'post_migrate'))).to be(false)
end
end
end end
def run_rake_task(task_name) def run_rake_task(task_name)
......
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