summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml77
-rw-r--r--CHANGELOG4
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock6
-rw-r--r--app/assets/javascripts/gl_dropdown.js20
-rw-r--r--app/assets/javascripts/shortcuts_navigation.js3
-rw-r--r--app/assets/stylesheets/framework/lists.scss4
-rw-r--r--app/assets/stylesheets/pages/issues.scss4
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss25
-rw-r--r--app/assets/stylesheets/pages/snippets.scss39
-rw-r--r--app/controllers/admin/groups_controller.rb10
-rw-r--r--app/controllers/groups_controller.rb12
-rw-r--r--app/controllers/projects/builds_controller.rb2
-rw-r--r--app/helpers/groups_helper.rb25
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/helpers/snippets_helper.rb6
-rw-r--r--app/models/ci/variable.rb6
-rw-r--r--app/models/group.rb7
-rw-r--r--app/models/namespace.rb5
-rw-r--r--app/models/project.rb5
-rw-r--r--app/views/admin/groups/_form.html.haml2
-rw-r--r--app/views/admin/groups/show.html.haml6
-rw-r--r--app/views/groups/_group_lfs_settings.html.haml11
-rw-r--r--app/views/groups/edit.html.haml2
-rw-r--r--app/views/help/_shortcuts.html.haml6
-rw-r--r--app/views/layouts/nav/_project.html.haml4
-rw-r--r--app/views/profiles/update_username.js.haml2
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml12
-rw-r--r--app/views/projects/edit.html.haml17
-rw-r--r--app/views/projects/issues/_issue.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml2
-rw-r--r--app/views/projects/pipelines/index.html.haml8
-rw-r--r--app/views/projects/snippets/_actions.html.haml14
-rw-r--r--app/views/projects/snippets/show.html.haml21
-rw-r--r--app/views/projects/variables/_table.html.haml2
-rw-r--r--app/views/shared/_visibility_level.html.haml2
-rw-r--r--app/views/shared/snippets/_header.html.haml8
-rw-r--r--app/views/shared/snippets/_snippet.html.haml21
-rw-r--r--app/views/snippets/_actions.html.haml14
-rw-r--r--app/views/snippets/show.html.haml19
-rw-r--r--db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb12
-rw-r--r--db/migrate/20160913162434_remove_projects_pushes_since_gc.rb2
-rw-r--r--db/schema.rb1
-rw-r--r--doc/api/groups.md2
-rw-r--r--lib/api/entities.rb4
-rw-r--r--lib/api/groups.rb6
-rw-r--r--spec/features/boards/boards_spec.rb35
-rw-r--r--spec/features/boards/keyboard_shortcut_spec.rb24
-rw-r--r--spec/features/issues_spec.rb2
-rw-r--r--spec/features/users/snippets_spec.rb5
-rw-r--r--spec/helpers/groups_helper_spec.rb63
-rw-r--r--spec/models/group_spec.rb46
-rw-r--r--spec/models/project_spec.rb66
-rw-r--r--spec/support/wait_for_vue_resource.rb7
55 files changed, 539 insertions, 179 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 5bd31ccf329..b054675d677 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -767,26 +767,33 @@ Rails/ScopeArgs:
RSpec/AnyInstance:
Enabled: false
-# Check that the first argument to the top level describe is the tested class or
-# module.
+# Check for expectations where `be(...)` can replace `eql(...)`.
+RSpec/BeEql:
+ Enabled: false
+
+# Check that the first argument to the top level describe is a constant.
RSpec/DescribeClass:
Enabled: false
-# Use `described_class` for tested class / module.
+# Checks that tests use `described_class`.
+RSpec/DescribedClass:
+ Enabled: false
+
+# Checks that the second argument to `describe` specifies a method.
RSpec/DescribeMethod:
Enabled: false
-# Checks that the second argument to top level describe is the tested method
-# name.
-RSpec/DescribedClass:
+# Checks if an example group does not include any tests.
+RSpec/EmptyExampleGroup:
Enabled: false
+ CustomIncludeMethods: []
-# Checks for long example.
+# Checks for long examples.
RSpec/ExampleLength:
Enabled: false
Max: 5
-# Do not use should when describing your tests.
+# Checks that example descriptions do not start with "should".
RSpec/ExampleWording:
Enabled: false
CustomTransform:
@@ -795,6 +802,10 @@ RSpec/ExampleWording:
not: does not
IgnoredWords: []
+# Checks for `expect(...)` calls containing literal values.
+RSpec/ExpectActual:
+ Enabled: false
+
# Checks the file and folder naming of the spec file.
RSpec/FilePath:
Enabled: false
@@ -806,19 +817,65 @@ RSpec/FilePath:
RSpec/Focus:
Enabled: true
+# Checks the arguments passed to `before`, `around`, and `after`.
+RSpec/HookArgument:
+ Enabled: false
+ EnforcedStyle: implicit
+
+# Check that a consistent implict expectation style is used.
+# TODO (rspeicher): Available in rubocop-rspec 1.8.0
+# RSpec/ImplicitExpect:
+# Enabled: true
+# EnforcedStyle: is_expected
+
# Checks for the usage of instance variables.
RSpec/InstanceVariable:
Enabled: false
-# Checks for multiple top-level describes.
+# Checks for `subject` definitions that come after `let` definitions.
+RSpec/LeadingSubject:
+ Enabled: false
+
+# Checks unreferenced `let!` calls being used for test setup.
+RSpec/LetSetup:
+ Enabled: false
+
+# Check that chains of messages are not being stubbed.
+RSpec/MessageChain:
+ Enabled: false
+
+# Checks for consistent message expectation style.
+RSpec/MessageExpectation:
+ Enabled: false
+ EnforcedStyle: allow
+
+# Checks for multiple top level describes.
RSpec/MultipleDescribes:
Enabled: false
-# Enforces the usage of the same method on all negative message expectations.
+# Checks if examples contain too many `expect` calls.
+RSpec/MultipleExpectations:
+ Enabled: false
+ Max: 1
+
+# Checks for explicitly referenced test subjects.
+RSpec/NamedSubject:
+ Enabled: false
+
+# Checks for nested example groups.
+RSpec/NestedGroups:
+ Enabled: false
+ MaxNesting: 2
+
+# Checks for consistent method usage for negating expectations.
RSpec/NotToNot:
EnforcedStyle: not_to
Enabled: true
+# Checks for stubbed test subjects.
+RSpec/SubjectStub:
+ Enabled: false
+
# Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles:
Enabled: false
diff --git a/CHANGELOG b/CHANGELOG
index f0a637507fe..b6ff9d91fb8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -31,6 +31,7 @@ v 8.12.0 (unreleased)
- Add `web_url` field to issue, merge request, and snippet API objects (Ben Boeckel)
- Enable pipeline events by default !6278
- Move parsing of sidekiq ps into helper !6245 (pascalbetz)
+ - Added go to issue boards keyboard shortcut
- Expose `sha` and `merge_commit_sha` in merge request API (Ben Boeckel)
- Set path for all JavaScript cookies to honor GitLab's subdirectory setting !5627 (Mike Greiling)
- Fix blame table layout width
@@ -76,7 +77,8 @@ v 8.12.0 (unreleased)
- Add last commit time to repo view (ClemMakesApps)
- Fix accessibility and visibility of project list dropdown button !6140
- Fix missing flash messages on service edit page (airatshigapov)
- - Added project specific enable/disable setting for LFS !5997
+ - Added project-specific enable/disable setting for LFS !5997
+ - Added group-specific enable/disable setting for LFS !6164
- Don't expose a user's token in the `/api/v3/user` API (!6047)
- Remove redundant js-timeago-pending from user activity log (ClemMakesApps)
- Ability to manage project issues, snippets, wiki, merge requests and builds access level
diff --git a/Gemfile b/Gemfile
index 70d8495325f..1f83f8c83f2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -296,7 +296,7 @@ group :development, :test do
gem 'spring-commands-teaspoon', '~> 0.0.2'
gem 'rubocop', '~> 0.42.0', require: false
- gem 'rubocop-rspec', '~> 1.5.0', require: false
+ gem 'rubocop-rspec', '~> 1.7.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'haml_lint', '~> 0.18.2', require: false
gem 'simplecov', '0.12.0', require: false
diff --git a/Gemfile.lock b/Gemfile.lock
index e2b5a58d973..1edb218373d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -625,8 +625,8 @@ GEM
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
- rubocop-rspec (1.5.0)
- rubocop (>= 0.40.0)
+ rubocop-rspec (1.7.0)
+ rubocop (>= 0.42.0)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
ruby-prof (0.15.9)
@@ -945,7 +945,7 @@ DEPENDENCIES
rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5)
rubocop (~> 0.42.0)
- rubocop-rspec (~> 1.5.0)
+ rubocop-rspec (~> 1.7.0)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 0.15.9)
sanitize (~> 2.0)
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index bea141bae51..087f27d9f4c 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -352,7 +352,13 @@
if (self.options.clicked) {
self.options.clicked(selected, $el, e);
}
- return $el.trigger('blur');
+
+ // Update label right after all modifications in dropdown has been done
+ if (self.options.toggleLabel) {
+ self.updateLabel(selected, $el, self);
+ }
+
+ $el.trigger('blur');
});
}
}
@@ -529,7 +535,7 @@
} else {
if (!selected) {
value = this.options.id ? this.options.id(data) : data.id;
- fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName() : this.options.fieldName;
+ fieldName = this.options.fieldName;
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
if (field.length) {
@@ -589,6 +595,7 @@
GitLabDropdown.prototype.rowClicked = function(el) {
var field, fieldName, groupName, isInput, selectedIndex, selectedObject, value;
+ fieldName = this.options.fieldName;
isInput = $(this.el).is('input');
if (this.renderedData) {
groupName = el.data('group');
@@ -600,7 +607,6 @@
selectedObject = this.renderedData[selectedIndex];
}
}
- fieldName = typeof this.options.fieldName === 'function' ? this.options.fieldName(selectedObject) : this.options.fieldName;
value = this.options.id ? this.options.id(selectedObject, el) : selectedObject.id;
if (isInput) {
field = $(this.el);
@@ -644,11 +650,6 @@
}
}
- // Update label right after input has been added
- if (this.options.toggleLabel) {
- this.updateLabel(selectedObject, el, this);
- }
-
return selectedObject;
};
@@ -659,9 +660,6 @@
if (this.options.inputId != null) {
$input.attr('id', this.options.inputId);
}
- if (selectedObject && selectedObject.type) {
- $input.attr('data-type', selectedObject.type);
- }
return this.dropdown.before($input);
};
diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js
index 469e25482bb..b04159420d1 100644
--- a/app/assets/javascripts/shortcuts_navigation.js
+++ b/app/assets/javascripts/shortcuts_navigation.js
@@ -34,6 +34,9 @@
Mousetrap.bind('g i', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues');
});
+ Mousetrap.bind('g l', function() {
+ ShortcutsNavigation.findAndFollowLink('.shortcuts-issue-boards');
+ });
Mousetrap.bind('g m', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-merge_requests');
});
diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss
index 965fcc06518..46af18580d5 100644
--- a/app/assets/stylesheets/framework/lists.scss
+++ b/app/assets/stylesheets/framework/lists.scss
@@ -162,6 +162,10 @@ ul.content-list {
margin-right: 0;
}
}
+
+ .no-comments {
+ opacity: 0.5;
+ }
}
// When dragging a list item
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index 60a0d50ba73..3ac34cbc829 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -10,10 +10,6 @@
.issue-labels {
display: inline-block;
}
-
- .issue-no-comments {
- opacity: 0.5;
- }
}
}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index 2a44b95de64..96c06086867 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -231,10 +231,6 @@
.merge-request-labels {
display: inline-block;
}
-
- .merge-request-no-comments {
- opacity: 0.5;
- }
}
.merge-request-angle {
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index cc71b8eb045..1b4d12d3053 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -147,14 +147,37 @@
}
.stage-cell {
- text-align: center;
+ font-size: 0;
svg {
height: 18px;
width: 18px;
+ position: relative;
+ z-index: 2;
vertical-align: middle;
overflow: visible;
}
+
+ .stage-container {
+ display: inline-block;
+ position: relative;
+ margin-right: 6px;
+
+ .tooltip {
+ white-space: nowrap;
+ }
+
+ &:not(:last-child) {
+ &::after {
+ content: '';
+ width: 8px;
+ position: absolute;;
+ right: -7px;
+ bottom: 8px;
+ border-bottom: 2px solid $border-color;
+ }
+ }
+ }
}
.duration,
diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
index 2aa939b7dc3..5270aea4e79 100644
--- a/app/assets/stylesheets/pages/snippets.scss
+++ b/app/assets/stylesheets/pages/snippets.scss
@@ -2,20 +2,6 @@
padding: 2px;
}
-.snippet-holder {
- margin-bottom: -$gl-padding;
-
- .file-holder {
- border-top: 0;
- }
-
- .file-actions {
- .btn-clipboard {
- @extend .btn;
- }
- }
-}
-
.markdown-snippet-copy {
position: fixed;
top: -10px;
@@ -24,29 +10,18 @@
max-width: 0;
}
-.file-holder.snippet-file-content {
- padding-bottom: $gl-padding;
- border-bottom: 1px solid $border-color;
-
- .file-title {
- padding-top: $gl-padding;
- padding-bottom: $gl-padding;
- }
-
- .file-actions {
- top: 12px;
- }
-
- .file-content {
- border-left: 1px solid $border-color;
- border-right: 1px solid $border-color;
- border-bottom: 1px solid $border-color;
+.snippet-file-content {
+ border-radius: 3px;
+ .btn-clipboard {
+ @extend .btn;
}
}
.snippet-title {
font-size: 24px;
- font-weight: normal;
+ font-weight: 600;
+ padding: $gl-padding;
+ padding-left: 0;
}
.snippet-actions {
diff --git a/app/controllers/admin/groups_controller.rb b/app/controllers/admin/groups_controller.rb
index cdfa8d91a28..aed77d0358a 100644
--- a/app/controllers/admin/groups_controller.rb
+++ b/app/controllers/admin/groups_controller.rb
@@ -60,6 +60,14 @@ class Admin::GroupsController < Admin::ApplicationController
end
def group_params
- params.require(:group).permit(:name, :description, :path, :avatar, :visibility_level, :request_access_enabled)
+ params.require(:group).permit(
+ :avatar,
+ :description,
+ :lfs_enabled,
+ :name,
+ :path,
+ :request_access_enabled,
+ :visibility_level
+ )
end
end
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index cb82d62616c..b83c3a872cf 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -121,7 +121,17 @@ class GroupsController < Groups::ApplicationController
end
def group_params
- params.require(:group).permit(:name, :description, :path, :avatar, :public, :visibility_level, :share_with_group_lock, :request_access_enabled)
+ params.require(:group).permit(
+ :avatar,
+ :description,
+ :lfs_enabled,
+ :name,
+ :path,
+ :public,
+ :request_access_enabled,
+ :share_with_group_lock,
+ :visibility_level
+ )
end
def load_events
diff --git a/app/controllers/projects/builds_controller.rb b/app/controllers/projects/builds_controller.rb
index 77934ff9962..f13fb1df373 100644
--- a/app/controllers/projects/builds_controller.rb
+++ b/app/controllers/projects/builds_controller.rb
@@ -74,7 +74,7 @@ class Projects::BuildsController < Projects::ApplicationController
def erase
@build.erase(erased_by: current_user)
redirect_to namespace_project_build_path(project.namespace, project, @build),
- notice: "Build has been sucessfully erased!"
+ notice: "Build has been successfully erased!"
end
def raw
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index b9211e88473..ab880ed6de0 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -23,4 +23,29 @@ module GroupsHelper
full_title
end
end
+
+ def projects_lfs_status(group)
+ lfs_status =
+ if group.lfs_enabled?
+ group.projects.select(&:lfs_enabled?).size
+ else
+ group.projects.reject(&:lfs_enabled?).size
+ end
+
+ size = group.projects.size
+
+ if lfs_status == size
+ 'for all projects'
+ else
+ "for #{lfs_status} out of #{pluralize(size, 'project')}"
+ end
+ end
+
+ def group_lfs_status(group)
+ status = group.lfs_enabled? ? 'enabled' : 'disabled'
+
+ content_tag(:span, class: "lfs-#{status}") do
+ "#{status.humanize} #{projects_lfs_status(group)}"
+ end
+ end
end
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 16a8e52a4ca..56477733ea2 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -27,7 +27,7 @@ module ProjectsHelper
author_html = ""
# Build avatar image tag
- author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar]
+ author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]} #{opts[:avatar_class] if opts[:avatar_class]}", alt: '') if opts[:avatar]
# Build name span tag
if opts[:by_username]
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index 0a5a8eb5aee..7e33a562077 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -1,10 +1,10 @@
module SnippetsHelper
- def reliable_snippet_path(snippet)
+ def reliable_snippet_path(snippet, opts = nil)
if snippet.project_id?
namespace_project_snippet_path(snippet.project.namespace,
- snippet.project, snippet)
+ snippet.project, snippet, opts)
else
- snippet_path(snippet)
+ snippet_path(snippet, opts)
end
end
diff --git a/app/models/ci/variable.rb b/app/models/ci/variable.rb
index c9c47ec7419..6959223aed9 100644
--- a/app/models/ci/variable.rb
+++ b/app/models/ci/variable.rb
@@ -1,7 +1,7 @@
module Ci
class Variable < ActiveRecord::Base
extend Ci::Model
-
+
belongs_to :project, class_name: '::Project', foreign_key: :gl_project_id
validates_uniqueness_of :key, scope: :gl_project_id
@@ -11,7 +11,9 @@ module Ci
format: { with: /\A[a-zA-Z0-9_]+\z/,
message: "can contain only letters, digits and '_'." }
- attr_encrypted :value,
+ scope :order_key_asc, -> { reorder(key: :asc) }
+
+ attr_encrypted :value,
mode: :per_attribute_iv_and_salt,
insecure_mode: true,
key: Gitlab::Application.secrets.db_key_base,
diff --git a/app/models/group.rb b/app/models/group.rb
index c48869ae465..aefb94b2ada 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -95,6 +95,13 @@ class Group < Namespace
end
end
+ def lfs_enabled?
+ return false unless Gitlab.config.lfs.enabled
+ return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?
+
+ self[:lfs_enabled]
+ end
+
def add_users(user_ids, access_level, current_user: nil, expires_at: nil)
user_ids.each do |user_id|
Member.add_user(
diff --git a/app/models/namespace.rb b/app/models/namespace.rb
index 7c29d27ce97..919b3b1f095 100644
--- a/app/models/namespace.rb
+++ b/app/models/namespace.rb
@@ -141,6 +141,11 @@ class Namespace < ActiveRecord::Base
projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id)
end
+ def lfs_enabled?
+ # User namespace will always default to the global setting
+ Gitlab.config.lfs.enabled
+ end
+
private
def repository_storage_paths
diff --git a/app/models/project.rb b/app/models/project.rb
index f3f3ffbbd28..8b5a6f167bd 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -393,10 +393,9 @@ class Project < ActiveRecord::Base
end
def lfs_enabled?
- return false unless Gitlab.config.lfs.enabled
- return Gitlab.config.lfs.enabled if self[:lfs_enabled].nil?
+ return namespace.lfs_enabled? if self[:lfs_enabled].nil?
- self[:lfs_enabled]
+ self[:lfs_enabled] && Gitlab.config.lfs.enabled
end
def repository_storage_path
diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml
index 5f7fdfdb011..817910f7ddf 100644
--- a/app/views/admin/groups/_form.html.haml
+++ b/app/views/admin/groups/_form.html.haml
@@ -13,6 +13,8 @@
.col-sm-offset-2.col-sm-10
= render 'shared/allow_request_access', form: f
+ = render 'groups/group_lfs_settings', f: f
+
- if @group.new_record?
.form-group
.col-sm-offset-2.col-sm-10
diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml
index bb374694400..0188ed448ce 100644
--- a/app/views/admin/groups/show.html.haml
+++ b/app/views/admin/groups/show.html.haml
@@ -37,6 +37,12 @@
%strong
= @group.created_at.to_s(:medium)
+ %li
+ %span.light Group Git LFS status:
+ %strong
+ = group_lfs_status(@group)
+ = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
+
.panel.panel-default
.panel-heading
%h3.panel-title
diff --git a/app/views/groups/_group_lfs_settings.html.haml b/app/views/groups/_group_lfs_settings.html.haml
new file mode 100644
index 00000000000..af57065f0fc
--- /dev/null
+++ b/app/views/groups/_group_lfs_settings.html.haml
@@ -0,0 +1,11 @@
+- if current_user.admin?
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :lfs_enabled do
+ = f.check_box :lfs_enabled, checked: @group.lfs_enabled?
+ %strong
+ Allow projects within this group to use Git LFS
+ = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
+ %br/
+ %span.descr This setting can be overridden in each project. \ No newline at end of file
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index decb89b2fd6..c766370d5a0 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -25,6 +25,8 @@
.col-sm-offset-2.col-sm-10
= render 'shared/allow_request_access', form: f
+ = render 'group_lfs_settings', f: f
+
.form-group
%hr
= f.label :share_with_group_lock, class: 'control-label' do
diff --git a/app/views/help/_shortcuts.html.haml b/app/views/help/_shortcuts.html.haml
index 16c16cec137..65842a0479b 100644
--- a/app/views/help/_shortcuts.html.haml
+++ b/app/views/help/_shortcuts.html.haml
@@ -165,6 +165,12 @@
%tr
%td.shortcut
.key g
+ .key l
+ %td
+ Go to issue boards
+ %tr
+ %td.shortcut
+ .key g
.key m
%td
Go to merge requests
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index f7012595a5a..8e4937b7aa0 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -113,3 +113,7 @@
%li.hidden
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
Commits
+
+ -# Shortcut to issue boards
+ %li.hidden
+ = link_to 'Issue Boards', namespace_project_board_path(@project.namespace, @project), title: 'Issue Boards', class: 'shortcuts-issue-boards'
diff --git a/app/views/profiles/update_username.js.haml b/app/views/profiles/update_username.js.haml
index 249680bcab6..de1337a2a24 100644
--- a/app/views/profiles/update_username.js.haml
+++ b/app/views/profiles/update_username.js.haml
@@ -1,6 +1,6 @@
- if @user.valid?
:plain
- new Flash("Username sucessfully changed", "notice")
+ new Flash("Username successfully changed", "notice")
- else
:plain
new Flash("Username change failed - #{@user.errors.full_messages.first}", "alert")
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index bb9493f5158..6391c67021b 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -36,16 +36,14 @@
- stages_status = pipeline.statuses.relevant.latest.stages_status
- - stages.each do |stage|
- %td.stage-cell
+ %td.stage-cell
+ - stages.each do |stage|
- status = stages_status[stage]
- tooltip = "#{stage.titleize}: #{status || 'not found'}"
- if status
- = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
- = ci_icon_for_status(status)
- - else
- .light.has-tooltip{ title: tooltip }
- \-
+ .stage-container
+ = link_to namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
+ = ci_icon_for_status(status)
%td
- if pipeline.duration
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index f6d751a343e..a04d53e02bf 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -84,15 +84,14 @@
= project_feature_access_select(:snippets_access_level)
- if Gitlab.config.lfs.enabled && current_user.admin?
- .form-group
- .checkbox
- = f.label :lfs_enabled do
- = f.check_box :lfs_enabled, checked: @project.lfs_enabled?
- %strong LFS
- %br
- %span.descr
- Git Large File Storage
- = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
+ .row
+ .col-md-9
+ = f.label :lfs_enabled, 'LFS', class: 'label-light'
+ %span.help-block
+ Git Large File Storage
+ = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
+ .col-md-3
+ = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control'
- if Gitlab.config.registry.enabled
.form-group
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 851d4c06990..8b1a8a8a2d9 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -29,7 +29,7 @@
- note_count = issue.notes.user.count
%li
- = link_to issue_path(issue, anchor: 'notes'), class: ('issue-no-comments' if note_count.zero?) do
+ = link_to issue_path(issue, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do
= icon('comments')
= note_count
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 31f8d0aeb5b..68fb7d5a414 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -41,7 +41,7 @@
- note_count = merge_request.mr_and_commit_notes.user.count
%li
- = link_to merge_request_path(merge_request, anchor: 'notes'), class: ('merge-request-no-comments' if note_count.zero?) do
+ = link_to merge_request_path(merge_request, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do
= icon('comments')
= note_count
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index 4d957e0d890..faf28db68d1 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -47,13 +47,7 @@
%tbody
%th Status
%th Commit
- - stages.each do |stage|
- %th.stage
- - if stage.titleize.length > 12
- %span.has-tooltip{ title: "#{stage.titleize}" }
- = stage.titleize
- - else
- = stage.titleize
+ %th Stages
%th
%th
= render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml
index bdbf3e5f4d6..a5a5619fa12 100644
--- a/app/views/projects/snippets/_actions.html.haml
+++ b/app/views/projects/snippets/_actions.html.haml
@@ -3,11 +3,11 @@
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
- = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
- Edit
- - if can?(current_user, :update_project_snippet, @snippet)
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
Delete
+ - if can?(current_user, :update_project_snippet, @snippet)
+ = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
+ Edit
- if can?(current_user, :create_project_snippet, @project) || can?(current_user, :update_project_snippet, @snippet)
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
@@ -21,9 +21,9 @@
New Snippet
- if can?(current_user, :update_project_snippet, @snippet)
%li
- = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
- Edit
- - if can?(current_user, :update_project_snippet, @snippet)
- %li
= link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
+ - if can?(current_user, :update_project_snippet, @snippet)
+ %li
+ = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
+ Edit
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index bae4d8f349f..b70fda88a79 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -1,15 +1,14 @@
- page_title @snippet.title, "Snippets"
-.snippet-holder
- = render 'shared/snippets/header'
+= render 'shared/snippets/header'
- %article.file-holder.file-holder-no-border.snippet-file-content
- .file-title.file-title-clear
- = blob_icon 0, @snippet.file_name
- = @snippet.file_name
- .file-actions.hidden-xs
- = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
- = link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
- = render 'shared/snippets/blob'
+%article.file-holder.snippet-file-content
+ .file-title
+ = blob_icon 0, @snippet.file_name
+ = @snippet.file_name
+ .file-actions
+ = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
+ = link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
+ = render 'shared/snippets/blob'
- %div#notes= render "projects/notes/notes_with_form"
+%div#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/variables/_table.html.haml b/app/views/projects/variables/_table.html.haml
index 6c43f822db4..07cee86ba4c 100644
--- a/app/views/projects/variables/_table.html.haml
+++ b/app/views/projects/variables/_table.html.haml
@@ -9,7 +9,7 @@
%th Value
%th
%tbody
- - @project.variables.each do |variable|
+ - @project.variables.order_key_asc.each do |variable|
- if variable.id?
%tr
%td= variable.key
diff --git a/app/views/shared/_visibility_level.html.haml b/app/views/shared/_visibility_level.html.haml
index 107ad19177c..add4536a0a2 100644
--- a/app/views/shared/_visibility_level.html.haml
+++ b/app/views/shared/_visibility_level.html.haml
@@ -1,7 +1,7 @@
.form-group.project-visibility-level-holder
= f.label :visibility_level, class: 'control-label' do
Visibility Level
- = link_to "(?)", help_page_path("public_access/public_access")
+ = link_to icon('question-circle'), help_page_path("public_access/public_access")
.col-sm-10
- if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index af753496260..7ae4211ddfd 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -6,12 +6,13 @@
%strong.item-title
Snippet #{@snippet.to_reference}
%span.creator
- created by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title")}
+ authored
= time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
- if @snippet.updated_at != @snippet.created_at
%span
= icon('edit', title: 'edited')
= time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
+ by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title", avatar_class: "hidden-xs")}
.snippet-actions
- if @snippet.project_id?
@@ -19,6 +20,5 @@
- else
= render "snippets/actions"
-.content-block.second-block
- %h2.snippet-title.prepend-top-0.append-bottom-0
- = markdown escape_once(@snippet.title), pipeline: :single_line, author: @snippet.author
+%h2.snippet-title.prepend-top-0.append-bottom-0
+ = markdown escape_once(@snippet.title), pipeline: :single_line, author: @snippet.author
diff --git a/app/views/shared/snippets/_snippet.html.haml b/app/views/shared/snippets/_snippet.html.haml
index c96dfefe17f..ea17bec8677 100644
--- a/app/views/shared/snippets/_snippet.html.haml
+++ b/app/views/shared/snippets/_snippet.html.haml
@@ -3,19 +3,30 @@
.title
= link_to reliable_snippet_path(snippet) do
- = truncate(snippet.title, length: 60)
+ = snippet.title
- if snippet.private?
- %span.label.label-gray
+ %span.label.label-gray.hidden-xs
= icon('lock')
private
- %span.monospace.pull-right
+ %span.monospace.pull-right.hidden-xs
= snippet.file_name
- %small.pull-right.cgray
+ %ul.controls.visible-xs
+ %li
+ - note_count = snippet.notes.user.count
+ = link_to reliable_snippet_path(snippet, anchor: 'notes'), class: ('no-comments' if note_count.zero?) do
+ = icon('comments')
+ = note_count
+ %li
+ %span.sr-only
+ = visibility_level_label(snippet.visibility_level)
+ = visibility_level_icon(snippet.visibility_level, fw: false)
+
+ %small.pull-right.cgray.hidden-xs
- if snippet.project_id?
= link_to snippet.project.name_with_namespace, namespace_project_path(snippet.project.namespace, snippet.project)
- .snippet-info
+ .snippet-info.hidden-xs
= link_to user_snippets_path(snippet.author) do
= snippet.author_name
authored #{time_ago_with_tooltip(snippet.created_at)}
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
index 160c6cd84da..fdaca199218 100644
--- a/app/views/snippets/_actions.html.haml
+++ b/app/views/snippets/_actions.html.haml
@@ -2,12 +2,12 @@
- if current_user
= link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do
New Snippet
- - if can?(current_user, :update_personal_snippet, @snippet)
- = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
- Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-danger", title: 'Delete Snippet' do
Delete
+ - if can?(current_user, :update_personal_snippet, @snippet)
+ = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
+ Edit
- if current_user
.visible-xs-block.dropdown
%button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
@@ -18,11 +18,11 @@
%li
= link_to new_snippet_path, title: "New Snippet" do
New Snippet
- - if can?(current_user, :update_personal_snippet, @snippet)
- %li
- = link_to edit_snippet_path(@snippet) do
- Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
%li
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
Delete
+ - if can?(current_user, :update_personal_snippet, @snippet)
+ %li
+ = link_to edit_snippet_path(@snippet) do
+ Edit
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index ed3992650d4..fa403da8f79 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -1,13 +1,12 @@
- page_title @snippet.title, "Snippets"
-.snippet-holder
- = render 'shared/snippets/header'
+= render 'shared/snippets/header'
- %article.file-holder.file-holder-no-border.snippet-file-content
- .file-title.file-title-clear
- = blob_icon 0, @snippet.file_name
- = @snippet.file_name
- .file-actions.hidden-xs
- = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
- = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
- = render 'shared/snippets/blob'
+%article.file-holder.snippet-file-content
+ .file-title
+ = blob_icon 0, @snippet.file_name
+ = @snippet.file_name
+ .file-actions
+ = clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
+ = link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
+ = render 'shared/snippets/blob'
diff --git a/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb b/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb
new file mode 100644
index 00000000000..fd413d1ca8c
--- /dev/null
+++ b/db/migrate/20160901213340_add_lfs_enabled_to_namespaces.rb
@@ -0,0 +1,12 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class AddLfsEnabledToNamespaces < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ def change
+ add_column :namespaces, :lfs_enabled, :boolean
+ end
+end
diff --git a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
index c5b8c35e961..18ea9d43a43 100644
--- a/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
+++ b/db/migrate/20160913162434_remove_projects_pushes_since_gc.rb
@@ -14,6 +14,6 @@ class RemoveProjectsPushesSinceGc < ActiveRecord::Migration
end
def down
- add_column_with_default! :projects, :pushes_since_gc, :integer, default: 0
+ add_column_with_default :projects, :pushes_since_gc, :integer, default: 0
end
end
diff --git a/db/schema.rb b/db/schema.rb
index 61873e38113..70279f372c9 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -650,6 +650,7 @@ ActiveRecord::Schema.define(version: 20160913162434) do
t.integer "visibility_level", default: 20, null: false
t.boolean "request_access_enabled", default: true, null: false
t.datetime "deleted_at"
+ t.boolean "lfs_enabled"
end
add_index "namespaces", ["created_at"], name: "index_namespaces_on_created_at", using: :btree
diff --git a/doc/api/groups.md b/doc/api/groups.md
index a898387eaa2..3e94e1e4efe 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -288,6 +288,7 @@ Parameters:
- `path` (required) - The path of the group
- `description` (optional) - The group's description
- `visibility_level` (optional) - The group's visibility. 0 for private, 10 for internal, 20 for public.
+- `lfs_enabled` (optional) - Enable/disable Large File Storage (LFS) for the projects in this group
## Transfer project to group
@@ -317,6 +318,7 @@ PUT /groups/:id
| `path` | string | no | The path of the group |
| `description` | string | no | The description of the group |
| `visibility_level` | integer | no | The visibility level of the group. 0 for private, 10 for internal, 20 for public. |
+| `lfs_enabled` (optional) | boolean | no | Enable/disable Large File Storage (LFS) for the projects in this group |
```bash
curl --request PUT --header "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/groups/5?name=Experimental"
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 4f736e4ec2b..bfee4b6c752 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -86,7 +86,8 @@ module API
expose(:snippets_enabled) { |project, options| project.feature_available?(:snippets, options[:user]) }
expose :created_at, :last_activity_at
- expose :shared_runners_enabled, :lfs_enabled
+ expose :shared_runners_enabled
+ expose :lfs_enabled?, as: :lfs_enabled
expose :creator_id
expose :namespace
expose :forked_from_project, using: Entities::BasicProjectDetails, if: lambda{ |project, options| project.forked? }
@@ -121,6 +122,7 @@ module API
class Group < Grape::Entity
expose :id, :name, :path, :description, :visibility_level
+ expose :lfs_enabled?, as: :lfs_enabled
expose :avatar_url
expose :web_url
end
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index d2df77238d5..60ac9bdfa33 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -27,13 +27,14 @@ module API
# path (required) - The path of the group
# description (optional) - The description of the group
# visibility_level (optional) - The visibility level of the group
+ # lfs_enabled (optional) - Enable/disable LFS for the projects in this group
# Example Request:
# POST /groups
post do
authorize! :create_group
required_attributes! [:name, :path]
- attrs = attributes_for_keys [:name, :path, :description, :visibility_level]
+ attrs = attributes_for_keys [:name, :path, :description, :visibility_level, :lfs_enabled]
@group = Group.new(attrs)
if @group.save
@@ -51,13 +52,14 @@ module API
# path (optional) - The path of the group
# description (optional) - The description of the group
# visibility_level (optional) - The visibility level of the group
+ # lfs_enabled (optional) - Enable/disable LFS for the projects in this group
# Example Request:
# PUT /groups/:id
put ':id' do
group = find_group(params[:id])
authorize! :admin_group, group
- attrs = attributes_for_keys [:name, :path, :description, :visibility_level]
+ attrs = attributes_for_keys [:name, :path, :description, :visibility_level, :lfs_enabled]
if ::Groups::UpdateService.new(group, current_user, attrs).execute
present group, with: Entities::GroupDetail
diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb
index c6c2e2095df..e51586d32ec 100644
--- a/spec/features/boards/boards_spec.rb
+++ b/spec/features/boards/boards_spec.rb
@@ -2,6 +2,7 @@ require 'rails_helper'
describe 'Issue Boards', feature: true, js: true do
include WaitForAjax
+ include WaitForVueResource
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
@@ -187,13 +188,13 @@ describe 'Issue Boards', feature: true, js: true do
expect(page).to have_content('Showing 20 of 56 issues')
evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight")
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
expect(page).to have_selector('.card', count: 40)
expect(page).to have_content('Showing 40 of 56 issues')
evaluate_script("document.querySelectorAll('.board .board-list')[0].scrollTop = document.querySelectorAll('.board .board-list')[0].scrollHeight")
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
expect(page).to have_selector('.card', count: 56)
expect(page).to have_content('Showing all issues')
@@ -372,7 +373,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within '.dropdown-menu-author' do
click_link(user2.name)
end
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
expect(find('.js-author-search')).to have_content(user2.name)
end
@@ -398,7 +399,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within '.dropdown-menu-assignee' do
click_link(user.name)
end
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
expect(find('.js-assignee-search')).to have_content(user.name)
end
@@ -424,7 +425,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within '.milestone-filter' do
click_link(milestone.title)
end
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
expect(find('.js-milestone-select')).to have_content(milestone.title)
end
@@ -449,7 +450,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within '.dropdown-menu-labels' do
click_link(testing.title)
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
@@ -478,7 +479,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within '.dropdown-menu-labels' do
click_link(testing.title)
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
@@ -509,9 +510,9 @@ describe 'Issue Boards', feature: true, js: true do
page.within(find('.dropdown-menu-labels')) do
click_link(testing.title)
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
click_link(bug.title)
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
@@ -536,7 +537,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within '.dropdown-menu-labels' do
click_link("No Label")
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
find('.dropdown-menu-close').click
end
end
@@ -559,7 +560,7 @@ describe 'Issue Boards', feature: true, js: true do
expect(page).to have_selector('.card', count: 6)
expect(find('.card', match: :first)).to have_content(bug.title)
click_button(bug.title)
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
end
wait_for_vue_resource
@@ -584,7 +585,7 @@ describe 'Issue Boards', feature: true, js: true do
page.within(find('.card', match: :first)) do
click_button(bug.title)
end
- wait_for_vue_resource(spinner: false)
+ wait_for_vue_resource
expect(page).to have_selector('.card', count: 1)
end
@@ -647,14 +648,4 @@ describe 'Issue Boards', feature: true, js: true do
wait_for_vue_resource
end
-
- def wait_for_vue_resource(spinner: true)
- Timeout.timeout(Capybara.default_max_wait_time) do
- loop until page.evaluate_script('Vue.activeResources').zero?
- end
-
- if spinner
- expect(find('.boards-list')).not_to have_selector('.fa-spinner')
- end
- end
end
diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb
new file mode 100644
index 00000000000..7ef68e9eb8d
--- /dev/null
+++ b/spec/features/boards/keyboard_shortcut_spec.rb
@@ -0,0 +1,24 @@
+require 'rails_helper'
+
+describe 'Issue Boards shortcut', feature: true, js: true do
+ include WaitForVueResource
+
+ let(:project) { create(:empty_project) }
+
+ before do
+ project.create_board
+ project.board.lists.create(list_type: :backlog)
+ project.board.lists.create(list_type: :done)
+
+ login_as :admin
+
+ visit namespace_project_path(project.namespace, project)
+ end
+
+ it 'takes user to issue board index' do
+ find('body').native.send_keys('gl')
+ expect(page).to have_selector('.boards-list')
+
+ wait_for_vue_resource
+ end
+end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index d744d0eb6af..22359c8f938 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -144,7 +144,7 @@ describe 'Issues', feature: true do
visit namespace_project_issues_path(project.namespace, project, assignee_id: @user.id)
expect(page).to have_content 'foobar'
- expect(page.all('.issue-no-comments').first.text).to eq "0"
+ expect(page.all('.no-comments').first.text).to eq "0"
end
end
diff --git a/spec/features/users/snippets_spec.rb b/spec/features/users/snippets_spec.rb
index 356a8d668b0..f00abd82fea 100644
--- a/spec/features/users/snippets_spec.rb
+++ b/spec/features/users/snippets_spec.rb
@@ -19,7 +19,10 @@ describe 'Snippets tab on a user profile', feature: true, js: true do
end
context 'clicking on the link to the second page' do
- before { click_link('2') }
+ before do
+ click_link('2')
+ wait_for_ajax
+ end
it 'shows the remaining snippets' do
expect(page.all('.snippets-list-holder .snippet-row').count).to eq(5)
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 0807534720a..233d00534e5 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -18,4 +18,67 @@ describe GroupsHelper do
expect(group_icon(group.path)).to match('group_avatar.png')
end
end
+
+ describe 'group_lfs_status' do
+ let(:group) { create(:group) }
+ let!(:project) { create(:empty_project, namespace_id: group.id) }
+
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ end
+
+ context 'only one project in group' do
+ before do
+ group.update_attribute(:lfs_enabled, true)
+ end
+
+ it 'returns all projects as enabled' do
+ expect(group_lfs_status(group)).to include('Enabled for all projects')
+ end
+
+ it 'returns all projects as disabled' do
+ project.update_attribute(:lfs_enabled, false)
+
+ expect(group_lfs_status(group)).to include('Enabled for 0 out of 1 project')
+ end
+ end
+
+ context 'more than one project in group' do
+ before do
+ create(:empty_project, namespace_id: group.id)
+ end
+
+ context 'LFS enabled in group' do
+ before do
+ group.update_attribute(:lfs_enabled, true)
+ end
+
+ it 'returns both projects as enabled' do
+ expect(group_lfs_status(group)).to include('Enabled for all projects')
+ end
+
+ it 'returns only one as enabled' do
+ project.update_attribute(:lfs_enabled, false)
+
+ expect(group_lfs_status(group)).to include('Enabled for 1 out of 2 projects')
+ end
+ end
+
+ context 'LFS disabled in group' do
+ before do
+ group.update_attribute(:lfs_enabled, false)
+ end
+
+ it 'returns both projects as disabled' do
+ expect(group_lfs_status(group)).to include('Disabled for all projects')
+ end
+
+ it 'returns only one as disabled' do
+ project.update_attribute(:lfs_enabled, true)
+
+ expect(group_lfs_status(group)).to include('Disabled for 1 out of 2 projects')
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index ea4b59c26b1..0b3ef9b98fd 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -187,6 +187,52 @@ describe Group, models: true do
it { expect(group.has_master?(@members[:requester])).to be_falsey }
end
+ describe '#lfs_enabled?' do
+ context 'LFS enabled globally' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ end
+
+ it 'returns true when nothing is set' do
+ expect(group.lfs_enabled?).to be_truthy
+ end
+
+ it 'returns false when set to false' do
+ group.update_attribute(:lfs_enabled, false)
+
+ expect(group.lfs_enabled?).to be_falsey
+ end
+
+ it 'returns true when set to true' do
+ group.update_attribute(:lfs_enabled, true)
+
+ expect(group.lfs_enabled?).to be_truthy
+ end
+ end
+
+ context 'LFS disabled globally' do
+ before do
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
+ end
+
+ it 'returns false when nothing is set' do
+ expect(group.lfs_enabled?).to be_falsey
+ end
+
+ it 'returns false when set to false' do
+ group.update_attribute(:lfs_enabled, false)
+
+ expect(group.lfs_enabled?).to be_falsey
+ end
+
+ it 'returns false when set to true' do
+ group.update_attribute(:lfs_enabled, true)
+
+ expect(group.lfs_enabled?).to be_falsey
+ end
+ end
+ end
+
describe '#owners' do
let(:owner) { create(:user) }
let(:developer) { create(:user) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f6e811828fc..7ca1bd1e5c9 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1417,6 +1417,68 @@ describe Project, models: true do
end
end
+ describe '#lfs_enabled?' do
+ let(:project) { create(:project) }
+
+ shared_examples 'project overrides group' do
+ it 'returns true when enabled in project' do
+ project.update_attribute(:lfs_enabled, true)
+
+ expect(project.lfs_enabled?).to be_truthy
+ end
+
+ it 'returns false when disabled in project' do
+ project.update_attribute(:lfs_enabled, false)
+
+ expect(project.lfs_enabled?).to be_falsey
+ end
+
+ it 'returns the value from the namespace, when no value is set in project' do
+ expect(project.lfs_enabled?).to eq(project.namespace.lfs_enabled?)
+ end
+ end
+
+ context 'LFS disabled in group' do
+ before do
+ project.namespace.update_attribute(:lfs_enabled, false)
+ enable_lfs
+ end
+
+ it_behaves_like 'project overrides group'
+ end
+
+ context 'LFS enabled in group' do
+ before do
+ project.namespace.update_attribute(:lfs_enabled, true)
+ enable_lfs
+ end
+
+ it_behaves_like 'project overrides group'
+ end
+
+ describe 'LFS disabled globally' do
+ shared_examples 'it always returns false' do
+ it do
+ expect(project.lfs_enabled?).to be_falsey
+ expect(project.namespace.lfs_enabled?).to be_falsey
+ end
+ end
+
+ context 'when no values are set' do
+ it_behaves_like 'it always returns false'
+ end
+
+ context 'when all values are set to true' do
+ before do
+ project.namespace.update_attribute(:lfs_enabled, true)
+ project.update_attribute(:lfs_enabled, true)
+ end
+
+ it_behaves_like 'it always returns false'
+ end
+ end
+ end
+
describe '.where_paths_in' do
context 'without any paths' do
it 'returns an empty relation' do
@@ -1581,4 +1643,8 @@ describe Project, models: true do
expect(project.pushes_since_gc).to eq(0)
end
end
+
+ def enable_lfs
+ allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
+ end
end
diff --git a/spec/support/wait_for_vue_resource.rb b/spec/support/wait_for_vue_resource.rb
new file mode 100644
index 00000000000..1029f84716f
--- /dev/null
+++ b/spec/support/wait_for_vue_resource.rb
@@ -0,0 +1,7 @@
+module WaitForVueResource
+ def wait_for_vue_resource(spinner: true)
+ Timeout.timeout(Capybara.default_max_wait_time) do
+ loop until page.evaluate_script('Vue.activeResources').zero?
+ end
+ end
+end