提交 c3afbe83 编写于 作者: C Clement Ho

Merge branch 'master' into 'projects-r-s'

# Conflicts:
#   app/assets/javascripts/dispatcher.js
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2017-12-14 12:04:26 +0100 using RuboCop version 0.52.0.
# on 2018-01-18 18:23:26 +0100 using RuboCop version 0.52.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 174
# Offense count: 181
Capybara/CurrentPathExpectation:
Enabled: false
# Offense count: 951
# Offense count: 956
Capybara/FeatureMethods:
Enabled: false
# Offense count: 24
# Offense count: 23
FactoryBot/DynamicAttributeDefinedStatically:
Exclude:
- 'spec/factories/broadcast_messages.rb'
- 'spec/factories/ci/builds.rb'
- 'spec/factories/ci/runners.rb'
- 'spec/factories/clusters/applications/helm.rb'
- 'spec/factories/clusters/applications/ingress.rb'
- 'spec/factories/clusters/platforms/kubernetes.rb'
- 'spec/factories/emails.rb'
- 'spec/factories/gpg_keys.rb'
......@@ -33,40 +32,31 @@ FactoryBot/DynamicAttributeDefinedStatically:
- 'spec/factories/todos.rb'
- 'spec/factories/uploads.rb'
# Offense count: 65
# Offense count: 167
# Cop supports --auto-correct.
Layout/EmptyLinesAroundArguments:
Enabled: false
# Offense count: 249
# Offense count: 253
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment.
Layout/ExtraSpacing:
Enabled: false
# Offense count: 82
# Offense count: 83
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets
Layout/IndentArray:
Enabled: false
# Offense count: 239
# Offense count: 237
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces
Layout/IndentHash:
Enabled: false
# Offense count: 15
# Cop supports --auto-correct.
# Configuration parameters: .
# SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceBeforeBlockBraces:
EnforcedStyle: space
EnforcedStyleForEmptyBraces: space
# Offense count: 11
# Cop supports --auto-correct.
# Configuration parameters: AllowForAlignment.
......@@ -97,7 +87,7 @@ Layout/SpaceInsideArrayLiteralBrackets:
Exclude:
- 'spec/lib/gitlab/import_export/relation_factory_spec.rb'
# Offense count: 323
# Offense count: 327
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space
......@@ -105,7 +95,7 @@ Layout/SpaceInsideArrayLiteralBrackets:
Layout/SpaceInsideBlockBraces:
Enabled: false
# Offense count: 146
# Offense count: 156
# Cop supports --auto-correct.
Layout/SpaceInsideParens:
Enabled: false
......@@ -118,7 +108,7 @@ Layout/SpaceInsidePercentLiteralDelimiters:
- 'lib/gitlab/health_checks/fs_shards_check.rb'
- 'spec/lib/gitlab/health_checks/fs_shards_check_spec.rb'
# Offense count: 25
# Offense count: 26
Lint/DuplicateMethods:
Exclude:
- 'app/models/application_setting.rb'
......@@ -144,7 +134,7 @@ Lint/InterpolationCheck:
- 'spec/features/users_spec.rb'
- 'spec/services/quick_actions/interpret_service_spec.rb'
# Offense count: 198
# Offense count: 206
# Configuration parameters: MaximumRangeSize.
Lint/MissingCopEnableDirective:
Enabled: false
......@@ -185,6 +175,12 @@ Lint/UriEscapeUnescape:
- 'spec/requests/api/issues_spec.rb'
- 'spec/requests/api/v3/issues_spec.rb'
# Offense count: 1
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
Max: 1310
# Offense count: 2
Naming/ConstantName:
Exclude:
......@@ -202,13 +198,13 @@ Naming/HeredocDelimiterCase:
- 'spec/support/repo_helpers.rb'
- 'spec/support/seed_repo.rb'
# Offense count: 101
# Offense count: 112
# Configuration parameters: Blacklist.
# Blacklist: END, (?-mix:EO[A-Z]{1})
Naming/HeredocDelimiterNaming:
Enabled: false
# Offense count: 28
# Offense count: 27
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect.
Performance/HashEachMethods:
......@@ -225,21 +221,27 @@ Performance/UriDefaultParser:
Exclude:
- 'lib/gitlab/url_sanitizer.rb'
# Offense count: 3745
# Offense count: 3821
# Configuration parameters: Prefixes.
# Prefixes: when, with, without
RSpec/ContextWording:
Enabled: false
# Offense count: 291
# Offense count: 293
RSpec/EmptyLineAfterFinalLet:
Enabled: false
# Offense count: 180
# Offense count: 188
RSpec/EmptyLineAfterSubject:
Enabled: false
# Offense count: 220
# Offense count: 258
# Configuration parameters: EnforcedStyle.
# SupportedStyles: method_call, block
RSpec/ExpectChange:
Enabled: false
# Offense count: 221
RSpec/ExpectInHook:
Enabled: false
......@@ -304,7 +306,7 @@ RSpec/OverwritingSetup:
- 'spec/services/merge_requests/add_todo_when_build_fails_service_spec.rb'
- 'spec/services/notes/quick_actions_service_spec.rb'
# Offense count: 917
# Offense count: 965
# Configuration parameters: Strict, EnforcedStyle.
# SupportedStyles: inflected, explicit
RSpec/PredicateMatcher:
......@@ -314,13 +316,13 @@ RSpec/PredicateMatcher:
RSpec/RepeatedExample:
Enabled: false
# Offense count: 132
# Offense count: 140
# Configuration parameters: EnforcedStyle.
# SupportedStyles: and_return, block
RSpec/ReturnFromStub:
Enabled: false
# Offense count: 105
# Offense count: 112
RSpec/ScatteredLet:
Enabled: false
......@@ -353,23 +355,23 @@ RSpec/VoidExpect:
- 'spec/models/ci/runner_spec.rb'
- 'spec/services/users/destroy_service_spec.rb'
# Offense count: 40
# Offense count: 41
# Configuration parameters: Include.
# Include: db/migrate/*.rb
Rails/CreateTableWithTimestamps:
Enabled: false
# Offense count: 149
# Offense count: 155
Rails/FilePath:
Enabled: false
# Offense count: 119
# Offense count: 121
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/HasManyOrHasOneDependent:
Enabled: false
# Offense count: 113
# Offense count: 157
# Configuration parameters: Include.
# Include: app/models/**/*.rb
Rails/InverseOf:
......@@ -399,12 +401,6 @@ Rails/Presence:
- 'lib/gitlab/git/hook.rb'
- 'lib/gitlab/github_import/importer/releases_importer.rb'
# Offense count: 14
# Cop supports --auto-correct.
Rails/RedundantReceiverInWithOptions:
Exclude:
- 'config/initializers/doorkeeper_openid_connect.rb'
# Offense count: 2
# Configuration parameters: Include.
# Include: db/migrate/*.rb
......@@ -412,7 +408,7 @@ Rails/ReversibleMigration:
Exclude:
- 'db/migrate/20160824103857_drop_unused_ci_tables.rb'
# Offense count: 430
# Offense count: 446
# Configuration parameters: Blacklist.
# Blacklist: decrement!, decrement_counter, increment!, increment_counter, toggle!, touch, update_all, update_attribute, update_column, update_columns, update_counters
Rails/SkipsModelValidations:
......@@ -439,7 +435,7 @@ Security/YAMLLoad:
- 'spec/models/clusters/platforms/kubernetes_spec.rb'
- 'spec/models/project_services/kubernetes_service_spec.rb'
# Offense count: 63
# Offense count: 64
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: percent_q, bare_percent
......@@ -506,7 +502,7 @@ Style/EmptyLiteral:
- 'spec/requests/api/jobs_spec.rb'
- 'spec/support/chat_slash_commands_shared_examples.rb'
# Offense count: 98
# Offense count: 102
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: compact, expanded
......@@ -523,35 +519,28 @@ Style/EvalWithLocation:
Exclude:
- 'app/models/service.rb'
# Offense count: 52
# Cop supports --auto-correct.
# Configuration parameters: Autocorrect, EnforcedStyle.
# SupportedStyles: module_function, extend_self
Style/ExtendSelf:
Enabled: false
# Offense count: 34
# Offense count: 35
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: format, sprintf, percent
Style/FormatString:
Enabled: false
# Offense count: 371
# Offense count: 384
# Configuration parameters: MinBodyLength.
Style/GuardClause:
Enabled: false
# Offense count: 21
# Offense count: 22
Style/IfInsideElse:
Enabled: false
# Offense count: 781
# Offense count: 809
# Cop supports --auto-correct.
Style/IfUnlessModifier:
Enabled: false
# Offense count: 71
# Offense count: 75
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: line_count_dependent, lambda, literal
......@@ -573,7 +562,7 @@ Style/LineEndConcatenation:
Style/MethodCallWithoutArgsParentheses:
Enabled: false
# Offense count: 17
# Offense count: 18
Style/MethodMissing:
Enabled: false
......@@ -599,28 +588,28 @@ Style/MultilineIfModifier:
- 'lib/api/commit_statuses.rb'
- 'lib/gitlab/ci/trace.rb'
# Offense count: 23
# Offense count: 25
# Cop supports --auto-correct.
# Configuration parameters: Whitelist.
# Whitelist: be, be_a, be_an, be_between, be_falsey, be_kind_of, be_instance_of, be_truthy, be_within, eq, eql, end_with, include, match, raise_error, respond_to, start_with
Style/NestedParenthesizedCalls:
Enabled: false
# Offense count: 20
# Offense count: 19
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength.
# SupportedStyles: skip_modifier_ifs, always
Style/Next:
Enabled: false
# Offense count: 58
# Offense count: 61
# Cop supports --auto-correct.
# Configuration parameters: EnforcedOctalStyle.
# SupportedOctalStyles: zero_with_o, zero_only
Style/NumericLiteralPrefix:
Enabled: false
# Offense count: 112
# Offense count: 114
# Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, EnforcedStyle.
# SupportedStyles: predicate, comparison
......@@ -641,7 +630,7 @@ Style/OrAssignment:
Style/ParallelAssignment:
Enabled: false
# Offense count: 891
# Offense count: 917
# Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters:
......@@ -663,14 +652,14 @@ Style/PerlBackrefs:
- 'lib/gitlab/search_results.rb'
- 'lib/gitlab/sherlock/query.rb'
# Offense count: 82
# Offense count: 87
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: compact, exploded
Style/RaiseArgs:
Enabled: false
# Offense count: 8
# Offense count: 9
# Cop supports --auto-correct.
Style/RedundantBegin:
Exclude:
......@@ -689,7 +678,7 @@ Style/RedundantConditional:
Exclude:
- 'lib/system_check/helpers.rb'
# Offense count: 58
# Offense count: 57
# Cop supports --auto-correct.
Style/RedundantFreeze:
Enabled: false
......@@ -709,31 +698,31 @@ Style/RedundantReturn:
- 'lib/gitlab/utils.rb'
- 'lib/google_api/auth.rb'
# Offense count: 454
# Offense count: 460
# Cop supports --auto-correct.
Style/RedundantSelf:
Enabled: false
# Offense count: 140
# Offense count: 142
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral:
Enabled: false
# Offense count: 35
# Offense count: 36
# Cop supports --auto-correct.
Style/RescueModifier:
Enabled: false
# Offense count: 105
# Offense count: 107
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, explicit
Style/RescueStandardError:
Enabled: false
# Offense count: 91
# Offense count: 92
# Cop supports --auto-correct.
# Configuration parameters: ConvertCodeThatCanStartToReturnNil.
Style/SafeNavigation:
......@@ -778,7 +767,7 @@ Style/StderrPuts:
Style/StringLiteralsInInterpolation:
Enabled: false
# Offense count: 99
# Offense count: 106
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method
......@@ -837,7 +826,7 @@ Style/UnlessElse:
- 'lib/tasks/gitlab/check.rake'
- 'spec/features/issues/award_emoji_spec.rb'
# Offense count: 30
# Offense count: 31
# Cop supports --auto-correct.
Style/UnneededInterpolation:
Enabled: false
......@@ -856,7 +845,7 @@ Style/ZeroLengthPredicate:
- 'lib/extracts_path.rb'
- 'lib/gitlab/git/repository.rb'
# Offense count: 22050
# Offense count: 22840
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https
Metrics/LineLength:
......
......@@ -341,10 +341,10 @@ group :development, :test do
gem 'spring-commands-rspec', '~> 1.0.4'
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'gitlab-styles', '~> 2.2.0', require: false
gem 'gitlab-styles', '~> 2.3', require: false
# Pin these dependencies, otherwise a new rule could break the CI pipelines
gem 'rubocop', '~> 0.52.0'
gem 'rubocop-rspec', '~> 1.20.1'
gem 'rubocop', '~> 0.52.1'
gem 'rubocop-rspec', '~> 1.22.1'
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.26.0', require: false
......
......@@ -304,7 +304,7 @@ GEM
mime-types (>= 1.16)
posix-spawn (~> 0.3)
gitlab-markup (1.6.3)
gitlab-styles (2.2.0)
gitlab-styles (2.3.0)
rubocop (~> 0.51)
rubocop-gitlab-security (~> 0.1.0)
rubocop-rspec (~> 1.19)
......@@ -583,7 +583,7 @@ GEM
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (0.9.6)
parallel (1.12.0)
parallel (1.12.1)
parser (2.4.0.2)
ast (~> 2.3)
parslet (1.5.0)
......@@ -786,7 +786,7 @@ GEM
pg
rails
sqlite3
rubocop (0.52.0)
rubocop (0.52.1)
parallel (~> 1.10)
parser (>= 2.4.0.2, < 3.0)
powerpack (~> 0.1)
......@@ -795,8 +795,8 @@ GEM
unicode-display_width (~> 1.0, >= 1.0.1)
rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51)
rubocop-rspec (1.20.1)
rubocop (>= 0.51.0)
rubocop-rspec (1.22.1)
rubocop (>= 0.52.1)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.16.2)
......@@ -1060,7 +1060,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)
gitlab-styles (~> 2.2.0)
gitlab-styles (~> 2.3)
gitlab_omniauth-ldap (~> 2.0.4)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.4)
......@@ -1162,8 +1162,8 @@ DEPENDENCIES
rspec-retry (~> 0.4.5)
rspec-set (~> 0.1.3)
rspec_profiling (~> 0.0.5)
rubocop (~> 0.52.0)
rubocop-rspec (~> 1.20.1)
rubocop (~> 0.52.1)
rubocop-rspec (~> 1.22.1)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.16.2)
ruby_parser (~> 3.8)
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
import projectSelect from './project_select';
import Milestone from './milestone';
import IssuableForm from './issuable_form';
import LabelsSelect from './labels_select';
import MilestoneSelect from './milestone_select';
import NotificationsForm from './notifications_form';
import notificationsDropdown from './notifications_dropdown';
import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
import LineHighlighter from './line_highlighter';
import MergeRequest from './merge_request';
import Compare from './compare';
import Labels from './labels';
import LabelManager from './label_manager';
import Sidebar from './right_sidebar';
import IssuableTemplateSelectors from './templates/issuable_template_selectors';
import Flash from './flash';
import BindInOut from './behaviors/bind_in_out';
import SecretValues from './behaviors/secret_values';
import Group from './group';
import ProjectsList from './projects_list';
import UserCallout from './user_callout';
import BlobViewer from './blob/viewer/index';
import UsersSelect from './users_select';
import GfmAutoComplete from './gfm_auto_complete';
import Star from './star';
import ZenMode from './zen_mode';
import PerformanceBar from './performance_bar';
import initNotes from './init_notes';
import initIssuableSidebar from './init_issuable_sidebar';
import NewGroupChild from './groups/new_group_child';
import { convertPermissionToBoolean } from './lib/utils/common_utils';
import GlFieldErrors from './gl_field_errors';
import GLForm from './gl_form';
import Shortcuts from './shortcuts';
import ShortcutsNavigation from './shortcuts_navigation';
import ShortcutsIssuable from './shortcuts_issuable';
import U2FAuthenticate from './u2f/authenticate';
import Members from './members';
import memberExpirationDate from './member_expiration_date';
import Diff from './diff';
import ProjectLabelSubscription from './project_label_subscription';
import SearchAutocomplete from './search_autocomplete';
import Activities from './activities';
......@@ -80,8 +65,6 @@ import Activities from './activities';
});
});
const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
switch (page) {
case 'sessions:new':
import('./pages/sessions/new')
......@@ -139,12 +122,14 @@ import Activities from './activities';
.catch(fail);
break;
case 'groups:issues':
import('./pages/groups/issues')
.then(callDefault)
.catch(fail);
break;
case 'groups:merge_requests':
if (filteredSearchEnabled) {
const filteredSearchManager = new gl.FilteredSearchManager(page === 'groups:issues' ? 'issues' : 'merge_requests');
filteredSearchManager.setup();
}
projectSelect();
import('./pages/groups/merge_requests')
.then(callDefault)
.catch(fail);
break;
case 'dashboard:todos:index':
import('./pages/dashboard/todos/index').then(callDefault).catch(fail);
......@@ -229,19 +214,9 @@ import Activities from './activities';
shortcut_handler = true;
break;
case 'projects:merge_requests:creations:new':
const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare');
if (mrNewCompareNode) {
new Compare({
targetProjectUrl: mrNewCompareNode.dataset.targetProjectUrl,
sourceBranchUrl: mrNewCompareNode.dataset.sourceBranchUrl,
targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl,
});
} else {
const mrNewSubmitNode = document.querySelector('.js-merge-request-new-submit');
new MergeRequest({
action: mrNewSubmitNode.dataset.mrSubmitAction,
});
}
import('./pages/projects/merge_requests/creations/new')
.then(callDefault)
.catch(fail);
case 'projects:merge_requests:creations:diffs':
case 'projects:merge_requests:edit':
new Diff();
......@@ -370,34 +345,36 @@ import Activities from './activities';
.catch(fail);
break;
case 'groups:activity':
new Activities();
import('./pages/groups/activity')
.then(callDefault)
.catch(fail);
break;
case 'groups:show':
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
shortcut_handler = new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
import('./pages/groups/show')
.then(callDefault)
.catch(fail);
shortcut_handler = true;
break;
case 'groups:group_members:index':
memberExpirationDate();
new Members();
new UsersSelect();
import('./pages/groups/group_members/index')
.then(callDefault)
.catch(fail);
break;
case 'projects:project_members:index':
import('./pages/projects/project_members/')
.then(callDefault)
.catch(fail);
break;
case 'groups:new':
case 'groups:create':
BindInOut.initAll();
new Group();
groupAvatar();
case 'groups:new':
import('./pages/groups/new')
.then(callDefault)
.catch(fail);
break;
case 'groups:edit':
import('./pages/groups/edit')
.then(callDefault)
.catch(fail);
break;
case 'admin:groups:create':
case 'admin:groups:new':
......@@ -410,9 +387,6 @@ import Activities from './activities';
.then(callDefault)
.catch(fail);
break;
case 'groups:edit':
groupAvatar();
break;
case 'projects:tree:show':
import('./pages/projects/tree/show')
.then(callDefault)
......@@ -438,8 +412,14 @@ import Activities from './activities';
shortcut_handler = true;
break;
case 'groups:labels:new':
import('./pages/groups/labels/new')
.then(callDefault)
.catch(fail);
break;
case 'groups:labels:edit':
new Labels();
import('./pages/groups/labels/edit')
.then(callDefault)
.catch(fail);
break;
case 'projects:labels:new':
import('./pages/projects/labels/new')
......@@ -451,25 +431,16 @@ import Activities from './activities';
.then(callDefault)
.catch(fail);
break;
case 'groups:labels:index':
import('./pages/groups/labels/index')
.then(callDefault)
.catch(fail);
break;
case 'projects:labels:index':
import('./pages/projects/labels/index')
.then(callDefault)
.catch(fail);
break;
case 'groups:labels:index':
if ($('.prioritized-labels').length) {
new LabelManager();
}
$('.label-subscription').each((i, el) => {
const $el = $(el);
if ($el.find('.dropdown-group-label').length) {
new GroupLabelSubscription($el);
} else {
new ProjectLabelSubscription($el);
}
});
break;
case 'projects:network:show':
// Ensure we don't create a particular shortcut handler here. This is
// already created, where the network graph is created.
......@@ -513,11 +484,9 @@ import Activities from './activities';
.catch(fail);
break;
case 'groups:settings:ci_cd:show':
const secretVariableTable = document.querySelector('.js-secret-variable-table');
if (secretVariableTable) {
const secretVariableTableValues = new SecretValues(secretVariableTable);
secretVariableTableValues.init();
}
import('./pages/groups/settings/ci_cd/show')
.then(callDefault)
.catch(fail);
break;
case 'ci:lints:create':
case 'ci:lints:show':
......
......@@ -66,9 +66,7 @@
<template>
<div class="note-header-info">
<a :href="author.path">
<span class="note-header-author-name">
{{ author.name }}
</span>
<span class="note-header-author-name">{{ author.name }}</span>
<span class="note-headline-light">
@{{ author.username }}
</span>
......
/* eslint-disable import/prefer-default-export */
export const FILTERED_SEARCH = {
MERGE_REQUESTS: 'merge_requests',
ISSUES: 'issues',
};
import Activities from '~/activities';
export default new Activities();
import groupAvatar from '~/group_avatar';
export default groupAvatar;
/* eslint-disable no-new */
import memberExpirationDate from '~/member_expiration_date';
import Members from '~/members';
import UsersSelect from '~/users_select';
export default () => {
memberExpirationDate();
new Members();
new UsersSelect();
};
import projectSelect from '~/project_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
export default () => {
initFilteredSearch(FILTERED_SEARCH.ISSUES);
projectSelect();
};
import Labels from '~/labels';
export default new Labels();
import initLabels from '~/init_labels';
export default initLabels;
import Labels from '~/labels';
export default new Labels();
import projectSelect from '~/project_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
export default () => {
initFilteredSearch(FILTERED_SEARCH.MERGE_REQUESTS);
projectSelect();
};
import BindInOut from '~/behaviors/bind_in_out';
import Group from '~/group';
import groupAvatar from '~/group_avatar';
export default () => {
BindInOut.initAll();
new Group(); // eslint-disable-line no-new
groupAvatar();
};
import SecretValues from '~/behaviors/secret_values';
export default () => {
const secretVariableTable = document.querySelector('.js-secret-variable-table');
if (secretVariableTable) {
const secretVariableTableValues = new SecretValues(secretVariableTable);
secretVariableTableValues.init();
}
};
/* eslint-disable no-new */
import NewGroupChild from '~/groups/new_group_child';
import notificationsDropdown from '~/notifications_dropdown';
import NotificationsForm from '~/notifications_form';
import ProjectsList from '~/projects_list';
import ShortcutsNavigation from '~/shortcuts_navigation';
export default () => {
const newGroupChildWrapper = document.querySelector('.js-new-project-subgroup');
new ShortcutsNavigation();
new NotificationsForm();
notificationsDropdown();
new ProjectsList();
if (newGroupChildWrapper) {
new NewGroupChild(newGroupChildWrapper);
}
};
/* eslint-disable import/prefer-default-export */
export const ISSUABLE_INDEX = {
MERGE_REQUEST: 'merge_request_',
ISSUE: 'issue_',
};
/* eslint-disable no-new */
import IssuableIndex from '~/issuable_index';
import ShortcutsNavigation from '~/shortcuts_navigation';
import UsersSelect from '~/users_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
export default () => {
const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
if (filteredSearchEnabled) {
const filteredSearchManager = new gl.FilteredSearchManager('issues');
filteredSearchManager.setup();
}
new IssuableIndex('issue_');
initFilteredSearch(FILTERED_SEARCH.ISSUES);
new IssuableIndex(ISSUABLE_INDEX.ISSUE);
new ShortcutsNavigation();
new UsersSelect();
......
import Compare from '~/compare';
import MergeRequest from '~/merge_request';
export default () => {
const mrNewCompareNode = document.querySelector('.js-merge-request-new-compare');
if (mrNewCompareNode) {
new Compare({ // eslint-disable-line no-new
targetProjectUrl: mrNewCompareNode.dataset.targetProjectUrl,
sourceBranchUrl: mrNewCompareNode.dataset.sourceBranchUrl,
targetBranchUrl: mrNewCompareNode.dataset.targetBranchUrl,
});
} else {
const mrNewSubmitNode = document.querySelector('.js-merge-request-new-submit');
new MergeRequest({ // eslint-disable-line no-new
action: mrNewSubmitNode.dataset.mrSubmitAction,
});
}
};
import IssuableIndex from '~/issuable_index';
import ShortcutsNavigation from '~/shortcuts_navigation';
import UsersSelect from '~/users_select';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { FILTERED_SEARCH } from '~/pages/constants';
import { ISSUABLE_INDEX } from '~/pages/projects/constants';
export default () => {
const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
if (filteredSearchEnabled) {
const filteredSearchManager = new gl.FilteredSearchManager('merge_requests');
filteredSearchManager.setup();
}
new IssuableIndex('merge_request_'); // eslint-disable-line no-new
initFilteredSearch(FILTERED_SEARCH.MERGE_REQUESTS);
new IssuableIndex(ISSUABLE_INDEX.MERGE_REQUEST); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new
new UsersSelect(); // eslint-disable-line no-new
};
export default (page) => {
const filteredSearchEnabled = gl.FilteredSearchManager && document.querySelector('.filtered-search');
if (filteredSearchEnabled) {
const filteredSearchManager = new gl.FilteredSearchManager(page);
filteredSearchManager.setup();
}
};
......@@ -39,7 +39,7 @@ export default {
class="js-sidebar-dropdown-toggle edit-link pull-right"
href="#"
>
Edit
{{ __('Edit') }}
</a>
<a
v-if="showToggle"
......
......@@ -65,7 +65,7 @@
href="#"
@click.prevent="toggleForm"
>
Edit
{{ __('Edit') }}
</a>
</div>
<div class="value sidebar-item-value hide-collapsed">
......
......@@ -45,7 +45,7 @@ module IssuableActions
}
if issuable.edited?
response[:updated_at] = issuable.updated_at
response[:updated_at] = issuable.last_edited_at.to_time.iso8601
response[:updated_by_name] = issuable.last_edited_by.name
response[:updated_by_path] = user_path(issuable.last_edited_by)
end
......
......@@ -241,7 +241,7 @@ module IssuablesHelper
return {} unless issuable.edited?
{
updatedAt: issuable.updated_at.to_time.iso8601,
updatedAt: issuable.last_edited_at.to_time.iso8601,
updatedBy: {
name: issuable.last_edited_by.name,
path: user_path(issuable.last_edited_by)
......
......@@ -37,7 +37,7 @@ class ProjectStatistics < ActiveRecord::Base
def update_build_artifacts_size
self.build_artifacts_size =
project.builds.sum(:artifacts_size) +
Ci::JobArtifact.artifacts_size_for(self)
Ci::JobArtifact.artifacts_size_for(self.project)
end
def update_storage_size
......
class Route < ActiveRecord::Base
include CaseSensitivity
belongs_to :source, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
validates :source, presence: true
......@@ -10,6 +12,7 @@ class Route < ActiveRecord::Base
validate :ensure_permanent_paths, if: :path_changed?
before_validation :delete_conflicting_orphaned_routes
after_create :delete_conflicting_redirects
after_update :delete_conflicting_redirects, if: :path_changed?
after_update :create_redirect_for_old_path
......@@ -78,4 +81,13 @@ class Route < ActiveRecord::Base
def conflicting_redirect_exists?
RedirectRoute.permanent.matching_path_and_descendants(path).exists?
end
def delete_conflicting_orphaned_routes
conflicting = self.class.iwhere(path: path)
conflicting_orphaned_routes = conflicting.select do |route|
route.source.nil?
end
conflicting_orphaned_routes.each(&:destroy)
end
end
......@@ -34,7 +34,7 @@
Milestone
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
.value.hide-collapsed
- if issuable.milestone
= link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_tooltip_title(issuable.milestone), data: { container: "body", html: 1 }
......@@ -60,7 +60,7 @@
Due date
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
= link_to 'Edit', '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
.value.hide-collapsed
%span.value-content
- if issuable.due_date
......@@ -95,7 +95,7 @@
Labels
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
.value.issuable-show-labels.hide-collapsed{ class: ("has-labels" if selected_labels.any?) }
- if selected_labels.any?
- selected_labels.each do |label|
......
......@@ -13,7 +13,7 @@
Assignee
= icon('spinner spin', class: 'hidden block-loading', 'aria-hidden': 'true')
- if can_edit_issuable
= link_to 'Edit', '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
= link_to _('Edit'), '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
- if !signed_in
%a.gutter-toggle.pull-right.js-sidebar-toggle{ role: "button", href: "#", "aria-label" => "Toggle sidebar" }
= sidebar_gutter_toggle_icon
......
---
title: For issues display time of last edit of title or description instead of time
of any attribute change
merge_request:
author:
type: fixed
---
title: Fix a bug calculating artifact size for project statistics
merge_request: 16539
author:
type: fixed
---
title: Ensure that users can reclaim a namespace or project path that is blocked by
an orphaned route
merge_request: 16242
author:
type: fixed
......@@ -503,3 +503,16 @@
:versions:
- 1.0.9
:when: 2017-11-16 13:02:06.765282000 Z
- - :license
- JSONStream
- MIT
- :who: Tim Zallmann
:why: https://github.com/dominictarr/JSONStream/blob/master/LICENSE.MIT
:versions: []
:when: 2018-01-17 22:46:12.367554000 Z
- - :approve
- uws
- :who: Tim Zallmann
:why: zlib license + Development Lib + https://github.com/uNetworking/uWebSockets/blob/master/LICENSE
:versions: []
:when: 2018-01-17 23:46:12.367554000 Z
# Fast lookup of authorized SSH keys in the database
> [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/1631) in
> [GitLab Enterprise Edition Standard](https://about.gitlab.com/gitlab-ee) 9.3.
>
> [Available in](https://gitlab.com/gitlab-org/gitlab-ee/issues/3953) GitLab
> Community Edition 10.4.
Regular SSH operations become slow as the number of users grows because OpenSSH
searches for a key to authorize a user via a linear search. In the worst case,
such as when the user is not authorized to access GitLab, OpenSSH will scan the
......
......@@ -301,6 +301,53 @@ describe Projects::IssuesController do
end
end
describe 'GET #realtime_changes' do
def go(id:)
get :realtime_changes,
namespace_id: project.namespace.to_param,
project_id: project,
id: id
end
context 'when an issue was edited' do
before do
project.add_developer(user)
issue.update!(last_edited_by: user, last_edited_at: issue.created_at + 1.minute)
sign_in(user)
end
it 'returns last edited time' do
go(id: issue.iid)
data = JSON.parse(response.body)
expect(data).to include('updated_at')
expect(data['updated_at']).to eq(issue.last_edited_at.to_time.iso8601)
end
end
context 'when an issue was edited by a deleted user' do
let(:deleted_user) { create(:user) }
before do
project.add_developer(user)
issue.update!(last_edited_by: deleted_user, last_edited_at: Time.now)
deleted_user.destroy
sign_in(user)
end
it 'returns 200' do
go(id: issue.iid)
expect(response).to have_gitlab_http_status(200)
end
end
end
describe 'Confidential Issues' do
let(:project) { create(:project_empty_repo, :public) }
let(:assignee) { create(:assignee) }
......@@ -589,25 +636,6 @@ describe Projects::IssuesController do
project_id: project,
id: id
end
context 'when an issue was edited by a deleted user' do
let(:deleted_user) { create(:user) }
before do
project.add_developer(user)
issue.update!(last_edited_by: deleted_user, last_edited_at: Time.now)
deleted_user.destroy
sign_in(user)
end
it 'returns 200' do
go(id: issue.iid)
expect(response).to have_gitlab_http_status(200)
end
end
end
describe 'GET #edit' do
......
require 'rails_helper'
describe 'Merge request > User assigns themselves' do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user, description: "fixes #{issue1.to_reference} and #{issue2.to_reference}") }
context 'logged in as a member of the project' do
before do
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'updates related issues', :js do
click_link 'Assign yourself to these issues'
expect(page).to have_content '2 issues have been assigned to you'
end
it 'returns user to the merge request', :js do
click_link 'Assign yourself to these issues'
expect(page).to have_content merge_request.description
end
context 'when related issues are already assigned' do
before do
[issue1, issue2].each { |issue| issue.update!(assignees: [user]) }
end
it 'does not display if related issues are already assigned' do
expect(page).not_to have_content 'Assign yourself'
end
end
end
context 'logged in as a non-member of the project' do
before do
sign_in(create(:user))
visit project_merge_request_path(project, merge_request)
end
it 'does not not show assignment link' do
expect(page).not_to have_content 'Assign yourself'
end
end
end
require 'rails_helper'
feature 'Merge request awards', :js do
let(:user) { create(:user) }
describe 'Merge request > User awards emoji', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
describe 'logged in' do
......
require 'spec_helper'
require 'rails_helper'
describe 'Cherry-pick Merge Requests', :js do
let(:user) { create(:user) }
describe 'Merge request > User cherry-picks', :js do
let(:group) { create(:group) }
let(:project) { create(:project, :repository, namespace: group) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user) }
before do
sign_in user
project.add_master(user)
sign_in(user)
end
context "Viewing a merged merge request" do
context 'Viewing a merged merge request' do
before do
service = MergeRequests::MergeService.new(project, user)
......@@ -21,24 +21,24 @@ describe 'Cherry-pick Merge Requests', :js do
end
# Fast-forward merge, or merged before GitLab 8.5.
context "Without a merge commit" do
context 'Without a merge commit' do
before do
merge_request.merge_commit_sha = nil
merge_request.save
end
it "doesn't show a Cherry-pick button" do
it 'does not show a Cherry-pick button' do
visit project_merge_request_path(project, merge_request)
expect(page).not_to have_link "Cherry-pick"
expect(page).not_to have_link 'Cherry-pick'
end
end
context "With a merge commit" do
it "shows a Cherry-pick button" do
context 'With a merge commit' do
it 'shows a Cherry-pick button' do
visit project_merge_request_path(project, merge_request)
expect(page).to have_link "Cherry-pick"
expect(page).to have_link 'Cherry-pick'
end
end
end
......
require 'spec_helper'
feature 'image diff notes', :js do
feature 'Merge request > User creates image diff notes', :js do
include NoteInteractionHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
before do
project.add_master(user)
sign_in user
sign_in(user)
# Stub helper to return any blob file as image from public app folder.
# This is necessary to run this specs since we don't display repo images in capybara.
......@@ -25,20 +24,14 @@ feature 'image diff notes', :js do
create_image_diff_note
end
it 'shows indicator badge on image diff' do
it 'shows indicator and avatar badges, and allows collapsing/expanding the discussion notes' do
indicator = find('.js-image-badge')
expect(indicator).to have_content('1')
end
it 'shows the avatar badge on the new note' do
badge = find('.image-diff-avatar-link .badge')
expect(indicator).to have_content('1')
expect(badge).to have_content('1')
end
it 'allows collapsing/expanding the discussion notes' do
find('.js-diff-notes-toggle', :first).click
find('.js-diff-notes-toggle').click
expect(page).not_to have_content('image diff test comment')
......@@ -86,15 +79,9 @@ feature 'image diff notes', :js do
wait_for_requests
end
it 'render diff indicators within the image diff frame' do
it 'render diff indicators within the image diff frame, diff notes, and avatar badge numbers' do
expect(page).to have_css('.js-image-badge', count: 2)
end
it 'shows the diff notes' do
expect(page).to have_css('.diff-content .note', count: 2)
end
it 'shows the diff notes with correct avatar badge numbers' do
expect(page).to have_css('.image-diff-avatar-link', text: 1)
expect(page).to have_css('.image-diff-avatar-link', text: 2)
end
......@@ -127,19 +114,13 @@ feature 'image diff notes', :js do
create_image_diff_note
end
it 'shows indicator badge on image diff' do
it 'shows indicator and avatar badges, and allows collapsing/expanding the discussion notes' do
indicator = find('.js-image-badge', match: :first)
expect(indicator).to have_content('1')
end
it 'shows the avatar badge on the new note' do
badge = find('.image-diff-avatar-link .badge', match: :first)
expect(indicator).to have_content('1')
expect(badge).to have_content('1')
end
it 'allows expanding/collapsing the discussion notes' do
page.all('.js-diff-notes-toggle')[0].click
page.all('.js-diff-notes-toggle')[1].click
......@@ -154,7 +135,7 @@ feature 'image diff notes', :js do
end
end
describe 'discussion tab polling', :js do
describe 'discussion tab polling' do
let(:merge_request) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, author: user) }
let(:path) { "files/images/ee_repo_logo.png" }
......
require 'rails_helper'
describe 'Merge request > User creates MR' do
it_behaves_like 'a creatable merge request'
context 'from a forked project' do
include ProjectForksHelper
let(:canonical_project) { create(:project, :public, :repository) }
let(:source_project) do
fork_project(canonical_project, user,
repository: true,
namespace: user.namespace)
end
context 'to canonical project' do
it_behaves_like 'a creatable merge request'
end
context 'to another forked project' do
let(:target_project) do
fork_project(canonical_project, user,
repository: true,
namespace: user.namespace)
end
it_behaves_like 'a creatable merge request'
end
end
end
require 'spec_helper'
require 'rails_helper'
feature 'Clicking toggle commit message link', :js do
let(:user) { create(:user) }
describe 'Merge request < User customizes merge commit message', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:issue_1) { create(:issue, project: project)}
let(:issue_2) { create(:issue, project: project)}
let(:merge_request) do
......@@ -33,17 +33,14 @@ feature 'Clicking toggle commit message link', :js do
before do
project.add_master(user)
sign_in user
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'toggles commit message between message with description and without description' do
expect(page).not_to have_selector('.js-commit-message')
click_button "Modify commit message"
expect(textbox).to be_visible
end
it "toggles commit message between message with description and without description " do
expect(textbox.value).to eq(default_message)
click_link "Include description in commit message"
......
require 'rails_helper'
describe 'Merge request > User edits MR' do
it_behaves_like 'an editable merge request'
context 'for a forked project' do
it_behaves_like 'an editable merge request' do
let(:source_project) { create(:project, :repository, forked_from_project: target_project) }
end
end
end
require 'spec_helper'
require 'rails_helper'
describe 'Discussion Lock', :js do
describe 'Merge request > User locks discussion', :js do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request, source_project: project, author: user) }
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
before do
sign_in(user)
......
require 'spec_helper'
require 'rails_helper'
feature 'Merge immediately', :js do
let(:user) { create(:user) }
describe 'Merge requests > User merges immediately', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let!(:merge_request) do
create(:merge_request_with_diffs, source_project: project,
author: user,
......@@ -11,25 +10,18 @@ feature 'Merge immediately', :js do
head_pipeline: pipeline,
source_branch: pipeline.ref)
end
let(:pipeline) do
create(:ci_pipeline, project: project,
ref: 'master',
sha: project.repository.commit('master').id)
end
before do
project.add_master(user)
end
context 'when there is active pipeline for merge request' do
background do
create(:ci_build, pipeline: pipeline)
end
before do
sign_in user
visit project_merge_request_path(merge_request.project, merge_request)
create(:ci_build, pipeline: pipeline)
project.add_master(user)
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'enables merge immediately' do
......
require 'spec_helper'
require 'rails_helper'
feature 'Only allow merge requests to be merged if the pipeline succeeds', :js do
describe 'Merge request > User merges only if pipeline succeeds', :js do
let(:merge_request) { create(:merge_request_with_diffs) }
let(:project) { merge_request.target_project }
before do
sign_in merge_request.author
project.add_master(merge_request.author)
sign_in(merge_request.author)
end
context 'project does not have CI enabled', :js do
context 'project does not have CI enabled' do
it 'allows MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -20,8 +19,8 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
end
context 'when project has CI enabled', :js do
given!(:pipeline) do
context 'when project has CI enabled' do
let!(:pipeline) do
create(:ci_empty_pipeline,
project: project,
sha: merge_request.diff_head_sha,
......@@ -35,10 +34,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI is running' do
given(:status) { :running }
let(:status) { :running }
it 'does not allow to merge immediately' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -48,10 +47,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI failed' do
given(:status) { :failed }
let(:status) { :failed }
it 'does not allow MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -61,10 +60,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI canceled' do
given(:status) { :canceled }
let(:status) { :canceled }
it 'does not allow MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -74,10 +73,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI succeeded' do
given(:status) { :success }
let(:status) { :success }
it 'allows MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -86,10 +85,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI skipped' do
given(:status) { :skipped }
let(:status) { :skipped }
it 'allows MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -104,10 +103,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI is running' do
given(:status) { :running }
let(:status) { :running }
it 'allows MR to be merged immediately' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -119,10 +118,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI failed' do
given(:status) { :failed }
let(:status) { :failed }
it 'allows MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -131,10 +130,10 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
context 'when CI succeeded' do
given(:status) { :success }
let(:status) { :success }
it 'allows MR to be merged' do
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -143,8 +142,4 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', :js d
end
end
end
def visit_merge_request(merge_request)
visit project_merge_request_path(merge_request.project, merge_request)
end
end
require 'spec_helper'
require 'rails_helper'
feature 'Merge When Pipeline Succeeds', :js do
let(:user) { create(:user) }
describe 'Merge request > User merges when pipeline succeeds', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) do
create(:merge_request_with_diffs, source_project: project,
author: user,
title: 'Bug NS-04',
merge_params: { force_remove_source_branch: '1' })
end
let(:pipeline) do
create(:ci_pipeline, project: project,
sha: merge_request.diff_head_sha,
......@@ -23,17 +21,10 @@ feature 'Merge When Pipeline Succeeds', :js do
end
context 'when there is active pipeline for merge request' do
background do
create(:ci_build, pipeline: pipeline)
end
before do
sign_in user
visit_merge_request(merge_request)
end
it 'displays the Merge when pipeline succeeds button' do
expect(page).to have_button "Merge when pipeline succeeds"
create(:ci_build, pipeline: pipeline)
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
describe 'enabling Merge when pipeline succeeds' do
......@@ -44,7 +35,7 @@ feature 'Merge When Pipeline Succeeds', :js do
expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds"
expect(page).to have_content "The source branch will not be removed"
expect(page).to have_selector ".js-cancel-auto-merge"
visit_merge_request(merge_request) # Needed to refresh the page
visit project_merge_request_path(project, merge_request) # Needed to refresh the page
expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i
end
end
......@@ -115,14 +106,13 @@ feature 'Merge When Pipeline Succeeds', :js do
title: 'MepMep',
merge_when_pipeline_succeeds: true)
end
let!(:build) do
create(:ci_build, pipeline: pipeline)
end
before do
sign_in user
visit_merge_request(merge_request)
visit project_merge_request_path(project, merge_request)
end
it 'allows to cancel the automatic merge' do
......@@ -130,31 +120,67 @@ feature 'Merge When Pipeline Succeeds', :js do
expect(page).to have_button "Merge when pipeline succeeds"
visit_merge_request(merge_request) # refresh the page
refresh
expect(page).to have_content "canceled the automatic merge"
end
context 'when pipeline succeeds' do
background { build.success }
before do
build.success
refresh
end
it 'merges merge request' do
visit_merge_request(merge_request) # refresh the page
expect(page).to have_content 'The changes were merged'
expect(merge_request.reload).to be_merged
end
end
context 'view merge request with MWPS enabled but automatically merge fails' do
before do
merge_request.update(
merge_user: merge_request.author,
merge_error: 'Something went wrong'
)
refresh
end
it 'shows information about the merge error' do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
page.within('.mr-widget-body') do
expect(page).to have_content('Something went wrong')
end
end
end
context 'view merge request with MWPS enabled but automatically merge fails' do
before do
merge_request.update(
merge_user: merge_request.author,
merge_error: 'Something went wrong'
)
refresh
end
it 'shows information about the merge error' do
# Wait for the `ci_status` and `merge_check` requests
wait_for_requests
page.within('.mr-widget-body') do
expect(page).to have_content('Something went wrong')
end
end
end
end
context 'when pipeline is not active' do
it "does not allow to enable merge when pipeline succeeds" do
visit_merge_request(merge_request)
it 'does not allow to enable merge when pipeline succeeds' do
visit project_merge_request_path(project, merge_request)
expect(page).not_to have_link 'Merge when pipeline succeeds'
end
end
def visit_merge_request(merge_request)
visit project_merge_request_path(merge_request.project, merge_request)
end
end
require 'spec_helper'
require 'rails_helper'
feature 'Merge requests > User posts diff notes', :js do
describe 'Merge request > User posts diff notes', :js do
include MergeRequestDiffHelpers
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.source_project }
let(:user) { project.creator }
let(:comment_button_class) { '.add-diff-note' }
let(:notes_holder_input_class) { 'js-temp-notes-holder' }
let(:notes_holder_input_xpath) { './following-sibling::*[contains(concat(" ", @class, " "), " notes_holder ")]' }
let(:test_note_comment) { 'this is a test note!' }
before do
set_cookie('sidebar_collapsed', 'true')
......@@ -14,11 +18,6 @@ feature 'Merge requests > User posts diff notes', :js do
sign_in(user)
end
let(:comment_button_class) { '.add-diff-note' }
let(:notes_holder_input_class) { 'js-temp-notes-holder' }
let(:notes_holder_input_xpath) { './following-sibling::*[contains(concat(" ", @class, " "), " notes_holder ")]' }
let(:test_note_comment) { 'this is a test note!' }
context 'when hovering over a parallel view diff file' do
before do
visit diffs_project_merge_request_path(project, merge_request, view: 'parallel')
......
require 'spec_helper'
require 'rails_helper'
describe 'Merge requests > User posts notes', :js do
describe 'Merge request > User posts notes', :js do
include NoteInteractionHelpers
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let(:merge_request) do
create(:merge_request, source_project: project, target_project: project)
end
......@@ -13,7 +14,8 @@ describe 'Merge requests > User posts notes', :js do
end
before do
sign_in(create(:admin))
project.add_master(user)
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
......
require 'spec_helper'
require 'rails_helper'
feature 'Merge request conflict resolution', :js do
let(:user) { create(:user) }
describe 'Merge request > User resolves conflicts', :js do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
before do
# In order to have the diffs collapsed, we need to disable the increase feature
......@@ -177,7 +177,6 @@ feature 'Merge request conflict resolution', :js do
before do
project.add_developer(user)
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
......
require 'spec_helper'
require 'rails_helper'
feature 'Diff notes resolve', :js do
let(:user) { create(:user) }
describe 'Merge request > User resolves diff notes and discussions', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:guest) { create(:user) }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) }
let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) }
let(:path) { "files/ruby/popen.rb" }
let(:position) do
Gitlab::Diff::Position.new(
......@@ -19,7 +20,7 @@ feature 'Diff notes resolve', :js do
context 'no discussions' do
before do
project.add_master(user)
sign_in user
sign_in(user)
note.destroy
visit_merge_request
end
......@@ -33,7 +34,7 @@ feature 'Diff notes resolve', :js do
context 'as authorized user' do
before do
project.add_master(user)
sign_in user
sign_in(user)
visit_merge_request
end
......@@ -67,6 +68,8 @@ feature 'Diff notes resolve', :js do
click_button 'Resolve discussion'
end
expect(page).to have_selector('.discussion-body', visible: false)
page.within '.diff-content .note' do
expect(page).to have_selector('.line-resolve-btn.is-active')
end
......@@ -318,9 +321,7 @@ feature 'Diff notes resolve', :js do
end
it 'shows jump to next discussion button' do
page.all('.discussion-reply-holder').each do |holder|
expect(holder).to have_selector('.discussion-next-btn')
end
expect(page.all('.discussion-reply-holder')).to all(have_selector('.discussion-next-btn'))
end
it 'displays next discussion even if hidden' do
......@@ -426,11 +427,9 @@ feature 'Diff notes resolve', :js do
end
context 'as a guest' do
let(:guest) { create(:user) }
before do
project.add_guest(guest)
sign_in guest
sign_in(guest)
end
context 'someone elses merge request' do
......@@ -456,10 +455,10 @@ feature 'Diff notes resolve', :js do
end
context 'guest users merge request' do
let(:user) { guest }
before do
mr = create(:merge_request_with_diffs, source_project: project, source_branch: 'markdown', author: guest, title: "Bug")
create(:diff_note_on_merge_request, project: project, noteable: mr)
visit_merge_request(mr)
visit_merge_request
end
it 'allows user to mark a note as resolved' do
......@@ -521,7 +520,7 @@ feature 'Diff notes resolve', :js do
end
def visit_merge_request(mr = nil)
mr = mr || merge_request
mr ||= merge_request
visit project_merge_request_path(mr.project, mr)
end
end
require 'spec_helper'
feature 'Resolve outdated diff discussions', :js do
feature 'Merge request > User resolves outdated diff discussions', :js do
let(:project) { create(:project, :repository, :public) }
let(:merge_request) do
......
require 'spec_helper'
require 'rails_helper'
feature 'toggler_behavior', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
describe 'Merge request > User scrolls to note on load', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project, author: user) }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:fragment_id) { "#note_#{note.id}" }
before do
sign_in(create(:admin))
project = merge_request.source_project
sign_in(user)
page.current_window.resize_to(1000, 300)
visit "#{project_merge_request_path(project, merge_request)}#{fragment_id}"
end
describe 'scroll position' do
it 'should be scrolled down to fragment' do
page_height = page.current_window.size[1]
page_scroll_y = page.evaluate_script("window.scrollY")
fragment_position_top = page.evaluate_script("Math.round($('#{fragment_id}').offset().top)")
expect(find('.js-toggle-content').visible?).to eq true
expect(find(fragment_id).visible?).to eq true
expect(fragment_position_top).to be >= page_scroll_y
expect(fragment_position_top).to be < (page_scroll_y + page_height)
end
it 'scrolls down to fragment' do
page_height = page.current_window.size[1]
page_scroll_y = page.evaluate_script("window.scrollY")
fragment_position_top = page.evaluate_script("Math.round($('#{fragment_id}').offset().top)")
expect(find('.js-toggle-content').visible?).to eq true
expect(find(fragment_id).visible?).to eq true
expect(fragment_position_top).to be >= page_scroll_y
expect(fragment_position_top).to be < (page_scroll_y + page_height)
end
end
require 'spec_helper'
require 'rails_helper'
feature 'Diff note avatars', :js do
describe 'Merge request > User sees avatars on diff notes', :js do
include NoteInteractionHelpers
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
let(:path) { "files/ruby/popen.rb" }
let(:position) do
......@@ -151,7 +151,6 @@ feature 'Diff note avatars', :js do
page.within '.js-discussion-note-form' do
find('.js-note-text').native.send_keys('Test')
find('.js-comment-button').click
wait_for_requests
......@@ -169,7 +168,6 @@ feature 'Diff note avatars', :js do
context 'multiple comments' do
before do
create_list(:diff_note_on_merge_request, 3, project: project, noteable: merge_request, in_reply_to: note)
visit diffs_project_merge_request_path(project, merge_request, view: view)
wait_for_requests
......
require 'spec_helper'
require 'rails_helper'
feature 'Merge Request closing issues message', :js do
let(:user) { create(:user) }
describe 'Merge request > User sees closing issues message', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:issue_1) { create(:issue, project: project)}
let(:issue_2) { create(:issue, project: project)}
let(:merge_request) do
......@@ -19,9 +19,7 @@ feature 'Merge Request closing issues message', :js do
before do
project.add_master(user)
sign_in user
sign_in(user)
visit project_merge_request_path(project, merge_request)
wait_for_requests
end
......
require 'rails_helper'
describe 'Merge request > User sees deleted target branch', :js do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:user) { project.creator }
before do
project.add_master(user)
DeleteBranchService.new(project, user).execute('feature')
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'shows a message about missing target branch' do
expect(page).to have_content('Target branch does not exist')
end
it 'does not show link to target branch' do
expect(page).not_to have_selector('.mr-widget-body .js-branch-text a')
end
end
require 'spec_helper'
require 'rails_helper'
feature 'Widget Deployments Header', :js do
describe 'Merge request > User sees deployment widget', :js do
describe 'when deployed to an environment' do
given(:user) { create(:user) }
given(:project) { merge_request.target_project }
given(:merge_request) { create(:merge_request, :merged) }
given(:environment) { create(:environment, project: project) }
given(:role) { :developer }
given(:sha) { project.commit('master').id }
given!(:deployment) { create(:deployment, environment: environment, sha: sha) }
given!(:manual) { }
background do
let(:user) { create(:user) }
let(:project) { merge_request.target_project }
let(:merge_request) { create(:merge_request, :merged) }
let(:environment) { create(:environment, project: project) }
let(:role) { :developer }
let(:sha) { project.commit('master').id }
let!(:deployment) { create(:deployment, environment: environment, sha: sha) }
let!(:manual) { }
before do
project.add_user(user, role)
sign_in(user)
project.add_role(user, role)
visit project_merge_request_path(project, merge_request)
wait_for_requests
end
scenario 'displays that the environment is deployed' do
it 'displays that the environment is deployed' do
wait_for_requests
expect(page).to have_content("Deployed to #{environment.name}")
......@@ -25,32 +26,28 @@ feature 'Widget Deployments Header', :js do
end
context 'with stop action' do
given(:pipeline) { create(:ci_pipeline, project: project) }
given(:build) { create(:ci_build, pipeline: pipeline) }
given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') }
given(:deployment) do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') }
let(:deployment) do
create(:deployment, environment: environment, ref: merge_request.target_branch,
sha: sha, deployable: build, on_stop: 'close_app')
end
background do
before do
wait_for_requests
end
scenario 'does show stop button' do
expect(page).to have_button('Stop environment')
end
scenario 'does start build when stop button clicked' do
it 'does start build when stop button clicked' do
accept_confirm { click_button('Stop environment') }
expect(page).to have_content('close_app')
end
context 'for reporter' do
given(:role) { :reporter }
let(:role) { :reporter }
scenario 'does not show stop button' do
it 'does not show stop button' do
expect(page).not_to have_button('Stop environment')
end
end
......
require 'spec_helper'
require 'rails_helper'
feature 'Diffs URL', :js do
describe 'Merge request > User sees diff', :js do
include ProjectForksHelper
let(:project) { create(:project, :public, :repository) }
......
require 'spec_helper'
require 'rails_helper'
describe 'Merge request > User sees discussions' do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
feature 'Merge Request Discussions' do
before do
sign_in(create(:admin))
project.add_master(user)
sign_in(user)
end
describe "Diff discussions" do
let(:merge_request) { create(:merge_request, importing: true) }
let(:project) { merge_request.source_project }
let!(:old_merge_request_diff) { merge_request.merge_request_diffs.create(diff_refs: outdated_diff_refs) }
let!(:new_merge_request_diff) { merge_request.merge_request_diffs.create }
let!(:outdated_discussion) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: outdated_position).to_discussion }
let!(:active_discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion }
let(:outdated_position) do
Gitlab::Diff::Position.new(
old_path: "files/ruby/popen.rb",
......@@ -23,7 +24,6 @@ feature 'Merge Request Discussions' do
diff_refs: outdated_diff_refs
)
end
let(:outdated_diff_refs) { project.commit("874797c3a73b60d2187ed6e2fcabd289ff75171e").diff_refs }
before do
......@@ -50,9 +50,6 @@ feature 'Merge Request Discussions' do
end
describe 'Commit comments displayed in MR context', :js do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
shared_examples 'a functional discussion' do
let(:discussion_id) { note.discussion_id(merge_request) }
......
require 'spec_helper'
require 'rails_helper'
feature 'Merge Requests List' do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
background do
project.add_developer(user)
describe 'Merge request > User sees empty state' do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
before do
project.add_master(user)
sign_in(user)
end
scenario 'user does not see create new list button' do
create(:merge_request, source_project: project)
visit project_merge_requests_path(project)
expect(page).not_to have_selector('.js-new-board-list')
end
it 'should show an empty state' do
it 'shows an empty state and a "New merge request" button' do
visit project_merge_requests_path(project)
expect(page).to have_selector('.empty-state')
end
it 'empty state should have a create merge request button' do
visit project_merge_requests_path(project)
expect(page).to have_link 'New merge request', href: project_new_merge_request_path(project)
end
context 'if there are merge requests' do
before do
create(:merge_request, assignee: user, source_project: project)
create(:merge_request, source_project: project)
visit project_merge_requests_path(project)
end
it 'should not show an empty state' do
it 'does not show an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
......
require 'spec_helper'
require 'rails_helper'
feature 'Check if mergeable with unresolved discussions', :js do
let(:user) { create(:user) }
describe 'Merge request > User sees merge button depending on unresolved discussions', :js do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let!(:merge_request) { create(:merge_request_with_diff_notes, source_project: project, author: user) }
before do
sign_in user
project.add_master(user)
sign_in(user)
end
context 'when project.only_allow_merge_if_all_discussions_are_resolved == true' do
before do
project.update_column(:only_allow_merge_if_all_discussions_are_resolved, true)
visit project_merge_request_path(project, merge_request)
end
context 'with unresolved discussions' do
it 'does not allow to merge' do
visit_merge_request(merge_request)
expect(page).not_to have_button 'Merge'
expect(page).to have_content('There are unresolved discussions.')
end
......@@ -27,11 +26,10 @@ feature 'Check if mergeable with unresolved discussions', :js do
context 'with all discussions resolved' do
before do
merge_request.discussions.each { |d| d.resolve!(user) }
visit project_merge_request_path(project, merge_request)
end
it 'allows MR to be merged' do
visit_merge_request(merge_request)
expect(page).to have_button 'Merge'
end
end
......@@ -40,12 +38,11 @@ feature 'Check if mergeable with unresolved discussions', :js do
context 'when project.only_allow_merge_if_all_discussions_are_resolved == false' do
before do
project.update_column(:only_allow_merge_if_all_discussions_are_resolved, false)
visit project_merge_request_path(project, merge_request)
end
context 'with unresolved discussions' do
it 'does not allow to merge' do
visit_merge_request(merge_request)
expect(page).to have_button 'Merge'
end
end
......@@ -53,17 +50,12 @@ feature 'Check if mergeable with unresolved discussions', :js do
context 'with all discussions resolved' do
before do
merge_request.discussions.each { |d| d.resolve!(user) }
visit project_merge_request_path(project, merge_request)
end
it 'allows MR to be merged' do
visit_merge_request(merge_request)
expect(page).to have_button 'Merge'
end
end
end
def visit_merge_request(merge_request)
visit project_merge_request_path(merge_request.project, merge_request)
end
end
require 'rails_helper'
describe 'Merge request', :js do
let(:user) { create(:user) }
describe 'Merge request > User sees merge widget', :js do
let(:project) { create(:project, :repository) }
let(:project_only_mwps) { create(:project, :repository, only_allow_merge_if_pipeline_succeeds: true) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:merge_request_in_only_mwps_project) { create(:merge_request, source_project: project_only_mwps) }
......
require 'rails_helper'
feature 'Mini Pipeline Graph', :js do
let(:user) { create(:user) }
describe 'Merge request < User sees mini pipeline graph', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:merge_request) { create(:merge_request, source_project: project, head_pipeline: pipeline) }
let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running', sha: project.commit.id) }
let(:build) { create(:ci_build, pipeline: pipeline, stage: 'test', commands: 'test') }
before do
build.run
sign_in(user)
visit_merge_request
end
......@@ -19,13 +17,13 @@ feature 'Mini Pipeline Graph', :js do
visit project_merge_request_path(project, merge_request, format: format, serializer: serializer)
end
it 'should display a mini pipeline graph' do
it 'displays a mini pipeline graph' do
expect(page).to have_selector('.mr-widget-pipeline-graph')
end
context 'as json' do
let(:artifacts_file1) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') }
let(:artifacts_file2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/png') }
let(:artifacts_file1) { fixture_file_upload(Rails.root.join('spec/fixtures/banana_sample.gif'), 'image/gif') }
let(:artifacts_file2) { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') }
before do
create(:ci_build, pipeline: pipeline, legacy_artifacts_file: artifacts_file1)
......@@ -51,7 +49,7 @@ feature 'Mini Pipeline Graph', :js do
first('.mini-pipeline-graph-dropdown-toggle')
end
it 'should expand when hovered' do
it 'expands when hovered' do
find('.mini-pipeline-graph-dropdown-toggle')
before_width = evaluate_script("$('.mini-pipeline-graph-dropdown-toggle:visible').outerWidth();")
......@@ -63,13 +61,13 @@ feature 'Mini Pipeline Graph', :js do
expect(before_width).to be < after_width
end
it 'should show dropdown caret when hovered' do
it 'shows dropdown caret when hovered' do
toggle.hover
expect(toggle).to have_selector('.fa-caret-down')
end
it 'should show tooltip when hovered' do
it 'shows tooltip when hovered' do
toggle.hover
expect(page).to have_selector('.tooltip')
......@@ -87,17 +85,17 @@ feature 'Mini Pipeline Graph', :js do
wait_for_requests
end
it 'should open when toggle is clicked' do
it 'pens when toggle is clicked' do
expect(toggle.find(:xpath, '..')).to have_selector('.mini-pipeline-graph-dropdown-menu')
end
it 'should close when toggle is clicked again' do
it 'closes when toggle is clicked again' do
toggle.click
expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
end
it 'should close when clicking somewhere else' do
it 'closes when clicking somewhere else' do
find('body').click
expect(toggle.find(:xpath, '..')).not_to have_selector('.mini-pipeline-graph-dropdown-menu')
......@@ -109,14 +107,14 @@ feature 'Mini Pipeline Graph', :js do
first('.mini-pipeline-graph-dropdown-item')
end
it 'should visit the build page when clicked' do
it 'visits the build page when clicked' do
build_item.click
find('.build-page')
expect(current_path).to eql(project_job_path(project, build))
end
it 'should show tooltip when hovered' do
it 'shows tooltip when hovered' do
build_item.hover
expect(page).to have_selector('.tooltip')
......
require 'rails_helper'
describe 'Merge request > User sees MR from deleted forked project', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:fork_project) { create(:project, :public, :repository, forked_from_project: project) }
let!(:merge_request) do
create(:merge_request_with_diffs, source_project: fork_project,
target_project: project,
description: 'Test merge request')
end
before do
MergeRequests::MergeService.new(project, user).execute(merge_request)
fork_project.destroy!
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'user can access merge request' do
expect(page).to have_content 'Test merge request'
expect(page).to have_content "(removed):#{merge_request.source_branch}"
end
end
require 'spec_helper'
require 'rails_helper'
# This test serves as a regression test for a bug that caused an error
# message to be shown by JavaScript when the source branch was deleted.
# Please do not remove "js: true".
describe 'Deleted source branch', :js do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
# Please do not remove ":js".
describe 'Merge request > User sees MR with deleted source branch', :js do
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:user) { project.creator }
before do
sign_in user
merge_request.project.add_master(user)
merge_request.update!(source_branch: 'this-branch-does-not-exist')
visit project_merge_request_path(merge_request.project, merge_request)
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
it 'shows a message about missing source branch' do
expect(page).to have_content(
'Source branch does not exist.'
)
expect(page).to have_content('Source branch does not exist.')
end
it 'still contains Discussion, Commits and Changes tabs' do
......
require 'rails_helper'
describe 'Merge request > User sees notes from forked project', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:fork_project) { create(:project, :public, :repository, forked_from_project: project) }
let!(:merge_request) do
create(:merge_request_with_diffs, source_project: fork_project,
target_project: project,
description: 'Test merge request')
end
before do
create(:note_on_commit, note: 'A commit comment',
project: fork_project,
commit_id: merge_request.commit_shas.first)
sign_in(user)
end
it 'user can reply to the comment' do
visit project_merge_request_path(project, merge_request)
expect(page).to have_content('A commit comment')
page.within('.discussion-notes') do
find('.btn-text-field').click
find('#note_note').send_keys('A reply comment')
find('.comment-btn').click
end
wait_for_requests
expect(page).to have_content('A reply comment')
end
end
require 'rails_helper'
describe 'Merge request > User sees pipelines from forked project', :js do
let(:target_project) { create(:project, :public, :repository) }
let(:user) { target_project.creator }
let(:fork_project) { create(:project, :repository, forked_from_project: target_project) }
let!(:merge_request) do
create(:merge_request_with_diffs, source_project: fork_project,
target_project: target_project,
description: 'Test merge request')
end
let(:pipeline) do
create(:ci_pipeline,
project: fork_project,
sha: merge_request.diff_head_sha,
ref: merge_request.source_branch)
end
before do
create(:ci_build, pipeline: pipeline, name: 'rspec')
create(:ci_build, pipeline: pipeline, name: 'spinach')
sign_in(user)
visit project_merge_request_path(target_project, merge_request)
end
it 'user visits a pipelines page' do
page.within('.merge-request-tabs') { click_link 'Pipelines' }
page.within('.ci-table') do
expect(page).to have_content(pipeline.id)
end
end
end
require 'spec_helper'
require 'rails_helper'
feature 'Pipelines for Merge Requests', :js do
describe 'Merge request > User sees pipelines', :js do
describe 'pipeline tab' do
given(:user) { create(:user) }
given(:merge_request) { create(:merge_request) }
given(:project) { merge_request.target_project }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.target_project }
let(:user) { project.creator }
before do
project.add_master(user)
sign_in user
sign_in(user)
end
context 'with pipelines' do
......@@ -23,7 +23,7 @@ feature 'Pipelines for Merge Requests', :js do
merge_request.update_attribute(:head_pipeline_id, pipeline.id)
end
scenario 'user visits merge request pipelines tab' do
it 'user visits merge request pipelines tab' do
visit project_merge_request_path(project, merge_request)
expect(page.find('.ci-widget')).to have_content('pending')
......@@ -36,7 +36,7 @@ feature 'Pipelines for Merge Requests', :js do
expect(page).to have_selector('.stage-cell')
end
scenario 'pipeline sha does not equal last commit sha' do
it 'pipeline sha does not equal last commit sha' do
pipeline.update_attribute(:sha, '19e2e9b4ef76b422ce1154af39a91323ccc57434')
visit project_merge_request_path(project, merge_request)
wait_for_requests
......@@ -51,7 +51,7 @@ feature 'Pipelines for Merge Requests', :js do
visit project_merge_request_path(project, merge_request)
end
scenario 'user visits merge request page' do
it 'user visits merge request page' do
page.within('.merge-request-tabs') do
expect(page).to have_no_link('Pipelines')
end
......@@ -60,22 +60,22 @@ feature 'Pipelines for Merge Requests', :js do
end
describe 'race condition' do
given(:project) { create(:project, :repository) }
given(:user) { create(:user) }
given(:build_push_data) { { ref: 'feature', checkout_sha: TestEnv::BRANCH_SHA['feature'] } }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:build_push_data) { { ref: 'feature', checkout_sha: TestEnv::BRANCH_SHA['feature'] } }
given(:merge_request_params) do
let(:merge_request_params) do
{ "source_branch" => "feature", "source_project_id" => project.id,
"target_branch" => "master", "target_project_id" => project.id, "title" => "A" }
end
background do
before do
project.add_master(user)
sign_in user
end
context 'when pipeline and merge request were created simultaneously' do
background do
before do
stub_ci_pipeline_to_return_yaml_file
threads = []
......@@ -91,7 +91,7 @@ feature 'Pipelines for Merge Requests', :js do
threads.each { |thr| thr.join }
end
scenario 'user sees pipeline in merge request widget' do
it 'user sees pipeline in merge request widget' do
visit project_merge_request_path(project, @merge_request)
expect(page.find(".ci-widget")).to have_content(TestEnv::BRANCH_SHA['feature'])
......
require 'spec_helper'
require 'rails_helper'
feature 'Merge requests > User sees system notes' do
describe 'Merge request > User sees system notes' do
let(:public_project) { create(:project, :public, :repository) }
let(:private_project) { create(:project, :private, :repository) }
let(:user) { private_project.creator }
let(:issue) { create(:issue, project: private_project) }
let(:merge_request) { create(:merge_request, source_project: public_project, source_branch: 'markdown') }
let!(:note) { create(:note_on_merge_request, :system, noteable: merge_request, project: public_project, note: "mentioned in #{issue.to_reference(public_project)}") }
context 'when logged-in as a member of the private project' do
before do
user = create(:user)
private_project.add_developer(user)
sign_in(user)
end
......
require 'spec_helper'
require 'rails_helper'
feature 'Merge Request versions', :js do
describe 'Merge request > User sees versions', :js do
let(:merge_request) { create(:merge_request, importing: true) }
let(:project) { merge_request.source_project }
let(:user) { project.creator }
let!(:merge_request_diff1) { merge_request.merge_request_diffs.create(head_commit_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
let!(:merge_request_diff2) { merge_request.merge_request_diffs.create(head_commit_sha: nil) }
let!(:merge_request_diff3) { merge_request.merge_request_diffs.create(head_commit_sha: '5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
let!(:params) { Hash.new }
let!(:params) { {} }
before do
sign_in(create(:admin))
project.add_master(user)
sign_in(user)
visit diffs_project_merge_request_path(project, merge_request, params)
end
......@@ -62,19 +64,10 @@ feature 'Merge Request versions', :js do
end
end
it 'should show older version' do
page.within '.mr-version-dropdown' do
expect(page).to have_content 'version 1'
end
it 'shows comments that were last relevant at that version' do
expect(page).to have_content '5 changed files'
end
it 'show the message about comments' do
expect(page).to have_content 'Not all comments are displayed'
end
it 'shows comments that were last relevant at that version' do
position = Gitlab::Diff::Position.new(
old_path: ".gitmodules",
new_path: ".gitmodules",
......@@ -86,7 +79,7 @@ feature 'Merge Request versions', :js do
outdated_diff_note.position = outdated_diff_note.original_position
outdated_diff_note.save!
visit current_url
refresh
expect(page).to have_css(".diffs .notes[data-discussion-id='#{outdated_diff_note.discussion_id}']")
end
......@@ -110,26 +103,16 @@ feature 'Merge Request versions', :js do
end
end
it 'has a path with comparison context' do
it 'has a path with comparison context and shows comments that were last relevant at that version' do
expect(page).to have_current_path diffs_project_merge_request_path(
project,
merge_request.iid,
diff_id: merge_request_diff3.id,
start_sha: '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9'
)
end
it 'should have correct value in the compare dropdown' do
page.within '.mr-version-compare-dropdown' do
expect(page).to have_content 'version 1'
end
end
it 'show the message about comments' do
expect(page).to have_content '4 changed files with 15 additions and 6 deletions'
expect(page).to have_content 'Not all comments are displayed'
end
it 'shows comments that were last relevant at that version' do
position = Gitlab::Diff::Position.new(
old_path: ".gitmodules",
new_path: ".gitmodules",
......@@ -141,7 +124,7 @@ feature 'Merge Request versions', :js do
outdated_diff_note.position = outdated_diff_note.original_position
outdated_diff_note.save!
visit current_url
refresh
wait_for_requests
expect(page).to have_css(".diffs .notes[data-discussion-id='#{outdated_diff_note.discussion_id}']")
......@@ -151,7 +134,7 @@ feature 'Merge Request versions', :js do
expect(page).to have_content '4 changed files with 15 additions and 6 deletions'
end
it 'should return to latest version when "Show latest version" button is clicked' do
it 'returns to latest version when "Show latest version" button is clicked' do
click_link 'Show latest version'
page.within '.mr-version-dropdown' do
expect(page).to have_content 'latest version'
......@@ -173,7 +156,7 @@ feature 'Merge Request versions', :js do
end
end
it 'should have 0 chages between versions' do
it 'has 0 chages between versions' do
page.within '.mr-version-compare-dropdown' do
expect(find('.dropdown-toggle')).to have_content 'version 1'
end
......@@ -194,7 +177,7 @@ feature 'Merge Request versions', :js do
end
end
it 'should set the compared versions to be the same' do
it 'sets the compared versions to be the same' do
page.within '.mr-version-compare-dropdown' do
expect(find('.dropdown-toggle')).to have_content 'version 2'
end
......
require 'spec_helper'
require 'rails_helper'
feature 'Work In Progress help message' do
let!(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user) }
describe 'Merge request > User sees WIP help message' do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
before do
project.add_master(user)
......
require 'spec_helper'
require 'rails_helper'
feature 'Create New Merge Request', :js do
let(:user) { create(:user) }
describe 'Merge request > User selects branches for new MR', :js do
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
before do
project.add_master(user)
sign_in user
sign_in(user)
end
it 'selects the source branch sha when a tag with the same name exists' do
......
require 'spec_helper'
require 'rails_helper'
describe 'Merge request > User toggles whitespace changes', :js do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
let(:user) { project.creator }
feature 'Toggle Whitespace Changes', :js do
before do
sign_in(create(:admin))
merge_request = create(:merge_request)
project = merge_request.source_project
project.add_master(user)
sign_in(user)
visit diffs_project_merge_request_path(project, merge_request)
end
......
require 'rails_helper'
feature 'Merge Requests > User uses quick actions', :js do
describe 'Merge request > User uses quick actions', :js do
include QuickActionsHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:guest) { create(:user) }
let(:merge_request) { create(:merge_request, source_project: project) }
let!(:milestone) { create(:milestone, project: project, title: 'ASAP') }
it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do
let(:issuable) { create(:merge_request, source_project: project) }
let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } }
......@@ -20,15 +26,7 @@ feature 'Merge Requests > User uses quick actions', :js do
visit project_merge_request_path(project, merge_request)
end
after do
wait_for_requests
end
describe 'time tracking' do
before do
visit project_merge_request_path(project, merge_request)
end
it_behaves_like 'issuable time tracker'
end
......@@ -56,7 +54,6 @@ feature 'Merge Requests > User uses quick actions', :js do
end
context 'when the current user cannot toggle the WIP prefix' do
let(:guest) { create(:user) }
before do
project.add_guest(guest)
sign_out(:user)
......@@ -102,7 +99,6 @@ feature 'Merge Requests > User uses quick actions', :js do
end
context 'when the current user cannot merge the MR' do
let(:guest) { create(:user) }
before do
project.add_guest(guest)
sign_out(:user)
......@@ -186,7 +182,6 @@ feature 'Merge Requests > User uses quick actions', :js do
end
context 'when current user can not change target branch' do
let(:guest) { create(:user) }
before do
project.add_guest(guest)
sign_out(:user)
......
require 'rails_helper'
feature 'Merge request issue assignment', :js do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
let(:merge_request) { create(:merge_request, :simple, source_project: project, author: user, description: "fixes #{issue1.to_reference} and #{issue2.to_reference}") }
let(:service) { MergeRequests::AssignIssuesService.new(merge_request, user, user, project) }
before do
project.add_developer(user)
end
def visit_merge_request(current_user = nil)
sign_in(current_user || user)
visit project_merge_request_path(project, merge_request)
end
context 'logged in as author' do
it 'updates related issues' do
visit_merge_request
click_link "Assign yourself to these issues"
expect(page).to have_content "2 issues have been assigned to you"
end
it 'returns user to the merge request' do
visit_merge_request
click_link "Assign yourself to these issues"
expect(page).to have_content merge_request.description
end
it "doesn't display if related issues are already assigned" do
[issue1, issue2].each { |issue| issue.update!(assignees: [user]) }
visit_merge_request
expect(page).not_to have_content "Assign yourself"
end
end
context 'not MR author' do
it "doesn't not show assignment link" do
visit_merge_request(create(:user))
expect(page).not_to have_content "Assign yourself"
end
end
end
require 'spec_helper'
feature 'Creating a merge request from a fork', :js do
include ProjectForksHelper
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let!(:source_project) do
fork_project(project, user,
repository: true,
namespace: user.namespace)
end
before do
source_project.add_master(user)
sign_in(user)
end
shared_examples 'create merge request to other project' do
it 'has all possible target projects' do
visit project_new_merge_request_path(source_project)
first('.js-target-project').click
within('.dropdown-target-project .dropdown-content') do
expect(page).to have_content(project.full_path)
expect(page).to have_content(target_project.full_path)
expect(page).to have_content(source_project.full_path)
end
end
it 'allows creating the merge request to another target project' do
visit project_merge_requests_path(source_project)
page.within '.content' do
click_link 'New merge request'
end
find('.js-source-branch', match: :first).click
find('.dropdown-source-branch .dropdown-content a', match: :first).click
first('.js-target-project').click
find('.dropdown-target-project .dropdown-content a', text: target_project.full_path).click
click_button 'Compare branches and continue'
wait_for_requests
expect { click_button 'Submit merge request' }
.to change { target_project.merge_requests.reload.size }.by(1)
end
it 'updates the branches when selecting a new target project' do
target_project_member = target_project.owner
CreateBranchService.new(target_project, target_project_member)
.execute('a-brand-new-branch-to-test', 'master')
visit project_new_merge_request_path(source_project)
first('.js-target-project').click
find('.dropdown-target-project .dropdown-content a', text: target_project.full_path).click
wait_for_requests
first('.js-target-branch').click
within('.dropdown-target-branch .dropdown-content') do
expect(page).to have_content('a-brand-new-branch-to-test')
end
end
end
context 'creating to the source of a fork' do
let!(:target_project) { project }
it_behaves_like('create merge request to other project')
end
context 'creating to a sibling of a fork' do
let!(:target_project) do
other_user = create(:user)
fork_project(project, other_user,
repository: true,
namespace: other_user.namespace)
end
it_behaves_like('create merge request to other project')
end
end
require 'spec_helper'
feature 'Merge request created from fork' do
include ProjectForksHelper
given(:user) { create(:user) }
given(:project) { create(:project, :public, :repository) }
given(:forked_project) { fork_project(project, user, repository: true) }
given!(:merge_request) do
create(:merge_request_with_diffs, source_project: forked_project,
target_project: project,
description: 'Test merge request')
end
background do
forked_project.add_master(user)
sign_in user
end
scenario 'user can access merge request' do
visit_merge_request(merge_request)
expect(page).to have_content 'Test merge request'
end
context 'when a commit comment exists on the merge request' do
given(:comment) { 'A commit comment' }
given(:reply) { 'A reply comment' }
background do
create(:note_on_commit, note: comment,
project: forked_project,
commit_id: merge_request.commit_shas.first)
end
scenario 'user can reply to the comment', :js do
visit_merge_request(merge_request)
expect(page).to have_content(comment)
page.within('.discussion-notes') do
find('.btn-text-field').click
find('#note_note').send_keys(reply)
find('.comment-btn').click
end
wait_for_requests
expect(page).to have_content(reply)
end
end
context 'source project is deleted' do
background do
MergeRequests::MergeService.new(project, user).execute(merge_request)
forked_project.destroy!
end
scenario 'user can access merge request', :js do
visit_merge_request(merge_request)
expect(page).to have_content 'Test merge request'
expect(page).to have_content "(removed):#{merge_request.source_branch}"
end
end
context 'pipeline present in source project' do
given(:pipeline) do
create(:ci_pipeline,
project: forked_project,
sha: merge_request.diff_head_sha,
ref: merge_request.source_branch)
end
background do
create(:ci_build, pipeline: pipeline, name: 'rspec')
create(:ci_build, pipeline: pipeline, name: 'spinach')
end
scenario 'user visits a pipelines page', :js do
visit_merge_request(merge_request)
page.within('.merge-request-tabs') { click_link 'Pipelines' }
page.within('.ci-table') do
expect(page).to have_content pipeline.id
end
end
end
def visit_merge_request(mr)
visit project_merge_request_path(project, mr)
end
end
require 'spec_helper'
feature 'Edit Merge Request' do
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, :simple, source_project: project) }
before do
project.add_master(user)
sign_in user
visit edit_project_merge_request_path(project, merge_request)
end
context 'editing a MR' do
it 'has class js-quick-submit in form' do
expect(page).to have_selector('.js-quick-submit')
end
it 'warns about version conflict' do
merge_request.update(title: "New title")
fill_in 'merge_request_title', with: 'bug 345'
fill_in 'merge_request_description', with: 'bug description'
click_button 'Save changes'
expect(page).to have_content 'Someone edited the merge request the same time you did'
end
it 'allows to unselect "Remove source branch"', :js do
merge_request.update(merge_params: { 'force_remove_source_branch' => '1' })
expect(merge_request.merge_params['force_remove_source_branch']).to be_truthy
visit edit_project_merge_request_path(project, merge_request)
uncheck 'Remove source branch when merge request is accepted'
click_button 'Save changes'
expect(page).to have_unchecked_field 'remove-source-branch-input'
expect(page).to have_content 'Remove source branch'
end
it 'should preserve description textarea height', :js do
long_description = %q(
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ac ornare ligula, ut tempus arcu. Etiam ultricies accumsan dolor vitae faucibus. Donec at elit lacus. Mauris orci ante, aliquam quis lorem eget, convallis faucibus arcu. Aenean at pulvinar lacus. Ut viverra quam massa, molestie ornare tortor dignissim a. Suspendisse tristique pellentesque tellus, id lacinia metus elementum id. Nam tristique, arcu rhoncus faucibus viverra, lacus ipsum sagittis ligula, vitae convallis odio lacus a nibh. Ut tincidunt est purus, ac vestibulum augue maximus in. Suspendisse vel erat et mi ultricies semper. Pellentesque volutpat pellentesque consequat.
Cras congue nec ligula tristique viverra. Curabitur fringilla fringilla fringilla. Donec rhoncus dignissim orci ut accumsan. Ut rutrum urna a rhoncus varius. Maecenas blandit, mauris nec accumsan gravida, augue nibh finibus magna, sed maximus turpis libero nec neque. Suspendisse at semper est. Nunc imperdiet dapibus dui, varius sollicitudin erat luctus non. Sed pellentesque ligula eget posuere facilisis. Donec dictum commodo volutpat. Donec egestas dui ac magna sollicitudin bibendum. Vivamus purus neque, ullamcorper ac feugiat et, tempus sit amet metus. Praesent quis viverra neque. Sed bibendum viverra est, eu aliquam mi ornare vitae. Proin et dapibus ipsum. Nunc tortor diam, malesuada nec interdum vel, placerat quis justo. Ut viverra at erat eu laoreet.
Pellentesque commodo, diam sit amet dignissim condimentum, tortor justo pretium est, non venenatis metus eros ut nunc. Etiam ut neque eget sem dapibus aliquam. Curabitur vel elit lorem. Nulla nec enim elit. Sed ut ex id justo facilisis convallis at ac augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam cursus egestas turpis non tristique. Suspendisse in erat sem. Fusce libero elit, fermentum gravida mauris id, auctor iaculis felis. Nullam vulputate tempor laoreet.
Nam tempor et magna sed convallis. Fusce sit amet sollicitudin risus, a ullamcorper lacus. Morbi gravida quis sem eget porttitor. Donec eu egestas mauris, in elementum tortor. Sed eget ex mi. Mauris iaculis tortor ut est auctor, nec dignissim quam sagittis. Suspendisse vel metus non quam suscipit tincidunt. Cras molestie lacus non justo finibus sodales quis vitae erat. In a porttitor nisi, id sollicitudin urna. Ut at felis tellus. Suspendisse potenti.
Maecenas leo ligula, varius at neque vitae, ornare maximus justo. Nullam convallis luctus risus et vulputate. Duis suscipit faucibus iaculis. Etiam quis tortor faucibus, tristique tellus sit amet, sodales neque. Nulla dapibus nisi vel aliquet consequat. Etiam faucibus, metus eget condimentum iaculis, enim urna lobortis sem, id efficitur eros sapien nec nisi. Aenean ut finibus ex.
)
fill_in 'merge_request_description', with: long_description
height = get_textarea_height
find('.js-md-preview-button').click
find('.js-md-write-button').click
new_height = get_textarea_height
expect(height).to eq(new_height)
end
def get_textarea_height
find('#merge_request_description')
page.evaluate_script('document.getElementById("merge_request_description").offsetHeight')
end
end
end
require 'rails_helper'
feature 'Merge Request filtering by Labels', :js do
include FilteredSearchHelpers
include MergeRequestHelpers
let(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user) }
let!(:label) { create(:label, project: project) }
let!(:bug) { create(:label, project: project, title: 'bug') }
let!(:feature) { create(:label, project: project, title: 'feature') }
let!(:enhancement) { create(:label, project: project, title: 'enhancement') }
let!(:mr1) { create(:merge_request, title: "Bugfix1", source_project: project, target_project: project, source_branch: "fix") }
let!(:mr2) { create(:merge_request, title: "Bugfix2", source_project: project, target_project: project, source_branch: "wip") }
let!(:mr3) { create(:merge_request, title: "Feature1", source_project: project, target_project: project, source_branch: "improve/awesome") }
before do
mr1.labels << bug
mr2.labels << bug
mr2.labels << enhancement
mr3.title = "Feature1"
mr3.labels << feature
project.add_master(user)
sign_in(user)
visit project_merge_requests_path(project)
end
context 'filter by label bug' do
before do
input_filtered_search('label:~bug')
end
it 'apply the filter' do
expect(page).to have_content "Bugfix1"
expect(page).to have_content "Bugfix2"
expect(page).not_to have_content "Feature1"
end
end
context 'filter by label feature' do
before do
input_filtered_search('label:~feature')
end
it 'applies the filter' do
expect(page).to have_content "Feature1"
expect(page).not_to have_content "Bugfix2"
expect(page).not_to have_content "Bugfix1"
end
end
context 'filter by label enhancement' do
before do
input_filtered_search('label:~enhancement')
end
it 'applies the filter' do
expect(page).to have_content "Bugfix2"
expect(page).not_to have_content "Feature1"
expect(page).not_to have_content "Bugfix1"
end
end
context 'filter by label enhancement and bug in issues list' do
before do
input_filtered_search('label:~bug label:~enhancement')
end
it 'applies the filters' do
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content "Bugfix2"
expect(page).not_to have_content "Feature1"
end
end
context 'filter dropdown' do
it 'filters by label name' do
init_label_search
filtered_search.send_keys('~bug')
page.within '.filter-dropdown' do
expect(page).not_to have_content 'enhancement'
expect(page).to have_content 'bug'
end
end
end
end
require 'rails_helper'
feature 'Merge Request filtering by Milestone' do
include FilteredSearchHelpers
include MergeRequestHelpers
let(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user)}
let(:milestone) { create(:milestone, project: project) }
def filter_by_milestone(title)
find(".js-milestone-select").click
find(".milestone-filter a", text: title).click
end
before do
project.add_master(user)
sign_in(user)
end
scenario 'filters by no Milestone', :js do
create(:merge_request, :with_diffs, source_project: project)
create(:merge_request, :simple, source_project: project, milestone: milestone)
visit_merge_requests(project)
input_filtered_search('milestone:none')
expect_tokens([milestone_token('none', false)])
expect_filtered_search_input_empty
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
context 'filters by upcoming milestone', :js do
it 'does not show merge requests with no expiry' do
create(:merge_request, :with_diffs, source_project: project)
create(:merge_request, :simple, source_project: project, milestone: milestone)
visit_merge_requests(project)
input_filtered_search('milestone:upcoming')
expect(page).to have_css('.merge-request', count: 0)
end
it 'shows merge requests in future' do
milestone = create(:milestone, project: project, due_date: Date.tomorrow)
create(:merge_request, :with_diffs, source_project: project)
create(:merge_request, :simple, source_project: project, milestone: milestone)
visit_merge_requests(project)
input_filtered_search('milestone:upcoming')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
it 'does not show merge requests in past' do
milestone = create(:milestone, project: project, due_date: Date.yesterday)
create(:merge_request, :with_diffs, source_project: project)
create(:merge_request, :simple, source_project: project, milestone: milestone)
visit_merge_requests(project)
input_filtered_search('milestone:upcoming')
expect(page).to have_css('.merge-request', count: 0)
end
end
scenario 'filters by a specific Milestone', :js do
create(:merge_request, :with_diffs, source_project: project, milestone: milestone)
create(:merge_request, :simple, source_project: project)
visit_merge_requests(project)
input_filtered_search("milestone:%'#{milestone.title}'")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
context 'when milestone has single quotes in title' do
background do
milestone.update(name: "rock 'n' roll")
end
scenario 'filters by a specific Milestone', :js do
create(:merge_request, :with_diffs, source_project: project, milestone: milestone)
create(:merge_request, :simple, source_project: project)
visit_merge_requests(project)
input_filtered_search("milestone:%\"#{milestone.title}\"")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
end
end
require 'rails_helper'
describe 'Filter merge requests' do
include FilteredSearchHelpers
include MergeRequestHelpers
let!(:project) { create(:project, :repository) }
let!(:group) { create(:group) }
let!(:user) { create(:user) }
let!(:milestone) { create(:milestone, project: project) }
let!(:label) { create(:label, project: project) }
let!(:wontfix) { create(:label, project: project, title: "Won't fix") }
before do
project.add_master(user)
group.add_developer(user)
sign_in(user)
create(:merge_request, source_project: project, target_project: project)
visit project_merge_requests_path(project)
end
describe 'for assignee from mr#index' do
let(:search_query) { "assignee:@#{user.username}" }
def expect_assignee_visual_tokens
wait_for_requests
expect_tokens([assignee_token(user.name)])
expect_filtered_search_input_empty
end
before do
input_filtered_search(search_query)
expect_mr_list_count(0)
end
context 'assignee', :js do
it 'updates to current user' do
expect_assignee_visual_tokens()
end
it 'does not change when closed link is clicked' do
find('.issues-state-filters [data-state="closed"]').click
expect_assignee_visual_tokens()
end
it 'does not change when all link is clicked' do
find('.issues-state-filters [data-state="all"]').click
expect_assignee_visual_tokens()
end
end
end
describe 'for milestone from mr#index' do
let(:search_query) { "milestone:%\"#{milestone.title}\"" }
def expect_milestone_visual_tokens
expect_tokens([milestone_token("\"#{milestone.title}\"")])
expect_filtered_search_input_empty
end
before do
input_filtered_search(search_query)
expect_mr_list_count(0)
end
context 'milestone', :js do
it 'updates to current milestone' do
expect_milestone_visual_tokens()
end
it 'does not change when closed link is clicked' do
find('.issues-state-filters [data-state="closed"]').click
expect_milestone_visual_tokens()
end
it 'does not change when all link is clicked' do
find('.issues-state-filters [data-state="all"]').click
expect_milestone_visual_tokens()
end
end
end
describe 'for label from mr#index', :js do
it 'filters by no label' do
input_filtered_search('label:none')
expect_mr_list_count(1)
expect_tokens([label_token('none', false)])
expect_filtered_search_input_empty
end
it 'filters by a label' do
input_filtered_search("label:~#{label.title}")
expect_mr_list_count(0)
expect_tokens([label_token(label.title)])
expect_filtered_search_input_empty
end
it "filters by `won't fix` and another label" do
input_filtered_search("label:~\"#{wontfix.title}\" label:~#{label.title}")
expect_mr_list_count(0)
expect_tokens([label_token("\"#{wontfix.title}\""), label_token(label.title)])
expect_filtered_search_input_empty
end
it "filters by `won't fix` label followed by another label after page load" do
input_filtered_search("label:~\"#{wontfix.title}\"")
expect_mr_list_count(0)
expect_tokens([label_token("\"#{wontfix.title}\"")])
expect_filtered_search_input_empty
input_filtered_search_keys("label:~#{label.title}")
expect_mr_list_count(0)
expect_tokens([label_token("\"#{wontfix.title}\""), label_token(label.title)])
expect_filtered_search_input_empty
end
end
describe 'for assignee and label from mr#index' do
let(:search_query) { "assignee:@#{user.username} label:~#{label.title}" }
before do
input_filtered_search(search_query)
expect_mr_list_count(0)
end
context 'assignee and label', :js do
def expect_assignee_label_visual_tokens
wait_for_requests
expect_tokens([assignee_token(user.name), label_token(label.title)])
expect_filtered_search_input_empty
end
it 'updates to current assignee and label' do
expect_assignee_label_visual_tokens()
end
it 'does not change when closed link is clicked' do
find('.issues-state-filters [data-state="closed"]').click
expect_assignee_label_visual_tokens()
end
it 'does not change when all link is clicked' do
find('.issues-state-filters [data-state="all"]').click
expect_assignee_label_visual_tokens()
end
end
end
describe 'filter merge requests by text' do
before do
create(:merge_request, title: "Bug", source_project: project, target_project: project, source_branch: "wip")
bug_label = create(:label, project: project, title: 'bug')
milestone = create(:milestone, title: "8", project: project)
mr = create(:merge_request,
title: "Bug 2",
source_project: project,
target_project: project,
source_branch: "fix",
milestone: milestone,
author: user,
assignee: user)
mr.labels << bug_label
visit project_merge_requests_path(project)
end
context 'only text', :js do
it 'filters merge requests by searched text' do
input_filtered_search('bug')
expect_mr_list_count(2)
end
it 'does not show any merge requests' do
input_filtered_search('testing')
page.within '.mr-list' do
expect(page).not_to have_selector('.merge-request')
end
end
end
context 'filters and searches', :js do
it 'filters by text and label' do
input_filtered_search('Bug')
expect_mr_list_count(2)
expect_filtered_search_input('Bug')
input_filtered_search_keys(' label:~bug')
expect_mr_list_count(1)
expect_tokens([label_token('bug')])
expect_filtered_search_input('Bug')
end
it 'filters by text and milestone' do
input_filtered_search('Bug')
expect_mr_list_count(2)
expect_filtered_search_input('Bug')
input_filtered_search_keys(' milestone:%8')
expect_mr_list_count(1)
expect_tokens([milestone_token('8')])
expect_filtered_search_input('Bug')
end
it 'filters by text and assignee' do
input_filtered_search('Bug')
expect_mr_list_count(2)
expect_filtered_search_input('Bug')
input_filtered_search_keys(" assignee:@#{user.username}")
expect_mr_list_count(1)
wait_for_requests
expect_tokens([assignee_token(user.name)])
expect_filtered_search_input('Bug')
end
it 'filters by text and author' do
input_filtered_search('Bug')
expect_mr_list_count(2)
expect_filtered_search_input('Bug')
input_filtered_search_keys(" author:@#{user.username}")
wait_for_requests
expect_mr_list_count(1)
expect_tokens([author_token(user.name)])
expect_filtered_search_input('Bug')
end
end
end
describe 'filter merge requests and sort', :js do
before do
bug_label = create(:label, project: project, title: 'bug')
mr1 = create(:merge_request, title: "Frontend", source_project: project, target_project: project, source_branch: "wip")
mr2 = create(:merge_request, title: "Bug 2", source_project: project, target_project: project, source_branch: "fix")
mr1.labels << bug_label
mr2.labels << bug_label
visit project_merge_requests_path(project)
end
it 'is able to filter and sort merge requests' do
input_filtered_search('label:~bug')
expect_mr_list_count(2)
click_button 'Created date'
page.within '.dropdown-menu-sort' do
click_link 'Priority'
end
wait_for_requests
page.within '.mr-list' do
expect(page).to have_content('Frontend')
end
end
end
describe 'filter by assignee id', :js do
it 'filter by current user' do
visit project_merge_requests_path(project, assignee_id: user.id)
wait_for_requests
expect_tokens([assignee_token(user.name)])
expect_filtered_search_input_empty
end
it 'filter by new user' do
new_user = create(:user)
project.add_developer(new_user)
visit project_merge_requests_path(project, assignee_id: new_user.id)
wait_for_requests
expect_tokens([assignee_token(new_user.name)])
expect_filtered_search_input_empty
end
end
describe 'filter by author id', :js do
it 'filter by current user' do
visit project_merge_requests_path(project, author_id: user.id)
wait_for_requests
expect_tokens([author_token(user.name)])
expect_filtered_search_input_empty
end
it 'filter by new user' do
new_user = create(:user)
project.add_developer(new_user)
visit project_merge_requests_path(project, author_id: new_user.id)
wait_for_requests
expect_tokens([author_token(new_user.name)])
expect_filtered_search_input_empty
end
end
end
require 'rails_helper'
describe 'Merge Requests > Filters generic behavior', :js do
include FilteredSearchHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:bug) { create(:label, project: project, title: 'bug') }
let(:open_mr) { create(:merge_request, title: 'Bugfix1', source_project: project, target_project: project, source_branch: 'bugfix1') }
let(:merged_mr) { create(:merge_request, :merged, title: 'Bugfix2', source_project: project, target_project: project, source_branch: 'bugfix2') }
let(:closed_mr) { create(:merge_request, :closed, title: 'Feature', source_project: project, target_project: project, source_branch: 'improve/awesome') }
before do
open_mr.labels << bug
merged_mr.labels << bug
closed_mr.labels << bug
sign_in(user)
visit project_merge_requests_path(project)
end
context 'when filtered by a label' do
before do
input_filtered_search('label:~bug')
end
describe 'state tabs' do
it 'does not change when state tabs are clicked' do
expect(page).to have_issuable_counts(open: 1, merged: 1, closed: 1, all: 3)
expect(page).to have_content 'Bugfix1'
expect(page).not_to have_content 'Bugfix2'
expect(page).not_to have_content 'Feature'
find('.issues-state-filters [data-state="merged"]').click
expect(page).to have_issuable_counts(open: 1, merged: 1, closed: 1, all: 3)
expect(page).not_to have_content 'Bugfix1'
expect(page).to have_content 'Bugfix2'
expect(page).not_to have_content 'Feature'
find('.issues-state-filters [data-state="closed"]').click
expect(page).to have_issuable_counts(open: 1, merged: 1, closed: 1, all: 3)
expect(page).not_to have_content 'Bugfix1'
expect(page).not_to have_content 'Bugfix2'
expect(page).to have_content 'Feature'
find('.issues-state-filters [data-state="all"]').click
expect(page).to have_issuable_counts(open: 1, merged: 1, closed: 1, all: 3)
expect(page).to have_content 'Bugfix1'
expect(page).to have_content 'Bugfix2'
expect(page).to have_content 'Feature'
end
end
describe 'clear button' do
it 'allows user to remove filtered labels' do
first('.clear-search').click
filtered_search.send_keys(:enter)
expect(page).to have_issuable_counts(open: 1, merged: 1, closed: 1, all: 3)
expect(page).to have_content 'Bugfix1'
expect(page).not_to have_content 'Bugfix2'
expect(page).not_to have_content 'Feature'
end
end
end
context 'filter dropdown' do
it 'filters by label name' do
init_label_search
filtered_search.send_keys('~bug')
page.within '.filter-dropdown' do
expect(page).not_to have_content 'enhancement'
expect(page).to have_content 'bug'
end
end
end
end
require 'rails_helper'
describe 'New/edit merge request', :js do
include ProjectForksHelper
let!(:project) { create(:project, :public, :repository) }
let(:forked_project) { fork_project(project, nil, repository: true) }
let!(:user) { create(:user) }
let!(:user2) { create(:user) }
let!(:milestone) { create(:milestone, project: project) }
let!(:label) { create(:label, project: project) }
let!(:label2) { create(:label, project: project) }
before do
project.add_master(user)
project.add_master(user2)
end
context 'owned projects' do
before do
sign_in(user)
end
context 'new merge request' do
before do
visit project_new_merge_request_path(
project,
merge_request: {
source_project_id: project.id,
target_project_id: project.id,
source_branch: 'fix',
target_branch: 'master'
})
end
it 'creates new merge request' do
click_button 'Assignee'
page.within '.dropdown-menu-user' do
click_link user2.name
end
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user2.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user2.name
end
find('a', text: 'Assign to me').click
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
end
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
end
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
end
click_button 'Labels'
page.within '.dropdown-menu-labels' do
click_link label.title
click_link label2.title
end
page.within '.js-label-select' do
expect(page).to have_content label.title
end
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
click_button 'Submit merge request'
page.within '.issuable-sidebar' do
page.within '.assignee' do
expect(page).to have_content user.name
end
page.within '.milestone' do
expect(page).to have_content milestone.title
end
page.within '.labels' do
expect(page).to have_content label.title
expect(page).to have_content label2.title
end
end
page.within '.breadcrumbs' do
merge_request = MergeRequest.find_by(source_branch: 'fix')
expect(page).to have_text("Merge Requests #{merge_request.to_reference}")
end
end
it 'description has autocomplete' do
find('#merge_request_description').native.send_keys('')
fill_in 'merge_request_description', with: '@'
expect(page).to have_selector('.atwho-view')
end
end
context 'edit merge request' do
before do
merge_request = create(:merge_request,
source_project: project,
target_project: project,
source_branch: 'fix',
target_branch: 'master'
)
visit edit_project_merge_request_path(project, merge_request)
end
it 'updates merge request' do
click_button 'Assignee'
page.within '.dropdown-menu-user' do
click_link user.name
end
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
end
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
end
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
end
click_button 'Labels'
page.within '.dropdown-menu-labels' do
click_link label.title
click_link label2.title
end
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
page.within '.js-label-select' do
expect(page).to have_content label.title
end
click_button 'Save changes'
page.within '.issuable-sidebar' do
page.within '.assignee' do
expect(page).to have_content user.name
end
page.within '.milestone' do
expect(page).to have_content milestone.title
end
page.within '.labels' do
expect(page).to have_content label.title
expect(page).to have_content label2.title
end
end
end
it 'description has autocomplete' do
find('#merge_request_description').native.send_keys('')
fill_in 'merge_request_description', with: '@'
expect(page).to have_selector('.atwho-view')
end
end
end
context 'forked project' do
before do
forked_project.add_master(user)
sign_in(user)
end
context 'new merge request' do
before do
visit project_new_merge_request_path(
forked_project,
merge_request: {
source_project_id: forked_project.id,
target_project_id: project.id,
source_branch: 'fix',
target_branch: 'master'
})
end
it 'creates new merge request' do
click_button 'Assignee'
page.within '.dropdown-menu-user' do
click_link user.name
end
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
end
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
end
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
end
click_button 'Labels'
page.within '.dropdown-menu-labels' do
click_link label.title
click_link label2.title
end
page.within '.js-label-select' do
expect(page).to have_content label.title
end
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
click_button 'Submit merge request'
page.within '.issuable-sidebar' do
page.within '.assignee' do
expect(page).to have_content user.name
end
page.within '.milestone' do
expect(page).to have_content milestone.title
end
page.within '.labels' do
expect(page).to have_content label.title
expect(page).to have_content label2.title
end
end
end
end
context 'edit merge request' do
before do
merge_request = create(:merge_request,
source_project: forked_project,
target_project: project,
source_branch: 'fix',
target_branch: 'master'
)
visit edit_project_merge_request_path(project, merge_request)
end
it 'should update merge request' do
click_button 'Assignee'
page.within '.dropdown-menu-user' do
click_link user.name
end
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
end
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
end
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
end
click_button 'Labels'
page.within '.dropdown-menu-labels' do
click_link label.title
click_link label2.title
end
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
page.within '.js-label-select' do
expect(page).to have_content label.title
end
click_button 'Save changes'
page.within '.issuable-sidebar' do
page.within '.assignee' do
expect(page).to have_content user.name
end
page.within '.milestone' do
expect(page).to have_content milestone.title
end
page.within '.labels' do
expect(page).to have_content label.title
expect(page).to have_content label2.title
end
end
end
end
end
end
require 'rails_helper'
feature 'Merge requests filter clear button', :js do
include FilteredSearchHelpers
include MergeRequestHelpers
include IssueHelpers
let!(:project) { create(:project, :public, :repository) }
let!(:user) { create(:user) }
let!(:milestone) { create(:milestone, project: project) }
let!(:bug) { create(:label, project: project, name: 'bug')}
let!(:mr1) { create(:merge_request, title: "Feature", source_project: project, target_project: project, source_branch: "improve/awesome", milestone: milestone, author: user, assignee: user) }
let!(:mr2) { create(:merge_request, title: "Bugfix1", source_project: project, target_project: project, source_branch: "fix") }
let(:merge_request_css) { '.merge-request' }
let(:clear_search_css) { '.filtered-search-box .clear-search' }
before do
mr2.labels << bug
project.add_developer(user)
end
context 'when a milestone filter has been applied' do
it 'resets the milestone filter' do
visit_merge_requests(project, milestone_title: milestone.title)
expect(page).to have_css(merge_request_css, count: 1)
expect(get_filtered_search_placeholder).to eq('')
reset_filters
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
end
end
context 'when a label filter has been applied' do
it 'resets the label filter' do
visit_merge_requests(project, label_name: bug.name)
expect(page).to have_css(merge_request_css, count: 1)
expect(get_filtered_search_placeholder).to eq('')
reset_filters
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
end
end
context 'when multiple label filters have been applied' do
let!(:label) { create(:label, project: project, name: 'Frontend') }
let(:filter_dropdown) { find("#js-dropdown-label .filter-dropdown") }
before do
visit_merge_requests(project)
init_label_search
end
it 'filters bug label' do
filtered_search.set('~bug')
filter_dropdown.find('.filter-dropdown-item', text: bug.title).click
init_label_search
expect(filter_dropdown.find('.filter-dropdown-item', text: bug.title)).to be_visible
expect(filter_dropdown.find('.filter-dropdown-item', text: label.title)).to be_visible
end
end
context 'when a text search has been conducted' do
it 'resets the text search filter' do
visit_merge_requests(project, search: 'Bug')
expect(page).to have_css(merge_request_css, count: 1)
expect(get_filtered_search_placeholder).to eq('')
reset_filters
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
end
end
context 'when author filter has been applied' do
it 'resets the author filter' do
visit_merge_requests(project, author_username: user.username)
expect(page).to have_css(merge_request_css, count: 1)
expect(get_filtered_search_placeholder).to eq('')
reset_filters
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
end
end
context 'when assignee filter has been applied' do
it 'resets the assignee filter' do
visit_merge_requests(project, assignee_username: user.username)
expect(page).to have_css(merge_request_css, count: 1)
expect(get_filtered_search_placeholder).to eq('')
reset_filters
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
end
end
context 'when all filters have been applied' do
it 'clears all filters' do
visit_merge_requests(project, assignee_username: user.username, author_username: user.username, milestone_title: milestone.title, label_name: bug.name, search: 'Bug')
expect(page).to have_css(merge_request_css, count: 0)
expect(get_filtered_search_placeholder).to eq('')
reset_filters
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
end
end
context 'when no filters have been applied' do
it 'the clear button should not be visible' do
visit_merge_requests(project)
expect(page).to have_css(merge_request_css, count: 2)
expect(get_filtered_search_placeholder).to eq(default_placeholder)
expect(page).not_to have_css(clear_search_css)
end
end
end
require 'spec_helper'
describe 'Target branch', :js do
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.project }
def path_to_merge_request
project_merge_request_path(project, merge_request)
end
before do
sign_in user
project.add_master(user)
end
context 'when branch was deleted' do
before do
DeleteBranchService.new(project, user).execute('feature')
visit path_to_merge_request
end
it 'shows a message about missing target branch' do
expect(page).to have_content(
'Target branch does not exist'
)
end
it 'does not show link to target branch' do
expect(page).not_to have_selector('.mr-widget-body .js-branch-text a')
end
end
end
require 'rails_helper'
describe 'Merge Requests > User filters by assignees', :js do
include FilteredSearchHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
before do
create(:merge_request, assignee: user, title: 'Bugfix1', source_project: project, target_project: project, source_branch: 'bugfix1')
create(:merge_request, title: 'Bugfix2', source_project: project, target_project: project, source_branch: 'bugfix2')
sign_in(user)
visit project_merge_requests_path(project)
end
context 'filtering by assignee:none' do
it 'applies the filter' do
input_filtered_search('assignee:none')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).not_to have_content 'Bugfix1'
expect(page).to have_content 'Bugfix2'
end
end
context 'filtering by assignee:@username' do
it 'applies the filter' do
input_filtered_search("assignee:@#{user.username}")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix1'
expect(page).not_to have_content 'Bugfix2'
end
end
end
require 'rails_helper'
describe 'Merge Requests > User filters by labels', :js do
include FilteredSearchHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:mr1) { create(:merge_request, title: 'Bugfix1', source_project: project, target_project: project, source_branch: 'bugfix1') }
let(:mr2) { create(:merge_request, title: 'Bugfix2', source_project: project, target_project: project, source_branch: 'bugfix2') }
before do
bug_label = create(:label, project: project, title: 'bug')
enhancement_label = create(:label, project: project, title: 'enhancement')
mr1.labels << bug_label
mr2.labels << bug_label << enhancement_label
sign_in(user)
visit project_merge_requests_path(project)
end
context 'filtering by label:none' do
it 'applies the filter' do
input_filtered_search('label:none')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).not_to have_content 'Bugfix1'
expect(page).not_to have_content 'Bugfix2'
end
end
context 'filtering by label:~enhancement' do
it 'applies the filter' do
input_filtered_search('label:~enhancement')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
expect(page).not_to have_content 'Bugfix1'
end
end
context 'filtering by label:~enhancement and label:~bug' do
it 'applies the filters' do
input_filtered_search('label:~bug label:~enhancement')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
end
end
end
require 'rails_helper'
describe 'Merge Requests > User filters by milestones', :js do
include FilteredSearchHelpers
let(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let(:milestone) { create(:milestone, project: project) }
before do
create(:merge_request, :with_diffs, source_project: project)
create(:merge_request, :simple, source_project: project, milestone: milestone)
sign_in(user)
visit project_merge_requests_path(project)
end
it 'filters by no milestone' do
input_filtered_search('milestone:none')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
it 'filters by a specific milestone' do
input_filtered_search("milestone:%'#{milestone.title}'")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
describe 'filters by upcoming milestone' do
it 'does not show merge requests with no expiry' do
input_filtered_search('milestone:upcoming')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).to have_css('.merge-request', count: 0)
end
context 'with an upcoming milestone' do
let(:milestone) { create(:milestone, project: project, due_date: Date.tomorrow) }
it 'shows merge requests' do
input_filtered_search('milestone:upcoming')
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_css('.merge-request', count: 1)
end
end
context 'with a due milestone' do
let(:milestone) { create(:milestone, project: project, due_date: Date.yesterday) }
it 'does not show any merge requests' do
input_filtered_search('milestone:upcoming')
expect(page).to have_issuable_counts(open: 0, closed: 0, all: 0)
expect(page).to have_css('.merge-request', count: 0)
end
end
end
end
require 'rails_helper'
describe 'Merge requests > User filters by multiple criteria', :js do
include FilteredSearchHelpers
let!(:project) { create(:project, :public, :repository) }
let(:user) { project.creator }
let!(:milestone) { create(:milestone, title: 'v1.1', project: project) }
let!(:wontfix) { create(:label, project: project, title: "Won't fix") }
before do
sign_in(user)
mr = create(:merge_request, title: 'Bugfix2', author: user, assignee: user, source_project: project, target_project: project, milestone: milestone)
mr.labels << wontfix
visit project_merge_requests_path(project)
end
describe 'filtering by label:~"Won\'t fix" and assignee:~bug' do
it 'applies the filters' do
input_filtered_search("label:~\"Won't fix\" assignee:@#{user.username}")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
expect_filtered_search_input_empty
end
end
describe 'filtering by text, author, assignee, milestone, and label' do
it 'filters by text, author, assignee, milestone, and label' do
input_filtered_search_keys("author:@#{user.username} assignee:@#{user.username} milestone:%\"v1.1\" label:~\"Won't fix\" Bug")
expect(page).to have_issuable_counts(open: 1, closed: 0, all: 1)
expect(page).to have_content 'Bugfix2'
expect_filtered_search_input('Bug')
end
end
end
require 'spec_helper'
require 'rails_helper'
describe 'Projects > Merge requests > User lists merge requests' do
describe 'Merge requests > User lists merge requests' do
include MergeRequestHelpers
include SortingHelper
......
require 'rails_helper'
feature 'Multiple merge requests updating from merge_requests#index' do
let!(:user) { create(:user)}
let!(:project) { create(:project, :repository) }
describe 'Merge requests > User mass updates', :js do
let(:project) { create(:project, :repository) }
let(:user) { project.creator }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
before do
......@@ -10,7 +10,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do
sign_in(user)
end
context 'status', :js do
context 'status' do
describe 'close merge request' do
before do
visit project_merge_requests_path(project)
......@@ -37,13 +37,13 @@ feature 'Multiple merge requests updating from merge_requests#index' do
end
end
context 'assignee', :js do
context 'assignee' do
describe 'set assignee' do
before do
visit project_merge_requests_path(project)
end
it "updates merge request with assignee" do
it 'updates merge request with assignee' do
change_assignee(user.name)
page.within('.merge-request .controls') do
......@@ -59,7 +59,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do
visit project_merge_requests_path(project)
end
it "removes assignee from the merge request" do
it 'removes assignee from the merge request' do
change_assignee('Unassigned')
expect(find('.merge-request .controls')).not_to have_css('.author_link')
......@@ -67,7 +67,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do
end
end
context 'milestone', :js do
context 'milestone' do
let(:milestone) { create(:milestone, project: project) }
describe 'set milestone' do
......@@ -75,7 +75,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do
visit project_merge_requests_path(project)
end
it "updates merge request with milestone" do
it 'updates merge request with milestone' do
change_milestone(milestone.title)
expect(find('.merge-request')).to have_content milestone.title
......@@ -89,7 +89,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do
visit project_merge_requests_path(project)
end
it "removes milestone from the merge request" do
it 'removes milestone from the merge request' do
change_milestone("No Milestone")
expect(find('.merge-request')).not_to have_content milestone.title
......
......@@ -125,10 +125,10 @@ describe IssuablesHelper do
describe '#updated_at_by' do
let(:user) { create(:user) }
let(:unedited_issuable) { create(:issue) }
let(:edited_issuable) { create(:issue, last_edited_by: user, created_at: 3.days.ago, updated_at: 2.days.ago, last_edited_at: 2.days.ago) }
let(:edited_issuable) { create(:issue, last_edited_by: user, created_at: 3.days.ago, updated_at: 1.day.ago, last_edited_at: 2.days.ago) }
let(:edited_updated_at_by) do
{
updatedAt: edited_issuable.updated_at.to_time.iso8601,
updatedAt: edited_issuable.last_edited_at.to_time.iso8601,
updatedBy: {
name: user.name,
path: user_path(user)
......@@ -142,7 +142,7 @@ describe IssuablesHelper do
context 'when updated by a deleted user' do
let(:edited_updated_at_by) do
{
updatedAt: edited_issuable.updated_at.to_time.iso8601,
updatedAt: edited_issuable.last_edited_at.to_time.iso8601,
updatedBy: {
name: User.ghost.name,
path: user_path(User.ghost)
......
......@@ -146,6 +146,12 @@ describe ProjectStatistics do
expect(statistics.build_artifacts_size).to be(106365)
end
it 'calculates related build artifacts by project' do
expect(Ci::JobArtifact).to receive(:artifacts_size_for).with(project) { 0 }
statistics.update_build_artifacts_size
end
end
context 'when legacy artifacts are used' do
......
......@@ -79,6 +79,13 @@ describe Route do
end
describe 'callbacks' do
context 'before validation' do
it 'calls #delete_conflicting_orphaned_routes' do
expect(route).to receive(:delete_conflicting_orphaned_routes)
route.valid?
end
end
context 'after update' do
it 'calls #create_redirect_for_old_path' do
expect(route).to receive(:create_redirect_for_old_path)
......@@ -378,4 +385,58 @@ describe Route do
end
end
end
describe '#delete_conflicting_orphaned_routes' do
context 'when there is a conflicting route' do
let!(:conflicting_group) { create(:group, path: 'foo') }
before do
route.path = conflicting_group.route.path
end
context 'when the route is orphaned' do
let!(:offending_route) { conflicting_group.route }
before do
Group.delete(conflicting_group) # Orphan the route
end
it 'deletes the orphaned route' do
expect do
route.valid?
end.to change { described_class.count }.from(2).to(1)
end
it 'passes validation, as usual' do
expect(route.valid?).to be_truthy
end
end
context 'when the route is not orphaned' do
it 'does not delete the conflicting route' do
expect do
route.valid?
end.not_to change { described_class.count }
end
it 'fails validation, as usual' do
expect(route.valid?).to be_falsey
end
end
end
context 'when there are no conflicting routes' do
it 'does not delete any routes' do
route
expect do
route.valid?
end.not_to change { described_class.count }
end
it 'passes validation, as usual' do
expect(route.valid?).to be_truthy
end
end
end
end
......@@ -53,7 +53,7 @@ describe API::Jobs do
expect(json_job['pipeline']['status']).to eq job.pipeline.status
end
it 'avoids N+1 queries', skip_before_request: true do
it 'avoids N+1 queries', :skip_before_request do
first_build = create(:ci_build, :artifacts, pipeline: pipeline)
first_build.runner = create(:ci_runner)
first_build.user = create(:user)
......
......@@ -42,7 +42,7 @@ describe API::V3::Builds do
expect(json_build['pipeline']['status']).to eq build.pipeline.status
end
it 'avoids N+1 queries', skip_before_request: true do
it 'avoids N+1 queries', :skip_before_request do
first_build = create(:ci_build, :artifacts, pipeline: pipeline)
first_build.runner = create(:ci_runner)
first_build.user = create(:user)
......
RSpec.shared_examples 'a creatable merge request' do
include WaitForRequests
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:target_project) { create(:project, :public, :repository) }
let(:source_project) { target_project }
let!(:milestone) { create(:milestone, project: target_project) }
let!(:label) { create(:label, project: target_project) }
let!(:label2) { create(:label, project: target_project) }
before do
source_project.add_master(user)
target_project.add_master(user)
target_project.add_master(user2)
sign_in(user)
visit project_new_merge_request_path(
target_project,
merge_request: {
source_project_id: source_project.id,
target_project_id: target_project.id,
source_branch: 'fix',
target_branch: 'master'
})
end
it 'creates new merge request', :js do
click_button 'Assignee'
page.within '.dropdown-menu-user' do
click_link user2.name
end
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user2.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user2.name
end
click_link 'Assign to me'
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
end
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
end
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
end
click_button 'Labels'
page.within '.dropdown-menu-labels' do
click_link label.title
click_link label2.title
end
page.within '.js-label-select' do
expect(page).to have_content label.title
end
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
click_button 'Submit merge request'
page.within '.issuable-sidebar' do
page.within '.assignee' do
expect(page).to have_content user.name
end
page.within '.milestone' do
expect(page).to have_content milestone.title
end
page.within '.labels' do
expect(page).to have_content label.title
expect(page).to have_content label2.title
end
end
end
it 'updates the branches when selecting a new target project' do
target_project_member = target_project.owner
CreateBranchService.new(target_project, target_project_member)
.execute('a-brand-new-branch-to-test', 'master')
visit project_new_merge_request_path(source_project)
first('.js-target-project').click
find('.dropdown-target-project .dropdown-content a', text: target_project.full_path).click
wait_for_requests
first('.js-target-branch').click
within('.dropdown-target-branch .dropdown-content') do
expect(page).to have_content('a-brand-new-branch-to-test')
end
end
end
RSpec.shared_examples 'an editable merge request' do
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:milestone) { create(:milestone, project: target_project) }
let!(:label) { create(:label, project: target_project) }
let!(:label2) { create(:label, project: target_project) }
let(:target_project) { create(:project, :public, :repository) }
let(:source_project) { target_project }
let(:merge_request) do
create(:merge_request,
source_project: source_project,
target_project: target_project,
source_branch: 'fix',
target_branch: 'master')
end
before do
source_project.add_master(user)
target_project.add_master(user)
target_project.add_master(user2)
sign_in(user)
visit edit_project_merge_request_path(target_project, merge_request)
end
it 'updates merge request', :js do
click_button 'Assignee'
page.within '.dropdown-menu-user' do
click_link user.name
end
expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
end
click_button 'Milestone'
page.within '.issue-milestone' do
click_link milestone.title
end
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
end
click_button 'Labels'
page.within '.dropdown-menu-labels' do
click_link label.title
click_link label2.title
end
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[1].value).to match(label.id.to_s)
expect(page.all('input[name="merge_request[label_ids][]"]', visible: false)[2].value).to match(label2.id.to_s)
page.within '.js-label-select' do
expect(page).to have_content label.title
end
click_button 'Save changes'
page.within '.issuable-sidebar' do
page.within '.assignee' do
expect(page).to have_content user.name
end
page.within '.milestone' do
expect(page).to have_content milestone.title
end
page.within '.labels' do
expect(page).to have_content label.title
expect(page).to have_content label2.title
end
end
end
it 'description has autocomplete', :js do
find('#merge_request_description').native.send_keys('')
fill_in 'merge_request_description', with: '@'
expect(page).to have_selector('.atwho-view')
end
it 'has class js-quick-submit in form' do
expect(page).to have_selector('.js-quick-submit')
end
it 'warns about version conflict' do
merge_request.update(title: "New title")
fill_in 'merge_request_title', with: 'bug 345'
fill_in 'merge_request_description', with: 'bug description'
click_button 'Save changes'
expect(page).to have_content 'Someone edited the merge request the same time you did'
end
it 'preserves description textarea height', :js do
long_description = %q(
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam ac ornare ligula, ut tempus arcu. Etiam ultricies accumsan dolor vitae faucibus. Donec at elit lacus. Mauris orci ante, aliquam quis lorem eget, convallis faucibus arcu. Aenean at pulvinar lacus. Ut viverra quam massa, molestie ornare tortor dignissim a. Suspendisse tristique pellentesque tellus, id lacinia metus elementum id. Nam tristique, arcu rhoncus faucibus viverra, lacus ipsum sagittis ligula, vitae convallis odio lacus a nibh. Ut tincidunt est purus, ac vestibulum augue maximus in. Suspendisse vel erat et mi ultricies semper. Pellentesque volutpat pellentesque consequat.
Cras congue nec ligula tristique viverra. Curabitur fringilla fringilla fringilla. Donec rhoncus dignissim orci ut accumsan. Ut rutrum urna a rhoncus varius. Maecenas blandit, mauris nec accumsan gravida, augue nibh finibus magna, sed maximus turpis libero nec neque. Suspendisse at semper est. Nunc imperdiet dapibus dui, varius sollicitudin erat luctus non. Sed pellentesque ligula eget posuere facilisis. Donec dictum commodo volutpat. Donec egestas dui ac magna sollicitudin bibendum. Vivamus purus neque, ullamcorper ac feugiat et, tempus sit amet metus. Praesent quis viverra neque. Sed bibendum viverra est, eu aliquam mi ornare vitae. Proin et dapibus ipsum. Nunc tortor diam, malesuada nec interdum vel, placerat quis justo. Ut viverra at erat eu laoreet.
Pellentesque commodo, diam sit amet dignissim condimentum, tortor justo pretium est, non venenatis metus eros ut nunc. Etiam ut neque eget sem dapibus aliquam. Curabitur vel elit lorem. Nulla nec enim elit. Sed ut ex id justo facilisis convallis at ac augue. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nullam cursus egestas turpis non tristique. Suspendisse in erat sem. Fusce libero elit, fermentum gravida mauris id, auctor iaculis felis. Nullam vulputate tempor laoreet.
Nam tempor et magna sed convallis. Fusce sit amet sollicitudin risus, a ullamcorper lacus. Morbi gravida quis sem eget porttitor. Donec eu egestas mauris, in elementum tortor. Sed eget ex mi. Mauris iaculis tortor ut est auctor, nec dignissim quam sagittis. Suspendisse vel metus non quam suscipit tincidunt. Cras molestie lacus non justo finibus sodales quis vitae erat. In a porttitor nisi, id sollicitudin urna. Ut at felis tellus. Suspendisse potenti.
Maecenas leo ligula, varius at neque vitae, ornare maximus justo. Nullam convallis luctus risus et vulputate. Duis suscipit faucibus iaculis. Etiam quis tortor faucibus, tristique tellus sit amet, sodales neque. Nulla dapibus nisi vel aliquet consequat. Etiam faucibus, metus eget condimentum iaculis, enim urna lobortis sem, id efficitur eros sapien nec nisi. Aenean ut finibus ex.
)
fill_in 'merge_request_description', with: long_description
height = get_textarea_height
find('.js-md-preview-button').click
find('.js-md-write-button').click
new_height = get_textarea_height
expect(height).to eq(new_height)
end
context 'when "Remove source branch" is set' do
before do
merge_request.update!(merge_params: { 'force_remove_source_branch' => '1' })
end
it 'allows to unselect "Remove source branch"', :js do
expect(merge_request.merge_params['force_remove_source_branch']).to be_truthy
visit edit_project_merge_request_path(target_project, merge_request)
uncheck 'Remove source branch when merge request is accepted'
click_button 'Save changes'
expect(page).to have_unchecked_field 'remove-source-branch-input'
expect(page).to have_content 'Remove source branch'
end
end
end
def get_textarea_height
page.evaluate_script('document.getElementById("merge_request_description").offsetHeight')
end
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册