summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-05-23 21:23:32 -0500
committerKamil Trzcinski <ayufan@ayufan.eu>2016-05-23 21:23:32 -0500
commit2f252d8f0ee0303db25a0a329f2325bec2ea3979 (patch)
tree2e2c7d70748bc17475f585c0f1406d623430891e
parent8d0332368fba65f167f2109daf8a2184d781082b (diff)
parent16ca3ee636a50c81674309bb95e067d3faf56bb6 (diff)
downloadgitlab-ce-2f252d8f0ee0303db25a0a329f2325bec2ea3979.tar.gz
Merge branch 'master' into improve-pipeline-design
-rw-r--r--.rubocop.yml160
-rw-r--r--CHANGELOG16
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock29
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee2
-rw-r--r--app/assets/javascripts/due_date_select.js.coffee35
-rw-r--r--app/assets/javascripts/gl_dropdown.js.coffee2
-rw-r--r--app/assets/javascripts/issuable_form.js.coffee9
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee4
-rw-r--r--app/assets/javascripts/shortcuts_dashboard_navigation.js.coffee8
-rw-r--r--app/assets/stylesheets/framework/avatar.scss1
-rw-r--r--app/assets/stylesheets/framework/blocks.scss11
-rw-r--r--app/assets/stylesheets/framework/forms.scss8
-rw-r--r--app/assets/stylesheets/framework/mobile.scss4
-rw-r--r--app/assets/stylesheets/framework/nav.scss15
-rw-r--r--app/assets/stylesheets/framework/variables.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss4
-rw-r--r--app/assets/stylesheets/pages/projects.scss166
-rw-r--r--app/controllers/jwt_controller.rb2
-rw-r--r--app/helpers/application_helper.rb3
-rw-r--r--app/helpers/gitlab_markdown_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb4
-rw-r--r--app/helpers/tab_helper.rb6
-rw-r--r--app/models/ability.rb1
-rw-r--r--app/models/application_setting.rb2
-rw-r--r--app/models/network/graph.rb2
-rw-r--r--app/services/auth/container_registry_authentication_service.rb4
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml10
-rw-r--r--app/views/layouts/nav/_project.html.haml70
-rw-r--r--app/views/layouts/nav/_project_settings.html.haml102
-rw-r--r--app/views/layouts/project.html.haml2
-rw-r--r--app/views/layouts/project_settings.html.haml3
-rw-r--r--app/views/projects/_home_panel.html.haml86
-rw-r--r--app/views/projects/buttons/_dropdown.html.haml2
-rw-r--r--app/views/projects/buttons/_fork.html.haml5
-rw-r--r--app/views/projects/buttons/_notifications.html.haml6
-rw-r--r--app/views/projects/ci/builds/_build.html.haml24
-rw-r--r--app/views/projects/commit/_ci_commit.html.haml11
-rw-r--r--app/views/projects/container_registry/index.html.haml2
-rw-r--r--app/views/projects/show.html.haml78
-rw-r--r--app/views/shared/_clone_panel.html.haml2
-rw-r--r--app/views/shared/groups/_list.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml82
-rw-r--r--app/views/shared/issuable/_sidebar.html.haml14
-rw-r--r--app/views/shared/milestones/_participants_tab.html.haml2
-rw-r--r--config/gitlab.yml.example8
-rw-r--r--doc/README.md3
-rw-r--r--doc/administration/container_registry.md375
-rw-r--r--doc/api/groups.md2
-rw-r--r--doc/container_registry/README.md113
-rw-r--r--doc/container_registry/img/container_registry.pngbin0 -> 354050 bytes
-rw-r--r--doc/container_registry/img/project_feature.pngbin0 -> 392842 bytes
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/monitoring/health_check.md66
-rw-r--r--doc/monitoring/img/health_check_token.pngbin0 -> 10884 bytes
-rw-r--r--features/project/active_tab.feature18
-rw-r--r--features/project/project.feature9
-rw-r--r--features/steps/admin/active_tab.rb10
-rw-r--r--features/steps/dashboard/active_tab.rb6
-rw-r--r--features/steps/dashboard/shortcuts.rb3
-rw-r--r--features/steps/profile/active_tab.rb4
-rw-r--r--features/steps/project/active_tab.rb28
-rw-r--r--features/steps/project/fork.rb2
-rw-r--r--features/steps/project/project.rb12
-rw-r--r--features/steps/project/project_milestone.rb2
-rw-r--r--features/steps/project/project_shortcuts.rb1
-rw-r--r--features/steps/project/source/browse_files.rb16
-rw-r--r--features/steps/shared/active_tab.rb28
-rw-r--r--features/steps/shared/issuable.rb8
-rw-r--r--features/steps/shared/project_tab.rb4
-rw-r--r--features/steps/shared/shortcuts.rb2
-rw-r--r--features/steps/shared/sidebar_active_tab.rb35
-rw-r--r--lib/api/helpers.rb2
-rw-r--r--lib/ci/ansi2html.rb2
-rw-r--r--lib/ci/charts.rb3
-rw-r--r--lib/gitlab/bitbucket_import/client.rb2
-rw-r--r--lib/gitlab/database/migration_helpers.rb10
-rw-r--r--lib/support/nginx/registry-ssl53
-rw-r--r--lib/tasks/rubocop.rake1
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb2
-rw-r--r--spec/factories_spec.rb2
-rw-r--r--spec/features/issues_spec.rb97
-rw-r--r--spec/features/pipelines_spec.rb6
-rw-r--r--spec/features/projects/badges/list_spec.rb5
-rw-r--r--spec/features/projects/files/project_owner_creates_license_file_spec.rb8
-rw-r--r--spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb4
-rw-r--r--spec/features/tags/master_updates_tag_spec.rb2
-rw-r--r--spec/lib/ci/charts_spec.rb7
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb18
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb2
-rw-r--r--spec/requests/api/licenses_spec.rb12
-rw-r--r--spec/requests/jwt_controller_spec.rb2
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb17
-rw-r--r--spec/services/issues/create_service_spec.rb2
-rw-r--r--vendor/gitignore/README.md14
97 files changed, 1502 insertions, 546 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 0946ef5d848..4e6ced4e1ab 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -1,3 +1,5 @@
+require: rubocop-rspec
+
AllCops:
TargetRubyVersion: 2.1
# Cop names are not displayed in offense messages by default. Change behavior
@@ -152,7 +154,7 @@ Style/ConstantName:
# Use def with parentheses when there are arguments.
Style/DefWithParentheses:
- Enabled: false
+ Enabled: true
# Checks for use of deprecated Hash methods.
Style/DeprecatedHashMethods:
@@ -299,7 +301,7 @@ Style/IndentHash:
# Use Kernel#loop for infinite loops.
Style/InfiniteLoop:
- Enabled: false
+ Enabled: true
# Use the new lambda literal syntax for single-line blocks.
Style/Lambda:
@@ -333,6 +335,12 @@ Style/MethodName:
Style/ModuleFunction:
Enabled: false
+# Checks that the closing brace in an array literal is either on the same line
+# as the last array element, or a new line.
+Style/MultilineArrayBraceLayout:
+ Enabled: false
+ EnforcedStyle: symmetrical
+
# Avoid multi-line chains of blocks.
Style/MultilineBlockChain:
Enabled: false
@@ -341,10 +349,22 @@ Style/MultilineBlockChain:
Style/MultilineBlockLayout:
Enabled: true
+# Checks that the closing brace in a hash literal is either on the same line as
+# the last hash element, or a new line.
+Style/MultilineHashBraceLayout:
+ Enabled: false
+ EnforcedStyle: symmetrical
+
# Do not use then for multi-line if/unless.
Style/MultilineIfThen:
Enabled: false
+# Checks that the closing brace in a method call is either on the same line as
+# the last method argument, or a new line.
+Style/MultilineMethodCallBraceLayout:
+ Enabled: false
+ EnforcedStyle: symmetrical
+
# Checks indentation of method calls with the dot operator that span more than
# one line.
Style/MultilineMethodCallIndentation:
@@ -525,10 +545,9 @@ Style/SpaceAfterSemicolon:
Style/SpaceAroundEqualsInParameterDefault:
Enabled: false
-# TODO: Enable SpaceAroundKeyword Cop.
# Use a space around keywords if appropriate.
Style/SpaceAroundKeyword:
- Enabled: false
+ Enabled: true
# Use a single space around operators.
Style/SpaceAroundOperators:
@@ -755,19 +774,19 @@ Lint/BlockAlignment:
# Default values in optional keyword arguments and optional ordinal arguments
# should not refer back to the name of the argument.
Lint/CircularArgumentReference:
- Enabled: false
+ Enabled: true
# Checks for condition placed in a confusing position relative to the keyword.
Lint/ConditionPosition:
- Enabled: false
+ Enabled: true
# Check for debugger calls.
Lint/Debugger:
- Enabled: false
+ Enabled: true
# Align ends corresponding to defs correctly.
Lint/DefEndAlignment:
- Enabled: false
+ Enabled: true
# Check for deprecated class method calls.
Lint/DeprecatedClassMethods:
@@ -783,15 +802,15 @@ Lint/DuplicatedKey:
# Check for immutable argument given to each_with_object.
Lint/EachWithObjectArgument:
- Enabled: false
+ Enabled: true
# Check for odd code arrangement in an else block.
Lint/ElseLayout:
- Enabled: false
+ Enabled: true
# Checks for empty ensure block.
Lint/EmptyEnsure:
- Enabled: false
+ Enabled: true
# Checks for empty string interpolation.
Lint/EmptyInterpolation:
@@ -799,37 +818,36 @@ Lint/EmptyInterpolation:
# Align ends correctly.
Lint/EndAlignment:
- Enabled: false
+ Enabled: true
# END blocks should not be placed inside method definitions.
Lint/EndInMethod:
- Enabled: false
+ Enabled: true
# Do not use return in an ensure block.
Lint/EnsureReturn:
- Enabled: false
+ Enabled: true
# The use of eval represents a serious security risk.
Lint/Eval:
- Enabled: false
+ Enabled: true
# Catches floating-point literals too large or small for Ruby to represent.
Lint/FloatOutOfRange:
- Enabled: false
+ Enabled: true
# The number of parameters to format/sprint must match the fields.
Lint/FormatParameterMismatch:
- Enabled: false
+ Enabled: true
# Don't suppress exception.
Lint/HandleExceptions:
Enabled: false
-# TODO: Enable ImplicitStringConcatenation Cop.
# Checks for adjacent string literals on the same line, which could better be
# represented as a single string literal.
Lint/ImplicitStringConcatenation:
- Enabled: false
+ Enabled: true
# TODO: Enable IneffectiveAccessModifier Cop.
# Checks for attempts to use `private` or `protected` to set the visibility
@@ -840,7 +858,7 @@ Lint/IneffectiveAccessModifier:
# Checks for invalid character literals with a non-escaped whitespace
# character.
Lint/InvalidCharacterLiteral:
- Enabled: false
+ Enabled: true
# Checks of literals used in conditions.
Lint/LiteralInCondition:
@@ -848,7 +866,7 @@ Lint/LiteralInCondition:
# Checks for literals used in interpolation.
Lint/LiteralInInterpolation:
- Enabled: false
+ Enabled: true
# Use Kernel#loop with break rather than begin/end/until or begin/end/while
# for post-loop tests.
@@ -857,11 +875,11 @@ Lint/Loop:
# Do not use nested method definitions.
Lint/NestedMethodDefinition:
- Enabled: false
+ Enabled: true
# Do not omit the accumulator when calling `next` in a `reduce`/`inject` block.
Lint/NextWithoutAccumulator:
- Enabled: false
+ Enabled: true
# Checks for method calls with a space before the opening parenthesis.
Lint/ParenthesesAsGroupedExpression:
@@ -870,11 +888,11 @@ Lint/ParenthesesAsGroupedExpression:
# Checks for `rand(1)` calls. Such calls always return `0` and most likely
# a mistake.
Lint/RandOne:
- Enabled: false
+ Enabled: true
# Use parentheses in the method call to avoid confusion about precedence.
Lint/RequireParentheses:
- Enabled: false
+ Enabled: true
# Avoid rescuing the Exception class.
Lint/RescueException:
@@ -909,7 +927,7 @@ Lint/UnusedMethodArgument:
# Unreachable code.
Lint/UnreachableCode:
- Enabled: false
+ Enabled: true
# Checks for useless access modifiers.
Lint/UselessAccessModifier:
@@ -921,19 +939,19 @@ Lint/UselessAssignment:
# Checks for comparison of something with itself.
Lint/UselessComparison:
- Enabled: false
+ Enabled: true
# Checks for useless `else` in `begin..end` without `rescue`.
Lint/UselessElseWithoutRescue:
- Enabled: false
+ Enabled: true
# Checks for useless setter call to a local variable.
Lint/UselessSetterCall:
- Enabled: false
+ Enabled: true
# Possible use of operator/literal/variable in void context.
Lint/Void:
- Enabled: false
+ Enabled: true
##################### Performance ############################
@@ -942,11 +960,10 @@ Lint/Void:
Performance/Casecmp:
Enabled: true
-# TODO: Enable DoubleStartEndWith Cop.
# Use `str.{start,end}_with?(x, ..., y, ...)` instead of
# `str.{start,end}_with?(x, ...) || str.{start,end}_with?(y, ...)`.
Performance/DoubleStartEndWith:
- Enabled: false
+ Enabled: true
# TODO: Enable EndWith Cop.
# Use `end_with?` instead of a regex match anchored to the end of a string.
@@ -957,10 +974,9 @@ Performance/EndWith:
Performance/LstripRstrip:
Enabled: true
-# TODO: Enable RangeInclude Cop.
# Use `Range#cover?` instead of `Range#include?`.
Performance/RangeInclude:
- Enabled: false
+ Enabled: true
# TODO: Enable RedundantBlockCall Cop.
# Use `yield` instead of `block.call`.
@@ -980,16 +996,14 @@ Performance/RedundantMerge:
MaxKeyValuePairs: 2
Enabled: false
-# TODO: Enable RedundantSortBy Cop.
# Use `sort` instead of `sort_by { |x| x }`.
Performance/RedundantSortBy:
- Enabled: false
+ Enabled: true
-# TODO: Enable StartWith Cop.
# Use `start_with?` instead of a regex match anchored to the beginning of a
# string.
Performance/StartWith:
- Enabled: false
+ Enabled: true
# Use `tr` instead of `gsub` when you are replacing the same number of
# characters. Use `delete` instead of `gsub` when you are deleting
@@ -1025,11 +1039,11 @@ Rails/Delegate:
# Prefer `find_by` over `where.first`.
Rails/FindBy:
- Enabled: false
+ Enabled: true
# Prefer `all.find_each` over `all.find`.
Rails/FindEach:
- Enabled: false
+ Enabled: true
# Prefer has_many :through to has_and_belongs_to_many.
Rails/HasAndBelongsToMany:
@@ -1041,7 +1055,7 @@ Rails/Output:
# Checks for incorrect grammar when using methods like `3.day.ago`.
Rails/PluralizationGrammar:
- Enabled: false
+ Enabled: true
# Checks for `read_attribute(:attr)` and `write_attribute(:attr, val)`.
Rails/ReadWriteAttribute:
@@ -1049,7 +1063,7 @@ Rails/ReadWriteAttribute:
# Checks the arguments of ActiveRecord scopes.
Rails/ScopeArgs:
- Enabled: false
+ Enabled: true
# Checks the correct usage of time zone aware methods.
# http://danilenko.org/2012/7/6/rails_timezones
@@ -1059,3 +1073,65 @@ Rails/TimeZone:
# Use validates :attribute, hash of validations.
Rails/Validation:
Enabled: false
+
+##################### RSpec ##################################
+
+# Check that instances are not being stubbed globally.
+RSpec/AnyInstance:
+ Enabled: false
+
+# Check that the first argument to the top level describe is the tested class or
+# module.
+RSpec/DescribeClass:
+ Enabled: false
+
+# Use `described_class` for tested class / module.
+RSpec/DescribeMethod:
+ Enabled: false
+
+# Checks that the second argument to top level describe is the tested method
+# name.
+RSpec/DescribedClass:
+ Enabled: false
+
+# Checks for long example.
+RSpec/ExampleLength:
+ Enabled: false
+ Max: 5
+
+# Do not use should when describing your tests.
+RSpec/ExampleWording:
+ Enabled: false
+ CustomTransform:
+ be: is
+ have: has
+ not: does not
+ IgnoredWords: []
+
+# Checks the file and folder naming of the spec file.
+RSpec/FilePath:
+ Enabled: false
+ CustomTransform:
+ RuboCop: rubocop
+ RSpec: rspec
+
+# Checks if there are focused specs.
+RSpec/Focus:
+ Enabled: true
+
+# Checks for the usage of instance variables.
+RSpec/InstanceVariable:
+ Enabled: false
+
+# Checks for multiple top-level describes.
+RSpec/MultipleDescribes:
+ Enabled: false
+
+# Enforces the usage of the same method on all negative message expectations.
+RSpec/NotToNot:
+ EnforcedStyle: not_to
+ Enabled: false
+
+# Prefer using verifying doubles over normal doubles.
+RSpec/VerifiedDoubles:
+ Enabled: false
diff --git a/CHANGELOG b/CHANGELOG
index 0884ac1947d..ebc83df0a40 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,19 @@
Please view this file on the master branch, on stable branches it's out of date.
-v 8.8.0 (unreleased)
+v 8.9.0 (unreleased)
+ - Redesign navigation for project pages
+
+v 8.8.2 (unreleased)
+ - Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources
+ - Fix Error 500 in CI charts by gracefully handling commits with no durations
+
+v 8.8.1
+ - Add documentation for the "Health Check" feature
+ - Allow anonymous users to access a public project's pipelines
+ - Fix MySQL compatibility in zero downtime migrations helpers
+ - Fix the CI login to Container Registry (the gitlab-ci-token user)
+
+v 8.8.0
- Implement GFM references for milestones (Alejandro Rodríguez)
- Snippets tab under user profile. !4001 (Long Nguyen)
- Fix error when using link to uploads in global snippets
@@ -14,6 +27,7 @@ v 8.8.0 (unreleased)
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
- Escape HTML in commit titles in system note messages
- Improve design of Pipeline View
+ - Fix scope used when accessing container registry
- Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
- Improve multiple branch push performance by memoizing permission checking
- Log to application.log when an admin starts and stops impersonating a user
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 39e898a4f95..f38fc5393ff 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-0.7.1
+0.7.3
diff --git a/Gemfile b/Gemfile
index 91ad1706a07..e854a31b425 100644
--- a/Gemfile
+++ b/Gemfile
@@ -293,9 +293,10 @@ group :development, :test do
gem 'spring-commands-spinach', '~> 1.1.0'
gem 'spring-commands-teaspoon', '~> 0.0.2'
- gem 'rubocop', '~> 0.38.0', require: false
+ gem 'rubocop', '~> 0.40.0', require: false
+ gem 'rubocop-rspec', '~> 1.5.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
- gem 'coveralls', '~> 0.8.2', require: false
+ gem 'coveralls', '~> 0.8.2', require: false
gem 'simplecov', '~> 0.11.0', require: false
gem 'flog', require: false
gem 'flay', require: false
@@ -325,7 +326,7 @@ gem "mail_room", "~> 0.7"
gem 'email_reply_parser', '~> 0.5.8'
## CI
-gem 'activerecord-session_store', '~> 0.1.0'
+gem 'activerecord-session_store', '~> 1.0.0'
gem "nested_form", '~> 0.3.2'
# OAuth
diff --git a/Gemfile.lock b/Gemfile.lock
index b55764504c6..4533aa31d5f 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -33,10 +33,12 @@ GEM
activemodel (= 4.2.6)
activesupport (= 4.2.6)
arel (~> 6.0)
- activerecord-session_store (0.1.2)
- actionpack (>= 4.0.0, < 5)
- activerecord (>= 4.0.0, < 5)
- railties (>= 4.0.0, < 5)
+ activerecord-session_store (1.0.0)
+ actionpack (>= 4.0, < 5.1)
+ activerecord (>= 4.0, < 5.1)
+ multi_json (~> 1.11, >= 1.11.2)
+ rack (>= 1.5.2, < 3)
+ railties (>= 4.0, < 5.1)
activesupport (4.2.6)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
@@ -549,7 +551,7 @@ GEM
orm_adapter (0.5.0)
paranoia (2.1.4)
activerecord (~> 4.0)
- parser (2.3.0.6)
+ parser (2.3.1.0)
ast (~> 2.2)
pg (0.18.4)
poltergeist (1.9.0)
@@ -684,15 +686,17 @@ GEM
rspec-retry (0.4.5)
rspec-core
rspec-support (3.4.1)
- rubocop (0.38.0)
- parser (>= 2.3.0.6, < 3.0)
+ rubocop (0.40.0)
+ parser (>= 2.3.1.0, < 3.0)
powerpack (~> 0.1)
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)
ruby-fogbugz (0.2.1)
crack (~> 0.4)
- ruby-progressbar (1.7.5)
+ ruby-progressbar (1.8.1)
ruby-saml (1.1.2)
nokogiri (>= 1.5.10)
uuid (~> 2.3)
@@ -839,7 +843,7 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.2)
- unicode-display_width (1.0.2)
+ unicode-display_width (1.0.5)
unicorn (4.9.0)
kgio (~> 2.6)
rack
@@ -883,7 +887,7 @@ PLATFORMS
DEPENDENCIES
RedCloth (~> 4.2.9)
ace-rails-ap (~> 4.0.2)
- activerecord-session_store (~> 0.1.0)
+ activerecord-session_store (~> 1.0.0)
acts-as-taggable-on (~> 3.4)
addressable (~> 2.3.8)
after_commit_queue
@@ -1013,7 +1017,8 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.4.0)
rspec-retry
- rubocop (~> 0.38.0)
+ rubocop (~> 0.40.0)
+ rubocop-rspec (~> 1.5.0)
ruby-fogbugz (~> 0.2.1)
sanitize (~> 2.0)
sass-rails (~> 5.0.0)
@@ -1058,4 +1063,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
- 1.12.3
+ 1.12.4
diff --git a/VERSION b/VERSION
index d5a967c3933..6c07f656285 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-8.8.0-pre
+8.9.0-pre
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index f91aa3c5ad7..12c143fdf76 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -119,7 +119,7 @@ class Dispatcher
new UsersSelect()
when 'projects'
new NamespaceSelect()
- when 'dashboard'
+ when 'dashboard', 'root'
shortcut_handler = new ShortcutsDashboardNavigation()
when 'profiles'
new Profile()
diff --git a/app/assets/javascripts/due_date_select.js.coffee b/app/assets/javascripts/due_date_select.js.coffee
index a4304786cbb..3cc70185178 100644
--- a/app/assets/javascripts/due_date_select.js.coffee
+++ b/app/assets/javascripts/due_date_select.js.coffee
@@ -11,6 +11,7 @@ class @DueDateSelect
$block = $dropdown.closest('.block')
$selectbox = $dropdown.closest('.selectbox')
$value = $block.find('.value')
+ $valueContent = $block.find('.value-content')
$sidebarValue = $('.js-due-date-sidebar-value', $block)
fieldName = $dropdown.data('field-name')
@@ -23,11 +24,15 @@ class @DueDateSelect
$value.removeAttr('style')
)
- addDueDate = ->
+ addDueDate = (isDropdown) ->
# Create the post date
value = $("input[name='#{fieldName}']").val()
- date = new Date value.replace(new RegExp('-', 'g'), ',')
- mediumDate = $.datepicker.formatDate 'M d, yy', date
+
+ if value isnt ''
+ date = new Date value.replace(new RegExp('-', 'g'), ',')
+ mediumDate = $.datepicker.formatDate 'M d, yy', date
+ else
+ mediumDate = 'None'
data = {}
data[abilityName] = {}
@@ -39,23 +44,35 @@ class @DueDateSelect
data: data
beforeSend: ->
$loading.fadeIn()
- $dropdown.trigger('loading.gl.dropdown')
- $selectbox.hide()
+ if isDropdown
+ $dropdown.trigger('loading.gl.dropdown')
+ $selectbox.hide()
$value.removeAttr('style')
- $value.html(mediumDate)
+ $valueContent.html(mediumDate)
$sidebarValue.html(mediumDate)
+
+ if value isnt ''
+ $('.js-remove-due-date-holder').removeClass 'hidden'
+ else
+ $('.js-remove-due-date-holder').addClass 'hidden'
).done (data) ->
- $dropdown.trigger('loaded.gl.dropdown')
- $dropdown.dropdown('toggle')
+ if isDropdown
+ $dropdown.trigger('loaded.gl.dropdown')
+ $dropdown.dropdown('toggle')
$loading.fadeOut()
+ $block.on 'click', '.js-remove-due-date', (e) ->
+ e.preventDefault()
+ $("input[name='#{fieldName}']").val ''
+ addDueDate(false)
+
$datePicker.datepicker(
dateFormat: 'yy-mm-dd',
defaultDate: $("input[name='#{fieldName}']").val()
altField: "input[name='#{fieldName}']"
onSelect: ->
- addDueDate()
+ addDueDate(true)
)
$(document)
diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee
index 8cb31b2dbd7..b3f1dc969b8 100644
--- a/app/assets/javascripts/gl_dropdown.js.coffee
+++ b/app/assets/javascripts/gl_dropdown.js.coffee
@@ -512,7 +512,7 @@ class GitLabDropdown
return false
if currentKeyCode is 13
- @selectRowAtIndex currentIndex
+ @selectRowAtIndex if currentIndex < 0 then 0 else currentIndex
removeArrayKeyEvent: ->
$('body').off 'keydown'
diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee
index 7a788f761b7..72ae3bde81e 100644
--- a/app/assets/javascripts/issuable_form.js.coffee
+++ b/app/assets/javascripts/issuable_form.js.coffee
@@ -20,6 +20,15 @@ class @IssuableForm
@initWip()
+ $issuableDueDate = $('#issuable-due-date')
+
+ if $issuableDueDate.length
+ $('.datepicker').datepicker(
+ dateFormat: 'yy-mm-dd',
+ onSelect: (dateText, inst) ->
+ $issuableDueDate.val dateText
+ ).datepicker 'setDate', $.datepicker.parseDate('yy-mm-dd', $issuableDueDate.val())
+
initAutosave: ->
new Autosave @titleField, [
document.location.pathname,
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index f58647988a2..b6d590f681c 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -113,7 +113,7 @@ class @MergeRequestWidget
switch state
when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger')
- when "running", "pending"
+ when "running"
@setMergeButtonClass('btn-warning')
when "success"
@setMergeButtonClass('btn-create')
@@ -126,6 +126,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
- $('.accept_merge_request')
+ $('.js-merge-button')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)
diff --git a/app/assets/javascripts/shortcuts_dashboard_navigation.js.coffee b/app/assets/javascripts/shortcuts_dashboard_navigation.js.coffee
index 4a05bdccdb3..cca2b8a1fcc 100644
--- a/app/assets/javascripts/shortcuts_dashboard_navigation.js.coffee
+++ b/app/assets/javascripts/shortcuts_dashboard_navigation.js.coffee
@@ -3,10 +3,10 @@
class @ShortcutsDashboardNavigation extends Shortcuts
constructor: ->
super()
- Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-activity'))
- Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-issues'))
- Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-merge_requests'))
- Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndFollowLink('.shortcuts-projects'))
+ Mousetrap.bind('g a', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-activity'))
+ Mousetrap.bind('g i', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-issues'))
+ Mousetrap.bind('g m', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-merge_requests'))
+ Mousetrap.bind('g p', -> ShortcutsDashboardNavigation.findAndFollowLink('.dashboard-shortcuts-projects'))
@findAndFollowLink: (selector) ->
link = $(selector).attr('href')
diff --git a/app/assets/stylesheets/framework/avatar.scss b/app/assets/stylesheets/framework/avatar.scss
index f5ce70b606b..bb8d71fbae8 100644
--- a/app/assets/stylesheets/framework/avatar.scss
+++ b/app/assets/stylesheets/framework/avatar.scss
@@ -45,6 +45,7 @@
&.s32 { font-size: 20px; line-height: 32px; }
&.s40 { font-size: 16px; line-height: 40px; }
&.s60 { font-size: 32px; line-height: 60px; }
+ &.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 90px; }
&.s110 { font-size: 40px; line-height: 112px; font-weight: 300; }
&.s140 { font-size: 72px; line-height: 140px; }
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index 434a26d57c6..6981f834d30 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -24,8 +24,8 @@
background-color: $background-color;
padding: $gl-padding;
margin-bottom: 0;
- border-top: 1px solid $border-color;
- border-bottom: 1px solid $border-color;
+ border-top: 1px solid $white-dark;
+ border-bottom: 1px solid $white-dark;
color: $gl-gray;
&.oneline-block {
@@ -110,9 +110,9 @@
.cover-title {
color: $gl-header-color;
margin: 0;
- font-size: 23px;
+ font-size: 24px;
font-weight: normal;
- margin: 16px 0 5px;
+ margin-bottom: 5px;
color: #4c4e54;
font-size: 23px;
line-height: 1.1;
@@ -137,7 +137,6 @@
}
.cover-desc {
- padding: 0 $gl-padding 3px;
color: $gl-text-color;
&.username:last-child {
@@ -205,7 +204,7 @@
.content-block {
padding: $gl-padding 0;
- border-bottom: 1px solid $border-color;
+ border-bottom: 1px solid $white-dark;
&.oneline-block {
line-height: 36px;
diff --git a/app/assets/stylesheets/framework/forms.scss b/app/assets/stylesheets/framework/forms.scss
index 558b133f593..46acc3b772f 100644
--- a/app/assets/stylesheets/framework/forms.scss
+++ b/app/assets/stylesheets/framework/forms.scss
@@ -28,10 +28,6 @@ input[type='text'].danger {
}
label {
- &.control-label {
- @extend .col-sm-2;
- }
-
&.inline-label {
margin: 0;
}
@@ -41,6 +37,10 @@ label {
}
}
+.control-label {
+ @extend .col-sm-2;
+}
+
.inline-input-group {
width: 250px;
}
diff --git a/app/assets/stylesheets/framework/mobile.scss b/app/assets/stylesheets/framework/mobile.scss
index 33cbee85987..bd531f8376b 100644
--- a/app/assets/stylesheets/framework/mobile.scss
+++ b/app/assets/stylesheets/framework/mobile.scss
@@ -48,10 +48,6 @@
display: block;
}
- .project-home-desc {
- font-size: 21px;
- }
-
.project-repo-buttons,
.git-clone-holder {
display: none;
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index a81fcb1c6b3..c70be58f48f 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -196,7 +196,7 @@
position: fixed;
top: $header-height;
width: 100%;
- z-index: 1;
+ z-index: 3;
background: $background-color;
border-bottom: 1px solid $border-color;
transition-duration: .3s;
@@ -238,6 +238,10 @@
@media (max-width: $screen-xs-min) {
margin-left: 0;
}
+
+ li.active {
+ font-weight: bold;
+ }
}
}
@@ -246,6 +250,11 @@
height: 51px;
white-space: nowrap;
overflow-x: auto;
+ overflow-y: hidden;
+ -webkit-overflow-scrolling: touch;
+ &::-webkit-scrollbar {
+ display: none;
+ }
li {
@@ -279,4 +288,8 @@
margin-top: 96px;
}
}
+
+ .right-sidebar {
+ top: ($header-height * 2) + 2;
+ }
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index c5a4dbe372c..c7784e15844 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -119,8 +119,8 @@ $border-white-light: #f1f2f4;
$border-white-normal: #d6dae2;
$border-white-dark: #c6cacf;
-$border-gray-light: rgba(0, 0, 0, 0.06);
-$border-gray-normal: rgba(0, 0, 0, 0.10);;
+$border-gray-light: #dcdcdc;
+$border-gray-normal: rgba(0, 0, 0, 0.10);
$border-gray-dark: #c6cacf;
$border-green-light: #2faa60;
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index d06086a581b..787c387379e 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -150,6 +150,10 @@
font-weight: 600;
}
+ .light {
+ font-weight: normal;
+ }
+
.sidebar-collapsed-icon {
display: none;
}
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index a3690e40e28..b7653a833ec 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -26,8 +26,13 @@
}
.project-home-panel {
- padding-bottom: 40px;
- border-bottom: 1px solid $border-color;
+ background: $white-light;
+ text-align: left;
+ padding: 24px 0;
+
+ .container-fluid {
+ position: relative;
+ }
.cover-controls {
.project-settings-dropdown {
@@ -43,21 +48,55 @@
}
}
- .project-identicon-holder {
- margin-bottom: 16px;
+ .cover-title {
+ margin-bottom: 0;
+ }
+
+ .project-image-container {
+ @include make-sm-column(1);
+ max-width: 86px;
+ min-width: 86px;
+ padding-right: 0;
+ margin: 11px 0;
- .avatar, .identicon {
- margin: 0 auto;
- float: none;
+ @media (max-width: $screen-md-max) {
+ padding-left: 0;
+ margin: 0 0 10px;
+ max-width: none;
+ min-width: none;
+
+ .avatar.s70 {
+ margin: auto;
+ }
}
+ }
- .identicon {
- @include border-radius(50%);
+ .project-info {
+ @include make-sm-column(10);
+
+ h1 {
+ font-size: 24px;
+ font-weight: normal;
+ margin: 0;
+ }
+
+ .project-home-desc {
+ p {
+ margin: 0;
+ }
}
}
+ .identicon {
+ float: left;
+ @include border-radius(50%);
+ }
+
+ .avatar {
+ float: none;
+ }
+
.notifications-btn {
- margin-top: -28px;
.fa-bell {
margin-right: 6px;
@@ -69,28 +108,45 @@
}
.project-repo-buttons {
- margin-top: 20px;
- margin-bottom: 0;
+ font-size: 0;
- .count-buttons {
- display: block;
- margin-bottom: 20px;
- }
+ .btn {
+ @include btn-gray;
+ padding: 3px 10px;
+ text-transform: none;
+ background-color: $background-color;
- .clone-row {
- .split-repo-buttons,
- .project-clone-holder {
- display: inline-block;
+ .fa {
+ color: $layout-link-gray;
}
- .split-repo-buttons {
- margin: 0 12px;
+ .fa-caret-down {
+ margin-left: 3px;
}
}
- .btn {
- @include btn-gray;
- text-transform: none;
+ .btn-group:not(:first-child):not(:last-child) > .btn {
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ }
+
+ form {
+ margin-left: 10px;
+ }
+
+ .count-buttons {
+ display: inline-block;
+ vertical-align: top;
+ margin-top: 16px;
+ }
+
+ .project-clone-holder {
+ display: inline-block;
+ margin-top: 16px;
+
+ input {
+ height: 29px;
+ }
}
.count-with-arrow {
@@ -140,14 +196,18 @@
line-height: 13px;
padding: $gl-vert-padding $gl-padding;
letter-spacing: .4px;
- padding: 10px 14px;
+ padding: 7px 14px;
text-align: center;
vertical-align: middle;
touch-action: manipulation;
cursor: pointer;
background-image: none;
white-space: nowrap;
- margin: 0 11px 0 4px;
+ margin: 0 10px 0 4px;
+
+ a {
+ color: inherit;
+ }
&:hover {
background: #fff;
@@ -155,13 +215,37 @@
}
}
}
+
+ .project-right-buttons {
+ position: absolute;
+ right: 16px;
+ bottom: 0;
+
+ .btn {
+ padding: 3px 10px;
+ background-color: $background-color;
+ }
+
+ @media (max-width: 1304px) {
+ top: 0;
+ }
+ }
+
+ @media (max-width: $screen-md-max) {
+ text-align: center;
+
+ .project-info,
+ .project-image-container {
+ width: 100%;
+ }
+ }
}
.split-one {
display: inline-table;
margin-right: 12px;
- a {
+ > a {
margin: -1px;
}
}
@@ -285,11 +369,11 @@ a.deploy-project-label {
}
.project-stats {
- text-align: center;
margin-top: $gl-padding;
margin-bottom: 0;
- padding-top: 10px;
- padding-bottom: 4px;
+ padding: 16px 0;
+ background-color: $white-light;
+ font-size: 0;
ul.nav {
display: inline-block;
@@ -300,12 +384,11 @@ a.deploy-project-label {
}
.nav > li > a {
- @include btn-default;
- @include btn-gray;
-
background-color: transparent;
- border: 1px solid #f7f8fa;
- margin-left: 12px;
+ margin-right: 12px;
+ padding: 0 10px;
+ font-size: 15px;
+ color: $notes-light-color;
}
li {
@@ -325,6 +408,10 @@ a.deploy-project-label {
background-color: #f0f2f5;
}
}
+
+ &.row-content-block.second-block {
+ margin-top: 0;
+ }
}
pre.light-well {
@@ -442,9 +529,14 @@ pre.light-well {
border-top: 0;
.edit-project-readme {
- z-index: 100;
+ z-index: 2;
position: relative;
}
+
+ .wiki h1 {
+ border-bottom: none;
+ padding: 0;
+ }
}
.git-clone-holder {
diff --git a/app/controllers/jwt_controller.rb b/app/controllers/jwt_controller.rb
index f5aa5397ff1..156ab2811d6 100644
--- a/app/controllers/jwt_controller.rb
+++ b/app/controllers/jwt_controller.rb
@@ -36,7 +36,7 @@ class JwtController < ApplicationController
end
def authenticate_project(login, password)
- if login == 'gitlab_ci_token'
+ if login == 'gitlab-ci-token'
Project.find_by(builds_enabled: true, runners_token: password)
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 3e0074da394..e6e2546b92f 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -110,8 +110,7 @@ module ApplicationHelper
]
# If reference is commit id - we should add it to branch/tag selectbox
- if(@ref && !options.flatten.include?(@ref) &&
- @ref =~ /\A[0-9a-zA-Z]{6,52}\z/)
+ if @ref && !options.flatten.include?(@ref) && @ref =~ /\A[0-9a-zA-Z]{6,52}\z/
options << ['Commit', [@ref]]
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 3a45205563e..0a1b48af219 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -13,7 +13,7 @@ module GitlabMarkdownHelper
def link_to_gfm(body, url, html_options = {})
return "" if body.blank?
- escaped_body = if body =~ /\A\<img/
+ escaped_body = if body.start_with?('<img')
body
else
escape_once(body)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 0825b5b6437..5e5d170a9f3 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -144,6 +144,10 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
+ if can?(current_user, :read_pipeline, project)
+ nav_tabs << :pipelines
+ end
+
if can?(current_user, :read_build, project)
nav_tabs << :builds
end
diff --git a/app/helpers/tab_helper.rb b/app/helpers/tab_helper.rb
index 96a83671009..563ddd2a511 100644
--- a/app/helpers/tab_helper.rb
+++ b/app/helpers/tab_helper.rb
@@ -95,7 +95,9 @@ module TabHelper
end
def project_tab_class
- return "active" if current_page?(controller: "/projects", action: :edit, id: @project)
+ if controller.controller_path.start_with?('projects')
+ return 'active'
+ end
if ['services', 'hooks', 'deploy_keys', 'protected_branches'].include? controller.controller_name
"active"
@@ -112,7 +114,7 @@ module TabHelper
end
def profile_tab_class
- if controller.controller_path =~ /\Aprofiles/
+ if controller.controller_path.start_with?('profiles')
return 'active'
end
diff --git a/app/models/ability.rb b/app/models/ability.rb
index f7ea2fd2b1f..b354b1990c7 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -60,6 +60,7 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
+ :read_pipeline,
:read_commit_status,
:read_container_image,
:download_code
diff --git a/app/models/application_setting.rb b/app/models/application_setting.rb
index f5079f92444..9a14954b4a7 100644
--- a/app/models/application_setting.rb
+++ b/app/models/application_setting.rb
@@ -7,7 +7,7 @@ class ApplicationSetting < ActiveRecord::Base
serialize :restricted_visibility_levels
serialize :import_sources
- serialize :disabled_oauth_sign_in_sources
+ serialize :disabled_oauth_sign_in_sources, Array
serialize :restricted_signup_domains, Array
attr_accessor :restricted_signup_domains_raw
diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb
index f4e90125373..9259cb1a0fa 100644
--- a/app/models/network/graph.rb
+++ b/app/models/network/graph.rb
@@ -253,7 +253,7 @@ module Network
leaves = []
leaves.push(commit) if commit.space.zero?
- while true
+ loop do
return leaves if commit.parents(@map).count.zero?
commit = commit.parents(@map).first
diff --git a/app/services/auth/container_registry_authentication_service.rb b/app/services/auth/container_registry_authentication_service.rb
index 3144e96ba31..2bbab643e69 100644
--- a/app/services/auth/container_registry_authentication_service.rb
+++ b/app/services/auth/container_registry_authentication_service.rb
@@ -6,7 +6,7 @@ module Auth
return error('not found', 404) unless registry.enabled
if params[:offline_token]
- return error('unauthorized', 401) unless current_user
+ return error('unauthorized', 401) unless current_user || project
else
return error('forbidden', 403) unless scope
end
@@ -20,7 +20,7 @@ module Auth
token.issuer = registry.issuer
token.audience = AUDIENCE
token[:access] = names.map do |name|
- { type: 'repository', name: name, actions: %w(pull push) }
+ { type: 'repository', name: name, actions: %w(*) }
end
token.encoded
end
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index fad4224e945..43532b0c155 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -1,6 +1,6 @@
%ul.nav.nav-sidebar
- = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: 'home'}) do
- = link_to dashboard_projects_path, title: 'Projects' do
+ = nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
+ = link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
= icon('bookmark fw')
%span
Projects
@@ -11,7 +11,7 @@
Todos
%span.count.todos-pending-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do
- = link_to activity_dashboard_path, class: 'shortcuts-activity', title: 'Activity' do
+ = link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
= icon('dashboard fw')
%span
Activity
@@ -26,13 +26,13 @@
%span
Milestones
= nav_link(path: 'dashboard#issues') do
- = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
+ = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
= icon('exclamation-circle fw')
%span
Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count)
= nav_link(path: 'dashboard#merge_requests') do
- = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
+ = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
= icon('tasks fw')
%span
Merge Requests
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index a97fefcfb46..33ba654bbee 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,19 +1,25 @@
-%ul.nav.nav-sidebar
- - if @project.group
- = nav_link do
- = link_to group_path(@project.group), title: 'Go to group', class: 'back-link' do
- = icon('caret-square-o-left fw')
- %span
- Go to group
- - else
- = nav_link do
- = link_to root_path, title: 'Go to dashboard', class: 'back-link' do
- = icon('caret-square-o-left fw')
- %span
- Go to dashboard
-
- %li.separate-item
-
+- if current_user
+ .controls
+ - access = user_max_access_in_project(current_user.id, @project)
+ - can_edit = can?(current_user, :admin_project, @project)
+ .dropdown.project-settings-dropdown
+ %a.dropdown-new.btn.btn-default#project-settings-button{href: '#', 'data-toggle' => 'dropdown'}
+ = icon('cog')
+ = icon('caret-down')
+ %ul.dropdown-menu.dropdown-menu-align-right
+ = render 'layouts/nav/project_settings'
+ %li.divider
+ - if can_edit
+ %li
+ = link_to edit_project_path(@project) do
+ Edit Project
+ - if access
+ %li
+ = link_to leave_namespace_project_project_members_path(@project.namespace, @project),
+ data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
+ Leave Project
+
+%ul.nav-links
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
= icon('bookmark fw')
@@ -38,20 +44,21 @@
%span
Commits
- - if project_nav_tab? :builds
+ - if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
= icon('ship fw')
%span
Pipelines
- %span.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
+ %span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
+ - if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
= icon('cubes fw')
%span
Builds
- %span.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
+ %span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- if project_nav_tab? :container_registry
= nav_link(controller: %w(container_registry)) do
@@ -81,7 +88,7 @@
%span
Issues
- if @project.default_issues_tracker?
- %span.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
+ %span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
- if project_nav_tab? :merge_requests
= nav_link(controller: :merge_requests) do
@@ -89,14 +96,7 @@
= icon('tasks fw')
%span
Merge Requests
- %span.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
-
- - if project_nav_tab? :team
- = nav_link(controller: [:project_members, :teams]) do
- = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
- = icon('users fw')
- %span
- Members
+ %span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- if project_nav_tab? :labels
= nav_link(controller: :labels) do
@@ -112,13 +112,6 @@
%span
Wiki
- - if project_nav_tab? :forks
- = nav_link(controller: :forks, action: :index) do
- = link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks' do
- = icon('code-fork fw')
- %span
- Forks
-
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
@@ -126,13 +119,6 @@
%span
Snippets
- - if project_nav_tab? :settings
- = nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
- = link_to edit_project_path(@project), title: 'Settings' do
- = icon('cogs fw')
- %span
- Settings
-
-# Global shortcut to network page for compatibility
- if project_nav_tab? :network
%li.hidden
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index d429a928464..885e78d38c6 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -1,63 +1,45 @@
-%ul.nav.nav-sidebar
- = nav_link do
- = link_to project_path(@project), title: 'Go to project', class: 'back-link' do
- = icon('caret-square-o-left fw')
+- if project_nav_tab? :team
+ = nav_link(controller: [:project_members, :teams]) do
+ = link_to namespace_project_project_members_path(@project.namespace, @project), title: 'Members', class: 'team-tab tab' do
%span
- Go to project
+ Members
- %li.separate-item
-
- %ul.sidebar-subnav
- = nav_link(path: 'projects#edit') do
- = link_to edit_project_path(@project), title: 'Project Settings' do
- = icon('pencil-square-o fw')
- %span
- Project Settings
- - if @project.allowed_to_share_with_group?
- = nav_link(controller: :group_links) do
- = link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do
- = icon('share-square-o fw')
- %span
- Groups
- = nav_link(controller: :deploy_keys) do
- = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
- = icon('key fw')
- %span
- Deploy Keys
- = nav_link(controller: :hooks) do
- = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do
- = icon('link fw')
- %span
- Webhooks
- = nav_link(controller: :services) do
- = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
- = icon('cogs fw')
- %span
- Services
- = nav_link(controller: :protected_branches) do
- = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
- = icon('lock fw')
- %span
- Protected Branches
+- if @project.allowed_to_share_with_group?
+ = nav_link(controller: :group_links) do
+ = link_to namespace_project_group_links_path(@project.namespace, @project), title: "Groups" do
+ %span
+ Groups
+= nav_link(controller: :deploy_keys) do
+ = link_to namespace_project_deploy_keys_path(@project.namespace, @project), title: 'Deploy Keys' do
+ %span
+ Deploy Keys
+= nav_link(controller: :hooks) do
+ = link_to namespace_project_hooks_path(@project.namespace, @project), title: 'Webhooks' do
+ %span
+ Webhooks
+= nav_link(controller: :services) do
+ = link_to namespace_project_services_path(@project.namespace, @project), title: 'Services' do
+ %span
+ Services
+= nav_link(controller: :protected_branches) do
+ = link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches' do
+ %span
+ Protected Branches
- - if @project.builds_enabled?
- = nav_link(controller: :runners) do
- = link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do
- = icon('cog fw')
- %span
- Runners
- = nav_link(controller: :variables) do
- = link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do
- = icon('code fw')
- %span
- Variables
- = nav_link(controller: :triggers) do
- = link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
- = icon('retweet fw')
- %span
- Triggers
- = nav_link(controller: :badges) do
- = link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do
- = icon('star-half-empty fw')
- %span
- Badges
+- if @project.builds_enabled?
+ = nav_link(controller: :runners) do
+ = link_to namespace_project_runners_path(@project.namespace, @project), title: 'Runners' do
+ %span
+ Runners
+ = nav_link(controller: :variables) do
+ = link_to namespace_project_variables_path(@project.namespace, @project), title: 'Variables' do
+ %span
+ Variables
+ = nav_link(controller: :triggers) do
+ = link_to namespace_project_triggers_path(@project.namespace, @project), title: 'Triggers' do
+ %span
+ Triggers
+ = nav_link(controller: :badges) do
+ = link_to namespace_project_badges_path(@project.namespace, @project), title: 'Badges' do
+ %span
+ Badges
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index 6dfe7fbdae8..20d6cdf7246 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -1,7 +1,7 @@
- page_title @project.name_with_namespace
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
-- sidebar "project" unless sidebar
+- nav "project"
- content_for :scripts_body_top do
- project = @target_project || @project
diff --git a/app/views/layouts/project_settings.html.haml b/app/views/layouts/project_settings.html.haml
index 59ce38f67bb..4bc94bd132d 100644
--- a/app/views/layouts/project_settings.html.haml
+++ b/app/views/layouts/project_settings.html.haml
@@ -1,5 +1,4 @@
- page_title "Settings"
-- header_title project_title(@project, "Settings", edit_project_path(@project))
-- sidebar "project_settings"
+- nav "project"
= render template: "layouts/project"
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 9b5de17dd3b..57c3d1b0a65 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -1,59 +1,37 @@
- empty_repo = @project.empty_repo?
.project-home-panel.cover-block.clearfix{:class => ("empty-project" if empty_repo)}
- .project-identicon-holder
- = project_icon(@project, alt: '', class: 'project-avatar avatar s90')
- .cover-title.project-home-desc
- %h1
- = @project.name
- %span.visibility-icon.has-tooltip{data: { container: 'body' }, title: visibility_icon_description(@project)}
- = visibility_level_icon(@project.visibility_level, fw: false)
-
- - if @project.description.present?
- .cover-desc.project-home-desc
- = markdown(@project.description, pipeline: :description)
-
- - if forked_from_project = @project.forked_from_project
- .cover-desc
- Forked from
- = link_to project_path(forked_from_project) do
- = forked_from_project.namespace.try(:name)
-
- .cover-controls
- - if current_user
- = link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), class: 'btn btn-gray' do
- = icon('rss')
- - access = user_max_access_in_project(current_user.id, @project)
- - can_edit = can?(current_user, :admin_project, @project)
- - if access || can_edit
- %span.dropdown.project-settings-dropdown
- %a.dropdown-new.btn.btn-gray#project-settings-button{href: '#', 'data-toggle' => 'dropdown'}
- = icon('cog')
- = icon('angle-down')
- %ul.dropdown-menu.dropdown-menu-right
- - if can_edit
- %li
- = link_to edit_project_path(@project) do
- Edit Project
- - if access
- %li
- = link_to leave_namespace_project_project_members_path(@project.namespace, @project),
- data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
- Leave Project
-
- .project-repo-buttons
- .split-one.count-buttons
- = render 'projects/buttons/star'
- = render 'projects/buttons/fork'
-
- .clone-row
- .project-clone-holder
- = render "shared/clone_panel"
-
- .split-repo-buttons
- .btn-group.pull-left
- = render "projects/buttons/download"
- = render 'projects/buttons/dropdown'
-
+ .container-fluid.container-limited
+ .row
+ .project-image-container
+ = project_icon(@project, alt: '', class: 'project-avatar avatar s70')
+ .project-info
+ .cover-title.project-home-desc
+ %h1
+ = @project.name
+ %span.visibility-icon.has-tooltip{data: { container: 'body' }, title: visibility_icon_description(@project)}
+ = visibility_level_icon(@project.visibility_level, fw: false)
+
+ - if @project.description.present?
+ .cover-desc.project-home-desc
+ = markdown(@project.description, pipeline: :description)
+
+ - if forked_from_project = @project.forked_from_project
+ .cover-desc
+ Forked from
+ = link_to project_path(forked_from_project) do
+ = forked_from_project.namespace.try(:name)
+
+ .project-repo-buttons
+ .count-buttons
+ = render 'projects/buttons/star'
+ = render 'projects/buttons/fork'
+
+ .project-clone-holder
+ = render "shared/clone_panel"
+
+ .project-repo-buttons.btn-group.project-right-buttons
+ = render "projects/buttons/download"
+ = render 'projects/buttons/dropdown'
= render 'projects/buttons/notifications'
:javascript
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index 1e4c46fca2f..16b8e1cca91 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -2,7 +2,7 @@
.btn-group
%a.btn.dropdown-toggle{href: '#', "data-toggle" => "dropdown"}
= icon('plus')
- %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
+ %ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
- can_create_issue = can?(current_user, :create_issue, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- can_create_snippet = can?(current_user, :create_snippet, @project)
diff --git a/app/views/projects/buttons/_fork.html.haml b/app/views/projects/buttons/_fork.html.haml
index 5fb5fe5af2f..34ad9fe2c43 100644
--- a/app/views/projects/buttons/_fork.html.haml
+++ b/app/views/projects/buttons/_fork.html.haml
@@ -12,7 +12,8 @@
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has-tooltip' do
= icon('code-fork fw')
Fork
- = link_to namespace_project_forks_path(@project.namespace, @project), class: 'count-with-arrow' do
+ %div.count-with-arrow
%span.arrow
%span.count
- = @project.forks_count
+ = link_to namespace_project_forks_path(@project.namespace, @project) do
+ = @project.forks_count
diff --git a/app/views/projects/buttons/_notifications.html.haml b/app/views/projects/buttons/_notifications.html.haml
index c1e3e5b73a2..1d05da50581 100644
--- a/app/views/projects/buttons/_notifications.html.haml
+++ b/app/views/projects/buttons/_notifications.html.haml
@@ -1,11 +1,11 @@
- if @notification_setting
= form_for @notification_setting, url: namespace_project_notification_setting_path(@project.namespace.becomes(Namespace), @project), method: :patch, remote: true, html: { class: 'inline', id: 'notification-form' } do |f|
= f.hidden_field :level
- %span.dropdown
+ .dropdown
%a.dropdown-new.btn.notifications-btn#notifications-button{href: '#', "data-toggle" => "dropdown"}
= icon('bell')
= notification_title(@notification_setting.level)
- = icon('angle-down')
- %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
+ = icon('caret-down')
+ %ul.dropdown-menu.dropdown-menu-align-right.project-home-dropdown
- NotificationSetting.levels.each do |level|
= notification_list_item(level.first, @notification_setting)
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index 962b9fb2595..e23a3782c6b 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -42,18 +42,18 @@
%td
= build.name
- .pull-right
- .label-container
- - if build.tags.any?
- - build.tags.each do |tag|
- %span.label.label-primary
- = tag
- - if build.try(:trigger_request)
- %span.label.label-info triggered
- - if build.try(:allow_failure)
- %span.label.label-danger allowed to fail
- - if defined?(retried) && retried
- %span.label.label-warning retried
+ %td
+ .label-container
+ - if build.tags.any?
+ - build.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - if build.try(:trigger_request)
+ %span.label.label-info triggered
+ - if build.try(:allow_failure)
+ %span.label.label-danger allowed to fail
+ - if defined?(retried) && retried
+ %span.label.label-warning retried
%td.duration
- if build.duration
diff --git a/app/views/projects/commit/_ci_commit.html.haml b/app/views/projects/commit/_ci_commit.html.haml
index 8228c067be0..ce5c550b441 100644
--- a/app/views/projects/commit/_ci_commit.html.haml
+++ b/app/views/projects/commit/_ci_commit.html.haml
@@ -37,5 +37,16 @@
.table-holder
%table.table.builds
+ %thead
+ %tr
+ %th Status
+ %th Build ID
+ %th Name
+ %th Tags
+ %th Duration
+ %th Finished at
+ - if @project.build_coverage_enabled?
+ %th Coverage
+ %th
- ci_commit.statuses.stages.each do |stage|
= render 'projects/commit/ci_stage', stage: stage, statuses: ci_commit.statuses.where(stage: stage)
diff --git a/app/views/projects/container_registry/index.html.haml b/app/views/projects/container_registry/index.html.haml
index 40957993b22..e1e762410f2 100644
--- a/app/views/projects/container_registry/index.html.haml
+++ b/app/views/projects/container_registry/index.html.haml
@@ -4,7 +4,7 @@
%hr
%ul.content-list
- .light.prepend-top-default
+ %li.light.prepend-top-default
%p
A 'container image' is a snapshot of a container.
You can host your container images with GitLab.
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 74feb9e3282..a19c7c406a0 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -13,50 +13,50 @@
= render "home_panel"
.project-stats.row-content-block.second-block
- %ul.nav
- %li
- = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
- = pluralize(number_with_delimiter(@project.commit_count), 'commit')
- %li
- = link_to namespace_project_branches_path(@project.namespace, @project) do
- = pluralize(number_with_delimiter(@repository.branch_names.count), 'branch')
- %li
- = link_to namespace_project_tags_path(@project.namespace, @project) do
- = pluralize(number_with_delimiter(@repository.tag_names.count), 'tag')
-
- %li
- = link_to project_files_path(@project) do
- = repository_size
-
- - if default_project_view != 'readme' && @repository.readme
+ .container-fluid.container-limited
+ %ul.nav
%li
- = link_to 'Readme', readme_path(@project)
-
- - if @repository.changelog
+ = link_to project_files_path(@project) do
+ Files (#{repository_size})
%li
- = link_to 'Changelog', changelog_path(@project)
-
- - if @repository.license_blob
+ = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
+ #{'Commit'.pluralize(@project.commit_count)} (#{number_with_delimiter(@project.commit_count)})
%li
- = link_to license_short_name(@project), license_path(@project)
-
- - if @repository.contribution_guide
+ = link_to namespace_project_branches_path(@project.namespace, @project) do
+ #{'Branch'.pluralize(@repository.branch_names.count)} (#{number_with_delimiter(@repository.branch_names.count)})
%li
- = link_to 'Contribution guide', contribution_guide_path(@project)
+ = link_to namespace_project_tags_path(@project.namespace, @project) do
+ #{'Tag'.pluralize(@repository.tag_names.count)} (#{number_with_delimiter(@repository.tag_names.count)})
+
+ - if default_project_view != 'readme' && @repository.readme
+ %li
+ = link_to 'Readme', readme_path(@project)
+
+ - if @repository.changelog
+ %li
+ = link_to 'Changelog', changelog_path(@project)
+
+ - if @repository.license_blob
+ %li
+ = link_to license_short_name(@project), license_path(@project)
+
+ - if @repository.contribution_guide
+ %li
+ = link_to 'Contribution guide', contribution_guide_path(@project)
- - if current_user && can_push_branch?(@project, @project.default_branch)
- - unless @repository.changelog
- %li.missing
- = link_to add_special_file_path(@project, file_name: 'CHANGELOG') do
- Add Changelog
- - unless @repository.license_blob
- %li.missing
- = link_to add_special_file_path(@project, file_name: 'LICENSE') do
- Add License
- - unless @repository.contribution_guide
- %li.missing
- = link_to add_special_file_path(@project, file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide') do
- Add Contribution guide
+ - if current_user && can_push_branch?(@project, @project.default_branch)
+ - unless @repository.changelog
+ %li.missing
+ = link_to add_special_file_path(@project, file_name: 'CHANGELOG') do
+ Add Changelog
+ - unless @repository.license_blob
+ %li.missing
+ = link_to add_special_file_path(@project, file_name: 'LICENSE') do
+ Add License
+ - unless @repository.contribution_guide
+ %li.missing
+ = link_to add_special_file_path(@project, file_name: 'CONTRIBUTING.md', commit_message: 'Add contribution guide') do
+ Add Contribution guide
- if @repository.commit
.content-block.second-block.white
diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml
index 974751d9970..84b3f44c0ad 100644
--- a/app/views/shared/_clone_panel.html.haml
+++ b/app/views/shared/_clone_panel.html.haml
@@ -5,7 +5,7 @@
%a#clone-dropdown.clone-dropdown-btn.btn{href: '#', 'data-toggle' => 'dropdown'}
%span
= default_clone_protocol.upcase
- = icon('angle-down')
+ = icon('caret-down')
%ul.dropdown-menu.dropdown-menu-right.clone-options-dropdown
%li
= ssh_clone_button(project)
diff --git a/app/views/shared/groups/_list.html.haml b/app/views/shared/groups/_list.html.haml
index 1aa7ed1f2eb..427595c47a5 100644
--- a/app/views/shared/groups/_list.html.haml
+++ b/app/views/shared/groups/_list.html.haml
@@ -3,4 +3,4 @@
- groups.each_with_index do |group, i|
= render "shared/groups/group", group: group
- else
- %h3 No groups found
+ .nothing-here-block No groups found
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 1181edec3f9..fc3410f425d 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -44,45 +44,53 @@
This issue is confidential and should only be visible to team members
- if can?(current_user, :"admin_#{issuable.to_ability_name}", issuable.project)
+ - has_due_date = issuable.has_attribute?(:due_date)
%hr
- .form-group
- .issue-assignee
- = f.label :assignee_id, "Assignee", class: 'control-label'
- .col-sm-10
- .issuable-form-select-holder
- = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
- placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
- selected: issuable.assignee_id, project: @target_project || @project,
- first_user: true, current_user: true, include_blank: true)
- &nbsp;
- = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
- .form-group
- .issue-milestone
- = f.label :milestone_id, "Milestone", class: 'control-label'
- .col-sm-10
- - if milestone_options(issuable).present?
+ .row
+ %div{ class: (has_due_date ? "col-lg-6" : "col-sm-12") }
+ .form-group.issue-assignee
+ = f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}"
+ .col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder
- = f.select(:milestone_id, milestone_options(issuable),
- { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
- - else
- .prepend-top-10
- %span.light No open milestones available.
- &nbsp;
- - if can? current_user, :admin_milestone, issuable.project
- = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
- .form-group
- - has_labels = issuable.project.labels.any?
- = f.label :label_ids, "Labels", class: 'control-label'
- .col-sm-10{ class: ('issuable-form-padding-top' if !has_labels) }
- - if has_labels
- .issuable-form-select-holder
- = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
- { selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
- - else
- %span.light No labels yet.
- &nbsp;
- - if can? current_user, :admin_label, issuable.project
- = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
+ = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
+ placeholder: 'Select assignee', class: 'custom-form-control', null_user: true,
+ selected: issuable.assignee_id, project: @target_project || @project,
+ first_user: true, current_user: true, include_blank: true)
+ %div
+ = link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline'
+ .form-group.issue-milestone
+ = f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}"
+ .col-sm-10{ class: ("col-lg-8" if has_due_date) }
+ - if milestone_options(issuable).present?
+ .issuable-form-select-holder
+ = f.select(:milestone_id, milestone_options(issuable),
+ { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
+ - else
+ .prepend-top-10
+ %span.light No open milestones available.
+ - if can? current_user, :admin_milestone, issuable.project
+ %div
+ = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
+ .form-group
+ - has_labels = issuable.project.labels.any?
+ = f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}"
+ .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
+ - if has_labels
+ .issuable-form-select-holder
+ = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
+ { selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
+ - else
+ %span.light No labels yet.
+ - if can? current_user, :admin_label, issuable.project
+ %div
+ = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
+ - if has_due_date
+ .col-lg-6
+ .form-group
+ = f.label :due_date, "Due date", class: "control-label"
+ = f.hidden_field :due_date, id: "issuable-due-date"
+ .col-sm-10
+ .datepicker
- if issuable.can_move?(current_user)
%hr
diff --git a/app/views/shared/issuable/_sidebar.html.haml b/app/views/shared/issuable/_sidebar.html.haml
index ed1b8a8da2a..c1eec450193 100644
--- a/app/views/shared/issuable/_sidebar.html.haml
+++ b/app/views/shared/issuable/_sidebar.html.haml
@@ -87,10 +87,16 @@
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
= link_to 'Edit', '#', class: 'edit-link pull-right'
.value.bold.hide-collapsed
- - if issuable.due_date
- = issuable.due_date.to_s(:medium)
- - else
- .light None
+ %span.value-content
+ - if issuable.due_date
+ = issuable.due_date.to_s(:medium)
+ - else
+ None
+ - if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
+ %span.light.js-remove-due-date-holder{ class: ("hidden" if issuable.due_date.nil?) }
+ \-
+ %a.js-remove-due-date{ href: "#", role: "button" }
+ remove due date
- if can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.selectbox.hide-collapsed
= f.hidden_field :due_date, value: issuable.due_date
diff --git a/app/views/shared/milestones/_participants_tab.html.haml b/app/views/shared/milestones/_participants_tab.html.haml
index 67ae85ac276..549d2e2f61e 100644
--- a/app/views/shared/milestones/_participants_tab.html.haml
+++ b/app/views/shared/milestones/_participants_tab.html.haml
@@ -3,6 +3,6 @@
%li
= link_to user, title: user.name, class: "darken" do
= image_tag avatar_icon(user, 32), class: "avatar s32"
- %strong= truncate(user.name, lenght: 40)
+ %strong= truncate(user.name, length: 40)
%br
%small.cgray= user.username
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 0cef2794f4e..0510e7df597 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -179,11 +179,11 @@ production: &base
registry:
# enabled: true
# host: registry.example.com
- # port: 5000
- # api_url: http://localhost:5000/
- # key: config/registry.key
- # issuer: omnibus-certificate
+ # port: 5005
+ # api_url: http://localhost:5000/ # internal address to the registry, will be used by GitLab to directly communicate with API
+ # key_path: config/registry.key
# path: shared/registry
+ # issuer: gitlab-issuer
#
# 2. GitLab CI settings
diff --git a/doc/README.md b/doc/README.md
index e358da1c424..d1345ab2493 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -13,6 +13,7 @@
- [Profile Settings](profile/README.md)
- [Project Services](project_services/project_services.md) Integrate a project with external services, such as CI and chat.
- [Public access](public_access/public_access.md) Learn how you can allow public and internal access to projects.
+- [Container Registry](container_registry/README.md) Learn how to use GitLab Container Registry.
- [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
- [Webhooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
- [Workflow](workflow/README.md) Using GitLab functionality and importing projects from GitHub and SVN.
@@ -41,8 +42,10 @@
- [Git LFS configuration](workflow/lfs/lfs_administration.md)
- [Housekeeping](administration/housekeeping.md) Keep your Git repository tidy and fast.
- [GitLab Performance Monitoring](monitoring/performance/introduction.md) Configure GitLab and InfluxDB for measuring performance metrics
+- [Monitoring uptime](monitoring/health_check.md) Check the server status using the health check endpoint
- [Sidekiq Troubleshooting](administration/troubleshooting/sidekiq.md) Debug when Sidekiq appears hung and is not processing jobs
- [High Availability](administration/high_availability/README.md) Configure multiple servers for scaling or high availability
+- [Container Registry](administration/container_registry.md) Configure Docker Registry with GitLab
## Contributor documentation
diff --git a/doc/administration/container_registry.md b/doc/administration/container_registry.md
new file mode 100644
index 00000000000..caf9a5bef2c
--- /dev/null
+++ b/doc/administration/container_registry.md
@@ -0,0 +1,375 @@
+# GitLab Container Registry Administration
+
+> **Note:**
+This feature was [introduced][ce-4040] in GitLab 8.8.
+
+With the Docker Container Registry integrated into GitLab, every project can
+have its own space to store its Docker images.
+
+You can read more about Docker Registry at https://docs.docker.com/registry/introduction/.
+
+---
+
+<!-- START doctoc generated TOC please keep comment here to allow auto update -->
+<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)*
+
+- [Enable the Container Registry](#enable-the-container-registry)
+- [Container Registry domain configuration](#container-registry-domain-configuration)
+ - [Configure Container Registry under an existing GitLab domain](#configure-container-registry-under-an-existing-gitlab-domain)
+ - [Configure Container Registry under its own domain](#configure-container-registry-under-its-own-domain)
+- [Disable Container Registry site-wide](#disable-container-registry-site-wide)
+- [Disable Container Registry per project](#disable-container-registry-per-project)
+- [Disable Container Registry for new projects site-wide](#disable-container-registry-for-new-projects-site-wide)
+- [Container Registry storage path](#container-registry-storage-path)
+- [Storage limitations](#storage-limitations)
+- [Changelog](#changelog)
+
+<!-- END doctoc generated TOC please keep comment here to allow auto update -->
+
+## Enable the Container Registry
+
+**Omnibus GitLab installations**
+
+All you have to do is configure the domain name under which the Container
+Registry will listen to. Read [#container-registry-domain-configuration](#container-registry-domain-configuration)
+and pick one of the two options that fits your case.
+
+>**Note:**
+The container Registry works under HTTPS by default. Using HTTP is possible
+but not recommended and out of the scope of this document.
+Read the [insecure Registry documentation][docker-insecure] if you want to
+implement this.
+
+---
+
+**Installations from source**
+
+If you have installed GitLab from source:
+
+1. You will have to [install Docker Registry][registry-deploy] by yourself.
+1. After the installation is complete, you will have to configure the Registry's
+ settings in `gitlab.yml` in order to enable it.
+1. Use the sample NGINX configuration file that is found under
+ [`lib/support/nginx/registry-ssl`][registry-ssl] and edit it to match the
+ `host`, `port` and TLS certs paths.
+
+The contents of `gitlab.yml` are:
+
+```
+registry:
+ enabled: true
+ host: registry.gitlab.example.com
+ port: 5005
+ api_url: http://localhost:5000/
+ key_path: config/registry.key
+ path: shared/registry
+ issuer: gitlab-issuer
+```
+
+where:
+
+| Parameter | Description |
+| --------- | ----------- |
+| `enabled` | `true` or `false`. Enables the Registry in GitLab. By default this is `false`. |
+| `host` | The host URL under which the Registry will run and the users will be able to use. |
+| `port` | The port under which the external Registry domain will listen on. |
+| `api_url` | The internal API URL under which the Registry is exposed to. It defaults to `http://localhost:5000`. |
+| `key_path`| The private key location that is a pair of Registry's `rootcertbundle`. Read the [token auth configuration documentation][token-config]. |
+| `path` | This should be the same directory like specified in Registry's `rootdirectory`. Read the [storage configuration documentation][storage-config]. This path needs to be readable by the GitLab user, the web-server user and the Registry user. Read more in [#container-registry-storage-path](#container-registry-storage-path). |
+| `issuer` | This should be the same value as configured in Registry's `issuer`. Read the [token auth configuration documentation][token-config]. |
+
+>**Note:**
+GitLab does not ship with a Registry init file. Hence, [restarting GitLab][restart gitlab]
+will not restart the Registry should you modify its settings. Read the upstream
+documentation on how to achieve that.
+
+## Container Registry domain configuration
+
+There are two ways you can configure the Registry's external domain.
+
+- Either [use the existing GitLab domain][existing-domain] where in that case
+ the Registry will have to listen on a port and reuse GitLab's TLS certificate,
+- or [use a completely separate domain][new-domain] with a new TLS certificate
+ for that domain.
+
+Since the container Registry requires a TLS certificate, in the end it all boils
+down to how easy or pricey is to get a new one.
+
+Please take this into consideration before configuring the Container Registry
+for the first time.
+
+### Configure Container Registry under an existing GitLab domain
+
+If the Registry is configured to use the existing GitLab domain, you can
+expose the Registry on a port so that you can reuse the existing GitLab TLS
+certificate.
+
+Assuming that the GitLab domain is `https://gitlab.example.com` and the port the
+Registry is exposed to the outside world is `4567`, here is what you need to set
+in `gitlab.rb` or `gitlab.yml` if you are using Omnibus GitLab or installed
+GitLab from source respectively.
+
+---
+
+**Omnibus GitLab installations**
+
+1. Your `/etc/gitlab/gitlab.rb` should contain the Registry URL as well as the
+ path to the existing TLS certificate and key used by GitLab:
+
+ ```ruby
+ registry_external_url 'https://gitlab.example.com:4567'
+ ```
+
+ Note how the `registry_external_url` is listening on HTTPS under the
+ existing GitLab URL, but on a different port.
+
+ If your TLS certificate is not in `/etc/gitlab/ssl/gitlab.example.com.crt`
+ and key not in `/etc/gitlab/ssl/gitlab.example.com.key` uncomment the lines
+ below:
+
+ ```ruby
+ registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
+ registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ configure it with the following settings:
+
+ ```
+ registry:
+ enabled: true
+ host: gitlab.example.com
+ port: 4567
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
+
+---
+
+Users should now be able to login to the Container Registry with their GitLab
+credentials using:
+
+```bash
+docker login gitlab.example.com:4567
+```
+
+### Configure Container Registry under its own domain
+
+If the Registry is configured to use its own domain, you will need a TLS
+certificate for that specific domain (e.g., `registry.example.com`) or maybe
+a wildcard certificate if hosted under a subdomain of your existing GitLab
+domain (e.g., `registry.gitlab.example.com`).
+
+Let's assume that you want the container Registry to be accessible at
+`https://registry.gitlab.example.com`.
+
+---
+
+**Omnibus GitLab installations**
+
+1. Place your TLS certificate and key in
+ `/etc/gitlab/ssl/registry.gitlab.example.com.crt` and
+ `/etc/gitlab/ssl/registry.gitlab.example.com.key` and make sure they have
+ correct permissions:
+
+ ```bash
+ chmod 600 /etc/gitlab/ssl/registry.gitlab.example.com.*
+ ```
+
+1. Once the TLS certificate is in place, edit `/etc/gitlab/gitlab.rb` with:
+
+ ```ruby
+ registry_external_url 'https://registry.gitlab.example.com'
+ ```
+
+ Note how the `registry_external_url` is listening on HTTPS.
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+> **Note:**
+If you have a [wildcard certificate][], you need to specify the path to the
+certificate in addition to the URL, in this case `/etc/gitlab/gitlab.rb` will
+look like:
+>
+```ruby
+registry_nginx['ssl_certificate'] = "/etc/gitlab/ssl/certificate.pem"
+registry_nginx['ssl_certificate_key'] = "/etc/gitlab/ssl/certificate.key"
+```
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ configure it with the following settings:
+
+ ```
+ registry:
+ enabled: true
+ host: registry.gitlab.example.com
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+1. Make the relevant changes in NGINX as well (domain, port, TLS certificates path).
+
+---
+
+Users should now be able to login to the Container Registry using their GitLab
+credentials:
+
+```bash
+docker login registry.gitlab.example.com
+```
+
+## Disable Container Registry site-wide
+
+>**Note:**
+Disabling the Registry in the Rails GitLab application as set by the following
+steps, will not remove any existing Docker images. This is handled by the
+Registry application itself.
+
+**Omnibus GitLab**
+
+1. Open `/etc/gitlab/gitlab.rb` and set `registry['enable']` to `false`:
+
+ ```ruby
+ registry['enable'] = false
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ set `enabled` to `false`:
+
+ ```
+ registry:
+ enabled: false
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Disable Container Registry per project
+
+If Registry is enabled in your GitLab instance, but you don't need it for your
+project, you can disable it from your project's settings. Read the user guide
+on how to achieve that.
+
+## Disable Container Registry for new projects site-wide
+
+If the Container Registry is enabled, then it will be available on all new
+projects. To disable this function and let the owners of a project to enable
+the Container Registry by themselves, follow the steps below.
+
+---
+
+**Omnibus GitLab installations**
+
+1. Edit `/etc/gitlab/gitlab.rb` and add the following line:
+
+ ```ruby
+ gitlab_rails['gitlab_default_projects_features_container_registry'] = false
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `default_projects_features`
+ entry and configure it so that `container_registry` is set to `false`:
+
+ ```
+ ## Default project features settings
+ default_projects_features:
+ issues: true
+ merge_requests: true
+ wiki: true
+ snippets: false
+ builds: true
+ container_registry: false
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Container Registry storage path
+
+To change the storage path where Docker images will be stored, follow the
+steps below.
+
+This path is accessible to:
+
+- the user running the Container Registry daemon,
+- the user running GitLab
+
+> **Warning** You should confirm that all GitLab, Registry and web server users
+have access to this directory.
+
+---
+
+**Omnibus GitLab installations**
+
+The default location where images are stored in Omnibus, is
+`/var/opt/gitlab/gitlab-rails/shared/registry`. To change it:
+
+1. Edit `/etc/gitlab/gitlab.rb`:
+
+ ```ruby
+ gitlab_rails['registry_path'] = "/path/to/registry/storage"
+ ```
+
+1. Save the file and [reconfigure GitLab][] for the changes to take effect.
+
+---
+
+**Installations from source**
+
+The default location where images are stored in source installations, is
+`/home/git/gitlab/shared/registry`. To change it:
+
+1. Open `/home/git/gitlab/config/gitlab.yml`, find the `registry` entry and
+ change the `path` setting:
+
+ ```
+ registry:
+ path: shared/registry
+ ```
+
+1. Save the file and [restart GitLab][] for the changes to take effect.
+
+## Storage limitations
+
+Currently, there is no storage limitation, which means a user can upload an
+infinite amount of Docker images with arbitrary sizes. This setting will be
+configurable in future releases.
+
+## Changelog
+
+**GitLab 8.8 ([source docs][8-8-docs])**
+
+- GitLab Container Registry feature was introduced.
+
+[reconfigure gitlab]: restart_gitlab.md#omnibus-gitlab-reconfigure
+[restart gitlab]: restart_gitlab.md#installations-from-source
+[wildcard certificate]: https://en.wikipedia.org/wiki/Wildcard_certificate
+[ce-4040]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4040
+[docker-insecure]: https://docs.docker.com/registry/insecure/
+[registry-deploy]: https://docs.docker.com/registry/deploying/
+[storage-config]: https://docs.docker.com/registry/configuration/#storage
+[token-config]: https://docs.docker.com/registry/configuration/#token
+[8-8-docs]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/doc/administration/container_registry.md
+[registry-ssl]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/support/nginx/registry-ssl
+[existing-domain]: #configure-container-registry-under-an-existing-gitlab-domain
+[new-domain]: #configure-container-registry-under-its-own-domain
diff --git a/doc/api/groups.md b/doc/api/groups.md
index 2821bc21b81..1ccb9715e96 100644
--- a/doc/api/groups.md
+++ b/doc/api/groups.md
@@ -265,7 +265,6 @@ GET /groups/:id/members
{
"id": 1,
"username": "raymond_smith",
- "email": "ray@smith.org",
"name": "Raymond Smith",
"state": "active",
"created_at": "2012-10-22T14:13:35Z",
@@ -274,7 +273,6 @@ GET /groups/:id/members
{
"id": 2,
"username": "john_doe",
- "email": "joh@doe.org",
"name": "John Doe",
"state": "active",
"created_at": "2012-10-22T14:13:35Z",
diff --git a/doc/container_registry/README.md b/doc/container_registry/README.md
new file mode 100644
index 00000000000..4df24ef13cc
--- /dev/null
+++ b/doc/container_registry/README.md
@@ -0,0 +1,113 @@
+# GitLab Container Registry
+
+> **Note:**
+This feature was [introduced][ce-4040] in GitLab 8.8.
+
+> **Note:**
+This document is about the user guide. To learn how to enable GitLab Container
+Registry across your GitLab instance, visit the
+[administrator documentation](../administration/container_registry.md).
+
+With the Docker Container Registry integrated into GitLab, every project can
+have its own space to store its Docker images.
+
+You can read more about Docker Registry at https://docs.docker.com/registry/introduction/.
+
+---
+
+## Enable the Container Registry for your project
+
+1. First, ask your system administrator to enable GitLab Container Registry
+ following the [administration documentation](../administration/container_registry.md).
+ If you are using GitLab.com, this is enabled by default so you can start using
+ the Registry immediately.
+
+1. Go to your project's settings and enable the **Container Registry** feature
+ on your project. For new projects this might be enabled by default. For
+ existing projects you will have to explicitly enable it.
+
+ ![Enable Container Registry](img/project_feature.png)
+
+## Build and push images
+
+After you save your project's settings, you should see a new link in the
+sidebar called **Container Registry**. Following this link will get you to
+your project's Registry panel where you can see how to login to the Container
+Registry using your GitLab credentials.
+
+For example if the Registry's URL is `registry.example.com`, the you should be
+able to login with:
+
+```
+docker login registry.example.com
+```
+
+Building and publishing images should be a straightforward process. Just make
+sure that you are using the Registry URL with the namespace and project name
+that is hosted on GitLab:
+
+```
+docker build -t registry.example.com/group/project .
+docker push registry.example.com/group/project
+```
+
+## Use images from GitLab Container Registry
+
+To download and run a container from images hosted in GitLab Container Registry,
+use `docker run`:
+
+```
+docker run [options] registry.example.com/group/project [arguments]
+```
+
+For more information on running Docker containers, visit the
+[Docker documentation][docker-docs].
+
+## Control Container Registry from within GitLab
+
+GitLab offers a simple Container Registry management panel. Go to your project
+and click **Container Registry** in the left sidebar.
+
+This view will show you all tags in your project and will easily allow you to
+delete them.
+
+![Container Registry panel](img/container_registry.png)
+
+## Build and push images using GitLab CI
+
+> **Note:**
+This feature requires GitLab 8.8 and GitLab Runner 1.2.
+
+Make sure that your GitLab Runner is configured to allow building docker images.
+You have to check the [Using Docker Build documentation](../../ci/docker/using_docker_build.md).
+
+You can use [docker:dind](https://hub.docker.com/_/docker/) to build your images,
+and this is how `.gitlab-ci.yml` should look like:
+
+```
+ build_image:
+ image: docker:git
+ services:
+ - docker:dind
+ stage: build
+ script:
+ - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN registry.example.com
+ - docker build -t registry.example.com/group/project:latest .
+ - docker push registry.example.com/group/project:latest
+```
+
+You have to use the credentials of the special `gitlab-ci-token` user with its
+password stored in `$CI_BUILD_TOKEN` in order to push to the Registry connected
+to your project. This allows you to automated building and deployment of your
+Docker images.
+
+## Limitations
+
+In order to use a container image from your private project as an `image:` in
+your `.gitlab-ci.yml`, you have to follow the
+[Using a private Docker Registry][private-docker]
+documentation. This workflow will be simplified in the future.
+
+[ce-4040]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/4040
+[docker-docs]: https://docs.docker.com/engine/userguide/intro/
+[private-docker]: https://gitlab.com/gitlab-org/gitlab-ci-multi-runner/blob/master/docs/configuration/advanced-configuration.md#using-a-private-docker-registry
diff --git a/doc/container_registry/img/container_registry.png b/doc/container_registry/img/container_registry.png
new file mode 100644
index 00000000000..e9505a73b40
--- /dev/null
+++ b/doc/container_registry/img/container_registry.png
Binary files differ
diff --git a/doc/container_registry/img/project_feature.png b/doc/container_registry/img/project_feature.png
new file mode 100644
index 00000000000..57a73d253c0
--- /dev/null
+++ b/doc/container_registry/img/project_feature.png
Binary files differ
diff --git a/doc/install/installation.md b/doc/install/installation.md
index fa11eb9ba6a..526f127178d 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -394,7 +394,7 @@ GitLab Shell is an SSH access and repository management software developed speci
cd /home/git
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-workhorse.git
cd gitlab-workhorse
- sudo -u git -H git checkout v0.7.1
+ sudo -u git -H git checkout v0.7.3
sudo -u git -H make
### Initialize Database and Activate Advanced Features
diff --git a/doc/monitoring/health_check.md b/doc/monitoring/health_check.md
new file mode 100644
index 00000000000..defbf37ac19
--- /dev/null
+++ b/doc/monitoring/health_check.md
@@ -0,0 +1,66 @@
+# Health Check
+
+>**Note:** This feature was [introduced][ce-3888] in GitLab 8.8.
+
+GitLab provides a health check endpoint for uptime monitoring on the `health_check` web
+endpoint. The health check reports on the overall system status based on the status of
+the database connection, the state of the database migrations, and the ability to write
+and access the cache. This endpoint can be provided to uptime monitoring services like
+[Pingdom][pingdom], [Nagios][nagios-health], and [NewRelic][newrelic-health].
+
+## Access Token
+
+An access token needs to be provided while accessing the health check endpoint. The current
+accepted token can be found on the `admin/heath_check` page of your GitLab instance.
+
+![access token](img/health_check_token.png)
+
+The access token can be passed as a URL parameter:
+
+```
+https://gitlab.example.com/health_check.json?token=ACCESS_TOKEN
+```
+
+or as an HTTP header:
+
+```bash
+curl -H "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
+```
+
+## Using the Endpoint
+
+Once you have the access token, health information can be retrieved as plain text, JSON,
+or XML using the `health_check` endpoint:
+
+- `https://gitlab.example.com/health_check?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check.json?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check.xml?token=ACCESS_TOKEN`
+
+You can also ask for the status of specific services:
+
+- `https://gitlab.example.com/health_check/cache.json?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check/database.json?token=ACCESS_TOKEN`
+- `https://gitlab.example.com/health_check/migrations.json?token=ACCESS_TOKEN`
+
+For example, the JSON output of the following health check:
+
+```bash
+curl -H "TOKEN: ACCESS_TOKEN" https://gitlab.example.com/health_check.json
+```
+
+would be like:
+
+```
+{"healthy":true,"message":"success"}
+```
+
+## Status
+
+On failure, the endpoint will return a `500` HTTP status code. On success, the endpoint
+will return a valid successful HTTP status code, and a `success` message. Ideally your
+uptime monitoring should look for the success message.
+
+[ce-3888]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3888
+[pingdom]: https://www.pingdom.com
+[nagios-health]: https://nagios-plugins.org/doc/man/check_http.html
+[newrelic-health]: https://docs.newrelic.com/docs/alerts/alert-policies/downtime-alerts/availability-monitoring
diff --git a/doc/monitoring/img/health_check_token.png b/doc/monitoring/img/health_check_token.png
new file mode 100644
index 00000000000..2daf8606b00
--- /dev/null
+++ b/doc/monitoring/img/health_check_token.png
Binary files differ
diff --git a/features/project/active_tab.feature b/features/project/active_tab.feature
index 2fd097d100b..5125a3e5773 100644
--- a/features/project/active_tab.feature
+++ b/features/project/active_tab.feature
@@ -30,11 +30,6 @@ Feature: Project Active Tab
Then the active main tab should be Merge Requests
And no other main tabs should be active
- Scenario: On Project Members
- Given I visit my project's members page
- Then the active main tab should be Members
- And no other main tabs should be active
-
Scenario: On Project Wiki
Given I visit my project's wiki page
Then the active main tab should be Wiki
@@ -49,13 +44,6 @@ Feature: Project Active Tab
# Sub Tabs: Settings
- Scenario: On Project Settings/Edit
- Given I visit my project's settings page
- And I click the "Edit" tab
- Then the active sub nav should be Edit
- And no other sub navs should be active
- And the active main tab should be Settings
-
Scenario: On Project Settings/Hooks
Given I visit my project's settings page
And I click the "Hooks" tab
@@ -70,6 +58,12 @@ Feature: Project Active Tab
And no other sub navs should be active
And the active main tab should be Settings
+ Scenario: On Project Members
+ Given I visit my project's members page
+ Then the active sub nav should be Members
+ And no other sub navs should be active
+ And the active main tab should be Settings
+
# Sub Tabs: Commits
Scenario: On Project Commits/Commits
diff --git a/features/project/project.feature b/features/project/project.feature
index f1f3ed26065..aa22401c88e 100644
--- a/features/project/project.feature
+++ b/features/project/project.feature
@@ -18,15 +18,6 @@ Feature: Project
Then I should see the default project avatar
And I should not see the "Remove avatar" button
- Scenario: I should have back to group button
- And project "Shop" belongs to group
- And I visit project "Shop" page
- Then I should see back to group button
-
- Scenario: I should have back to group button
- And I visit project "Shop" page
- Then I should see back to dashboard button
-
Scenario: I should have readme on page
And I visit project "Shop" page
Then I should see project "Shop" README
diff --git a/features/steps/admin/active_tab.rb b/features/steps/admin/active_tab.rb
index 90d13abdb13..f2db1801389 100644
--- a/features/steps/admin/active_tab.rb
+++ b/features/steps/admin/active_tab.rb
@@ -1,7 +1,7 @@
class Spinach::Features::AdminActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
- include SharedActiveTab
+ include SharedSidebarActiveTab
step 'the active main tab should be Home' do
ensure_active_main_tab('Overview')
@@ -34,4 +34,12 @@ class Spinach::Features::AdminActiveTab < Spinach::FeatureSteps
step 'the active main tab should be Messages' do
ensure_active_main_tab('Messages')
end
+
+ step 'no other main tabs should be active' do
+ expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
+ end
+
+ def ensure_active_main_tab(content)
+ expect(find('.nav-sidebar > li.active')).to have_content(content)
+ end
end
diff --git a/features/steps/dashboard/active_tab.rb b/features/steps/dashboard/active_tab.rb
index 0e2c04fb299..04fe96cef22 100644
--- a/features/steps/dashboard/active_tab.rb
+++ b/features/steps/dashboard/active_tab.rb
@@ -1,9 +1,5 @@
class Spinach::Features::DashboardActiveTab < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
- include SharedActiveTab
-
- step 'the active main tab should be Help' do
- ensure_active_main_tab('Help')
- end
+ include SharedSidebarActiveTab
end
diff --git a/features/steps/dashboard/shortcuts.rb b/features/steps/dashboard/shortcuts.rb
index a9083850b52..118d27888df 100644
--- a/features/steps/dashboard/shortcuts.rb
+++ b/features/steps/dashboard/shortcuts.rb
@@ -2,5 +2,6 @@ class Spinach::Features::DashboardShortcuts < Spinach::FeatureSteps
include SharedAuthentication
include SharedPaths
include SharedProject
- include SharedActiveTab
+ include SharedSidebarActiveTab
+ include SharedShortcuts
end
diff --git a/features/steps/profile/active_tab.rb b/features/steps/profile/active_tab.rb
index 3b59089a093..4724a326277 100644
--- a/features/steps/profile/active_tab.rb
+++ b/features/steps/profile/active_tab.rb
@@ -22,8 +22,4 @@ class Spinach::Features::ProfileActiveTab < Spinach::FeatureSteps
step 'the active main tab should be Audit Log' do
ensure_active_main_tab('Audit Log')
end
-
- def ensure_active_main_tab(content)
- expect(find('.layout-nav li.active')).to have_content(content)
- end
end
diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb
index 19d81453d8c..4a5a71e7e61 100644
--- a/features/steps/project/active_tab.rb
+++ b/features/steps/project/active_tab.rb
@@ -16,12 +16,14 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
end
step 'I click the "Snippets" tab' do
- click_link('Snippets')
+ page.within('.layout-nav') do
+ click_link('Snippets')
+ end
end
- step 'I click the "Edit" tab' do
- page.within '.sidebar-subnav' do
- click_link('Project Settings')
+ step 'I click the "Edit Project"' do
+ page.within '.layout-nav .controls' do
+ click_link('Edit Project')
end
end
@@ -33,14 +35,10 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
click_link('Deploy Keys')
end
- step 'the active sub nav should be Team' do
+ step 'the active sub nav should be Members' do
ensure_active_sub_nav('Members')
end
- step 'the active sub nav should be Edit' do
- ensure_active_sub_nav('Project')
- end
-
step 'the active sub nav should be Hooks' do
ensure_active_sub_nav('Webhooks')
end
@@ -56,7 +54,9 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
end
step 'I click the "Branches" tab' do
- click_link('Branches')
+ page.within '.content' do
+ click_link('Branches')
+ end
end
step 'I click the "Tags" tab' do
@@ -82,11 +82,15 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
# Sub Tabs: Issues
step 'I click the "Milestones" tab' do
- click_link('Milestones')
+ page.within('.layout-nav') do
+ click_link('Milestones')
+ end
end
step 'I click the "Labels" tab' do
- click_link('Labels')
+ page.within('.layout-nav') do
+ click_link('Labels')
+ end
end
step 'the active sub tab should be Issues' do
diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb
index 527f7853da9..8abeb5ee242 100644
--- a/features/steps/project/fork.rb
+++ b/features/steps/project/fork.rb
@@ -36,7 +36,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
end
step 'I goto the Merge Requests page' do
- page.within '.page-sidebar-expanded' do
+ page.within '.layout-nav' do
click_link "Merge Requests"
end
end
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index ef185861e00..a1785311c2b 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -114,7 +114,9 @@ class Spinach::Features::Project < Spinach::FeatureSteps
end
step 'I should not see "Snippets" button' do
- expect(page).not_to have_link 'Snippets'
+ page.within '.content' do
+ expect(page).not_to have_link 'Snippets'
+ end
end
step 'project "Shop" belongs to group' do
@@ -123,14 +125,6 @@ class Spinach::Features::Project < Spinach::FeatureSteps
@project.save!
end
- step 'I should see back to dashboard button' do
- expect(page).to have_content 'Go to dashboard'
- end
-
- step 'I should see back to group button' do
- expect(page).to have_content 'Go to group'
- end
-
step 'I click notifications drop down button' do
click_link 'notifications-button'
end
diff --git a/features/steps/project/project_milestone.rb b/features/steps/project/project_milestone.rb
index 2508c09e36d..1864b3a2b52 100644
--- a/features/steps/project/project_milestone.rb
+++ b/features/steps/project/project_milestone.rb
@@ -52,7 +52,7 @@ class Spinach::Features::ProjectMilestone < Spinach::FeatureSteps
end
step 'I click link "Labels"' do
- page.within('.nav-links') do
+ page.within('.layout-nav .nav-links') do
page.find(:xpath, "//a[@href='#tab-labels']").click
end
end
diff --git a/features/steps/project/project_shortcuts.rb b/features/steps/project/project_shortcuts.rb
index 49e9c5520bb..8143b01ca40 100644
--- a/features/steps/project/project_shortcuts.rb
+++ b/features/steps/project/project_shortcuts.rb
@@ -3,6 +3,7 @@ class Spinach::Features::ProjectShortcuts < Spinach::FeatureSteps
include SharedPaths
include SharedProject
include SharedProjectTab
+ include SharedShortcuts
step 'I press "g" and "f"' do
find('body').native.send_key('g')
diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb
index c26d7a15212..2c0498de3b9 100644
--- a/features/steps/project/source/browse_files.rb
+++ b/features/steps/project/source/browse_files.rb
@@ -337,13 +337,15 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
end
step 'I should see buttons for allowed commands' do
- expect(page).to have_content 'Raw'
- expect(page).to have_content 'History'
- expect(page).to have_content 'Permalink'
- expect(page).not_to have_content 'Edit'
- expect(page).not_to have_content 'Blame'
- expect(page).to have_content 'Delete'
- expect(page).to have_content 'Replace'
+ page.within '.content' do
+ expect(page).to have_content 'Raw'
+ expect(page).to have_content 'History'
+ expect(page).to have_content 'Permalink'
+ expect(page).not_to have_content 'Edit'
+ expect(page).not_to have_content 'Blame'
+ expect(page).to have_content 'Delete'
+ expect(page).to have_content 'Replace'
+ end
end
step 'I should see a notice about a new fork having been created' do
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
index 0bee91d758d..ace717b9909 100644
--- a/features/steps/shared/active_tab.rb
+++ b/features/steps/shared/active_tab.rb
@@ -2,7 +2,7 @@ module SharedActiveTab
include Spinach::DSL
def ensure_active_main_tab(content)
- expect(find('.nav-sidebar > li.active')).to have_content(content)
+ expect(find('.layout-nav li.active')).to have_content(content)
end
def ensure_active_sub_tab(content)
@@ -10,11 +10,11 @@ module SharedActiveTab
end
def ensure_active_sub_nav(content)
- expect(find('.sidebar-subnav > li.active')).to have_content(content)
+ expect(find('.layout-nav .controls li.active')).to have_content(content)
end
step 'no other main tabs should be active' do
- expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
+ expect(page).to have_selector('.layout-nav .nav-links > li.active', count: 1)
end
step 'no other sub tabs should be active' do
@@ -22,26 +22,6 @@ module SharedActiveTab
end
step 'no other sub navs should be active' do
- expect(page).to have_selector('.sidebar-subnav > li.active', count: 1)
- end
-
- step 'the active main tab should be Home' do
- ensure_active_main_tab('Projects')
- end
-
- step 'the active main tab should be Projects' do
- ensure_active_main_tab('Projects')
- end
-
- step 'the active main tab should be Issues' do
- ensure_active_main_tab('Issues')
- end
-
- step 'the active main tab should be Merge Requests' do
- ensure_active_main_tab('Merge Requests')
- end
-
- step 'the active main tab should be Help' do
- ensure_active_main_tab('Help')
+ expect(page).to have_selector('.layout-nav .controls li.active', count: 1)
end
end
diff --git a/features/steps/shared/issuable.rb b/features/steps/shared/issuable.rb
index a58b3cb7e16..733e80b7279 100644
--- a/features/steps/shared/issuable.rb
+++ b/features/steps/shared/issuable.rb
@@ -111,7 +111,7 @@ module SharedIssuable
step 'I sort the list by "Oldest updated"' do
find('button.dropdown-toggle.btn').click
- page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
+ page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link "Oldest updated"
end
end
@@ -119,7 +119,7 @@ module SharedIssuable
step 'I sort the list by "Least popular"' do
find('button.dropdown-toggle.btn').click
- page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
+ page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link 'Least popular'
end
end
@@ -127,13 +127,13 @@ module SharedIssuable
step 'I sort the list by "Most popular"' do
find('button.dropdown-toggle.btn').click
- page.within('ul.dropdown-menu.dropdown-menu-align-right li') do
+ page.within('.content ul.dropdown-menu.dropdown-menu-align-right li') do
click_link 'Most popular'
end
end
step 'The list should be sorted by "Oldest updated"' do
- page.within('div.dropdown.inline.prepend-left-10') do
+ page.within('.content div.dropdown.inline.prepend-left-10') do
expect(page.find('button.dropdown-toggle.btn')).to have_content('Oldest updated')
end
end
diff --git a/features/steps/shared/project_tab.rb b/features/steps/shared/project_tab.rb
index 4fc2ece79ff..b209020c5a9 100644
--- a/features/steps/shared/project_tab.rb
+++ b/features/steps/shared/project_tab.rb
@@ -41,9 +41,7 @@ module SharedProjectTab
end
step 'the active main tab should be Settings' do
- page.within '.nav-sidebar' do
- expect(page).to have_content('Go to project')
- end
+ expect(page).to have_selector('.layout-nav .nav-links > li.active', count: 0)
end
step 'the active main tab should be Activity' do
diff --git a/features/steps/shared/shortcuts.rb b/features/steps/shared/shortcuts.rb
index bbb7afec0ad..a75a8474d26 100644
--- a/features/steps/shared/shortcuts.rb
+++ b/features/steps/shared/shortcuts.rb
@@ -1,4 +1,4 @@
-module SharedActiveTab
+module SharedShortcuts
include Spinach::DSL
step 'I press "g" and "p"' do
diff --git a/features/steps/shared/sidebar_active_tab.rb b/features/steps/shared/sidebar_active_tab.rb
new file mode 100644
index 00000000000..5c47238777f
--- /dev/null
+++ b/features/steps/shared/sidebar_active_tab.rb
@@ -0,0 +1,35 @@
+module SharedSidebarActiveTab
+ include Spinach::DSL
+
+ step 'the active main tab should be Help' do
+ ensure_active_main_tab('Help')
+ end
+
+ step 'no other main tabs should be active' do
+ expect(page).to have_selector('.nav-sidebar > li.active', count: 1)
+ end
+
+ def ensure_active_main_tab(content)
+ expect(find('.nav-sidebar li.active')).to have_content(content)
+ end
+
+ step 'the active main tab should be Home' do
+ ensure_active_main_tab('Projects')
+ end
+
+ step 'the active main tab should be Projects' do
+ ensure_active_main_tab('Projects')
+ end
+
+ step 'the active main tab should be Issues' do
+ ensure_active_main_tab('Issues')
+ end
+
+ step 'the active main tab should be Merge Requests' do
+ ensure_active_main_tab('Merge Requests')
+ end
+
+ step 'the active main tab should be Help' do
+ ensure_active_main_tab('Help')
+ end
+end
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index cadf9f98fe3..2aaa0557ea3 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -29,7 +29,7 @@ module API
@current_user
end
- def sudo_identifier()
+ def sudo_identifier
identifier ||= params[SUDO_PARAM] || env[SUDO_HEADER]
# Regex for integers
diff --git a/lib/ci/ansi2html.rb b/lib/ci/ansi2html.rb
index 5fed43aaebd..c628257e3f4 100644
--- a/lib/ci/ansi2html.rb
+++ b/lib/ci/ansi2html.rb
@@ -98,7 +98,7 @@ module Ci
open_new_tag
s = StringScanner.new(ansi)
- while(!s.eos?)
+ until s.eos?
if s.scan(/\e([@-_])(.*?)([@-~])/)
handle_sequence(s)
elsif s.scan(/\e(([@-_])(.*?)?)?$/)
diff --git a/lib/ci/charts.rb b/lib/ci/charts.rb
index d53bdcbd0f2..e1636636934 100644
--- a/lib/ci/charts.rb
+++ b/lib/ci/charts.rb
@@ -64,7 +64,8 @@ module Ci
commits.each do |commit|
@labels << commit.short_sha
- @build_times << (commit.duration / 60)
+ duration = commit.duration || 0
+ @build_times << (duration / 60)
end
end
end
diff --git a/lib/gitlab/bitbucket_import/client.rb b/lib/gitlab/bitbucket_import/client.rb
index 9b83292ef33..8d1ad62fae0 100644
--- a/lib/gitlab/bitbucket_import/client.rb
+++ b/lib/gitlab/bitbucket_import/client.rb
@@ -121,7 +121,7 @@ module Gitlab
def get(url)
response = api.get(url)
- raise Unauthorized if (400..499).include?(response.code.to_i)
+ raise Unauthorized if (400..499).cover?(response.code.to_i)
response
end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 9b662d163f0..fd14234c558 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -39,7 +39,15 @@ module Gitlab
def update_column_in_batches(table, column, value)
quoted_table = quote_table_name(table)
quoted_column = quote_column_name(column)
- quoted_value = quote(value)
+
+ ##
+ # Workaround for #17711
+ #
+ # It looks like for MySQL `ActiveRecord::Base.conntection.quote(true)`
+ # returns correct value (1), but `ActiveRecord::Migration.new.quote`
+ # returns incorrect value ('true'), which causes migrations to fail.
+ #
+ quoted_value = connection.quote(value)
processed = 0
total = exec_query("SELECT COUNT(*) AS count FROM #{quoted_table}").
diff --git a/lib/support/nginx/registry-ssl b/lib/support/nginx/registry-ssl
new file mode 100644
index 00000000000..92511e26861
--- /dev/null
+++ b/lib/support/nginx/registry-ssl
@@ -0,0 +1,53 @@
+## Lines starting with two hashes (##) are comments with information.
+## Lines starting with one hash (#) are configuration parameters that can be uncommented.
+##
+###################################
+## configuration ##
+###################################
+
+## Redirects all HTTP traffic to the HTTPS host
+server {
+ listen *:80;
+ server_name registry.gitlab.example.com;
+ server_tokens off; ## Don't show the nginx version number, a security best practice
+ return 301 https://$http_host:$request_uri;
+ access_log /var/log/nginx/gitlab_registry_access.log gitlab_access;
+ error_log /var/log/nginx/gitlab_registry_error.log;
+}
+
+server {
+ # If a different port is specified in https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/config/gitlab.yml.example#L182,
+ # it should be declared here as well
+ listen *:443 ssl http2;
+ server_name registry.gitlab.example.com;
+ server_tokens off; ## Don't show the nginx version number, a security best practice
+
+ client_max_body_size 0;
+ chunked_transfer_encoding on;
+
+ ## Strong SSL Security
+ ## https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html & https://cipherli.st/
+ ssl on;
+ ssl_certificate /etc/gitlab/ssl/registry.gitlab.example.com.crt
+ ssl_certificate_key /etc/gitlab/ssl/registry.gitlab.example.com.key
+
+ ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4';
+ ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
+ ssl_prefer_server_ciphers on;
+ ssl_session_cache builtin:1000 shared:SSL:10m;
+ ssl_session_timeout 5m;
+
+ access_log /var/log/gitlab/nginx/gitlab_registry_access.log gitlab_access;
+ error_log /var/log/gitlab/nginx/gitlab_registry_error.log;
+
+ location / {
+ proxy_set_header Host $http_host; # required for docker client's sake
+ proxy_set_header X-Real-IP $remote_addr; # pass on real client's IP
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_read_timeout 900;
+
+ proxy_pass http://localhost:5000;
+ }
+
+}
diff --git a/lib/tasks/rubocop.rake b/lib/tasks/rubocop.rake
index ddfaf5d51f2..78ffccc9d06 100644
--- a/lib/tasks/rubocop.rake
+++ b/lib/tasks/rubocop.rake
@@ -1,4 +1,5 @@
unless Rails.env.production?
require 'rubocop/rake_task'
+
RuboCop::RakeTask.new
end
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index 40bd83af861..1bd1fc5189e 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -28,7 +28,7 @@ describe Projects::GroupLinksController do
expect(group.shared_projects).to include project
end
- it 'redirects to project group links page'do
+ it 'redirects to project group links page' do
expect(response).to redirect_to(
namespace_project_group_links_path(project.namespace, project)
)
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index 62de081661d..a073a1f9d7c 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -5,7 +5,7 @@ describe 'factories' do
describe "#{factory.name} factory" do
let(:entity) { build(factory.name) }
- it 'does not raise error when created 'do
+ it 'does not raise error when created' do
expect { entity }.to_not raise_error
end
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index d5755c293c5..749ee01890c 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -64,6 +64,64 @@ describe 'Issues', feature: true do
end
end
+ describe 'due date', js: true do
+ context 'on new form' do
+ before do
+ visit new_namespace_project_issue_path(project.namespace, project)
+ end
+
+ it 'should save with due date' do
+ date = Date.today.at_beginning_of_month
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+
+ page.within '.datepicker' do
+ click_link date.day
+ end
+
+ expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+
+ click_button 'Submit issue'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
+ end
+
+ context 'on edit form' do
+ let(:issue) { create(:issue, author: @user,project: project, due_date: Date.today.at_beginning_of_month.to_s) }
+
+ before do
+ visit edit_namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should save with due date' do
+ date = Date.today.at_beginning_of_month
+
+ expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+
+ date = date.tomorrow
+
+ fill_in 'issue_title', with: 'bug 345'
+ fill_in 'issue_description', with: 'bug description'
+
+ page.within '.datepicker' do
+ click_link date.day
+ end
+
+ expect(find('#issuable-due-date', visible: false).value).to eq date.to_s
+
+ click_button 'Save changes'
+
+ page.within '.issuable-sidebar' do
+ expect(page).to have_content date.to_s(:medium)
+ end
+ end
+ end
+ end
+
describe 'Issue info' do
it 'excludes award_emoji from comment count' do
issue = create(:issue, author: @user, assignee: @user, project: project, title: 'foobar')
@@ -331,7 +389,7 @@ describe 'Issues', feature: true do
page.within '.assignee' do
click_link 'Edit'
end
-
+
page.within '.dropdown-menu-user' do
click_link @user.name
end
@@ -431,6 +489,43 @@ describe 'Issues', feature: true do
end
end
+ describe 'due date' do
+ context 'update due on issue#show', js: true do
+ let(:issue) { create(:issue, project: project, author: @user, assignee: @user) }
+
+ before do
+ visit namespace_project_issue_path(project.namespace, project, issue)
+ end
+
+ it 'should add due date to issue' do
+ page.within '.due_date' do
+ click_link 'Edit'
+
+ page.within '.ui-datepicker-calendar' do
+ first('.ui-state-default').click
+ end
+
+ expect(page).to have_no_content 'None'
+ end
+ end
+
+ it 'should remove due date from issue' do
+ page.within '.due_date' do
+ click_link 'Edit'
+
+ page.within '.ui-datepicker-calendar' do
+ first('.ui-state-default').click
+ end
+
+ expect(page).to have_no_content 'None'
+
+ click_link 'remove due date'
+ expect(page).to have_content 'None'
+ end
+ end
+ end
+ end
+
def first_issue
page.all('ul.issues-list > li').first.text
end
diff --git a/spec/features/pipelines_spec.rb b/spec/features/pipelines_spec.rb
index 32665aadd22..1d6f4485c81 100644
--- a/spec/features/pipelines_spec.rb
+++ b/spec/features/pipelines_spec.rb
@@ -24,6 +24,12 @@ describe "Pipelines" do
end
end
+ context 'anonymous access' do
+ before { visit namespace_project_pipelines_path(project.namespace, project) }
+
+ it { expect(page).to have_http_status(:success) }
+ end
+
context 'cancelable pipeline' do
let!(:running) { create(:ci_build, :running, commit: pipeline, stage: 'test', commands: 'test') }
diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb
index 13c9b95b316..51be81d634c 100644
--- a/spec/features/projects/badges/list_spec.rb
+++ b/spec/features/projects/badges/list_spec.rb
@@ -8,12 +8,10 @@ feature 'list of badges' do
project = create(:project)
project.team << [user, :master]
login_as(user)
- visit edit_namespace_project_path(project.namespace, project)
+ visit namespace_project_badges_path(project.namespace, project)
end
scenario 'user displays list of badges' do
- click_link 'Badges'
-
expect(page).to have_content 'build status'
expect(page).to have_content 'Markdown'
expect(page).to have_content 'HTML'
@@ -26,7 +24,6 @@ feature 'list of badges' do
end
scenario 'user changes current ref on badges list page', js: true do
- click_link 'Badges'
select2('improve/awesome', from: '#ref')
expect(page).to have_content 'badges/improve/awesome/build.svg'
diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
index 3d6ffbc4c6b..ecc818eb1e1 100644
--- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb
+++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb
@@ -25,7 +25,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
@@ -33,7 +33,7 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
scenario 'project master creates a license file from the "Add license" link' do
@@ -48,7 +48,7 @@ feature 'project owner creates a license file', feature: true, js: true do
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
click_button 'Commit Changes'
@@ -56,6 +56,6 @@ feature 'project owner creates a license file', feature: true, js: true do
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
index 3268e240200..34eda29c285 100644
--- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
+++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb
@@ -24,7 +24,7 @@ feature 'project owner sees a link to create a license file in empty project', f
file_content = find('.file-content')
expect(file_content).to have_content('The MIT License (MIT)')
- expect(file_content).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(file_content).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
fill_in :commit_message, with: 'Add a LICENSE file', visible: true
# Remove pre-receive hook so we can push without auth
@@ -34,6 +34,6 @@ feature 'project owner sees a link to create a license file in empty project', f
expect(current_path).to eq(
namespace_project_blob_path(project.namespace, project, 'master/LICENSE'))
expect(page).to have_content('The MIT License (MIT)')
- expect(page).to have_content("Copyright (c) 2016 #{project.namespace.human_name}")
+ expect(page).to have_content("Copyright (c) #{Time.now.year} #{project.namespace.human_name}")
end
end
diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb
index c926e9841f3..6b5b3122f72 100644
--- a/spec/features/tags/master_updates_tag_spec.rb
+++ b/spec/features/tags/master_updates_tag_spec.rb
@@ -12,7 +12,7 @@ feature 'Master updates tag', feature: true do
context 'from the tags list page' do
scenario 'updates the release notes' do
- page.within(first('.controls')) do
+ page.within(first('.content-list .controls')) do
click_link 'Edit release notes'
end
diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb
index 50a77308cde..9d1215a5760 100644
--- a/spec/lib/ci/charts_spec.rb
+++ b/spec/lib/ci/charts_spec.rb
@@ -12,5 +12,12 @@ describe Ci::Charts, lib: true do
chart = Ci::Charts::BuildTime.new(@commit.project)
expect(chart.build_times).to eq([2])
end
+
+ it 'should handle nil build times' do
+ create(:ci_commit, duration: nil, project: @commit.project)
+
+ chart = Ci::Charts::BuildTime.new(@commit.project)
+ expect(chart.build_times).to eq([2, 0])
+ end
end
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index ec43165bb53..35ade7a2be0 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -2,15 +2,13 @@ require 'spec_helper'
describe Gitlab::Database::MigrationHelpers, lib: true do
let(:model) do
- Class.new do
- include Gitlab::Database::MigrationHelpers
-
- def method_missing(name, *args, &block)
- ActiveRecord::Base.connection.send(name, *args, &block)
- end
- end.new
+ ActiveRecord::Migration.new.extend(
+ Gitlab::Database::MigrationHelpers
+ )
end
+ before { allow(model).to receive(:puts) }
+
describe '#add_concurrent_index' do
context 'outside a transaction' do
before do
@@ -60,6 +58,12 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
expect(Project.where(import_error: 'foo').count).to eq(5)
end
+
+ it 'updates boolean values correctly' do
+ model.update_column_in_batches(:projects, :archived, true)
+
+ expect(Project.where(archived: true).count).to eq(5)
+ end
end
describe '#add_column_with_default' do
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index 30c0a04b840..b6adc2bf247 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -49,7 +49,7 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
context 'token is generated' do
before { subject.send("reset_#{token_field}!") }
- it 'persists a new token 'do
+ it 'persists a new token' do
expect(subject.send(:read_attribute, token_field)).to be_a String
end
end
diff --git a/spec/requests/api/licenses_spec.rb b/spec/requests/api/licenses_spec.rb
index c17dcb222a9..3726b2f5688 100644
--- a/spec/requests/api/licenses_spec.rb
+++ b/spec/requests/api/licenses_spec.rb
@@ -57,7 +57,7 @@ describe API::Licenses, api: true do
end
it 'replaces placeholder values' do
- expect(json_response['content']).to include('Copyright (c) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (c) #{Time.now.year} Anton")
end
end
@@ -70,7 +70,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
- expect(json_response['content']).to include('Copyright (C) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
@@ -83,7 +83,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
- expect(json_response['content']).to include('Copyright (C) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
@@ -96,7 +96,7 @@ describe API::Licenses, api: true do
it 'replaces placeholder values' do
expect(json_response['content']).to include('My Awesome Project')
- expect(json_response['content']).to include('Copyright (C) 2016 Anton')
+ expect(json_response['content']).to include("Copyright (C) #{Time.now.year} Anton")
end
end
@@ -108,7 +108,7 @@ describe API::Licenses, api: true do
end
it 'replaces placeholder values' do
- expect(json_response['content']).to include('Copyright 2016 Anton')
+ expect(json_response['content']).to include("Copyright #{Time.now.year} Anton")
end
end
@@ -128,7 +128,7 @@ describe API::Licenses, api: true do
it 'replaces the copyright owner placeholder with the name of the current user' do
get api('/licenses/mit', user)
- expect(json_response['content']).to include("Copyright (c) 2016 #{user.name}")
+ expect(json_response['content']).to include("Copyright (c) #{Time.now.year} #{user.name}")
end
end
end
diff --git a/spec/requests/jwt_controller_spec.rb b/spec/requests/jwt_controller_spec.rb
index 7bb71365a48..d006ff195cf 100644
--- a/spec/requests/jwt_controller_spec.rb
+++ b/spec/requests/jwt_controller_spec.rb
@@ -23,7 +23,7 @@ describe JwtController do
context 'when using authorized request' do
context 'using CI token' do
let(:project) { create(:empty_project, runners_token: 'token', builds_enabled: builds_enabled) }
- let(:headers) { { authorization: credentials('gitlab_ci_token', project.runners_token) } }
+ let(:headers) { { authorization: credentials('gitlab-ci-token', project.runners_token) } }
subject! { get '/jwt/auth', parameters, headers }
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 6c9f56a4fba..3f4a1ced2b6 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -10,7 +10,7 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
subject { described_class.new(current_project, current_user, current_params).execute }
before do
- stub_container_registry_config(enabled: true, issuer: 'rspec', key: nil)
+ allow(Gitlab.config.registry).to receive_messages(enabled: true, issuer: 'rspec', key: nil)
allow_any_instance_of(JSONWebToken::RSAToken).to receive(:key).and_return(rsa_key)
end
@@ -60,6 +60,17 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
it { is_expected.to_not include(:token) }
end
+ describe '#full_access_token' do
+ let(:project) { create(:empty_project) }
+ let(:token) { described_class.full_access_token(project.path_with_namespace) }
+
+ subject { { token: token } }
+
+ it_behaves_like 'a accessible' do
+ let(:actions) { ['*'] }
+ end
+ end
+
context 'user authorization' do
let(:project) { create(:project) }
let(:current_user) { create(:user) }
@@ -116,12 +127,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
context 'project authorization' do
let(:current_project) { create(:empty_project) }
- context 'disallow to use offline_token' do
+ context 'allow to use offline_token' do
let(:current_params) do
{ offline_token: true }
end
- it_behaves_like 'an unauthorized'
+ it_behaves_like 'an authenticated'
end
context 'allow to pull and push images' do
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index ac28b6f71f9..6aa0a89f893 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -54,7 +54,7 @@ describe Issues::CreateService, services: true do
label_ids: [label.id] }
end
- it 'does not assign label'do
+ it 'does not assign label' do
expect(issue.labels).to_not include label
end
end
diff --git a/vendor/gitignore/README.md b/vendor/gitignore/README.md
new file mode 100644
index 00000000000..43131e815cc
--- /dev/null
+++ b/vendor/gitignore/README.md
@@ -0,0 +1,14 @@
+# .gitignore templates
+
+This directory contains language-specific .gitignore templates that are used by GitLab.
+
+These files were automatically pulled from [this repository](https://github.com/github/gitignore).
+Please submit pull requests to that repository. There is no need to edit the files in this directory.
+
+## Bulk Update
+
+To update this directory with the latest changes in the repository, run:
+
+```sh
+bundle exec rake gitlab:update_gitignore
+```