summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.rubocop.yml70
-rw-r--r--CHANGELOG29
-rw-r--r--Gemfile5
-rw-r--r--Gemfile.lock12
-rw-r--r--app/assets/images/mailers/gitlab_header_logo.pngbin0 -> 7096 bytes
-rw-r--r--app/assets/images/mailers/gitlab_tanuki_2x.pngbin0 -> 2545 bytes
-rw-r--r--app/assets/javascripts/application.js.coffee33
-rw-r--r--app/assets/javascripts/calendar.js.coffee228
-rw-r--r--app/assets/javascripts/ci/build.coffee7
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee1
-rw-r--r--app/assets/javascripts/issuable.js.coffee48
-rw-r--r--app/assets/javascripts/issues.js.coffee38
-rw-r--r--app/assets/javascripts/layout_nav.js.coffee14
-rw-r--r--app/assets/javascripts/lib/url_utility.js.coffee11
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee3
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee3
-rw-r--r--app/assets/javascripts/notes.js.coffee2
-rw-r--r--app/assets/javascripts/right_sidebar.js.coffee36
-rw-r--r--app/assets/stylesheets/application.scss1
-rw-r--r--app/assets/stylesheets/framework/calendar.scss72
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss4
-rw-r--r--app/assets/stylesheets/framework/files.scss15
-rw-r--r--app/assets/stylesheets/framework/nav.scss93
-rw-r--r--app/assets/stylesheets/framework/sidebar.scss2
-rw-r--r--app/assets/stylesheets/mailers/devise.scss134
-rw-r--r--app/assets/stylesheets/pages/issues.scss10
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss6
-rw-r--r--app/assets/stylesheets/pages/pipelines.scss26
-rw-r--r--app/assets/stylesheets/pages/profile.scss14
-rw-r--r--app/assets/stylesheets/pages/projects.scss2
-rw-r--r--app/assets/stylesheets/pages/settings.scss8
-rw-r--r--app/assets/stylesheets/pages/snippets.scss44
-rw-r--r--app/assets/stylesheets/pages/todos.scss14
-rw-r--r--app/controllers/projects/merge_requests_controller.rb4
-rw-r--r--app/controllers/users_controller.rb2
-rw-r--r--app/finders/group_projects_finder.rb2
-rw-r--r--app/finders/issuable_finder.rb6
-rw-r--r--app/helpers/application_helper.rb17
-rw-r--r--app/helpers/events_helper.rb22
-rw-r--r--app/helpers/issues_helper.rb17
-rw-r--r--app/helpers/nav_helper.rb4
-rw-r--r--app/helpers/todos_helper.rb16
-rw-r--r--app/mailers/devise_mailer.rb2
-rw-r--r--app/models/concerns/issuable.rb11
-rw-r--r--app/models/project.rb8
-rw-r--r--app/models/project_services/slack_service/build_message.rb4
-rw-r--r--app/models/repository.rb6
-rw-r--r--app/services/git_push_service.rb17
-rw-r--r--app/services/projects/fork_service.rb14
-rw-r--r--app/views/admin/builds/index.html.haml1
-rw-r--r--app/views/dashboard/issues.atom.builder5
-rw-r--r--app/views/dashboard/projects/index.atom.builder4
-rw-r--r--app/views/dashboard/todos/_todo.html.haml2
-rw-r--r--app/views/devise/mailer/confirmation_instructions.html.erb9
-rw-r--r--app/views/devise/mailer/confirmation_instructions.html.haml16
-rw-r--r--app/views/devise/mailer/confirmation_instructions.text.erb9
-rw-r--r--app/views/doorkeeper/authorizations/new.html.haml2
-rw-r--r--app/views/events/_event.atom.builder20
-rw-r--r--app/views/groups/issues.atom.builder5
-rw-r--r--app/views/groups/show.atom.builder4
-rw-r--r--app/views/import/gitlab/status.html.haml2
-rw-r--r--app/views/issues/_issue.atom.builder14
-rw-r--r--app/views/layouts/_page.html.haml2
-rw-r--r--app/views/layouts/devise_mailer.html.haml34
-rw-r--r--app/views/layouts/nav/_group.html.haml75
-rw-r--r--app/views/layouts/nav/_profile.html.haml4
-rw-r--r--app/views/layouts/nav/_project.html.haml194
-rw-r--r--app/views/profiles/accounts/show.html.haml4
-rw-r--r--app/views/profiles/preferences/show.html.haml2
-rw-r--r--app/views/projects/_builds_settings.html.haml119
-rw-r--r--app/views/projects/builds/index.html.haml3
-rw-r--r--app/views/projects/ci/builds/_build.html.haml4
-rw-r--r--app/views/projects/ci/commits/_commit.html.haml36
-rw-r--r--app/views/projects/commit/_ci_stage.html.haml1
-rw-r--r--app/views/projects/commits/_commit.atom.builder14
-rw-r--r--app/views/projects/commits/show.atom.builder15
-rw-r--r--app/views/projects/edit.html.haml455
-rw-r--r--app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml18
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml2
-rw-r--r--app/views/projects/issues/_merge_requests.html.haml5
-rw-r--r--app/views/projects/issues/index.atom.builder4
-rw-r--r--app/views/projects/labels/index.html.haml2
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml2
-rw-r--r--app/views/projects/pipelines/index.html.haml16
-rw-r--r--app/views/projects/runners/_specific_runners.html.haml2
-rw-r--r--app/views/projects/services/_form.html.haml32
-rw-r--r--app/views/projects/services/index.html.haml52
-rw-r--r--app/views/projects/show.atom.builder4
-rw-r--r--app/views/projects/snippets/_actions.html.haml38
-rw-r--r--app/views/projects/snippets/show.html.haml8
-rw-r--r--app/views/projects/triggers/index.html.haml20
-rw-r--r--app/views/shared/_event_filter.html.haml4
-rw-r--r--app/views/shared/_sort_dropdown.html.haml2
-rw-r--r--app/views/shared/issuable/_filter.html.haml4
-rw-r--r--app/views/shared/issuable/_search_form.html.haml6
-rw-r--r--app/views/shared/projects/_project.html.haml3
-rw-r--r--app/views/shared/snippets/_header.html.haml19
-rw-r--r--app/views/snippets/_actions.html.haml38
-rw-r--r--app/views/snippets/show.html.haml7
-rw-r--r--app/views/users/calendar.html.haml19
-rw-r--r--app/views/users/calendar_activities.html.haml42
-rw-r--r--app/views/users/show.atom.builder4
-rw-r--r--app/views/users/show.html.haml7
-rw-r--r--config/application.rb2
-rw-r--r--config/environments/development.rb1
-rw-r--r--config/initializers/premailer.rb2
-rw-r--r--db/migrate/20160525205328_remove_main_language_from_projects.rb21
-rw-r--r--db/schema.rb3
-rw-r--r--doc/administration/high_availability/README.md4
-rw-r--r--doc/administration/high_availability/redis.md2
-rw-r--r--doc/administration/img/high_availability/active-active-diagram.pngbin0 -> 29607 bytes
-rw-r--r--doc/administration/img/high_availability/active-passive-diagram.pngbin0 -> 24246 bytes
-rw-r--r--doc/development/testing.md2
-rw-r--r--doc/development/ui_guide.md28
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/monitoring/health_check.md2
-rw-r--r--features/steps/admin/users.rb2
-rw-r--r--features/steps/dashboard/todos.rb2
-rw-r--r--features/steps/project/commits/commits.rb2
-rw-r--r--features/steps/project/issues/award_emoji.rb4
-rw-r--r--features/steps/project/issues/issues.rb4
-rw-r--r--features/steps/project/issues/labels.rb4
-rw-r--r--features/steps/project/merge_requests.rb4
-rw-r--r--features/steps/project/snippets.rb4
-rw-r--r--features/steps/shared/note.rb2
-rw-r--r--features/steps/shared/project.rb2
-rw-r--r--features/steps/snippets/snippets.rb4
-rw-r--r--features/steps/user.rb2
-rw-r--r--lib/api/groups.rb3
-rw-r--r--lib/backup/manager.rb15
-rw-r--r--lib/ci/ansi2html.rb4
-rw-r--r--lib/ci/gitlab_ci_yaml_processor.rb2
-rw-r--r--lib/gitlab/contributions_calendar.rb2
-rw-r--r--lib/gitlab/url_sanitizer.rb2
-rw-r--r--lib/gitlab/visibility_level.rb7
-rw-r--r--lib/tasks/gitlab/backup.rake20
-rw-r--r--lib/tasks/gitlab/db.rake10
-rw-r--r--spec/controllers/admin/projects_controller_spec.rb2
-rw-r--r--spec/controllers/projects/compare_controller_spec.rb4
-rw-r--r--spec/controllers/projects/group_links_controller_spec.rb2
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb2
-rw-r--r--spec/controllers/projects/project_members_controller_spec.rb2
-rw-r--r--spec/controllers/registrations_controller_spec.rb2
-rw-r--r--spec/controllers/sessions_controller_spec.rb6
-rw-r--r--spec/factories_spec.rb2
-rw-r--r--spec/features/admin/admin_runners_spec.rb2
-rw-r--r--spec/features/admin/admin_users_spec.rb2
-rw-r--r--spec/features/builds_spec.rb5
-rw-r--r--spec/features/commits_spec.rb10
-rw-r--r--spec/features/issues/filter_issues_spec.rb140
-rw-r--r--spec/features/issues/update_issues_spec.rb2
-rw-r--r--spec/features/pipelines_spec.rb14
-rw-r--r--spec/features/runners_spec.rb4
-rw-r--r--spec/features/todos/target_state_spec.rb65
-rw-r--r--spec/features/variables_spec.rb2
-rw-r--r--spec/helpers/auth_helper_spec.rb2
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb2
-rw-r--r--spec/javascripts/fixtures/right_sidebar.html.haml13
-rw-r--r--spec/javascripts/right_sidebar_spec.js.coffee69
-rw-r--r--spec/lib/award_emoji_spec.rb2
-rw-r--r--spec/lib/ci/ansi2html_spec.rb9
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb6
-rw-r--r--spec/lib/container_registry/registry_spec.rb2
-rw-r--r--spec/lib/container_registry/repository_spec.rb6
-rw-r--r--spec/lib/container_registry/tag_spec.rb4
-rw-r--r--spec/lib/gitlab/bitbucket_import/client_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb2
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb4
-rw-r--r--spec/lib/gitlab/gfm/uploads_rewriter_spec.rb8
-rw-r--r--spec/lib/gitlab/lfs/lfs_router_spec.rb4
-rw-r--r--spec/lib/gitlab/metrics/instrumentation_spec.rb8
-rw-r--r--spec/lib/gitlab/metrics/sampler_spec.rb2
-rw-r--r--spec/lib/gitlab/metrics/subscribers/active_record_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/collection_spec.rb6
-rw-r--r--spec/lib/gitlab/sherlock/query_spec.rb2
-rw-r--r--spec/lib/gitlab/sherlock/transaction_spec.rb4
-rw-r--r--spec/lib/json_web_token/rsa_token_spec.rb2
-rw-r--r--spec/mailers/previews/devise_mailer_preview.rb11
-rw-r--r--spec/mailers/shared/notify.rb4
-rw-r--r--spec/models/build_spec.rb8
-rw-r--r--spec/models/ci/commit_spec.rb2
-rw-r--r--spec/models/ci/runner_spec.rb2
-rw-r--r--spec/models/concerns/issuable_spec.rb31
-rw-r--r--spec/models/concerns/token_authenticatable_spec.rb4
-rw-r--r--spec/models/generic_commit_status_spec.rb4
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb2
-rw-r--r--spec/models/project_services/slack_service/build_message_spec.rb23
-rw-r--r--spec/models/project_spec.rb6
-rw-r--r--spec/models/repository_spec.rb22
-rw-r--r--spec/requests/api/groups_spec.rb21
-rw-r--r--spec/requests/api/project_members_spec.rb2
-rw-r--r--spec/requests/api/system_hooks_spec.rb2
-rw-r--r--spec/requests/ci/api/builds_spec.rb4
-rw-r--r--spec/services/auth/container_registry_authentication_service_spec.rb4
-rw-r--r--spec/services/create_commit_builds_service_spec.rb2
-rw-r--r--spec/services/git_push_service_spec.rb43
-rw-r--r--spec/services/groups/create_service_spec.rb2
-rw-r--r--spec/services/issues/create_service_spec.rb4
-rw-r--r--spec/services/issues/move_service_spec.rb6
-rw-r--r--spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb6
-rw-r--r--spec/services/projects/fork_service_spec.rb27
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb18
-rw-r--r--spec/tasks/gitlab/db_rake_spec.rb62
-rw-r--r--spec/workers/post_receive_spec.rb2
206 files changed, 2208 insertions, 1271 deletions
diff --git a/.rubocop.yml b/.rubocop.yml
index 4e6ced4e1ab..2d8eb4077f3 100644
--- a/.rubocop.yml
+++ b/.rubocop.yml
@@ -59,7 +59,7 @@ Style/AndOr:
# Use `Array#join` instead of `Array#*`.
Style/ArrayJoin:
- Enabled: false
+ Enabled: true
# Use only ascii symbols in comments.
Style/AsciiComments:
@@ -71,7 +71,7 @@ Style/AsciiIdentifiers:
# Checks for uses of Module#attr.
Style/Attr:
- Enabled: false
+ Enabled: true
# Avoid the use of BEGIN blocks.
Style/BeginBlock:
@@ -83,7 +83,7 @@ Style/BarePercentLiterals:
# Do not use block comments.
Style/BlockComments:
- Enabled: false
+ Enabled: true
# Put end statement of multiline block on its own line.
Style/BlockEndNewline:
@@ -124,7 +124,7 @@ Style/ClassCheck:
# Use self when defining module/class methods.
Style/ClassMethods:
- Enabled: false
+ Enabled: true
# Avoid the use of class variables.
Style/ClassVars:
@@ -218,7 +218,7 @@ Style/EmptyLiteral:
# Avoid the use of END blocks.
Style/EndBlock:
- Enabled: false
+ Enabled: true
# Use Unix-style line endings.
Style/EndOfLine:
@@ -226,7 +226,7 @@ Style/EndOfLine:
# Favor the use of Fixnum#even? && Fixnum#odd?
Style/EvenOdd:
- Enabled: false
+ Enabled: true
# Do not use unnecessary spacing.
Style/ExtraSpacing:
@@ -234,11 +234,16 @@ Style/ExtraSpacing:
# Use snake_case for source file names.
Style/FileName:
- Enabled: false
+ Enabled: true
+
+# Checks for a line break before the first parameter in a multi-line method
+# parameter definition.
+Style/FirstMethodParameterLineBreak:
+ Enabled: true
# Checks for flip flops.
Style/FlipFlop:
- Enabled: false
+ Enabled: true
# Checks use of for or each in multiline loops.
Style/For:
@@ -250,7 +255,7 @@ Style/FormatString:
# Do not introduce global variables.
Style/GlobalVars:
- Enabled: false
+ Enabled: true
# Check for conditionals that can be replaced with guard clauses.
Style/GuardClause:
@@ -271,7 +276,7 @@ Style/IfUnlessModifier:
# Do not use if x; .... Use the ternary operator instead.
Style/IfWithSemicolon:
- Enabled: false
+ Enabled: true
# Checks that conditional statements do not have an identical line at the
# end of each branch, which can validly be moved out of the conditional.
@@ -309,7 +314,7 @@ Style/Lambda:
# Use lambda.call(...) instead of lambda.(...).
Style/LambdaCall:
- Enabled: false
+ Enabled: true
# Comments should start with a space.
Style/LeadingCommentSpace:
@@ -329,7 +334,7 @@ Style/MethodDefParentheses:
# Use the configured style when naming methods.
Style/MethodName:
- Enabled: false
+ Enabled: true
# Checks for usage of `extend self` in modules.
Style/ModuleFunction:
@@ -370,6 +375,11 @@ Style/MultilineMethodCallBraceLayout:
Style/MultilineMethodCallIndentation:
Enabled: false
+# Checks that the closing brace in a method definition is symmetrical with
+# respect to the opening brace and the method parameters.
+Style/MultilineMethodDefinitionBraceLayout:
+ Enabled: false
+
# Checks indentation of binary operations that span more than one line.
Style/MultilineOperationIndentation:
Enabled: false
@@ -392,7 +402,7 @@ Style/NegatedWhile:
# Avoid using nested modifiers.
Style/NestedModifier:
- Enabled: false
+ Enabled: true
# Parenthesize method calls which are nested inside the argument list of
# another parenthesized method call.
@@ -429,7 +439,7 @@ Style/OneLineConditional:
# When defining binary operators, name the argument other.
Style/OpMethod:
- Enabled: false
+ Enabled: true
# Check for simple usages of parallel assignment. It will only warn when
# the number of variables matches on both sides of the assignment.
@@ -509,7 +519,8 @@ Style/Semicolon:
# Checks for proper usage of fail and raise.
Style/SignalException:
- Enabled: false
+ EnforcedStyle: only_raise
+ Enabled: true
# Enforces the names of some block params.
Style/SingleLineBlockParams:
@@ -534,11 +545,11 @@ Style/SpaceAfterMethodName:
# Tracks redundant space after the ! operator.
Style/SpaceAfterNot:
- Enabled: false
+ Enabled: true
# Use spaces after semicolons.
Style/SpaceAfterSemicolon:
- Enabled: false
+ Enabled: true
# Checks that the equals signs in parameter default assignments have or don't
# have surrounding space depending on configuration.
@@ -572,7 +583,7 @@ Style/SpaceBeforeFirstArg:
# No spaces before semicolons.
Style/SpaceBeforeSemicolon:
- Enabled: false
+ Enabled: true
# Checks that block braces have or don't have surrounding space.
# For blocks taking parameters, checks that the left brace has or doesn't
@@ -594,11 +605,12 @@ Style/SpaceInsideParens:
# No spaces inside range literals.
Style/SpaceInsideRangeLiteral:
- Enabled: false
+ Enabled: true
# Checks for padding/surrounding spaces inside string interpolation.
Style/SpaceInsideStringInterpolation:
- Enabled: false
+ EnforcedStyle: no_space
+ Enabled: true
# Avoid Perl-style global variables.
Style/SpecialGlobalVars:
@@ -606,7 +618,8 @@ Style/SpecialGlobalVars:
# Check for the usage of parentheses around stabby lambda arguments.
Style/StabbyLambdaParentheses:
- Enabled: false
+ EnforcedStyle: require_parentheses
+ Enabled: true
# Checks if uses of quotes match the configured preference.
Style/StringLiterals:
@@ -619,7 +632,9 @@ Style/StringLiteralsInInterpolation:
# Checks if configured preferred methods are used over non-preferred.
Style/StringMethods:
- Enabled: false
+ PreferredMethods:
+ intern: to_sym
+ Enabled: true
# Use %i or %I for arrays of symbols.
Style/SymbolArray:
@@ -677,15 +692,16 @@ Style/UnneededPercentQ:
# Don't interpolate global, instance and class variables directly in strings.
Style/VariableInterpolation:
- Enabled: false
+ Enabled: true
# Use the configured style when naming variables.
Style/VariableName:
- Enabled: false
+ EnforcedStyle: snake_case
+ Enabled: true
# Use when x then ... for one-line cases.
Style/WhenThen:
- Enabled: false
+ Enabled: true
# Checks for redundant do after while or until.
Style/WhileUntilDo:
@@ -693,7 +709,7 @@ Style/WhileUntilDo:
# Favor modifier while/until usage when you have a single-line body.
Style/WhileUntilModifier:
- Enabled: false
+ Enabled: true
# Use %w or %W for arrays of words.
Style/WordArray:
@@ -1130,7 +1146,7 @@ RSpec/MultipleDescribes:
# Enforces the usage of the same method on all negative message expectations.
RSpec/NotToNot:
EnforcedStyle: not_to
- Enabled: false
+ Enabled: true
# Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles:
diff --git a/CHANGELOG b/CHANGELOG
index a79c3048b79..9b8c6ddbeee 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,16 +1,31 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.9.0 (unreleased)
+ - Allow forking projects with restricted visibility level
- Redesign navigation for project pages
+ - Fix groups API to list only user's accessible projects
+ - Redesign account and email confirmation emails
- Use gitlab-shell v3.0.0
-
-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
+ - Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database
+ - Changed the Slack build message to use the singular duration if necessary (Aran Koning)
+ - Fix issues filter when ordering by milestone
+ - Todos will display target state if issuable target is 'Closed' or 'Merged'
+ - Remove 'main language' feature
+
+v 8.8.2
+ - Added remove due date button. !4209
+ - Fix Error 500 when accessing application settings due to nil disabled OAuth sign-in sources. !4242
+ - Fix Error 500 in CI charts by gracefully handling commits with no durations. !4245
+ - Fix table UI on CI builds page. !4249
+ - Fix backups if registry is disabled. !4263
+ - Fixed issue with merge button color. !4211
+ - Fixed issue with enter key selecting wrong option in dropdown. !4210
+ - When creating a .gitignore file a dropdown with templates will be provided. !4075
+ - Fix concurrent request when updating build log in browser. !4183
v 8.8.1
- Add documentation for the "Health Check" feature
- - Allow anonymous users to access a public project's pipelines
+ - Allow anonymous users to access a public project's pipelines !4233
- Fix MySQL compatibility in zero downtime migrations helpers
- Fix the CI login to Container Registry (the gitlab-ci-token user)
@@ -27,6 +42,7 @@ v 8.8.0
- Added inline diff styling for `change_title` system notes. (Adam Butler)
- 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
@@ -88,6 +104,9 @@ v 8.8.0
- Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
- When creating a .gitignore file a dropdown with templates will be provided
+v 8.7.7
+ - Fix import by `Any Git URL` broken if the URL contains a space
+
v 8.7.6
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
- Fix import from GitLab.com to a private instance failure. !4181
diff --git a/Gemfile b/Gemfile
index e854a31b425..b897dc0a741 100644
--- a/Gemfile
+++ b/Gemfile
@@ -121,7 +121,7 @@ group :unicorn do
end
# State machine
-gem "state_machines-activerecord", '~> 0.3.0'
+gem "state_machines-activerecord", '~> 0.4.0'
# Run events after state machine commits
gem 'after_commit_queue'
@@ -178,9 +178,6 @@ gem 'ruby-fogbugz', '~> 0.2.1'
# d3
gem 'd3_rails', '~> 3.5.0'
-#cal-heatmap
-gem 'cal-heatmap-rails', '~> 3.6.0'
-
# underscore-rails
gem "underscore-rails", "~> 1.8.0"
diff --git a/Gemfile.lock b/Gemfile.lock
index 4533aa31d5f..fa2b72b2524 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -102,7 +102,6 @@ GEM
bundler (~> 1.2)
thor (~> 0.18)
byebug (8.2.1)
- cal-heatmap-rails (3.6.0)
capybara (2.6.2)
addressable
mime-types (>= 1.16)
@@ -790,11 +789,11 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
state_machines (0.4.0)
- state_machines-activemodel (0.3.0)
- activemodel (~> 4.1)
+ state_machines-activemodel (0.4.0)
+ activemodel (>= 4.1, < 5.1)
state_machines (>= 0.4.0)
- state_machines-activerecord (0.3.0)
- activerecord (~> 4.1)
+ state_machines-activerecord (0.4.0)
+ activerecord (>= 4.1, < 5.1)
state_machines-activemodel (>= 0.3.0)
stringex (2.5.2)
systemu (2.6.5)
@@ -908,7 +907,6 @@ DEPENDENCIES
bullet
bundler-audit
byebug
- cal-heatmap-rails (~> 3.6.0)
capybara (~> 2.6.2)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 0.10.0)
@@ -1043,7 +1041,7 @@ DEPENDENCIES
spring-commands-spinach (~> 1.1.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 3.6.0)
- state_machines-activerecord (~> 0.3.0)
+ state_machines-activerecord (~> 0.4.0)
task_list (~> 1.0.2)
teaspoon (~> 1.1.0)
teaspoon-jasmine (~> 2.2.0)
diff --git a/app/assets/images/mailers/gitlab_header_logo.png b/app/assets/images/mailers/gitlab_header_logo.png
new file mode 100644
index 00000000000..35ca1860887
--- /dev/null
+++ b/app/assets/images/mailers/gitlab_header_logo.png
Binary files differ
diff --git a/app/assets/images/mailers/gitlab_tanuki_2x.png b/app/assets/images/mailers/gitlab_tanuki_2x.png
new file mode 100644
index 00000000000..551dd6ce2ce
--- /dev/null
+++ b/app/assets/images/mailers/gitlab_tanuki_2x.png
Binary files differ
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index bffce5a0c0f..7c547ac843b 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -19,7 +19,6 @@
#= require jquery.scrollTo
#= require jquery.turbolinks
#= require d3
-#= require cal-heatmap
#= require turbolinks
#= require autosave
#= require bootstrap/affix
@@ -246,38 +245,6 @@ $ ->
if $navIcon.hasClass('fa-angle-left')
$navIconToggle.trigger('click')
- $(document)
- .off 'click', '.js-sidebar-toggle'
- .on 'click', '.js-sidebar-toggle', (e, triggered) ->
- e.preventDefault()
- $this = $(this)
- $thisIcon = $this.find 'i'
- $allGutterToggleIcons = $('.js-sidebar-toggle i')
- if $thisIcon.hasClass('fa-angle-double-right')
- $allGutterToggleIcons
- .removeClass('fa-angle-double-right')
- .addClass('fa-angle-double-left')
- $('aside.right-sidebar')
- .removeClass('right-sidebar-expanded')
- .addClass('right-sidebar-collapsed')
- $('.page-with-sidebar')
- .removeClass('right-sidebar-expanded')
- .addClass('right-sidebar-collapsed')
- else
- $allGutterToggleIcons
- .removeClass('fa-angle-double-left')
- .addClass('fa-angle-double-right')
- $('aside.right-sidebar')
- .removeClass('right-sidebar-collapsed')
- .addClass('right-sidebar-expanded')
- $('.page-with-sidebar')
- .removeClass('right-sidebar-collapsed')
- .addClass('right-sidebar-expanded')
- if not triggered
- $.cookie("collapsed_gutter",
- $('.right-sidebar')
- .hasClass('right-sidebar-collapsed'), { path: '/' })
-
fitSidebarForSize = ->
oldBootstrapBreakpoint = bootstrapBreakpoint
bootstrapBreakpoint = bp.getBreakpointSize()
diff --git a/app/assets/javascripts/calendar.js.coffee b/app/assets/javascripts/calendar.js.coffee
index d80e0e716ce..f9c7bffdadb 100644
--- a/app/assets/javascripts/calendar.js.coffee
+++ b/app/assets/javascripts/calendar.js.coffee
@@ -1,34 +1,198 @@
class @Calendar
- constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
- cal = new CalHeatMap()
- cal.init
- itemName: ["contribution"]
- data: timestamps
- start: new Date(starting_year, starting_month)
- domainLabelFormat: "%b"
- id: "cal-heatmap"
- domain: "month"
- subDomain: "day"
- range: 12
- tooltip: true
- label:
- position: "top"
- legend: [
- 0
- 10
- 20
- 30
- ]
- legendCellPadding: 3
- cellSize: $('.user-calendar').width() / 73
- onClick: (date, count) ->
- formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
- $.ajax
- url: calendar_activities_path
- data:
- date: formated_date
- cache: false
- dataType: "html"
- success: (data) ->
- $(".user-calendar-activities").html data
+ constructor: (timestamps, @calendar_activities_path) ->
+ @currentSelectedDate = ''
+ @daySpace = 1
+ @daySize = 15
+ @daySizeWithSpace = @daySize + (@daySpace * 2)
+ @monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+ @months = []
+ @highestValue = 0
+ # Get the highest value from the timestampes
+ _.each timestamps, (count) =>
+ if count > @highestValue
+ @highestValue = count
+
+ # Loop through the timestamps to create a group of objects
+ # The group of objects will be grouped based on the day of the week they are
+ @timestampsTmp = []
+ i = 0
+ group = 0
+ _.each timestamps, (count, date) =>
+ newDate = new Date parseInt(date) * 1000
+ day = newDate.getDay()
+
+ # Create a new group array if this is the first day of the week
+ # or if is first object
+ if (day is 0 and i isnt 0) or i is 0
+ @timestampsTmp.push []
+ group++
+
+ innerArray = @timestampsTmp[group-1]
+
+ # Push to the inner array the values that will be used to render map
+ innerArray.push
+ count: count
+ date: newDate
+ day: day
+
+ i++
+
+ # Init color functions
+ @color = @initColor()
+ @colorKey = @initColorKey()
+
+ # Init the svg element
+ @renderSvg(group)
+ @renderDays()
+ @renderMonths()
+ @renderDayTitles()
+ @renderKey()
+
+ @initTooltips()
+
+ renderSvg: (group) ->
+ @svg = d3.select '.js-contrib-calendar'
+ .append 'svg'
+ .attr 'width', (group + 1) * @daySizeWithSpace
+ .attr 'height', 167
+ .attr 'class', 'contrib-calendar'
+
+ renderDays: ->
+ @svg.selectAll 'g'
+ .data @timestampsTmp
+ .enter()
+ .append 'g'
+ .attr 'transform', (group, i) =>
+ _.each group, (stamp, a) =>
+ if a is 0 and stamp.day is 0
+ month = stamp.date.getMonth()
+ x = (@daySizeWithSpace * i + 1) + @daySizeWithSpace
+ lastMonth = _.last(@months)
+ if lastMonth?
+ lastMonthX = lastMonth.x
+
+ if !lastMonth?
+ @months.push
+ month: month
+ x: x
+ else if month isnt lastMonth.month and x - @daySizeWithSpace isnt lastMonthX
+ @months.push
+ month: month
+ x: x
+
+ "translate(#{(@daySizeWithSpace * i + 1) + @daySizeWithSpace}, 18)"
+ .selectAll 'rect'
+ .data (stamp) ->
+ stamp
+ .enter()
+ .append 'rect'
+ .attr 'x', '0'
+ .attr 'y', (stamp, i) =>
+ (@daySizeWithSpace * stamp.day)
+ .attr 'width', @daySize
+ .attr 'height', @daySize
+ .attr 'title', (stamp) =>
+ contribText = 'No contributions'
+
+ if stamp.count > 0
+ contribText = "#{stamp.count} contribution#{if stamp.count > 1 then 's' else ''}"
+
+ date = dateFormat(stamp.date, 'mmm d, yyyy')
+
+ "#{contribText}<br />#{date}"
+ .attr 'class', 'user-contrib-cell js-tooltip'
+ .attr 'fill', (stamp) =>
+ if stamp.count isnt 0
+ @color(stamp.count)
+ else
+ '#ededed'
+ .attr 'data-container', 'body'
+ .on 'click', @clickDay
+
+ renderDayTitles: ->
+ days = [{
+ text: 'M'
+ y: 29 + (@daySizeWithSpace * 1)
+ }, {
+ text: 'W'
+ y: 29 + (@daySizeWithSpace * 3)
+ }, {
+ text: 'F'
+ y: 29 + (@daySizeWithSpace * 5)
+ }]
+ @svg.append 'g'
+ .selectAll 'text'
+ .data days
+ .enter()
+ .append 'text'
+ .attr 'text-anchor', 'middle'
+ .attr 'x', 8
+ .attr 'y', (day) ->
+ day.y
+ .text (day) ->
+ day.text
+ .attr 'class', 'user-contrib-text'
+
+ renderMonths: ->
+ @svg.append 'g'
+ .selectAll 'text'
+ .data @months
+ .enter()
+ .append 'text'
+ .attr 'x', (date) ->
+ date.x
+ .attr 'y', 10
+ .attr 'class', 'user-contrib-text'
+ .text (date) =>
+ @monthNames[date.month]
+
+ renderKey: ->
+ keyColors = ['#ededed', @colorKey(0), @colorKey(1), @colorKey(2), @colorKey(3)]
+ @svg.append 'g'
+ .attr 'transform', "translate(18, #{@daySizeWithSpace * 8 + 16})"
+ .selectAll 'rect'
+ .data keyColors
+ .enter()
+ .append 'rect'
+ .attr 'width', @daySize
+ .attr 'height', @daySize
+ .attr 'x', (color, i) =>
+ @daySizeWithSpace * i
+ .attr 'y', 0
+ .attr 'fill', (color) ->
+ color
+
+ initColor: ->
+ d3.scale
+ .linear()
+ .range(['#acd5f2', '#254e77'])
+ .domain([0, @highestValue])
+
+ initColorKey: ->
+ d3.scale
+ .linear()
+ .range(['#acd5f2', '#254e77'])
+ .domain([0, 3])
+
+ clickDay: (stamp) ->
+ if @currentSelectedDate isnt stamp.date
+ @currentSelectedDate = stamp.date
+ formatted_date = @currentSelectedDate.getFullYear() + "-" + (@currentSelectedDate.getMonth()+1) + "-" + @currentSelectedDate.getDate()
+
+ $.ajax
+ url: @calendar_activities_path
+ data:
+ date: formatted_date
+ cache: false
+ dataType: 'html'
+ beforeSend: ->
+ $('.user-calendar-activities').html '<div class="text-center"><i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i></div>'
+ success: (data) ->
+ $('.user-calendar-activities').html data
+ else
+ $('.user-calendar-activities').html ''
+
+ initTooltips: ->
+ $('.js-contrib-calendar .js-tooltip').tooltip
+ html: true
diff --git a/app/assets/javascripts/ci/build.coffee b/app/assets/javascripts/ci/build.coffee
index fca0c3bae5c..98d05e41273 100644
--- a/app/assets/javascripts/ci/build.coffee
+++ b/app/assets/javascripts/ci/build.coffee
@@ -28,12 +28,15 @@ class CiBuild
#
CiBuild.interval = setInterval =>
if window.location.href.split("#").first() is build_url
+ last_state = @state
$.ajax
url: build_url + "/trace.json?state=" + encodeURIComponent(@state)
dataType: "json"
success: (log) =>
- @state = log.state
- if log.status is "running"
+ return unless last_state is @state
+
+ if log.state and log.status is "running"
+ @state = log.state
if log.append
$('.fa-refresh').before log.html
else
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 12c143fdf76..a3185f87640 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -16,7 +16,6 @@ class Dispatcher
shortcut_handler = null
switch page
when 'projects:issues:index'
- Issues.init()
Issuable.init()
shortcut_handler = new ShortcutsNavigation()
when 'projects:issues:show'
diff --git a/app/assets/javascripts/issuable.js.coffee b/app/assets/javascripts/issuable.js.coffee
index afffed63ac5..6504e481102 100644
--- a/app/assets/javascripts/issuable.js.coffee
+++ b/app/assets/javascripts/issuable.js.coffee
@@ -1,7 +1,11 @@
+issuable_created = false
@Issuable =
init: ->
- Issuable.initTemplates()
- Issuable.initSearch()
+ unless issuable_created
+ issuable_created = true
+ Issuable.initTemplates()
+ Issuable.initSearch()
+ Issuable.initChecks()
initTemplates: ->
Issuable.labelRow = _.template(
@@ -19,7 +23,16 @@
.on 'keyup', ->
clearTimeout(@timer)
@timer = setTimeout( ->
- Issuable.filterResults $('#issue_search_form')
+ $search = $('#issue_search')
+ $form = $('.js-filter-form')
+ $input = $("input[name='#{$search.attr('name')}']", $form)
+
+ if $input.length is 0
+ $form.append "<input type='hidden' name='#{$search.attr('name')}' value='#{_.escape($search.val())}'/>"
+ else
+ $input.val $search.val()
+
+ Issuable.filterResults $form
, 500)
toggleLabelFilters: ->
@@ -59,15 +72,22 @@
dataType: "json"
reload: ->
- if Issues.created
- Issues.initChecks()
+ if Issuable.created
+ Issuable.initChecks()
$('#filter_issue_search').val($('#issue_search').val())
+ initChecks: ->
+ $('.check_all_issues').on 'click', ->
+ $('.selected_issue').prop('checked', @checked)
+ Issuable.checkChanged()
+
+ $('.selected_issue').on 'change', Issuable.checkChanged
+
updateStateFilters: ->
- stateFilters = $('.issues-state-filters')
+ stateFilters = $('.issues-state-filters, .dropdown-menu-sort')
newParams = {}
- paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search']
+ paramKeys = ['author_id', 'milestone_title', 'assignee_id', 'issue_search', 'issue_search']
for paramKey in paramKeys
newParams[paramKey] = gl.utils.getParameterValues(paramKey)[0] or ''
@@ -82,3 +102,17 @@
else
newUrl = gl.utils.mergeUrlParams(newParams, initialUrl)
$(this).attr 'href', newUrl
+
+ checkChanged: ->
+ checked_issues = $('.selected_issue:checked')
+ if checked_issues.length > 0
+ ids = $.map checked_issues, (value) ->
+ $(value).data('id')
+
+ $('#update_issues_ids').val ids
+ $('.issues-other-filters').hide()
+ $('.issues_bulk_update').show()
+ else
+ $('#update_issues_ids').val []
+ $('.issues_bulk_update').hide()
+ $('.issues-other-filters').show()
diff --git a/app/assets/javascripts/issues.js.coffee b/app/assets/javascripts/issues.js.coffee
deleted file mode 100644
index 3330e6c68ad..00000000000
--- a/app/assets/javascripts/issues.js.coffee
+++ /dev/null
@@ -1,38 +0,0 @@
-@Issues =
- init: ->
- Issues.created = true
- Issues.initChecks()
-
- $("body").on "ajax:success", ".close_issue, .reopen_issue", ->
- t = $(this)
- totalIssues = undefined
- reopen = t.hasClass("reopen_issue")
- $(".issue_counter").each ->
- issue = $(this)
- totalIssues = parseInt($(this).html(), 10)
- if reopen and issue.closest(".main_menu").length
- $(this).html totalIssues + 1
- else
- $(this).html totalIssues - 1
-
- initChecks: ->
- $(".check_all_issues").click ->
- $(".selected_issue").prop("checked", @checked)
- Issues.checkChanged()
-
- $(".selected_issue").bind "change", Issues.checkChanged
-
- checkChanged: ->
- checked_issues = $(".selected_issue:checked")
- if checked_issues.length > 0
- ids = []
- $.each checked_issues, (index, value) ->
- ids.push $(value).attr("data-id")
-
- $("#update_issues_ids").val ids
- $(".issues-other-filters").hide()
- $(".issues_bulk_update").show()
- else
- $("#update_issues_ids").val []
- $(".issues_bulk_update").hide()
- $(".issues-other-filters").show()
diff --git a/app/assets/javascripts/layout_nav.js.coffee b/app/assets/javascripts/layout_nav.js.coffee
new file mode 100644
index 00000000000..6adac6dac97
--- /dev/null
+++ b/app/assets/javascripts/layout_nav.js.coffee
@@ -0,0 +1,14 @@
+class @LayoutNav
+ $ ->
+ $('.fade-left').addClass('end-scroll')
+ $('.scrolling-tabs').on 'scroll', (event) ->
+ $this = $(this)
+ $el = $(event.target)
+ currentPosition = $this.scrollLeft()
+ size = bp.getBreakpointSize()
+ controlBtnWidth = $('.controls').width()
+ maxPosition = $this.get(0).scrollWidth - $this.parent().width()
+ maxPosition += controlBtnWidth if size isnt 'xs' and $('.nav-control').length
+
+ $el.find('.fade-left').toggleClass('end-scroll', currentPosition is 0)
+ $el.find('.fade-right').toggleClass('end-scroll', currentPosition is maxPosition)
diff --git a/app/assets/javascripts/lib/url_utility.js.coffee b/app/assets/javascripts/lib/url_utility.js.coffee
index 6a00932c028..e8085e1c2e4 100644
--- a/app/assets/javascripts/lib/url_utility.js.coffee
+++ b/app/assets/javascripts/lib/url_utility.js.coffee
@@ -26,10 +26,19 @@
newUrl = decodeURIComponent(url)
for paramName, paramValue of params
pattern = new RegExp "\\b(#{paramName}=).*?(&|$)"
- if url.search(pattern) >= 0
+ if not paramValue?
+ newUrl = newUrl.replace pattern, ''
+ else if url.search(pattern) isnt -1
newUrl = newUrl.replace pattern, "$1#{paramValue}$2"
else
newUrl = "#{newUrl}#{(if newUrl.indexOf('?') > 0 then '&' else '?')}#{paramName}=#{paramValue}"
+
+ # Remove a trailing ampersand
+ lastChar = newUrl[newUrl.length - 1]
+
+ if lastChar is '&'
+ newUrl = newUrl.slice 0, -1
+
newUrl
# removes parameter query string from url. returns the modified url
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index 372732d0aac..49a4727205a 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -75,6 +75,9 @@ class @MergeRequestTabs
@loadDiff($target.attr('href'))
if bp? and bp.getBreakpointSize() isnt 'lg'
@shrinkView()
+
+ navBarHeight = $('.navbar-gitlab').outerHeight()
+ $.scrollTo(".merge-request-details .merge-request-tabs", offset: -navBarHeight)
else if action == 'builds'
@loadBuilds($target.attr('href'))
@expandView()
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index b6d590f681c..d16f44d52f8 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -106,6 +106,7 @@ class @MergeRequestWidget
@firstCICheck = false
showCIStatus: (state) ->
+ return if not state?
$('.ci_widget').hide()
allowed_states = ["failed", "canceled", "running", "pending", "success", "skipped", "not_found"]
if state in allowed_states
@@ -126,6 +127,6 @@ class @MergeRequestWidget
$('.ci_widget:visible .ci-coverage').text(text)
setMergeButtonClass: (css_class) ->
- $('.js-merge-button')
+ $('.js-merge-button,.accept-action .dropdown-toggle')
.removeClass('btn-danger btn-warning btn-create')
.addClass(css_class)
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 6d9d6528f45..8131d923677 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -329,7 +329,7 @@ class @Notes
@renderDiscussionNote(note)
# cleanup after successfully creating a diff/discussion note
- @removeDiscussionNoteForm($("#new-discussion-note-form-#{note.discussion_id}"))
+ @removeDiscussionNoteForm($(xhr.target))
###
Called in response to the edit note form being submitted
diff --git a/app/assets/javascripts/right_sidebar.js.coffee b/app/assets/javascripts/right_sidebar.js.coffee
index 2d084b76cfe..c9cb0f4bb32 100644
--- a/app/assets/javascripts/right_sidebar.js.coffee
+++ b/app/assets/javascripts/right_sidebar.js.coffee
@@ -10,6 +10,40 @@ class @Sidebar
$('.dropdown').on('loading.gl.dropdown', @sidebarDropdownLoading)
$('.dropdown').on('loaded.gl.dropdown', @sidebarDropdownLoaded)
+
+ $(document)
+ .off 'click', '.js-sidebar-toggle'
+ .on 'click', '.js-sidebar-toggle', (e, triggered) ->
+ e.preventDefault()
+ $this = $(this)
+ $thisIcon = $this.find 'i'
+ $allGutterToggleIcons = $('.js-sidebar-toggle i')
+ if $thisIcon.hasClass('fa-angle-double-right')
+ $allGutterToggleIcons
+ .removeClass('fa-angle-double-right')
+ .addClass('fa-angle-double-left')
+ $('aside.right-sidebar')
+ .removeClass('right-sidebar-expanded')
+ .addClass('right-sidebar-collapsed')
+ $('.page-with-sidebar')
+ .removeClass('right-sidebar-expanded')
+ .addClass('right-sidebar-collapsed')
+ else
+ $allGutterToggleIcons
+ .removeClass('fa-angle-double-left')
+ .addClass('fa-angle-double-right')
+ $('aside.right-sidebar')
+ .removeClass('right-sidebar-collapsed')
+ .addClass('right-sidebar-expanded')
+ $('.page-with-sidebar')
+ .removeClass('right-sidebar-collapsed')
+ .addClass('right-sidebar-expanded')
+ if not triggered
+ $.cookie("collapsed_gutter",
+ $('.right-sidebar')
+ .hasClass('right-sidebar-collapsed'), { path: '/' })
+
+
sidebarDropdownLoading: (e) ->
$sidebarCollapsedIcon = $(@).closest('.block').find('.sidebar-collapsed-icon')
img = $sidebarCollapsedIcon.find('img')
@@ -76,7 +110,7 @@ class @Sidebar
@triggerOpenSidebar() if not @isOpen()
if action is 'hide'
- @triggerOpenSidebar() is @isOpen()
+ @triggerOpenSidebar() if @isOpen()
isOpen: ->
@sidebar.is('.right-sidebar-expanded')
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index e2d590f4df4..8b93665d085 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -8,7 +8,6 @@
*= require select2
*= require_self
*= require dropzone/basic
- *= require cal-heatmap
*= require cropper.css
*/
diff --git a/app/assets/stylesheets/framework/calendar.scss b/app/assets/stylesheets/framework/calendar.scss
index 11f39d583bd..8642b7530e2 100644
--- a/app/assets/stylesheets/framework/calendar.scss
+++ b/app/assets/stylesheets/framework/calendar.scss
@@ -1,70 +1,44 @@
.calender-block {
+ padding-left: 0;
+ padding-right: 0;
+
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) {
overflow-x: scroll;
}
}
.user-calendar-activities {
- .calendar_onclick_hr {
- padding: 0;
- margin: 10px 0;
- }
-
.str-truncated {
max-width: 70%;
}
- .text-expander {
- background: #eee;
- color: #555;
- padding: 0 5px;
- cursor: pointer;
- margin-left: 4px;
- &:hover {
- background-color: #ddd;
- }
+ .user-calendar-activities-loading {
+ font-size: 24px;
}
}
-/**
-* This overwrites the default values of the cal-heatmap gem
-*/
-.calendar {
- .qi {
- fill: #fff;
- }
-
- .q1 {
- fill: #ededed !important;
- }
+.user-calendar {
+ text-align: center;
- .q2 {
- fill: #acd5f2 !important;
- }
-
- .q3 {
- fill: #7fa8d1 !important;
- }
-
- .q4 {
- fill: #49729b !important;
- }
-
- .q5 {
- fill: #254e77 !important;
+ .calendar {
+ display: inline-block;
}
+}
- .future {
- visibility: hidden;
+.user-contrib-cell {
+ &:hover {
+ cursor: pointer;
+ stroke: #000;
}
+}
- .domain-background {
- fill: none;
- shape-rendering: crispedges;
- }
+.user-contrib-text {
+ font-size: 12px;
+ fill: #959494;
+}
- .ch-tooltip {
- padding: 3px;
- font-weight: 550;
- }
+.calendar-hint {
+ margin-top: -23px;
+ float: right;
+ font-size: 12px;
}
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 4bf3a050403..79a37d87e82 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -162,6 +162,10 @@
}
}
+.dropdown-menu-full-width {
+ width: 100%;
+}
+
.dropdown-menu-paging {
.dropdown-page-two,
.dropdown-menu-back {
diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss
index 8c96c7a9c31..71a9f79be3e 100644
--- a/app/assets/stylesheets/framework/files.scss
+++ b/app/assets/stylesheets/framework/files.scss
@@ -5,6 +5,10 @@
.file-holder {
border: 1px solid $border-color;
+ &.file-holder-no-border {
+ border: 0;
+ }
+
&.readme-holder {
margin: $gl-padding-top 0;
}
@@ -23,8 +27,17 @@
word-wrap: break-word;
border-radius: 3px 3px 0 0;
+ &.file-title-clear {
+ padding-left: 0;
+ padding-right: 0;
+ background-color: transparent;
+
+ .file-actions {
+ right: 0;
+ }
+ }
+
.file-actions {
- float: right;
position: absolute;
top: 5px;
right: 15px;
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index c70be58f48f..adfe5540704 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -1,3 +1,34 @@
+@mixin fade($gradient-direction, $rgba, $gradient-color) {
+ visibility: visible;
+ opacity: 1;
+ position: absolute;
+ bottom: 12px;
+ width: 43px;
+ height: 30px;
+ transition-duration: .3s;
+ -webkit-transform: translateZ(0);
+ background: -webkit-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
+ background: -o-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
+ background: -moz-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
+ background: linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
+
+ &.end-scroll {
+ visibility: hidden;
+ opacity: 0;
+ transition-duration: .3s;
+ }
+}
+
+@mixin scrolling-links() {
+ white-space: nowrap;
+ overflow-x: auto;
+ overflow-y: hidden;
+ -webkit-overflow-scrolling: touch;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
+
.nav-links {
padding: 0;
margin: 0;
@@ -119,7 +150,7 @@
}
input {
- height: 34px;
+ height: 35px;
display: inline-block;
position: relative;
top: 2px;
@@ -196,7 +227,7 @@
position: fixed;
top: $header-height;
width: 100%;
- z-index: 3;
+ z-index: 11;
background: $background-color;
border-bottom: 1px solid $border-color;
transition-duration: .3s;
@@ -209,13 +240,8 @@
float: right;
padding: 7px 0 0;
- @media (max-width: $screen-xs-min) {
- float: none;
- padding: 0 9px;
-
- .dropdown-new {
- width: 100%;
- }
+ @media (max-width: $screen-xs-max) {
+ display: none;
}
i {
@@ -246,14 +272,18 @@
}
.nav-links {
+ @include scrolling-links();
border-bottom: none;
height: 51px;
- white-space: nowrap;
- overflow-x: auto;
- overflow-y: hidden;
- -webkit-overflow-scrolling: touch;
- &::-webkit-scrollbar {
- display: none;
+
+ .fade-right {
+ @include fade(left, rgba(250, 250, 250, 0.4), $background-color);
+ right: 0;
+ }
+
+ .fade-left {
+ @include fade(right, rgba(250, 250, 250, 0.4), $background-color);
+ left: 0;
}
li {
@@ -278,16 +308,39 @@
}
}
+ .nav-control {
+ .fade-right {
+
+ @media (min-width: $screen-xs-max) {
+ right: 67px;
+ }
+ @media (max-width: $screen-xs-min) {
+ right: 0;
+ }
+ }
+ }
}
-.page-with-layout-nav {
- margin-top: 50px;
+.nav-block {
+ position: relative;
- &.controls-dropdown-visible {
- @media (max-width: $screen-xs-min) {
- margin-top: 96px;
+ .nav-links {
+ @include scrolling-links();
+
+ .fade-right {
+ @include fade(left, rgba(255, 255, 255, 0.4), $white-light);
+ right: 0;
+ }
+
+ .fade-left {
+ @include fade(right, rgba(255, 255, 255, 0.4), $white-light);
+ left: 0;
}
}
+}
+
+.page-with-layout-nav {
+ margin-top: $header-height + 2;
.right-sidebar {
top: ($header-height * 2) + 2;
diff --git a/app/assets/stylesheets/framework/sidebar.scss b/app/assets/stylesheets/framework/sidebar.scss
index f90d7a806d3..67f491b6d9c 100644
--- a/app/assets/stylesheets/framework/sidebar.scss
+++ b/app/assets/stylesheets/framework/sidebar.scss
@@ -324,7 +324,7 @@
.layout-nav {
@media (max-width: $screen-xs-min) {
- padding-right: 0;;
+ padding-right: 0;
}
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
diff --git a/app/assets/stylesheets/mailers/devise.scss b/app/assets/stylesheets/mailers/devise.scss
new file mode 100644
index 00000000000..28611a5ec81
--- /dev/null
+++ b/app/assets/stylesheets/mailers/devise.scss
@@ -0,0 +1,134 @@
+// NOTE: This stylesheet is for the exclusive use of the `devise_mailer` layout
+// used for Devise email templates, and _should not_ be included in any
+// application stylesheets.
+//
+// Styles defined here are embedded directly into the resulting email HTML via
+// the `premailer` gem.
+
+$body-background-color: #363636;
+$message-background-color: #fafafa;
+
+$header-color: #6b4fbb;
+$body-color: #444;
+$cta-color: #e14329;
+$footer-link-color: #7e7e7e;
+
+$font-family: Helvetica, Arial, sans-serif;
+
+body {
+ background-color: $body-background-color;
+ font-family: $font-family;
+ margin: 0;
+ padding: 0;
+}
+
+table {
+ -premailer-cellpadding: 0;
+ -premailer-cellspacing: 0;
+
+ border: 0;
+ border-collapse: separate;
+
+ &#wrapper {
+ background-color: $body-background-color;
+ width: 100%;
+ }
+
+ &#header {
+ margin: 0 auto;
+ text-align: left;
+ width: 600px;
+ }
+
+ &#body {
+ background-color: $message-background-color;
+ border: 1px solid #000;
+ border-radius: 4px;
+ margin: 0 auto;
+ width: 600px;
+ }
+
+ &#footer {
+ color: $footer-link-color;
+ font-size: 14px;
+ text-align: center;
+ width: 100%;
+ }
+
+ td {
+ &#body-container {
+ padding: 20px 40px;
+ }
+ }
+}
+
+.center {
+ text-align: center;
+}
+
+#logo {
+ border: none;
+ outline: none;
+ min-height: 88px;
+ width: 134px;
+}
+
+#content {
+ h2 {
+ color: $header-color;
+ font-size: 30px;
+ font-weight: 400;
+ line-height: 34px;
+ margin-top: 0;
+ }
+
+ p {
+ color: $body-color;
+ font-size: 17px;
+ line-height: 24px;
+ margin-bottom: 0;
+ }
+}
+
+#cta {
+ border: 1px solid $cta-color;
+ border-radius: 3px;
+ display: inline-block;
+ margin: 20px 0;
+ padding: 12px 24px;
+
+ a {
+ background-color: $message-background-color;
+ color: $cta-color;
+ display: inline-block;
+ text-decoration: none;
+ }
+}
+
+#tanuki {
+ padding: 40px 0 0;
+
+ img {
+ border: none;
+ outline: none;
+ width: 37px;
+ min-height: 36px;
+ }
+}
+
+#tagline {
+ font-size: 22px;
+ font-weight: 100;
+ padding: 4px 0 40px;
+}
+
+#social {
+ padding: 0 10px 20px;
+ width: 600px;
+ word-spacing: 20px;
+
+ a {
+ color: $footer-link-color;
+ text-decoration: none;
+ }
+}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index fc9db97132d..4e35ca329e4 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -40,11 +40,6 @@
}
}
-.issue-search-form {
- margin: 0;
- height: 24px;
-}
-
form.edit-issue {
margin: 0;
}
@@ -96,8 +91,3 @@ form.edit-issue {
.issue-form .select2-container {
width: 250px !important;
}
-
-.issue-closed-by-widget {
- color: $gl-text-color;
- margin-left: 52px;
-}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index c4005ba1e69..4f8a8748d3f 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -280,11 +280,5 @@
background-color: $white-light;
color: $gl-placeholder-color;
}
-
- th,
- td {
- padding: 16px;
- }
}
}
-
diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss
index 546176b65e4..6128868b670 100644
--- a/app/assets/stylesheets/pages/pipelines.scss
+++ b/app/assets/stylesheets/pages/pipelines.scss
@@ -1,4 +1,24 @@
-.pipeline-stage {
- overflow: hidden;
- text-overflow: ellipsis;
+.pipelines {
+ .stage {
+ max-width: 100px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .duration, .finished_at {
+ margin: 4px 0;
+ }
+
+ .commit-title {
+ margin: 0;
+ }
+
+ .controls {
+ white-space: nowrap;
+ }
+
+ .btn {
+ margin: 4px;
+ }
}
diff --git a/app/assets/stylesheets/pages/profile.scss b/app/assets/stylesheets/pages/profile.scss
index 843379a3f54..167ab40d881 100644
--- a/app/assets/stylesheets/pages/profile.scss
+++ b/app/assets/stylesheets/pages/profile.scss
@@ -66,12 +66,6 @@
}
}
-.calendar-hint {
- margin-top: -12px;
- float: right;
- font-size: 12px;
-}
-
.profile-link-holder {
display: inline;
@@ -134,14 +128,6 @@
}
}
-.change-username-title {
- color: $gl-warning;
-}
-
-.remove-account-title {
- color: $gl-danger;
-}
-
.provider-btn-group {
display: inline-block;
margin-right: 10px;
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index b7653a833ec..edef336481d 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -10,7 +10,7 @@
margin-bottom: 0;
}
.new_project,
-.edit_project {
+.edit-project {
fieldset.features {
.control-label {
font-weight: normal;
diff --git a/app/assets/stylesheets/pages/settings.scss b/app/assets/stylesheets/pages/settings.scss
index 3fb70085713..2e8f356298d 100644
--- a/app/assets/stylesheets/pages/settings.scss
+++ b/app/assets/stylesheets/pages/settings.scss
@@ -12,3 +12,11 @@
border: 1px solid $warning-message-border;
border-radius: $border-radius-base;
}
+
+.warning-title {
+ color: $gl-warning;
+}
+
+.danger-title {
+ color: $gl-danger;
+}
diff --git a/app/assets/stylesheets/pages/snippets.scss b/app/assets/stylesheets/pages/snippets.scss
index 639d639d5b0..2aa939b7dc3 100644
--- a/app/assets/stylesheets/pages/snippets.scss
+++ b/app/assets/stylesheets/pages/snippets.scss
@@ -16,19 +16,6 @@
}
}
-.snippet-box {
- @include border-radius(2px);
-
- display: block;
- float: left;
- padding: 0 $gl-padding;
- font-weight: normal;
- margin-right: 10px;
- font-size: $gl-font-size;
- border: 1px solid;
- line-height: 32px;
-}
-
.markdown-snippet-copy {
position: fixed;
top: -10px;
@@ -36,3 +23,34 @@
max-height: 0;
max-width: 0;
}
+
+.file-holder.snippet-file-content {
+ padding-bottom: $gl-padding;
+ border-bottom: 1px solid $border-color;
+
+ .file-title {
+ padding-top: $gl-padding;
+ padding-bottom: $gl-padding;
+ }
+
+ .file-actions {
+ top: 12px;
+ }
+
+ .file-content {
+ border-left: 1px solid $border-color;
+ border-right: 1px solid $border-color;
+ border-bottom: 1px solid $border-color;
+ }
+}
+
+.snippet-title {
+ font-size: 24px;
+ font-weight: normal;
+}
+
+.snippet-actions {
+ @media (min-width: $screen-sm-min) {
+ float: right;
+ }
+}
diff --git a/app/assets/stylesheets/pages/todos.scss b/app/assets/stylesheets/pages/todos.scss
index e51c3491dae..afc00a68572 100644
--- a/app/assets/stylesheets/pages/todos.scss
+++ b/app/assets/stylesheets/pages/todos.scss
@@ -29,6 +29,17 @@
.todo-item {
.todo-title {
@include str-truncated(calc(100% - 174px));
+ overflow: visible;
+ }
+
+ .status-box {
+ margin: 0;
+ float: none;
+ display: inline-block;
+ font-weight: normal;
+ padding: 0 5px;
+ line-height: inherit;
+ font-size: 14px;
}
.todo-body {
@@ -76,12 +87,11 @@
@media (max-width: $screen-xs-max) {
.todo-item {
- padding-left: $gl-padding;
-
.todo-title {
white-space: normal;
overflow: visible;
max-width: 100%;
+ margin-bottom: 10px;
}
.avatar {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index f137c12d215..17ce8e2ad20 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -229,6 +229,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
if ci_commit
status = ci_commit.status
coverage = ci_commit.try(:coverage)
+
+ status ||= "preparing"
else
ci_service = @merge_request.source_project.ci_service
status = ci_service.commit_status(merge_request.last_commit.sha, merge_request.source_branch) if ci_service
@@ -238,8 +240,6 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
end
- status = "preparing" if status.nil?
-
response = {
title: merge_request.title,
sha: merge_request.last_commit_short_sha,
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 799421c185b..a99632454d9 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -74,8 +74,6 @@ class UsersController < ApplicationController
def calendar
calendar = contributions_calendar
@timestamps = calendar.timestamps
- @starting_year = calendar.starting_year
- @starting_month = calendar.starting_month
render 'calendar', layout: false
end
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
index 3b9a421b118..aa8f4c1d0e4 100644
--- a/app/finders/group_projects_finder.rb
+++ b/app/finders/group_projects_finder.rb
@@ -18,7 +18,7 @@ class GroupProjectsFinder < UnionFinder
projects = []
if current_user
- if @group.users.include?(current_user)
+ if @group.users.include?(current_user) || current_user.admin?
projects << @group.projects unless only_shared
projects << @group.shared_projects unless only_owned
else
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 5849e00662b..8ed3ccf1c02 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -250,12 +250,12 @@ class IssuableFinder
def by_milestone(items)
if milestones?
if filter_by_no_milestone?
- items = items.where(milestone_id: [-1, nil])
+ items = items.left_joins_milestones.where(milestone_id: [-1, nil])
elsif filter_by_upcoming_milestone?
upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
- items = items.joins(:milestone).where(milestone_id: upcoming_ids)
+ items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
else
- items = items.joins(:milestone).where(milestones: { title: params[:milestone_title] })
+ items = items.with_milestone(params[:milestone_title])
if projects
items = items.where(milestones: { project_id: projects })
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index e6e2546b92f..439b015b3b8 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -262,6 +262,8 @@ module ApplicationHelper
assignee_id: params[:assignee_id],
author_id: params[:author_id],
sort: params[:sort],
+ issue_search: params[:issue_search],
+ label_name: params[:label_name]
}
options = exist_opts.merge(options)
@@ -272,16 +274,11 @@ module ApplicationHelper
end
end
- path = request.path
- path << "?#{options.to_param}"
- if add_label
- if params[:label_name].present? and params[:label_name].respond_to?('any?')
- params[:label_name].each do |label|
- path << "&label_name[]=#{label}"
- end
- end
- end
- path
+ params = options.compact
+
+ params.delete(:label_name) unless add_label
+
+ "#{request.path}?#{params.to_param}"
end
def outdated_browser?
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index e1489381706..bfedcb1c42b 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -159,28 +159,6 @@ module EventsHelper
"--broken encoding"
end
- def event_to_atom(xml, event)
- if event.visible_to_user?(current_user)
- xml.entry do
- event_link = event_feed_url(event)
- event_title = event_feed_title(event)
- event_summary = event_feed_summary(event)
-
- xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
- xml.link href: event_link
- xml.title truncate(event_title, length: 80)
- xml.updated event.created_at.xmlschema
- xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
- xml.author do |author|
- xml.name event.author_name
- xml.email event.author_email
- end
-
- xml.summary(type: "xhtml") { |x| x << event_summary unless event_summary.nil? }
- end
- end
- end
-
def event_row_class(event)
if event.body?
"event-block"
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 198d39455d7..551409e8855 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -105,23 +105,6 @@ module IssuesHelper
return 'hidden' if issue.closed? == closed
end
- def issue_to_atom(xml, issue)
- xml.entry do
- xml.id namespace_project_issue_url(issue.project.namespace,
- issue.project, issue)
- xml.link href: namespace_project_issue_url(issue.project.namespace,
- issue.project, issue)
- xml.title truncate(issue.title, length: 80)
- xml.updated issue.created_at.xmlschema
- xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
- xml.author do |author|
- xml.name issue.author_name
- xml.email issue.author_email
- end
- xml.summary issue.title
- end
- end
-
def merge_requests_sentence(merge_requests)
# Sorting based on the `!123` or `group/project!123` reference will sort
# local merge requests first.
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index fbb799eecd3..f685e547537 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -48,7 +48,7 @@ module NavHelper
"page-with-layout-nav" if defined?(nav) && nav
end
- def layout_dropdown_class
- "controls-dropdown-visible" if current_user
+ def nav_control_class
+ "nav-control" if current_user
end
end
diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb
index 81b9b5d7052..b9d7edb4185 100644
--- a/app/helpers/todos_helper.rb
+++ b/app/helpers/todos_helper.rb
@@ -37,6 +37,16 @@ module TodosHelper
end
end
+ def todo_target_state_pill(todo)
+ return unless show_todo_state?(todo)
+
+ content_tag(:span, nil, class: 'target-status') do
+ content_tag(:span, nil, class: "status-box status-box-#{todo.target.state.dasherize}") do
+ todo.target.state.capitalize
+ end
+ end
+ end
+
def todos_filter_params
{
state: params[:state],
@@ -95,4 +105,10 @@ module TodosHelper
options_from_collection_for_select(types, 'name', 'title', params[:type])
end
+
+ private
+
+ def show_todo_state?(todo)
+ (todo.target.is_a?(MergeRequest) || todo.target.is_a?(Issue)) && ['closed', 'merged'].include?(todo.target.state)
+ end
end
diff --git a/app/mailers/devise_mailer.rb b/app/mailers/devise_mailer.rb
index b616add283a..415f6e12885 100644
--- a/app/mailers/devise_mailer.rb
+++ b/app/mailers/devise_mailer.rb
@@ -1,4 +1,6 @@
class DeviseMailer < Devise::Mailer
default from: "#{Gitlab.config.gitlab.email_display_name} <#{Gitlab.config.gitlab.email_from}>"
default reply_to: Gitlab.config.gitlab.email_reply_to
+
+ layout 'devise_mailer'
end
diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb
index c1248b53031..91315b3459f 100644
--- a/app/models/concerns/issuable.rb
+++ b/app/models/concerns/issuable.rb
@@ -31,18 +31,21 @@ module Issuable
scope :unassigned, -> { where("assignee_id IS NULL") }
scope :of_projects, ->(ids) { where(project_id: ids) }
scope :of_milestones, ->(ids) { where(milestone_id: ids) }
+ scope :with_milestone, ->(title) { left_joins_milestones.where(milestones: { title: title }) }
scope :opened, -> { with_state(:opened, :reopened) }
scope :only_opened, -> { with_state(:opened) }
scope :only_reopened, -> { with_state(:reopened) }
scope :closed, -> { with_state(:closed) }
- scope :order_milestone_due_desc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date DESC, milestones.id DESC') }
- scope :order_milestone_due_asc, -> { outer_join_milestone.reorder('milestones.due_date IS NULL ASC, milestones.due_date ASC, milestones.id ASC') }
- scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
+ scope :left_joins_milestones, -> { joins("LEFT OUTER JOIN milestones ON #{table_name}.milestone_id = milestones.id") }
+ scope :order_milestone_due_desc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date DESC') }
+ scope :order_milestone_due_asc, -> { left_joins_milestones.reorder('milestones.due_date IS NULL, milestones.id IS NULL, milestones.due_date ASC') }
+
+ scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :join_project, -> { joins(:project) }
scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
- scope :outer_join_milestone, -> { joins("LEFT OUTER JOIN milestones ON milestones.id = #{table_name}.milestone_id") }
+
delegate :name,
:email,
diff --git a/app/models/project.rb b/app/models/project.rb
index 37de1dfe4d5..f3a56b86d5a 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -431,7 +431,13 @@ class Project < ActiveRecord::Base
def check_limit
unless creator.can_create_project? or namespace.kind == 'group'
- self.errors.add(:limit_reached, "Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
+ projects_limit = creator.projects_limit
+
+ if projects_limit == 0
+ self.errors.add(:limit_reached, "Personal project creation is not allowed. Please contact your administrator with questions")
+ else
+ self.errors.add(:limit_reached, "Your project limit is #{projects_limit} projects! Please contact your administrator to increase it")
+ end
end
rescue
self.errors.add(:base, "Can't check your ability to create project")
diff --git a/app/models/project_services/slack_service/build_message.rb b/app/models/project_services/slack_service/build_message.rb
index c124cad4afd..69c21b3fc38 100644
--- a/app/models/project_services/slack_service/build_message.rb
+++ b/app/models/project_services/slack_service/build_message.rb
@@ -35,8 +35,8 @@ class SlackService
private
def message
- "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status} in #{duration} second(s)"
- end
+ "#{project_link}: Commit #{commit_link} of #{branch_link} #{ref_type} by #{user_name} #{humanized_status} in #{duration} #{'second'.pluralize(duration)}"
+ end
def format(string)
Slack::Notifier::LinkFormatter.format(string)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index ecc8795c954..1ab163510bf 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -972,12 +972,6 @@ class Repository
end
end
- def main_language
- return unless head_exists?
-
- Linguist::Repository.new(rugged, rugged.head.target_id).language
- end
-
def avatar
return nil unless exists?
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 66136b62617..a886f35981f 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -53,10 +53,6 @@ class GitPushService < BaseService
# could cause the last commit of a merge request to change.
update_merge_requests
- # Checks if the main language has changed in the project and if so
- # it updates it accordingly
- update_main_language
-
perform_housekeeping
end
@@ -64,19 +60,6 @@ class GitPushService < BaseService
@project.repository.copy_gitattributes(params[:ref])
end
- def update_main_language
- # Performance can be bad so for now only check main_language once
- # See https://gitlab.com/gitlab-org/gitlab-ce/issues/14937
- return if @project.main_language.present?
-
- return unless is_default_branch?
- return unless push_to_new_branch? || push_to_existing_branch?
-
- current_language = @project.repository.main_language
- @project.update_attributes(main_language: current_language)
- true
- end
-
protected
def update_merge_requests
diff --git a/app/services/projects/fork_service.rb b/app/services/projects/fork_service.rb
index 0577ae778d5..de6dc38cc8e 100644
--- a/app/services/projects/fork_service.rb
+++ b/app/services/projects/fork_service.rb
@@ -3,7 +3,7 @@ module Projects
def execute
new_params = {
forked_from_project_id: @project.id,
- visibility_level: @project.visibility_level,
+ visibility_level: allowed_visibility_level,
description: @project.description,
name: @project.name,
path: @project.path,
@@ -19,5 +19,17 @@ module Projects
new_project = CreateService.new(current_user, new_params).execute
new_project
end
+
+ private
+
+ def allowed_visibility_level
+ project_level = @project.visibility_level
+
+ if Gitlab::VisibilityLevel.non_restricted_level?(project_level)
+ project_level
+ else
+ Gitlab::VisibilityLevel.highest_allowed_level
+ end
+ end
end
end
diff --git a/app/views/admin/builds/index.html.haml b/app/views/admin/builds/index.html.haml
index ed24757087b..d74cf8598e8 100644
--- a/app/views/admin/builds/index.html.haml
+++ b/app/views/admin/builds/index.html.haml
@@ -47,4 +47,3 @@
= render "admin/builds/build", build: build
= paginate @builds, theme: 'gitlab'
-
diff --git a/app/views/dashboard/issues.atom.builder b/app/views/dashboard/issues.atom.builder
index 0d7b1b30dc3..83c0c6da21b 100644
--- a/app/views/dashboard/issues.atom.builder
+++ b/app/views/dashboard/issues.atom.builder
@@ -6,8 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id issues_dashboard_url
xml.updated @issues.first.created_at.xmlschema if @issues.any?
- @issues.each do |issue|
- issue_to_atom(xml, issue)
- end
+ xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
end
-
diff --git a/app/views/dashboard/projects/index.atom.builder b/app/views/dashboard/projects/index.atom.builder
index d4daf07c6c0..fb5be63b472 100644
--- a/app/views/dashboard/projects/index.atom.builder
+++ b/app/views/dashboard/projects/index.atom.builder
@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id dashboard_projects_url
xml.updated @events[0].updated_at.xmlschema if @events[0]
- @events.each do |event|
- event_to_atom(xml, event)
- end
+ xml << render(partial: 'events/event', collection: @events) if @events.any?
end
diff --git a/app/views/dashboard/todos/_todo.html.haml b/app/views/dashboard/todos/_todo.html.haml
index 539f1dc6036..98f302d2f93 100644
--- a/app/views/dashboard/todos/_todo.html.haml
+++ b/app/views/dashboard/todos/_todo.html.haml
@@ -3,6 +3,8 @@
= image_tag avatar_icon(todo.author_email, 40), class: 'avatar s40', alt:''
.todo-title.title
- unless todo.build_failed?
+ = todo_target_state_pill(todo)
+
%span.author-name
- if todo.author
= link_to_author(todo)
diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb
deleted file mode 100644
index c6fa8f0ee36..00000000000
--- a/app/views/devise/mailer/confirmation_instructions.html.erb
+++ /dev/null
@@ -1,9 +0,0 @@
-<p>Welcome <%= @resource.name %>!</p>
-
-<% if @resource.unconfirmed_email.present? %>
- <p>You can confirm your email (<%= @resource.unconfirmed_email %>) through the link below:</p>
-<% else %>
- <p>You can confirm your account through the link below:</p>
-<% end %>
-
-<p><%= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token) %></p>
diff --git a/app/views/devise/mailer/confirmation_instructions.html.haml b/app/views/devise/mailer/confirmation_instructions.html.haml
new file mode 100644
index 00000000000..086bb8e083d
--- /dev/null
+++ b/app/views/devise/mailer/confirmation_instructions.html.haml
@@ -0,0 +1,16 @@
+.center
+ - if @resource.unconfirmed_email.present?
+ #content
+ %h2= @resource.unconfirmed_email
+ %p Click the link below to confirm your email address.
+ #cta
+ = link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
+ - else
+ #content
+ - if Gitlab.com?
+ %h2 Thanks for signing up to GitLab!
+ - else
+ %h2 Welcome, #{@resource.name}!
+ %p To get started, click the link below to confirm your account.
+ #cta
+ = link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token)
diff --git a/app/views/devise/mailer/confirmation_instructions.text.erb b/app/views/devise/mailer/confirmation_instructions.text.erb
new file mode 100644
index 00000000000..9f76edb76a4
--- /dev/null
+++ b/app/views/devise/mailer/confirmation_instructions.text.erb
@@ -0,0 +1,9 @@
+Welcome, <%= @resource.name %>!
+
+<% if @resource.unconfirmed_email.present? %>
+You can confirm your email (<%= @resource.unconfirmed_email %>) through the link below:
+<% else %>
+You can confirm your account through the link below:
+<% end %>
+
+<%= confirmation_url(@resource, confirmation_token: @token) %>
diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml
index eae80e5210f..ce050007204 100644
--- a/app/views/doorkeeper/authorizations/new.html.haml
+++ b/app/views/doorkeeper/authorizations/new.html.haml
@@ -1,4 +1,4 @@
-%h3.page-title Authorize required
+%h3.page-title Authorization required
%main{:role => "main"}
%p.h4
Authorize
diff --git a/app/views/events/_event.atom.builder b/app/views/events/_event.atom.builder
new file mode 100644
index 00000000000..7890e717aa7
--- /dev/null
+++ b/app/views/events/_event.atom.builder
@@ -0,0 +1,20 @@
+return unless event.visible_to_user?(current_user)
+
+xml.entry do
+ xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
+ xml.link href: event_feed_url(event)
+ xml.title truncate(event_feed_title(event), length: 80)
+ xml.updated event.created_at.xmlschema
+ xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
+
+ xml.author do
+ xml.name event.author_name
+ xml.email event.author_email
+ end
+
+ xml.summary(type: "xhtml") do |summary|
+ event_summary = event_feed_summary(event)
+
+ summary << event_summary unless event_summary.nil?
+ end
+end
diff --git a/app/views/groups/issues.atom.builder b/app/views/groups/issues.atom.builder
index a6eb9abada6..c19671295af 100644
--- a/app/views/groups/issues.atom.builder
+++ b/app/views/groups/issues.atom.builder
@@ -6,8 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id issues_group_url
xml.updated @issues.first.created_at.xmlschema if @issues.any?
- @issues.each do |issue|
- issue_to_atom(xml, issue)
- end
+ xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
end
-
diff --git a/app/views/groups/show.atom.builder b/app/views/groups/show.atom.builder
index c66b82bb484..b68bf444d27 100644
--- a/app/views/groups/show.atom.builder
+++ b/app/views/groups/show.atom.builder
@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id group_url(@group)
xml.updated @events[0].updated_at.xmlschema if @events[0]
- @events.each do |event|
- event_to_atom(xml, event)
- end
+ xml << render(@events) if @events.any?
end
diff --git a/app/views/import/gitlab/status.html.haml b/app/views/import/gitlab/status.html.haml
index e3a356b5379..aedb8468eca 100644
--- a/app/views/import/gitlab/status.html.haml
+++ b/app/views/import/gitlab/status.html.haml
@@ -47,7 +47,7 @@
%td.import-target
= repo["path_with_namespace"]
%td.import-actions.job-status
- = button_tag class: "btn js-add-to-import" do
+ = button_tag class: "btn btn-import js-add-to-import" do
Import
= icon("spinner spin", class: "loading-icon")
diff --git a/app/views/issues/_issue.atom.builder b/app/views/issues/_issue.atom.builder
new file mode 100644
index 00000000000..68a2d19e58d
--- /dev/null
+++ b/app/views/issues/_issue.atom.builder
@@ -0,0 +1,14 @@
+xml.entry do
+ xml.id namespace_project_issue_url(issue.project.namespace, issue.project, issue)
+ xml.link href: namespace_project_issue_url(issue.project.namespace, issue.project, issue)
+ xml.title truncate(issue.title, length: 80)
+ xml.updated issue.created_at.xmlschema
+ xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
+
+ xml.author do |author|
+ xml.name issue.author_name
+ xml.email issue.author_email
+ end
+
+ xml.summary issue.title
+end
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 5be0b546a62..1e961853c70 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -25,7 +25,7 @@
.layout-nav
.container-fluid
= render "layouts/nav/#{nav}"
- .content-wrapper{ class: "#{layout_nav_class} #{layout_dropdown_class}" }
+ .content-wrapper{ class: "#{layout_nav_class}" }
= render "layouts/broadcast"
= render "layouts/flash"
= yield :flash_message
diff --git a/app/views/layouts/devise_mailer.html.haml b/app/views/layouts/devise_mailer.html.haml
new file mode 100644
index 00000000000..c258eafdd51
--- /dev/null
+++ b/app/views/layouts/devise_mailer.html.haml
@@ -0,0 +1,34 @@
+!!! 5
+%html
+ %head
+ %meta(content='text/html; charset=UTF-8' http-equiv='Content-Type')
+ = stylesheet_link_tag 'mailers/devise'
+
+ %body
+ %table#wrapper
+ %tr
+ %td
+ %table#header
+ %td{valign: "top"}
+ = image_tag('mailers/gitlab_header_logo.png', id: 'logo', alt: 'GitLab Wordmark')
+
+ %table#body
+ %tr
+ %td#body-container
+ = yield
+
+ - if Gitlab.com?
+ %table#footer
+ %tr
+ %td#tanuki
+ = image_tag('mailers/gitlab_tanuki_2x.png', alt: 'GitLab Logo')
+ %tr
+ %td#tagline
+ Everyone can contribute
+ %tr
+ %td#social
+ = link_to 'Blog', 'https://about.gitlab.com/blog/'
+ = link_to 'Twitter', 'https://twitter.com/gitlab'
+ = link_to 'Facebook', 'https://www.facebook.com/gitlab/'
+ = link_to 'YouTube', 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg'
+ = link_to 'LinkedIn', 'https://www.linkedin.com/company/gitlab-com'
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 3438005863a..de15add3617 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -1,37 +1,40 @@
-= render 'layouts/nav/group_settings'
+%div{ class: nav_control_class }
+ = render 'layouts/nav/group_settings'
-%ul.nav-links
- = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
- = link_to group_path(@group), title: 'Home' do
- = icon('group fw')
- %span
- Group
- = nav_link(path: 'groups#activity') do
- = link_to activity_group_path(@group), title: 'Activity' do
- = icon('dashboard fw')
- %span
- Activity
- = nav_link(controller: [:group, :milestones]) do
- = link_to group_milestones_path(@group), title: 'Milestones' do
- = icon('clock-o fw')
- %span
- Milestones
- = nav_link(path: 'groups#issues') do
- = link_to issues_group_path(@group), title: 'Issues' do
- = icon('exclamation-circle fw')
- %span
- Issues
- - issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- %span.badge.count= number_with_delimiter(issues.count)
- = nav_link(path: 'groups#merge_requests') do
- = link_to merge_requests_group_path(@group), title: 'Merge Requests' do
- = icon('tasks fw')
- %span
- Merge Requests
- - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
- %span.badge.count= number_with_delimiter(merge_requests.count)
- = nav_link(controller: [:group_members]) do
- = link_to group_group_members_path(@group), title: 'Members' do
- = icon('users fw')
- %span
- Members
+ %ul.nav-links.scrolling-tabs
+ .fade-left
+ = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
+ = link_to group_path(@group), title: 'Home' do
+ = icon('group fw')
+ %span
+ Group
+ = nav_link(path: 'groups#activity') do
+ = link_to activity_group_path(@group), title: 'Activity' do
+ = icon('dashboard fw')
+ %span
+ Activity
+ = nav_link(controller: [:group, :milestones]) do
+ = link_to group_milestones_path(@group), title: 'Milestones' do
+ = icon('clock-o fw')
+ %span
+ Milestones
+ = nav_link(path: 'groups#issues') do
+ = link_to issues_group_path(@group), title: 'Issues' do
+ = icon('exclamation-circle fw')
+ %span
+ Issues
+ - issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
+ %span.badge.count= number_with_delimiter(issues.count)
+ = nav_link(path: 'groups#merge_requests') do
+ = link_to merge_requests_group_path(@group), title: 'Merge Requests' do
+ = icon('tasks fw')
+ %span
+ Merge Requests
+ - merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
+ %span.badge.count= number_with_delimiter(merge_requests.count)
+ = nav_link(controller: [:group_members]) do
+ = link_to group_group_members_path(@group), title: 'Members' do
+ = icon('users fw')
+ %span
+ Members
+ .fade-right
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index d730840d63a..2efc6c48a48 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -1,4 +1,5 @@
-%ul.nav-links
+%ul.nav-links.scrolling-tabs
+ .fade-left
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: 'Profile Settings' do
= icon('user fw')
@@ -47,3 +48,4 @@
= icon('history fw')
%span
Audit Log
+ .fade-right
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 33ba654bbee..087b7472701 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -19,113 +19,117 @@
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')
- %span
- Project
- = nav_link(path: 'projects#activity') do
- = link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
- = icon('dashboard fw')
- %span
- Activity
- - if project_nav_tab? :files
- = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
- = link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
- = icon('files-o fw')
+%div{ class: nav_control_class }
+ %ul.nav-links.scrolling-tabs
+ .fade-left
+ = nav_link(path: 'projects#show', html_options: {class: 'home'}) do
+ = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
+ = icon('bookmark fw')
%span
- Files
-
- - if project_nav_tab? :commits
- = nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
- = link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
- = icon('history fw')
+ Project
+ = nav_link(path: 'projects#activity') do
+ = link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
+ = icon('dashboard fw')
%span
- Commits
+ Activity
+ - if project_nav_tab? :files
+ = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
+ = link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
+ = icon('files-o fw')
+ %span
+ Files
- - 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.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
+ - if project_nav_tab? :commits
+ = nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
+ = link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
+ = icon('history fw')
+ %span
+ Commits
- - 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.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
+ - 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.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
- - if project_nav_tab? :container_registry
- = nav_link(controller: %w(container_registry)) do
- = link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
- = icon('hdd-o fw')
- %span
- Container Registry
+ - 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.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
- - if project_nav_tab? :graphs
- = nav_link(controller: %w(graphs)) do
- = link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
- = icon('area-chart fw')
- %span
- Graphs
+ - if project_nav_tab? :container_registry
+ = nav_link(controller: %w(container_registry)) do
+ = link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
+ = icon('hdd-o fw')
+ %span
+ Container Registry
- - if project_nav_tab? :milestones
- = nav_link(controller: :milestones) do
- = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
- = icon('clock-o fw')
- %span
- Milestones
+ - if project_nav_tab? :graphs
+ = nav_link(controller: %w(graphs)) do
+ = link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
+ = icon('area-chart fw')
+ %span
+ Graphs
- - if project_nav_tab? :issues
- = nav_link(controller: :issues) do
- = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
- = icon('exclamation-circle fw')
- %span
- Issues
- - if @project.default_issues_tracker?
- %span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
+ - if project_nav_tab? :milestones
+ = nav_link(controller: :milestones) do
+ = link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
+ = icon('clock-o fw')
+ %span
+ Milestones
- - if project_nav_tab? :merge_requests
- = nav_link(controller: :merge_requests) do
- = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
- = icon('tasks fw')
- %span
- Merge Requests
- %span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
+ - if project_nav_tab? :issues
+ = nav_link(controller: :issues) do
+ = link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
+ = icon('exclamation-circle fw')
+ %span
+ Issues
+ - if @project.default_issues_tracker?
+ %span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
- - if project_nav_tab? :labels
- = nav_link(controller: :labels) do
- = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
- = icon('tags fw')
- %span
- Labels
+ - if project_nav_tab? :merge_requests
+ = nav_link(controller: :merge_requests) do
+ = link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
+ = icon('tasks fw')
+ %span
+ Merge Requests
+ %span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
- - if project_nav_tab? :wiki
- = nav_link(controller: :wikis) do
- = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
- = icon('book fw')
- %span
- Wiki
+ - if project_nav_tab? :labels
+ = nav_link(controller: :labels) do
+ = link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
+ = icon('tags fw')
+ %span
+ Labels
- - 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
- = icon('clipboard fw')
- %span
- Snippets
+ - if project_nav_tab? :wiki
+ = nav_link(controller: :wikis) do
+ = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
+ = icon('book fw')
+ %span
+ Wiki
+
+ - 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
+ = icon('clipboard fw')
+ %span
+ Snippets
+
+ -# Global shortcut to network page for compatibility
+ - if project_nav_tab? :network
+ %li.hidden
+ = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
+ Network
- -# Global shortcut to network page for compatibility
- - if project_nav_tab? :network
+ -# Shortcut to create a new issue
%li.hidden
- = link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
- Network
+ = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
+ Create a new issue
- -# Shortcut to create a new issue
- %li.hidden
- = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
- Create a new issue
+ .fade-right
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index afd3d79321f..01ac8161945 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -70,7 +70,7 @@
- if current_user.can_change_username?
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
- %h4.prepend-top-0.change-username-title
+ %h4.prepend-top-0.warning-title
Change username
%p
Changing your username will change path to all personal projects!
@@ -94,7 +94,7 @@
- if signup_enabled?
.row.prepend-top-default
.col-lg-3.profile-settings-sidebar
- %h4.prepend-top-0.remove-account-title
+ %h4.prepend-top-0.danger-title
Remove account
.col-lg-9
- if @user.can_be_removed?
diff --git a/app/views/profiles/preferences/show.html.haml b/app/views/profiles/preferences/show.html.haml
index bfe53be6854..1b1b16d656f 100644
--- a/app/views/profiles/preferences/show.html.haml
+++ b/app/views/profiles/preferences/show.html.haml
@@ -5,7 +5,7 @@
%h4.prepend-top-0
Application theme
%p
- This setting allows you to customize the appearance of the site, ex. sidebar.
+ This setting allows you to customize the appearance of the site, e.g. the sidebar.
.col-lg-9.application-theme
- Gitlab::Themes.each do |theme|
= label_tag do
diff --git a/app/views/projects/_builds_settings.html.haml b/app/views/projects/_builds_settings.html.haml
index 0de019983ca..0568c2d305e 100644
--- a/app/views/projects/_builds_settings.html.haml
+++ b/app/views/projects/_builds_settings.html.haml
@@ -1,74 +1,65 @@
%fieldset.builds-feature
- %legend
- Builds:
-
+ %h5.prepend-top-0
+ Builds
- unless @repository.gitlab_ci_yml
.form-group
- .col-sm-offset-2.col-sm-10
- %p Builds need to be configured before you can begin using Continuous Integration.
- = link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
- %hr
-
+ %p Builds need to be configured before you can begin using Continuous Integration.
+ = link_to 'Get started with Builds', help_page_path('ci/quick_start', 'README'), class: 'btn btn-info'
.form-group
- .col-sm-offset-2.col-sm-10
- %p Get recent application code using the following command:
- .radio
- = f.label :build_allow_git_fetch_false do
- = f.radio_button :build_allow_git_fetch, 'false'
- %strong git clone
- %br
- %span.descr Slower but makes sure you have a clean dir before every build
- .radio
- = f.label :build_allow_git_fetch_true do
- = f.radio_button :build_allow_git_fetch, 'true'
- %strong git fetch
- %br
- %span.descr Faster
+ %p Get recent application code using the following command:
+ .radio
+ = f.label :build_allow_git_fetch_false do
+ = f.radio_button :build_allow_git_fetch, 'false'
+ %strong git clone
+ %br
+ %span.descr Slower but makes sure you have a clean dir before every build
+ .radio
+ = f.label :build_allow_git_fetch_true do
+ = f.radio_button :build_allow_git_fetch, 'true'
+ %strong git fetch
+ %br
+ %span.descr Faster
.form-group
- = f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
- .col-sm-10
- = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
- %p.help-block per build in minutes
+ = f.label :build_timeout_in_minutes, 'Timeout', class: 'label-light'
+ = f.number_field :build_timeout_in_minutes, class: 'form-control', min: '0'
+ %p.help-block per build in minutes
.form-group
- = f.label :build_coverage_regex, "Test coverage parsing", class: 'control-label'
- .col-sm-10
- .input-group
- %span.input-group-addon /
- = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
- %span.input-group-addon /
- %p.help-block
- We will use this regular expression to find test coverage output in build trace.
- Leave blank if you want to disable this feature
- .bs-callout.bs-callout-info
- %p Below are examples of regex for existing tools:
- %ul
- %li
- Simplecov (Ruby) -
- %code \(\d+.\d+\%\) covered
- %li
- pytest-cov (Python) -
- %code \d+\%\s*$
- %li
- phpunit --coverage-text --colors=never (PHP) -
- %code ^\s*Lines:\s*\d+.\d+\%
- %li
- gcovr (C/C++) -
- %code ^TOTAL.*\s+(\d+\%)$
- %li
- tap --coverage-report=text-summary (Node.js) -
- %code ^Statements\s*:\s*([^%]+)
+ = f.label :build_coverage_regex, "Test coverage parsing", class: 'label-light'
+ .input-group
+ %span.input-group-addon /
+ = f.text_field :build_coverage_regex, class: 'form-control', placeholder: '\(\d+.\d+\%\) covered'
+ %span.input-group-addon /
+ %p.help-block
+ We will use this regular expression to find test coverage output in build trace.
+ Leave blank if you want to disable this feature
+ .bs-callout.bs-callout-info
+ %p Below are examples of regex for existing tools:
+ %ul
+ %li
+ Simplecov (Ruby) -
+ %code \(\d+.\d+\%\) covered
+ %li
+ pytest-cov (Python) -
+ %code \d+\%\s*$
+ %li
+ phpunit --coverage-text --colors=never (PHP) -
+ %code ^\s*Lines:\s*\d+.\d+\%
+ %li
+ gcovr (C/C++) -
+ %code ^TOTAL.*\s+(\d+\%)$
+ %li
+ tap --coverage-report=text-summary (Node.js) -
+ %code ^Statements\s*:\s*([^%]+)
.form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :public_builds do
- = f.check_box :public_builds
- %strong Public builds
- .help-block Allow everyone to access builds for Public and Internal projects
+ .checkbox
+ = f.label :public_builds do
+ = f.check_box :public_builds
+ %strong Public builds
+ .help-block Allow everyone to access builds for Public and Internal projects
- .form-group
- = f.label :runners_token, "Runners token", class: 'control-label'
- .col-sm-10
- = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
- %p.help-block The secure token used to checkout project.
+ .form-group.append-bottom-0
+ = f.label :runners_token, "Runners token", class: 'label-light'
+ = f.text_field :runners_token, class: "form-control", placeholder: 'xEeFCaDAB89'
+ %p.help-block The secure token used to checkout project.
diff --git a/app/views/projects/builds/index.html.haml b/app/views/projects/builds/index.html.haml
index 98f4a9416e5..7c0bec264ab 100644
--- a/app/views/projects/builds/index.html.haml
+++ b/app/views/projects/builds/index.html.haml
@@ -35,9 +35,6 @@
= icon('wrench')
%span CI Lint
-.row-content-block
- #{(@scope || 'all').capitalize} builds from this project
-
%ul.content-list
- if @builds.blank?
%li
diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml
index e23a3782c6b..5bd6e3f0ebc 100644
--- a/app/views/projects/ci/builds/_build.html.haml
+++ b/app/views/projects/ci/builds/_build.html.haml
@@ -57,14 +57,10 @@
%td.duration
- if build.duration
- = icon("clock-o")
- &nbsp;
#{duration_in_words(build.finished_at, build.started_at)}
%td.timestamp
- if build.finished_at
- = icon("calendar")
- &nbsp;
%span #{time_ago_with_tooltip(build.finished_at)}
- if defined?(coverage) && coverage
diff --git a/app/views/projects/ci/commits/_commit.html.haml b/app/views/projects/ci/commits/_commit.html.haml
index 13162b41f9b..5b6b940a0c4 100644
--- a/app/views/projects/ci/commits/_commit.html.haml
+++ b/app/views/projects/ci/commits/_commit.html.haml
@@ -12,10 +12,10 @@
&middot;
= link_to commit.short_sha, namespace_project_commit_path(@project.namespace, @project, commit.sha), class: "commit-id monospace"
&nbsp;
- - if commit.latest?
- %span.label.label-success latest
- if commit.tag?
%span.label.label-primary tag
+ - elsif commit.latest?
+ %span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest
- if commit.triggered?
%span.label.label-primary triggered
- if commit.yaml_errors.present?
@@ -23,33 +23,29 @@
- if commit.builds.any?(&:stuck?)
%span.label.label-warning stuck
- %p
- %span
- - if commit_data = commit.commit_data
- = link_to_gfm commit_data.title, namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
- - else
- Cant find HEAD commit for this branch
+ %p.commit-title
+ - if commit_data = commit.commit_data
+ = link_to_gfm truncate(commit_data.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
+ - else
+ Cant find HEAD commit for this branch
- stages_status = commit.statuses.stages_status
- stages.each do |stage|
%td
- - if status = stages_status[stage]
- - tooltip = "#{stage.titleize}: #{status}"
- %span.has-tooltip{ title: "#{tooltip}", class: "ci-status-icon-#{status}" }
+ - status = stages_status[stage]
+ - tooltip = "#{stage.titleize}: #{status || 'not found'}"
+ - if status
+ = link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
= ci_icon_for_status(status)
+ - else
+ .light.has-tooltip{ title: tooltip }
+ \-
%td
- if commit.started_at && commit.finished_at
- %p
- = icon("clock-o")
- &nbsp;
+ %p.duration
#{duration_in_words(commit.finished_at, commit.started_at)}
- - if commit.finished_at
- %p
- = icon("calendar")
- &nbsp;
- #{time_ago_with_tooltip(commit.finished_at)}
%td
.controls.hidden-xs.pull-right
@@ -67,11 +63,9 @@
%span #{build.name}
- if can?(current_user, :update_pipeline, @project)
- &nbsp;
- if commit.retryable? && commit.builds.failed.any?
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do
= icon("repeat")
- &nbsp;
- if commit.active?
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
= icon("remove")
diff --git a/app/views/projects/commit/_ci_stage.html.haml b/app/views/projects/commit/_ci_stage.html.haml
index aaa318e1eb3..ae7bb01223e 100644
--- a/app/views/projects/commit/_ci_stage.html.haml
+++ b/app/views/projects/commit/_ci_stage.html.haml
@@ -1,6 +1,7 @@
%tr
%th{colspan: 10}
%strong
+ %a{name: stage}
- status = statuses.latest.status
%span{class: "ci-status-link ci-status-icon-#{status}"}
= ci_icon_for_status(status)
diff --git a/app/views/projects/commits/_commit.atom.builder b/app/views/projects/commits/_commit.atom.builder
new file mode 100644
index 00000000000..1657fb46163
--- /dev/null
+++ b/app/views/projects/commits/_commit.atom.builder
@@ -0,0 +1,14 @@
+xml.entry do
+ xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
+ xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
+ xml.title truncate(commit.title, length: 80)
+ xml.updated commit.committed_date.xmlschema
+ xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
+
+ xml.author do |author|
+ xml.name commit.author_name
+ xml.email commit.author_email
+ end
+
+ xml.summary markdown(commit.description, pipeline: :single_line)
+end
diff --git a/app/views/projects/commits/show.atom.builder b/app/views/projects/commits/show.atom.builder
index e310fafd82c..30bb7412073 100644
--- a/app/views/projects/commits/show.atom.builder
+++ b/app/views/projects/commits/show.atom.builder
@@ -6,18 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
xml.updated @commits.first.committed_date.xmlschema if @commits.any?
- @commits.each do |commit|
- xml.entry do
- xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
- xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
- xml.title truncate(commit.title, length: 80)
- xml.updated commit.committed_date.xmlschema
- xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
- xml.author do |author|
- xml.name commit.author_name
- xml.email commit.author_email
- end
- xml.summary markdown(commit.description, pipeline: :single_line)
- end
- end
+ xml << render(@commits) if @commits.any?
end
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index f6a53fddf17..18b125ff9d4 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -1,261 +1,221 @@
-.project-edit-container.prepend-top-default
- .project-edit-errors
- .project-edit-content
- .panel.panel-default
- .panel-heading
+.project-edit-container
+ .row.prepend-top-default
+ .col-lg-3.profile-settings-sidebar
+ %h4.prepend-top-0
Project settings
- .panel-body
- = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit_project form-horizontal fieldset-form" }, authenticity_token: true do |f|
-
- %fieldset
- .form-group.project_name_holder
- = f.label :name, class: 'control-label' do
- Project name
- .col-sm-10
- = f.text_field :name, class: "form-control", id: "project_name_edit"
-
-
- .form-group
- = f.label :description, class: 'control-label' do
- Project description
- %span.light (optional)
- .col-sm-10
- = f.text_area :description, class: "form-control", rows: 3, maxlength: 250
-
- - unless @project.empty_repo?
- .form-group
- = f.label :default_branch, "Default Branch", class: 'control-label'
- .col-sm-10= f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
-
-
- = render 'shared/visibility_level', f: f, visibility_level: @project.visibility_level, can_change_visibility_level: can_change_visibility_level?(@project, current_user), form_model: @project
-
+ .col-lg-9
+ = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
+ %fieldset.append-bottom-0
.form-group
- = f.label :tag_list, "Tags", class: 'control-label'
- .col-sm-10
- = f.text_field :tag_list, value: @project.tag_list.to_s, maxlength: 2000, class: "form-control"
- %p.help-block Separate tags with commas.
-
- %fieldset.features
- %legend
- Features:
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :issues_enabled do
- = f.check_box :issues_enabled
- %strong Issues
- %br
- %span.descr Lightweight issue tracking system for this project
-
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :merge_requests_enabled do
- = f.check_box :merge_requests_enabled
- %strong Merge Requests
- %br
- %span.descr Submit changes to be merged upstream
-
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :builds_enabled do
- = f.check_box :builds_enabled
- %strong Builds
- %br
- %span.descr Test and deploy your changes before merge
-
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :wiki_enabled do
- = f.check_box :wiki_enabled
- %strong Wiki
- %br
- %span.descr Pages for project documentation
-
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :snippets_enabled do
- = f.check_box :snippets_enabled
- %strong Snippets
- %br
- %span.descr Share code pastes with others out of git repository
-
- - if Gitlab.config.registry.enabled
- .form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :container_registry_enabled do
- = f.check_box :container_registry_enabled
- %strong Container Registry
- %br
- %span.descr Enable Container Registry for this repository
-
- = render 'builds_settings', f: f
+ = f.label :name, class: 'label-light' do
+ Project name
+ = f.text_field :name, class: "form-control", id: "project_name_edit"
+ .form-group
+ = f.label :description, class: 'label-light' do
+ Project description
+ %span.light (optional)
+ = f.text_area :description, class: "form-control", rows: 3, maxlength: 250
- %fieldset.features
- %legend
- Project avatar:
+ - unless @project.empty_repo?
.form-group
- .col-sm-offset-2.col-sm-10
- - if @project.avatar?
- = project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
- %p.light
- - if @project.avatar_in_git
- Project avatar in repository: #{ @project.avatar_in_git }
- %p.light
- - if @project.avatar?
- You can change your project avatar here
- - else
- You can upload a project avatar here
- %a.choose-btn.btn.btn-sm.js-choose-project-avatar-button
- %i.icon-paper-clip
- %span Choose File ...
- &nbsp;
- %span.file_name.js-avatar-filename File name...
- = f.file_field :avatar, class: "js-project-avatar-input hidden"
- .light The maximum file size allowed is 200KB.
- - if @project.avatar?
- %hr
- = link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
-
-
- .form-actions
- = f.submit 'Save changes', class: "btn btn-save"
-
-
-
- .danger-settings
- .panel.panel-default
- .panel-heading Housekeeping
- .errors-holder
- .panel-body
- %p
- Runs a number of housekeeping tasks within the current repository,
- such as compressing file revisions and removing unreachable objects.
- %br
-
- .form-actions
- = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project),
- method: :post, class: "btn btn-default"
-
- - if can? current_user, :archive_project, @project
- - if @project.archived?
- .panel.panel-success
- .panel-heading
- Unarchive project
- .panel-body
- %p
- Unarchiving the project will mark its repository as active.
+ = f.label :default_branch, "Default Branch", class: 'label-light'
+ = f.select(:default_branch, @project.repository.branch_names, {}, {class: 'select2 select-wide'})
+ .form-group.project-visibility-level-holder
+ = f.label :visibility_level, class: 'label-light' do
+ Visibility Level
+ = link_to "(?)", help_page_path("public_access", "public_access")
+ - if can_change_visibility_level?(@project, current_user)
+ = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: @project.visibility_level, form_model: @project)
+ - else
+ .info
+ = visibility_level_icon(@project.visibility_level)
+ %strong
+ = visibility_level_label(@project.visibility_level)
+ .light= visibility_level_description(@project.visibility_level, @project)
+ .form-group
+ = f.label :tag_list, "Tags", class: 'label-light'
+ = f.text_field :tag_list, value: @project.tag_list.to_s, maxlength: 2000, class: "form-control"
+ %p.help-block Separate tags with commas.
+ %hr
+ %fieldset.features.append-bottom-0
+ %h5.prepend-top-0
+ Features
+ .form-group
+ .checkbox
+ = f.label :issues_enabled do
+ = f.check_box :issues_enabled
+ %strong Issues
%br
- The project can be committed to.
+ %span.descr Lightweight issue tracking system for this project
+ .form-group
+ .checkbox
+ = f.label :merge_requests_enabled do
+ = f.check_box :merge_requests_enabled
+ %strong Merge Requests
%br
- %strong Once active this project shows up in the search and on the dashboard.
-
- .form-actions
- = link_to 'Unarchive project', unarchive_namespace_project_path(@project.namespace, @project),
- data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
- method: :post, class: "btn btn-success"
- - else
- .panel.panel-warning
- .panel-heading
- Archive project
- .panel-body
- %p
- Archiving the project will mark its repository as read-only.
+ %span.descr Submit changes to be merged upstream
+ .form-group
+ .checkbox
+ = f.label :builds_enabled do
+ = f.check_box :builds_enabled
+ %strong Builds
+ %br
+ %span.descr Test and deploy your changes before merge
+ .form-group
+ .checkbox
+ = f.label :wiki_enabled do
+ = f.check_box :wiki_enabled
+ %strong Wiki
%br
- It is hidden from the dashboard and doesn't show up in searches.
+ %span.descr Pages for project documentation
+ .form-group
+ .checkbox
+ = f.label :snippets_enabled do
+ = f.check_box :snippets_enabled
+ %strong Snippets
%br
- %strong Archived projects cannot be committed to!
-
- .form-actions
- = link_to 'Archive project', archive_namespace_project_path(@project.namespace, @project),
- data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
- method: :post, class: "btn btn-warning"
- - else
- .nothing-here-block Only the project owner can archive a project
-
- .panel.panel-default.panel.panel-warning
- .panel-heading Rename repository
- .errors-holder
- .panel-body
- = form_for([@project.namespace.becomes(Namespace), @project], html: { class: 'form-horizontal' }) do |f|
- .form-group.project_name_holder
- = f.label :name, class: 'control-label' do
- Project name
- .col-sm-9
- .form-group
- = f.text_field :name, class: "form-control"
+ %span.descr Share code pastes with others out of git repository
+ - if Gitlab.config.registry.enabled
.form-group
- = f.label :path, class: 'control-label' do
- %span Path
- .col-sm-9
- .form-group
- .input-group
- .input-group-addon
- #{URI.join(root_url, @project.namespace.path)}/
- = f.text_field :path, class: 'form-control'
- %ul
- %li Be careful. Renaming a project's repository can have unintended side effects.
- %li You will need to update your local repositories to point to the new location.
- .form-actions
- = f.submit 'Rename project', class: "btn btn-warning"
-
- - if can?(current_user, :change_namespace, @project)
- .panel.panel-default.panel.panel-danger
- .panel-heading Transfer project
- .errors-holder
- .panel-body
- = form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
- .form-group
- = label_tag :new_namespace_id, nil, class: 'control-label' do
- %span Namespace
- .col-sm-9
- .form-group
- = select_tag :new_namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace', class: 'select2' }
- %ul
- %li Be careful. Changing the project's namespace can have unintended side effects.
- %li You can only transfer the project to namespaces you manage.
- %li You will need to update your local repositories to point to the new location.
- %li Project visibility level will be changed to match namespace rules when transfering to a group.
- .form-actions
- = f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => transfer_project_message(@project) }
- - else
- .nothing-here-block Only the project owner can transfer a project
-
- - if @project.forked?
- - if can?(current_user, :remove_fork_project, @project)
- = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
- .panel.panel-default.panel.panel-danger
- .panel-heading Remove fork relationship
- .panel-body
- %p
- This will remove the fork relationship to source project
- #{link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)}.
+ .checkbox
+ = f.label :container_registry_enabled do
+ = f.check_box :container_registry_enabled
+ %strong Container Registry
%br
- %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
- .form-actions
- = button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
+ %span.descr Enable Container Registry for this repository
+ %hr
+ = render 'builds_settings', f: f
+ %hr
+ %fieldset.features.append-bottom-default
+ %h5.prepend-top-0
+ Project avatar
+ .form-group
+ - if @project.avatar?
+ = project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
+ %p.light
+ - if @project.avatar_in_git
+ Project avatar in repository: #{ @project.avatar_in_git }
+ %a.choose-btn.btn.js-choose-project-avatar-button
+ Browse file...
+ %span.file_name.prepend-left-default.js-avatar-filename No file chosen
+ = f.file_field :avatar, class: "js-project-avatar-input hidden"
+ .help-block The maximum file size allowed is 200KB.
+ - if @project.avatar?
+ %hr
+ = link_to 'Remove avatar', namespace_project_avatar_path(@project.namespace, @project), data: { confirm: "Project avatar will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-avatar"
+ = f.submit 'Save changes', class: "btn btn-save"
+ .row.prepend-top-default
+ %hr
+ .row.prepend-top-default
+ .col-lg-3
+ %h4.prepend-top-0
+ Housekeeping
+ %p.append-bottom-0
+ %p
+ Runs a number of housekeeping tasks within the current repository,
+ such as compressing file revisions and removing unreachable objects.
+ .col-lg-9
+ = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project),
+ method: :post, class: "btn btn-save"
+ %hr
+ - if can? current_user, :archive_project, @project
+ .row.prepend-top-default
+ .col-lg-3
+ %h4.warning-title.prepend-top-0
+ - if @project.archived?
+ Unarchive project
+ - else
+ Archive project
+ %p.append-bottom-0
+ - if @project.archived?
+ Unarchiving the project will mark its repository as active. The project can be committed to.
+ - else
+ Archiving the project will mark its repository as read-only. It is hidden from the dashboard and doesn't show up in searches.
+ .col-lg-9
+ - if @project.archived?
+ %p
+ %strong Once active this project shows up in the search and on the dashboard.
+ = link_to 'Unarchive project', unarchive_namespace_project_path(@project.namespace, @project),
+ data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be committed to again." },
+ method: :post, class: "btn btn-success"
- else
- .nothing-here-block Only the project owner can remove the fork relationship.
-
- - if can?(current_user, :remove_project, @project)
- .panel.panel-default.panel.panel-danger
- .panel-heading Remove project
- .panel-body
- = form_tag(namespace_project_path(@project.namespace, @project), method: :delete, class: 'form-horizontal') do
- %p
- Removing the project will delete its repository and all related resources including issues, merge requests etc.
- %br
- %strong Removed projects cannot be restored!
- .form-actions
- = button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
- - else
- .nothing-here-block Only the project owner can remove a project.
-
+ %p
+ %strong Archived projects cannot be committed to!
+ = link_to 'Archive project', archive_namespace_project_path(@project.namespace, @project),
+ data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
+ method: :post, class: "btn btn-warning"
+ %hr
+ .row.prepend-top-default
+ .col-lg-3
+ %h4.prepend-top-0.warning-title
+ Rename repository
+ .col-lg-9
+ = form_for([@project.namespace.becomes(Namespace), @project]) do |f|
+ .form-group.project_name_holder
+ = f.label :name, class: 'label-light' do
+ Project name
+ .form-group
+ = f.text_field :name, class: "form-control"
+ .form-group
+ = f.label :path, class: 'label-light' do
+ %span Path
+ .form-group
+ .input-group
+ .input-group-addon
+ #{URI.join(root_url, @project.namespace.path)}/
+ = f.text_field :path, class: 'form-control'
+ %ul
+ %li Be careful. Renaming a project's repository can have unintended side effects.
+ %li You will need to update your local repositories to point to the new location.
+ = f.submit 'Rename project', class: "btn btn-warning"
+ - if can?(current_user, :change_namespace, @project)
+ %hr
+ .row.prepend-top-default
+ .col-lg-3
+ %h4.prepend-top-0.danger-title
+ Transfer project
+ .col-lg-9
+ = form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true) do |f|
+ .form-group
+ = label_tag :new_namespace_id, nil, class: 'label-light' do
+ %span Namespace
+ .form-group
+ = select_tag :new_namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace', class: 'select2' }
+ %ul
+ %li Be careful. Changing the project's namespace can have unintended side effects.
+ %li You can only transfer the project to namespaces you manage.
+ %li You will need to update your local repositories to point to the new location.
+ %li Project visibility level will be changed to match namespace rules when transfering to a group.
+ = f.submit 'Transfer project', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => transfer_project_message(@project) }
+ - if @project.forked? && can?(current_user, :remove_fork_project, @project)
+ %hr
+ .row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ %h4.prepend-top-0.danger-title
+ Remove fork relationship
+ %p.append-bottom-0
+ %p
+ This will remove the fork relationship to source project
+ = succeed "." do
+ = link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
+ .col-lg-9
+ = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f|
+ %p
+ %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
+ = button_to 'Remove fork relationship', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_fork_project_message(@project) }
+ - if can?(current_user, :remove_project, @project)
+ %hr
+ .row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ %h4.prepend-top-0.danger-title
+ Remove project
+ %p.append-bottom-0
+ Removing the project will delete its repository and all related resources including issues, merge requests etc.
+ .col-lg-9
+ = form_tag(namespace_project_path(@project.namespace, @project), method: :delete) do
+ %p
+ %strong Removed projects cannot be restored!
+ = button_to 'Remove project', '#', class: "btn btn-remove js-confirm-danger", data: { "confirm-danger-message" => remove_project_message(@project) }
.save-project-loader.hide
.center
@@ -264,5 +224,4 @@
Saving project.
%p Please wait a moment, this page will automatically refresh when ready.
-
= render 'shared/confirm_modal', phrase: @project.path
diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
index 8129514964a..5bc5c71283e 100644
--- a/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
+++ b/app/views/projects/generic_commit_statuses/_generic_commit_status.html.haml
@@ -40,24 +40,20 @@
%td
= generic_commit_status.name
- .pull-right
- - if generic_commit_status.tags.any?
- - generic_commit_status.tags.each do |tag|
- %span.label.label-primary
- = tag
- - if defined?(retried) && retried
- %span.label.label-warning retried
+ %td
+ - if generic_commit_status.tags.any?
+ - generic_commit_status.tags.each do |tag|
+ %span.label.label-primary
+ = tag
+ - if defined?(retried) && retried
+ %span.label.label-warning retried
%td.duration
- if generic_commit_status.duration
- = icon("clock-o")
- &nbsp;
#{duration_in_words(generic_commit_status.finished_at, generic_commit_status.started_at)}
%td.timestamp
- if generic_commit_status.finished_at
- = icon("calendar")
- &nbsp;
%span #{time_ago_with_tooltip(generic_commit_status.finished_at)}
- if defined?(coverage) && coverage
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index ad4a932d391..f82c47301f4 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -19,7 +19,7 @@
.header.clearfix
%h3#date_header.page-title
%p.light
- Commits to #{@ref}, excluding merge commits. Limited by 6,000 commits
+ Commits to #{@ref}, excluding merge commits. Limited to 6,000 commits.
%input#brush_change{:type => "hidden"}
.graphs
#contributors-master
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 5cf70ea3bb7..78f64150601 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -6,7 +6,7 @@
.issue-title.title
%span.issue-title-text
= confidential_icon(issue)
- = link_to_gfm issue.title, issue_path(issue)
+ = link_to issue.title, issue_path(issue)
%ul.controls
- if issue.closed?
%li
diff --git a/app/views/projects/issues/_merge_requests.html.haml b/app/views/projects/issues/_merge_requests.html.haml
index e953353567e..2f9dc867d0d 100644
--- a/app/views/projects/issues/_merge_requests.html.haml
+++ b/app/views/projects/issues/_merge_requests.html.haml
@@ -24,5 +24,8 @@
MERGED
- elsif merge_request.closed?
CLOSED
- - if @closed_by_merge_requests.present?
+ %li
= render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count}
+ - if @closed_by_merge_requests.present?
+ %li
+ = render partial: 'projects/issues/closed_by_box', locals: {merge_request_count: @merge_requests.count}
diff --git a/app/views/projects/issues/index.atom.builder b/app/views/projects/issues/index.atom.builder
index ee8a9414657..7ad7c9c87e8 100644
--- a/app/views/projects/issues/index.atom.builder
+++ b/app/views/projects/issues/index.atom.builder
@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id namespace_project_issues_url(@project.namespace, @project)
xml.updated @issues.first.created_at.xmlschema if @issues.any?
- @issues.each do |issue|
- issue_to_atom(xml, issue)
- end
+ xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
end
diff --git a/app/views/projects/labels/index.html.haml b/app/views/projects/labels/index.html.haml
index cc41130a9dc..05382b9cee7 100644
--- a/app/views/projects/labels/index.html.haml
+++ b/app/views/projects/labels/index.html.haml
@@ -18,6 +18,6 @@
- else
.nothing-here-block
- if can? current_user, :admin_label, @project
- Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
+ Create a label or #{link_to 'generate a default set of labels', generate_namespace_project_labels_path(@project.namespace, @project), method: :post}.
- else
No labels created
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 2c54171c6bd..c02f94490a0 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -1,7 +1,7 @@
%li{ class: mr_css_classes(merge_request) }
.merge-request-title.title
%span.merge-request-title-text
- = link_to_gfm merge_request.title, merge_request_path(merge_request)
+ = link_to merge_request.title, merge_request_path(merge_request)
%ul.controls
- if merge_request.merged?
%li
diff --git a/app/views/projects/pipelines/index.html.haml b/app/views/projects/pipelines/index.html.haml
index 9d5b6d367c9..a6c12814adf 100644
--- a/app/views/projects/pipelines/index.html.haml
+++ b/app/views/projects/pipelines/index.html.haml
@@ -36,15 +36,7 @@
= icon('wrench')
%span CI Lint
-.row-content-block
- - if @scope == 'running'
- Running pipelines for this project
- - elsif @scope.nil?
- Pipelines for this project
- - else
- #{@scope.titleize} for this project
-
-%ul.content-list
+%ul.content-list.pipelines
- stages = @pipelines.stages
- if @pipelines.blank?
%li
@@ -56,10 +48,10 @@
%th ID
%th Commit
- stages.each do |stage|
- %th
- %span.pipeline-stage.has-tooltip{ title: "#{stage.titleize}" }
+ %th.stage
+ %span.has-tooltip{ title: "#{stage.titleize}" }
= stage.titleize.pluralize
- %th
+ %th Duration
%th
= render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
diff --git a/app/views/projects/runners/_specific_runners.html.haml b/app/views/projects/runners/_specific_runners.html.haml
index 30cd1263a12..8ae9f0d95f7 100644
--- a/app/views/projects/runners/_specific_runners.html.haml
+++ b/app/views/projects/runners/_specific_runners.html.haml
@@ -8,7 +8,7 @@
Install GitLab Runner software.
Checkout the #{link_to 'GitLab Runner section', 'https://about.gitlab.com/gitlab-ci/#gitlab-runner', target: '_blank'} to install it
%li
- Specify following URL during runner setup:
+ Specify the following URL during runner setup:
%code #{ci_root_url(only_path: false)}
%li
Use the following registration token during setup:
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index 1b70880043a..1f13ea28b4e 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -1,18 +1,16 @@
-%h3.page-title
- = @service.title
- = boolean_to_icon @service.activated?
+.row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ %h4.prepend-top-0
+ = @service.title
+ = boolean_to_icon @service.activated?
-%p= @service.description
-
-%hr
-
-= form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form|
- = render 'shared/service_settings', form: form
-
- .form-actions
- = form.submit 'Save changes', class: 'btn btn-save'
- &nbsp;
- - if @service.valid? && @service.activated?
- - disabled = @service.can_test? ? '':'disabled'
- = link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service.to_param), class: "btn #{disabled}"
- = link_to "Cancel", namespace_project_services_path(@project.namespace, @project), class: "btn btn-cancel"
+ %p= @service.description
+ .col-lg-9
+ = form_for(@service, as: :service, url: namespace_project_service_path(@project.namespace, @project, @service.to_param), method: :put, html: { class: 'form-horizontal' }) do |form|
+ = render 'shared/service_settings', form: form
+ = form.submit 'Save changes', class: 'btn btn-save'
+ &nbsp;
+ - if @service.valid? && @service.activated?
+ - disabled = @service.can_test? ? '':'disabled'
+ = link_to 'Test settings', test_namespace_project_service_path(@project.namespace, @project, @service.to_param), class: "btn #{disabled}"
+ = link_to "Cancel", namespace_project_services_path(@project.namespace, @project), class: "btn btn-cancel"
diff --git a/app/views/projects/services/index.html.haml b/app/views/projects/services/index.html.haml
index c1356f6db02..4a33a5bc6f6 100644
--- a/app/views/projects/services/index.html.haml
+++ b/app/views/projects/services/index.html.haml
@@ -1,24 +1,32 @@
- page_title "Services"
-%h3.page-title Project services
-%p.light Project services allow you to integrate GitLab with other applications
-.table-holder
- %table.table
- %thead
- %tr
- %th
- %th Service
- %th Description
- %th Last edit
- - @services.sort_by(&:title).each do |service|
- %tr
- %td
- = boolean_to_icon service.activated?
- %td
- = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
- %strong= service.title
- %td
- = service.description
- %td.light
- = time_ago_in_words service.updated_at
- ago
+.row.prepend-top-default.append-bottom-default
+ .col-lg-3
+ %h4.prepend-top-0
+ Project services
+ %p Project services allow you to integrate GitLab with other applications
+ .col-lg-9
+ %table.table
+ %colgroup
+ %col
+ %col
+ %col.hidden-xs
+ %col{ width: "120" }
+ %thead
+ %tr
+ %th
+ %th Service
+ %th.hidden-xs Description
+ %th Last edit
+ - @services.sort_by(&:title).each do |service|
+ %tr
+ %td
+ = boolean_to_icon service.activated?
+ %td
+ = link_to edit_namespace_project_service_path(@project.namespace, @project, service.to_param) do
+ %strong= service.title
+ %td.hidden-xs
+ = service.description
+ %td.light
+ = time_ago_in_words service.updated_at
+ ago
diff --git a/app/views/projects/show.atom.builder b/app/views/projects/show.atom.builder
index 9b3d3f069d9..11310d5e1e1 100644
--- a/app/views/projects/show.atom.builder
+++ b/app/views/projects/show.atom.builder
@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id namespace_project_url(@project.namespace, @project)
xml.updated @events[0].updated_at.xmlschema if @events[0]
- @events.each do |event|
- event_to_atom(xml, event)
- end
+ xml << render(@events) if @events.any?
end
diff --git a/app/views/projects/snippets/_actions.html.haml b/app/views/projects/snippets/_actions.html.haml
index 4a515469422..bf57beb9d07 100644
--- a/app/views/projects/snippets/_actions.html.haml
+++ b/app/views/projects/snippets/_actions.html.haml
@@ -1,11 +1,27 @@
-= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
- = icon('plus')
- New Snippet
-- if can?(current_user, :admin_project_snippet, @snippet)
- = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
- = icon('trash-o')
- Delete
-- if can?(current_user, :update_project_snippet, @snippet)
- = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
- = icon('pencil-square-o')
- Edit
+.hidden-xs
+ = link_to new_namespace_project_snippet_path(@project.namespace, @project), class: 'btn btn-grouped btn-create new-snippet-link', title: "New Snippet" do
+ = icon('plus')
+ New Snippet
+ - if can?(current_user, :update_project_snippet, @snippet)
+ = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-grouped snippable-edit" do
+ Edit
+ - if can?(current_user, :update_project_snippet, @snippet)
+ = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
+ Delete
+.visible-xs-block.dropdown
+ %button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
+ Options
+ %span.caret
+ .dropdown-menu.dropdown-menu-full-width
+ %ul
+ %li
+ = link_to new_namespace_project_snippet_path(@project.namespace, @project), title: "New Snippet" do
+ New Snippet
+ - if can?(current_user, :update_project_snippet, @snippet)
+ %li
+ = link_to edit_namespace_project_snippet_path(@project.namespace, @project, @snippet) do
+ Edit
+ - if can?(current_user, :update_project_snippet, @snippet)
+ %li
+ = link_to namespace_project_snippet_path(@project.namespace, @project, @snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
+ Delete
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index 7c599563ce4..6f7bdcb29e8 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -4,15 +4,13 @@
.snippet-holder
= render 'shared/snippets/header'
- %article.file-holder
- .file-title
+ %article.file-holder.file-holder-no-border.snippet-file-content
+ .file-title.file-title-clear
= blob_icon 0, @snippet.file_name
- %strong
- = @snippet.file_name
+ = @snippet.file_name
.file-actions.hidden-xs
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
-
= render 'shared/snippets/blob'
%div#notes= render "projects/notes/notes_with_form"
diff --git a/app/views/projects/triggers/index.html.haml b/app/views/projects/triggers/index.html.haml
index d73ac987161..7f3de47d7df 100644
--- a/app/views/projects/triggers/index.html.haml
+++ b/app/views/projects/triggers/index.html.haml
@@ -5,7 +5,7 @@
%h4.prepend-top-0
= page_title
%p
- Triggers can be used to force a rebuild of a specific branch or tag with an API call.
+ Triggers can force a specific branch or tag to rebuild with an API call.
.col-lg-9
%h5.prepend-top-0
Your triggers
@@ -19,7 +19,7 @@
= render partial: 'trigger', collection: @triggers, as: :trigger
- else
%p.settings-message.text-center.append-bottom-default
- There are no triggers to use, add one by the button below.
+ No triggers have been created yet. Add one using the button below.
= form_for @trigger, url: url_for(controller: 'projects/triggers', action: 'create') do |f|
= f.submit "Add Trigger", class: 'btn btn-success'
@@ -28,8 +28,7 @@
Use CURL
%p.light
- Copy the token above and set your branch or tag name. This is the reference that will be rebuild.
-
+ Copy the token above, set your branch or tag name, and that reference will be rebuilt.
%pre
:plain
@@ -41,10 +40,10 @@
Use .gitlab-ci.yml
%p.light
- Copy the snippet to
- %i .gitlab-ci.yml
- of dependent project.
- At the end of your build it will trigger this project to rebuilt.
+ In the
+ %code .gitlab-ci.yml
+ of the dependent project, include the following snippet.
+ The project will rebuild at the end of the build.
%pre
:plain
@@ -57,9 +56,8 @@
%p.light
Add
- %strong variables[VARIABLE]=VALUE
- to API request.
- The value of variable could then be used to distinguish triggered build from normal one.
+ %code variables[VARIABLE]=VALUE
+ to an API request. Variable values can be used to distinguish between triggered builds and normal builds.
%pre.append-bottom-0
:plain
diff --git a/app/views/shared/_event_filter.html.haml b/app/views/shared/_event_filter.html.haml
index c38d9313dba..30055002213 100644
--- a/app/views/shared/_event_filter.html.haml
+++ b/app/views/shared/_event_filter.html.haml
@@ -1,5 +1,7 @@
-%ul.nav-links.event-filter
+%ul.nav-links.event-filter.scrolling-tabs
+ .fade-left
= event_filter_link EventFilter.push, 'Push events'
= event_filter_link EventFilter.merged, 'Merge events'
= event_filter_link EventFilter.comments, 'Comments'
= event_filter_link EventFilter.team, 'Team'
+ .fade-right
diff --git a/app/views/shared/_sort_dropdown.html.haml b/app/views/shared/_sort_dropdown.html.haml
index d327bd0a96f..1e0f075b303 100644
--- a/app/views/shared/_sort_dropdown.html.haml
+++ b/app/views/shared/_sort_dropdown.html.haml
@@ -6,7 +6,7 @@
- else
= sort_title_recently_created
%b.caret
- %ul.dropdown-menu.dropdown-menu-align-right
+ %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort
%li
= link_to page_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created
diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index 9474462cbd1..323d563cd4a 100644
--- a/app/views/shared/issuable/_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -1,6 +1,8 @@
.issues-filters
.issues-details-filters.row-content-block.second-block
- = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
+ = form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name, :issue_search]), method: :get, class: 'filter-form js-filter-form' do
+ - if params[:issue_search].present?
+ = hidden_field_tag :issue_search, params[:issue_search]
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
.check-all-holder
= check_box_tag "check_all_issues", nil, false,
diff --git a/app/views/shared/issuable/_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml
index afad48499b7..186963b32b8 100644
--- a/app/views/shared/issuable/_search_form.html.haml
+++ b/app/views/shared/issuable/_search_form.html.haml
@@ -1,8 +1,2 @@
= form_tag(path, method: :get, id: "issue_search_form", class: 'issue-search-form') do
= search_field_tag :issue_search, params[:issue_search], { placeholder: 'Filter by name ...', class: 'form-control issue_search search-text-input input-short', spellcheck: false }
- = hidden_field_tag :state, params['state']
- = hidden_field_tag :scope, params['scope']
- = hidden_field_tag :assignee_id, params['assignee_id']
- = hidden_field_tag :author_id, params['author_id']
- = hidden_field_tag :milestone_id, params['milestone_id']
- = hidden_field_tag :label_id, params['label_id']
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 9ef021747a5..b8b66d08db8 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -12,9 +12,6 @@
%li.project-row{ class: css_class }
= cache(cache_key) do
.controls
- - if project.main_language
- %span
- = project.main_language
- if project.commit.try(:status)
%span
= render_commit_status(project.commit)
diff --git a/app/views/shared/snippets/_header.html.haml b/app/views/shared/snippets/_header.html.haml
index e65b1814872..897aa5b4462 100644
--- a/app/views/shared/snippets/_header.html.haml
+++ b/app/views/shared/snippets/_header.html.haml
@@ -1,25 +1,24 @@
-.detail-page-header
- .snippet-box.has-tooltip{class: visibility_level_color(@snippet.visibility_level), title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: 'body' }}
+.detail-page-header.clearfix
+ .snippet-box.has-tooltip.inline.append-right-5{ title: snippet_visibility_level_description(@snippet.visibility_level, @snippet), data: { container: "body" } }
+ %span.sr-only
+ = visibility_level_label(@snippet.visibility_level)
= visibility_level_icon(@snippet.visibility_level, fw: false)
- = visibility_level_label(@snippet.visibility_level)
- %span.identifier
+ %strong.item-title
Snippet ##{@snippet.id}
%span.creator
- &middot; created by #{link_to_member(@project, @snippet.author, size: 24)}
- &middot;
+ created by #{link_to_member(@project, @snippet.author, size: 24, author_class: "author item-title")}
= time_ago_with_tooltip(@snippet.created_at, placement: 'bottom', html_class: 'snippet_updated_ago')
- if @snippet.updated_at != @snippet.created_at
%span
- &middot;
= icon('edit', title: 'edited')
= time_ago_with_tooltip(@snippet.updated_at, placement: 'bottom', html_class: 'snippet_edited_ago')
- .pull-right
+ .snippet-actions
- if @snippet.project_id?
= render "projects/snippets/actions"
- else
= render "snippets/actions"
-.detail-page-description.row-content-block.second-block
- %h2.title
+.content-block.second-block
+ %h2.snippet-title.prepend-top-0.append-bottom-0
= markdown escape_once(@snippet.title), pipeline: :single_line
diff --git a/app/views/snippets/_actions.html.haml b/app/views/snippets/_actions.html.haml
index 1979ae6d5bc..a7769654b61 100644
--- a/app/views/snippets/_actions.html.haml
+++ b/app/views/snippets/_actions.html.haml
@@ -1,11 +1,27 @@
-= link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
- = icon('plus')
- New Snippet
-- if can?(current_user, :update_personal_snippet, @snippet)
- = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
- = icon('pencil-square-o')
- Edit
-- if can?(current_user, :admin_personal_snippet, @snippet)
- = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
- = icon('trash-o')
- Delete
+.hidden-xs
+ = link_to new_snippet_path, class: "btn btn-grouped btn-create new-snippet-link", title: "New Snippet" do
+ = icon('plus')
+ New Snippet
+ - if can?(current_user, :update_personal_snippet, @snippet)
+ = link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
+ Edit
+ - if can?(current_user, :admin_personal_snippet, @snippet)
+ = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-warning", title: 'Delete Snippet' do
+ Delete
+.visible-xs-block.dropdown
+ %button.btn.btn-default.btn-block.append-bottom-0.prepend-top-5{ data: { toggle: "dropdown" } }
+ Options
+ %span.caret
+ .dropdown-menu.dropdown-menu-full-width
+ %ul
+ %li
+ = link_to new_snippet_path, title: "New Snippet" do
+ New Snippet
+ - if can?(current_user, :update_personal_snippet, @snippet)
+ %li
+ = link_to edit_snippet_path(@snippet) do
+ Edit
+ - if can?(current_user, :admin_personal_snippet, @snippet)
+ %li
+ = link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, title: 'Delete Snippet' do
+ Delete
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index a2b36568770..ed3992650d4 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -3,11 +3,10 @@
.snippet-holder
= render 'shared/snippets/header'
- %article.file-holder
- .file-title
+ %article.file-holder.file-holder-no-border.snippet-file-content
+ .file-title.file-title-clear
= blob_icon 0, @snippet.file_name
- %strong
- = @snippet.file_name
+ = @snippet.file_name
.file-actions.hidden-xs
= clipboard_button(clipboard_target: ".blob-content[data-blob-id='#{@snippet.id}']")
= link_to 'Raw', raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml
index 1de71f37d1a..77f2ddefb1e 100644
--- a/app/views/users/calendar.html.haml
+++ b/app/views/users/calendar.html.haml
@@ -1,10 +1,9 @@
-#cal-heatmap.calendar
- :javascript
- new Calendar(
- #{@timestamps.to_json},
- #{@starting_year},
- #{@starting_month},
- '#{user_calendar_activities_path}'
- );
-
-.calendar-hint Summary of issues, merge requests, and push events
+.clearfix.calendar
+ .js-contrib-calendar
+ .calendar-hint
+ Summary of issues, merge requests, and push events
+:javascript
+ new Calendar(
+ #{@timestamps.to_json},
+ '#{user_calendar_activities_path}'
+ );
diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml
index 027a93a75fc..630d97e339d 100644
--- a/app/views/users/calendar_activities.html.haml
+++ b/app/views/users/calendar_activities.html.haml
@@ -1,23 +1,27 @@
%h4.prepend-top-20
- %span.light Contributions for
+ Contributions for
%strong #{@calendar_date.to_s(:short)}
-%ul.bordered-list
- - @events.sort_by(&:created_at).each do |event|
- %li
- %span.light
- %i.fa.fa-clock-o
- = event.created_at.to_s(:time)
- - if event.push?
- #{event.action_name} #{event.ref_type} #{event.ref_name}
- - else
- = event_action_name(event)
- - if event.target
- %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
-
- at
- %strong
- - if event.project
- = link_to_project event.project
+- if @events.any?
+ %ul.bordered-list
+ - @events.sort_by(&:created_at).each do |event|
+ %li
+ %span.light
+ %i.fa.fa-clock-o
+ = event.created_at.to_s(:time)
+ - if event.push?
+ #{event.action_name} #{event.ref_type} #{event.ref_name}
- else
- = event.project_name
+ = event_action_name(event)
+ - if event.target
+ %strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
+
+ at
+ %strong
+ - if event.project
+ = link_to_project event.project
+ - else
+ = event.project_name
+- else
+ %p
+ No contributions found for #{@calendar_date.to_s(:short)}
diff --git a/app/views/users/show.atom.builder b/app/views/users/show.atom.builder
index e9e466c6350..6c85e5f9fbd 100644
--- a/app/views/users/show.atom.builder
+++ b/app/views/users/show.atom.builder
@@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
xml.id user_url(@user)
xml.updated @events[0].updated_at.xmlschema if @events[0]
- @events.each do |event|
- event_to_atom(xml, event)
- end
+ xml << render(@events) if @events.any?
end
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 9017fd54fcc..0c513308308 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -89,10 +89,9 @@
.tab-content
#activity.tab-pane
.row-content-block.calender-block.white.second-block.hidden-xs
- %div{ class: container_class }
- .user-calendar{data: {href: user_calendar_path}}
- %h4.center.light
- %i.fa.fa-spinner.fa-spin
+ .user-calendar{data: {href: user_calendar_path}}
+ %h4.center.light
+ %i.fa.fa-spinner.fa-spin
.user-calendar-activities
.content_list{ data: {href: user_path} }
diff --git a/config/application.rb b/config/application.rb
index 0e5a77285e5..de2bb08c978 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -80,7 +80,7 @@ module Gitlab
config.assets.precompile << "*.png"
config.assets.precompile << "print.css"
config.assets.precompile << "notify.css"
- config.assets.precompile << "mailers/repository_push_email.css"
+ config.assets.precompile << "mailers/*.css"
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 4f39016bfa4..8cca0039b4a 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -39,6 +39,7 @@ Rails.application.configure do
config.action_mailer.delivery_method = :letter_opener_web
# Don't make a mess when bootstrapping a development environment
config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1')
+ config.action_mailer.preview_path = 'spec/mailers/previews'
config.eager_load = false
end
diff --git a/config/initializers/premailer.rb b/config/initializers/premailer.rb
index b9176688bc4..cb00d3cfe95 100644
--- a/config/initializers/premailer.rb
+++ b/config/initializers/premailer.rb
@@ -3,6 +3,6 @@ Premailer::Rails.config.merge!(
generate_text_part: false,
preserve_styles: true,
remove_comments: true,
- remove_ids: true,
+ remove_ids: false,
remove_scripts: false
)
diff --git a/db/migrate/20160525205328_remove_main_language_from_projects.rb b/db/migrate/20160525205328_remove_main_language_from_projects.rb
new file mode 100644
index 00000000000..0f9d60c385f
--- /dev/null
+++ b/db/migrate/20160525205328_remove_main_language_from_projects.rb
@@ -0,0 +1,21 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class RemoveMainLanguageFromProjects < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # When using the methods "add_concurrent_index" or "add_column_with_default"
+ # you must disable the use of transactions as these methods can not run in an
+ # existing transaction. When using "add_concurrent_index" make sure that this
+ # method is the _only_ method called in the migration, any other changes
+ # should go in a separate migration. This ensures that upon failure _only_ the
+ # index creation fails and can be retried or reverted easily.
+ #
+ # To disable transactions uncomment the following line and remove these
+ # comments:
+ # disable_ddl_transaction!
+
+ def change
+ remove_column :projects, :main_language
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index aee5fb90937..b42eef08a00 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20160516174813) do
+ActiveRecord::Schema.define(version: 20160525205328) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -760,7 +760,6 @@ ActiveRecord::Schema.define(version: 20160516174813) do
t.integer "build_timeout", default: 3600, null: false
t.boolean "pending_delete", default: false
t.boolean "public_builds", default: true, null: false
- t.string "main_language"
t.integer "pushes_since_gc", default: 0
t.boolean "last_repository_check_failed"
t.datetime "last_repository_check_at"
diff --git a/doc/administration/high_availability/README.md b/doc/administration/high_availability/README.md
index 43d85ffb775..d74a786ac24 100644
--- a/doc/administration/high_availability/README.md
+++ b/doc/administration/high_availability/README.md
@@ -19,6 +19,8 @@ Components/Servers Required:
- 2 servers/virtual machines (one active/one passive)
+![Active/Passive HA Diagram](../img/high_availability/active-passive-diagram.png)
+
### Active/Active
This architecture scales easily because all application servers handle
@@ -26,6 +28,8 @@ user requests simultaneously. The database, Redis, and GitLab application are
all deployed on separate servers. The configuration is **only** highly-available
if the database, Redis and storage are also configured as such.
+![Active/Active HA Diagram](../img/high_availability/active-active-diagram.png)
+
**Steps to configure active/active:**
1. [Configure the database](database.md)
diff --git a/doc/administration/high_availability/redis.md b/doc/administration/high_availability/redis.md
index d89a1e582ca..f6153216f33 100644
--- a/doc/administration/high_availability/redis.md
+++ b/doc/administration/high_availability/redis.md
@@ -26,7 +26,7 @@ that runs Redis.
```ruby
external_url 'https://gitlab.example.com'
- # Disable all components except PostgreSQL
+ # Disable all components except Redis
redis['enable'] = true
bootstrap['enable'] = false
nginx['enable'] = false
diff --git a/doc/administration/img/high_availability/active-active-diagram.png b/doc/administration/img/high_availability/active-active-diagram.png
new file mode 100644
index 00000000000..81259e0ae93
--- /dev/null
+++ b/doc/administration/img/high_availability/active-active-diagram.png
Binary files differ
diff --git a/doc/administration/img/high_availability/active-passive-diagram.png b/doc/administration/img/high_availability/active-passive-diagram.png
new file mode 100644
index 00000000000..f69ff1d0357
--- /dev/null
+++ b/doc/administration/img/high_availability/active-passive-diagram.png
Binary files differ
diff --git a/doc/development/testing.md b/doc/development/testing.md
index 33eed29ba5c..513457d203a 100644
--- a/doc/development/testing.md
+++ b/doc/development/testing.md
@@ -65,7 +65,7 @@ the command line via `bundle exec teaspoon`, or via a web browser at
- Use `context` to test branching logic.
- Don't `describe` symbols (see [Gotchas](gotchas.md#dont-describe-symbols)).
- Don't supply the `:each` argument to hooks since it's the default.
-- Prefer `not_to` to `to_not`.
+- Prefer `not_to` to `to_not` (_this is enforced by Rubocop_).
- Try to match the ordering of tests to the ordering within the class.
- Try to follow the [Four-Phase Test][four-phase-test] pattern, using newlines
to separate phases.
diff --git a/doc/development/ui_guide.md b/doc/development/ui_guide.md
index a3e260a5f89..b4dcb748351 100644
--- a/doc/development/ui_guide.md
+++ b/doc/development/ui_guide.md
@@ -6,3 +6,31 @@ We created a page inside GitLab where you can check commonly used html and css e
When you run GitLab instance locally - just visit http://localhost:3000/help/ui page to see UI examples
you can use during GitLab development.
+
+## Design repository
+
+All design files are stored in the [gitlab-design](https://gitlab.com/gitlab-org/gitlab-design)
+repository and maintained by GitLab UX designers.
+
+## Navigation
+
+GitLab's layout contains 2 sections: the left sidebar and the content. The left sidebar contains a static navigation menu.
+This menu will be visible regardless of what page you visit. The left sidebar also contains the GitLab logo
+and the current user's profile picture. The content section contains a header and the content itself.
+The header describes the current GitLab page and what navigation is
+available to user in this area. Depending on the area (project, group, profile setting) the header name and navigation may change. For example when user visits one of the
+project pages the header will contain a project name and navigation for that project. When the user visits a group page it will contain a group name and navigation related to this group.
+
+### Adding new tab to header navigation
+
+We try to keep the amount of tabs in the header navigation between 5 and 10 so that it fits on a typical laptop screen. We also try not to confuse the user with too many options. Ideally each
+tab should represent separate functionality. Everything related to the issue
+tracker should be under the 'Issues' tab while everything related to the wiki should
+be under 'Wiki' tab and so on and so forth.
+
+## Mobile screen size
+
+We want GitLab to work well on small mobile screens as well. Size limitations make it is impossible to fit everything on a mobile screen. In this case it is OK to hide
+part of the UI for smaller resolutions in favor of a better user experience.
+However core functionality like browsing files, creating issues, writing comments, should
+be available on all resolutions. \ No newline at end of file
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 526f127178d..108ceb593d0 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -271,7 +271,7 @@ sudo usermod -aG redis git
# Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 8-8-stable gitlab
-**Note:** You can change `8-7-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
+**Note:** You can change `8-8-stable` to `master` if you want the *bleeding edge* version, but never install master on a production server!
### Configure It
diff --git a/doc/monitoring/health_check.md b/doc/monitoring/health_check.md
index defbf37ac19..0d17799372f 100644
--- a/doc/monitoring/health_check.md
+++ b/doc/monitoring/health_check.md
@@ -11,7 +11,7 @@ and access the cache. This endpoint can be provided to uptime monitoring service
## 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.
+accepted token can be found on the `admin/health_check` page of your GitLab instance.
![access token](img/health_check_token.png)
diff --git a/features/steps/admin/users.rb b/features/steps/admin/users.rb
index 4bc290b6bdf..8fb8a86d58b 100644
--- a/features/steps/admin/users.rb
+++ b/features/steps/admin/users.rb
@@ -158,7 +158,7 @@ class Spinach::Features::AdminUsers < Spinach::FeatureSteps
step 'I should not see twitter details' do
expect(page).to have_content 'Pete'
- expect(page).to_not have_content 'twitter'
+ expect(page).not_to have_content 'twitter'
end
step 'click on ssh keys tab' do
diff --git a/features/steps/dashboard/todos.rb b/features/steps/dashboard/todos.rb
index 2b23df6764b..d3b6c7f6a15 100644
--- a/features/steps/dashboard/todos.rb
+++ b/features/steps/dashboard/todos.rb
@@ -106,7 +106,7 @@ class Spinach::Features::DashboardTodos < Spinach::FeatureSteps
if pending
expect(page).to have_link 'Done'
else
- expect(page).to_not have_link 'Done'
+ expect(page).not_to have_link 'Done'
end
end
end
diff --git a/features/steps/project/commits/commits.rb b/features/steps/project/commits/commits.rb
index f33f37be951..e1b29f1e57a 100644
--- a/features/steps/project/commits/commits.rb
+++ b/features/steps/project/commits/commits.rb
@@ -105,7 +105,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
end
step 'I should not see button to create a new merge request' do
- expect(page).to_not have_link 'Create Merge Request'
+ expect(page).not_to have_link 'Create Merge Request'
end
step 'I should see button to the merge request' do
diff --git a/features/steps/project/issues/award_emoji.rb b/features/steps/project/issues/award_emoji.rb
index c5d45709b44..1b14659b4df 100644
--- a/features/steps/project/issues/award_emoji.rb
+++ b/features/steps/project/issues/award_emoji.rb
@@ -39,8 +39,8 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
step 'I can see the activity and food categories' do
page.within '.emoji-menu' do
- expect(page).to_not have_selector 'Activity'
- expect(page).to_not have_selector 'Food'
+ expect(page).not_to have_selector 'Activity'
+ expect(page).not_to have_selector 'Food'
end
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index fc12843ea5c..f2c68f007ef 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -216,7 +216,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
page.within 'li.issue:nth-child(3)' do
expect(page).to have_content 'Bugfix'
- expect(page).to_not have_content '0 0'
+ expect(page).not_to have_content '0 0'
end
end
end
@@ -235,7 +235,7 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
page.within 'li.issue:nth-child(3)' do
expect(page).to have_content 'Bugfix'
- expect(page).to_not have_content '0 0'
+ expect(page).not_to have_content '0 0'
end
end
end
diff --git a/features/steps/project/issues/labels.rb b/features/steps/project/issues/labels.rb
index 0ca2d6257c3..8d87f6a7a58 100644
--- a/features/steps/project/issues/labels.rb
+++ b/features/steps/project/issues/labels.rb
@@ -24,8 +24,8 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps
step 'I should see labels help message' do
page.within '.labels' do
- expect(page).to have_content 'Create first label or generate default set of '\
- 'labels'
+ expect(page).to have_content 'Create a label or generate a default set '\
+ 'of labels'
end
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index b79d19f1c58..cfa586f859f 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -203,7 +203,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
page.within 'li.merge-request:nth-child(3)' do
expect(page).to have_content 'Bug NS-05'
- expect(page).to_not have_content '0 0'
+ expect(page).not_to have_content '0 0'
end
end
end
@@ -222,7 +222,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
page.within 'li.merge-request:nth-child(3)' do
expect(page).to have_content 'Bug NS-05'
- expect(page).to_not have_content '0 0'
+ expect(page).not_to have_content '0 0'
end
end
end
diff --git a/features/steps/project/snippets.rb b/features/steps/project/snippets.rb
index 786a0cad975..beb8ecfc799 100644
--- a/features/steps/project/snippets.rb
+++ b/features/steps/project/snippets.rb
@@ -43,12 +43,12 @@ class Spinach::Features::ProjectSnippets < Spinach::FeatureSteps
step 'I click link "Edit"' do
page.within ".detail-page-header" do
- click_link "Edit"
+ first(:link, "Edit").click
end
end
step 'I click link "Delete"' do
- click_link "Delete"
+ first(:link, "Delete").click
end
step 'I submit new snippet "Snippet three"' do
diff --git a/features/steps/shared/note.rb b/features/steps/shared/note.rb
index a3c3887ab46..3d7c6ef9d2d 100644
--- a/features/steps/shared/note.rb
+++ b/features/steps/shared/note.rb
@@ -107,7 +107,7 @@ module SharedNote
end
step 'I should see no notes at all' do
- expect(page).to_not have_css('.note')
+ expect(page).not_to have_css('.note')
end
# Markdown
diff --git a/features/steps/shared/project.rb b/features/steps/shared/project.rb
index ea5f9580308..ce9ea7ee18a 100644
--- a/features/steps/shared/project.rb
+++ b/features/steps/shared/project.rb
@@ -95,7 +95,7 @@ module SharedProject
step 'I should see project settings' do
expect(current_path).to eq edit_namespace_project_path(@project.namespace, @project)
expect(page).to have_content("Project name")
- expect(page).to have_content("Features:")
+ expect(page).to have_content("Features")
end
def current_project
diff --git a/features/steps/snippets/snippets.rb b/features/steps/snippets/snippets.rb
index 023032e679f..19366b11071 100644
--- a/features/steps/snippets/snippets.rb
+++ b/features/steps/snippets/snippets.rb
@@ -14,12 +14,12 @@ class Spinach::Features::Snippets < Spinach::FeatureSteps
step 'I click link "Edit"' do
page.within ".detail-page-header" do
- click_link "Edit"
+ first(:link, "Edit").click
end
end
step 'I click link "Delete"' do
- click_link "Delete"
+ first(:link, "Delete").click
end
step 'I submit new snippet "Personal snippet three"' do
diff --git a/features/steps/user.rb b/features/steps/user.rb
index b1d088f07f9..59385a6ab59 100644
--- a/features/steps/user.rb
+++ b/features/steps/user.rb
@@ -34,7 +34,7 @@ class Spinach::Features::User < Spinach::FeatureSteps
end
step 'I should see contributions calendar' do
- expect(page).to have_css('.cal-heatmap-container')
+ expect(page).to have_css('.js-contrib-calendar')
end
def contributed_project
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index 91e420832f3..9d8b8d737a9 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -95,8 +95,7 @@ module API
# GET /groups/:id/projects
get ":id/projects" do
group = find_group(params[:id])
- projects = group.projects
- projects = filter_projects(projects)
+ projects = GroupProjectsFinder.new(group).execute(current_user)
projects = paginate projects
present projects, with: Entities::Project
end
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 7d0608f09da..3e07096e6cc 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -1,5 +1,8 @@
module Backup
class Manager
+ ARCHIVES_TO_BACKUP = %w[uploads builds artifacts lfs registry]
+ FOLDERS_TO_BACKUP = %w[repositories db]
+
def pack
# Make sure there is a connection
ActiveRecord::Base.connection.reconnect!
@@ -147,7 +150,7 @@ module Backup
end
def skipped?(item)
- settings[:skipped] && settings[:skipped].include?(item)
+ settings[:skipped] && settings[:skipped].include?(item) || disabled_features.include?(item)
end
private
@@ -157,11 +160,17 @@ module Backup
end
def archives_to_backup
- %w{uploads builds artifacts lfs registry}.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact
+ ARCHIVES_TO_BACKUP.map{ |name| (name + ".tar.gz") unless skipped?(name) }.compact
end
def folders_to_backup
- %w{repositories db}.reject{ |name| skipped?(name) }
+ FOLDERS_TO_BACKUP.reject{ |name| skipped?(name) }
+ end
+
+ def disabled_features
+ features = []
+ features << 'registry' unless Gitlab.config.registry.enabled
+ features
end
def settings
diff --git a/lib/ci/ansi2html.rb b/lib/ci/ansi2html.rb
index c628257e3f4..229050151d3 100644
--- a/lib/ci/ansi2html.rb
+++ b/lib/ci/ansi2html.rb
@@ -90,7 +90,7 @@ module Ci
def convert(raw, new_state)
reset_state
- restore_state(raw, new_state) if new_state
+ restore_state(raw, new_state) if new_state.present?
start = @offset
ansi = raw[@offset..-1]
@@ -105,6 +105,8 @@ module Ci
break
elsif s.scan(/</)
@out << '&lt;'
+ elsif s.scan(/\n/)
+ @out << '<br>'
else
@out << s.scan(/./m)
end
diff --git a/lib/ci/gitlab_ci_yaml_processor.rb b/lib/ci/gitlab_ci_yaml_processor.rb
index 504d3df9d34..e4b4760c53b 100644
--- a/lib/ci/gitlab_ci_yaml_processor.rb
+++ b/lib/ci/gitlab_ci_yaml_processor.rb
@@ -1,6 +1,6 @@
module Ci
class GitlabCiYamlProcessor
- class ValidationError < StandardError;end
+ class ValidationError < StandardError; end
DEFAULT_STAGES = %w(build test deploy)
DEFAULT_STAGE = 'test'
diff --git a/lib/gitlab/contributions_calendar.rb b/lib/gitlab/contributions_calendar.rb
index 85583dce9ee..9dc2602867e 100644
--- a/lib/gitlab/contributions_calendar.rb
+++ b/lib/gitlab/contributions_calendar.rb
@@ -19,7 +19,7 @@ module Gitlab
select('date(created_at) as date, count(id) as total_amount').
map(&:attributes)
- dates = (1.year.ago.to_date..(Date.today + 1.day)).to_a
+ dates = (1.year.ago.to_date..Date.today).to_a
dates.each do |date|
date_id = date.to_time.to_i.to_s
diff --git a/lib/gitlab/url_sanitizer.rb b/lib/gitlab/url_sanitizer.rb
index c59d53b941a..7d02fe3c971 100644
--- a/lib/gitlab/url_sanitizer.rb
+++ b/lib/gitlab/url_sanitizer.rb
@@ -7,7 +7,7 @@ module Gitlab
end
def initialize(url, credentials: nil)
- @url = Addressable::URI.parse(URI.encode(url))
+ @url = Addressable::URI.parse(url)
@credentials = credentials
end
diff --git a/lib/gitlab/visibility_level.rb b/lib/gitlab/visibility_level.rb
index a1ee1cba216..9462f3368e6 100644
--- a/lib/gitlab/visibility_level.rb
+++ b/lib/gitlab/visibility_level.rb
@@ -32,6 +32,13 @@ module Gitlab
}
end
+ def highest_allowed_level
+ restricted_levels = current_application_settings.restricted_visibility_levels
+
+ allowed_levels = self.values - restricted_levels
+ allowed_levels.max || PRIVATE
+ end
+
def allowed_for?(user, level)
user.is_admin? || allowed_level?(level.to_i)
end
diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake
index d97d974ec20..596eaca6d0d 100644
--- a/lib/tasks/gitlab/backup.rake
+++ b/lib/tasks/gitlab/backup.rake
@@ -179,18 +179,26 @@ namespace :gitlab do
task create: :environment do
$progress.puts "Dumping container registry images ... ".blue
- if ENV["SKIP"] && ENV["SKIP"].include?("registry")
- $progress.puts "[SKIPPED]".cyan
+ if Gitlab.config.registry.enabled
+ if ENV["SKIP"] && ENV["SKIP"].include?("registry")
+ $progress.puts "[SKIPPED]".cyan
+ else
+ Backup::Registry.new.dump
+ $progress.puts "done".green
+ end
else
- Backup::Registry.new.dump
- $progress.puts "done".green
+ $progress.puts "[DISABLED]".cyan
end
end
task restore: :environment do
$progress.puts "Restoring container registry images ... ".blue
- Backup::Registry.new.restore
- $progress.puts "done".green
+ if Gitlab.config.registry.enabled
+ Backup::Registry.new.restore
+ $progress.puts "done".green
+ else
+ $progress.puts "[DISABLED]".cyan
+ end
end
end
diff --git a/lib/tasks/gitlab/db.rake b/lib/tasks/gitlab/db.rake
index e473b756023..86f5d65f128 100644
--- a/lib/tasks/gitlab/db.rake
+++ b/lib/tasks/gitlab/db.rake
@@ -36,5 +36,15 @@ namespace :gitlab do
# Add `IF EXISTS` because cascade could have already deleted a table.
tables.each { |t| connection.execute("DROP TABLE IF EXISTS #{t} CASCADE") }
end
+
+ desc 'Configures the database by running migrate, or by loading the schema and seeding if needed'
+ task configure: :environment do
+ if ActiveRecord::Base.connection.tables.any?
+ Rake::Task['db:migrate'].invoke
+ else
+ Rake::Task['db:schema:load'].invoke
+ Rake::Task['db:seed_fu'].invoke
+ end
+ end
end
end
diff --git a/spec/controllers/admin/projects_controller_spec.rb b/spec/controllers/admin/projects_controller_spec.rb
index 2ba0d489197..4cb8b8da150 100644
--- a/spec/controllers/admin/projects_controller_spec.rb
+++ b/spec/controllers/admin/projects_controller_spec.rb
@@ -17,7 +17,7 @@ describe Admin::ProjectsController do
it 'does not retrieve the project' do
get :index, visibility_levels: [Gitlab::VisibilityLevel::INTERNAL]
- expect(response.body).to_not match(project.name)
+ expect(response.body).not_to match(project.name)
end
end
end
diff --git a/spec/controllers/projects/compare_controller_spec.rb b/spec/controllers/projects/compare_controller_spec.rb
index 788a609ee40..4018dac95a2 100644
--- a/spec/controllers/projects/compare_controller_spec.rb
+++ b/spec/controllers/projects/compare_controller_spec.rb
@@ -19,7 +19,7 @@ describe Projects::CompareController do
to: ref_to)
expect(response).to be_success
- expect(assigns(:diffs).first).to_not be_nil
+ expect(assigns(:diffs).first).not_to be_nil
expect(assigns(:commits).length).to be >= 1
end
@@ -32,7 +32,7 @@ describe Projects::CompareController do
w: 1)
expect(response).to be_success
- expect(assigns(:diffs).first).to_not be_nil
+ expect(assigns(:diffs).first).not_to be_nil
expect(assigns(:commits).length).to be >= 1
# without whitespace option, there are more than 2 diff_splits
diff_splits = assigns(:diffs).first.diff.split("\n")
diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb
index 1bd1fc5189e..fbe8758dda7 100644
--- a/spec/controllers/projects/group_links_controller_spec.rb
+++ b/spec/controllers/projects/group_links_controller_spec.rb
@@ -43,7 +43,7 @@ describe Projects::GroupLinksController do
end
it 'does not share project with that group' do
- expect(group.shared_projects).to_not include project
+ expect(group.shared_projects).not_to include project
end
end
end
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index 2b2ad3b9412..c469480b086 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -56,7 +56,7 @@ describe Projects::IssuesController do
move_issue
expect(response).to have_http_status :found
- expect(another_project.issues).to_not be_empty
+ expect(another_project.issues).not_to be_empty
end
end
diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb
index ed64e7cf9af..750fbecdd07 100644
--- a/spec/controllers/projects/project_members_controller_spec.rb
+++ b/spec/controllers/projects/project_members_controller_spec.rb
@@ -38,7 +38,7 @@ describe Projects::ProjectMembersController do
include_context 'import applied'
it 'does not import team members' do
- expect(project.team_members).to_not include member
+ expect(project.team_members).not_to include member
end
it 'responds with not found' do
diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb
index df70a589a89..fbe50d10ec5 100644
--- a/spec/controllers/registrations_controller_spec.rb
+++ b/spec/controllers/registrations_controller_spec.rb
@@ -16,7 +16,7 @@ describe RegistrationsController do
it 'logs user in directly' do
post(:create, user_params)
expect(ActionMailer::Base.deliveries.last).to be_nil
- expect(subject.current_user).to_not be_nil
+ expect(subject.current_user).not_to be_nil
end
end
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 83cc8ec6d26..ab57c52c7cd 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -47,7 +47,7 @@ describe SessionsController do
authenticate_2fa(login: another_user.username,
otp_attempt: another_user.current_otp)
- expect(subject.current_user).to_not eq another_user
+ expect(subject.current_user).not_to eq another_user
end
end
@@ -56,7 +56,7 @@ describe SessionsController do
authenticate_2fa(login: another_user.username,
otp_attempt: 'invalid')
- expect(subject.current_user).to_not eq another_user
+ expect(subject.current_user).not_to eq another_user
end
end
@@ -73,7 +73,7 @@ describe SessionsController do
before { authenticate_2fa(otp_attempt: 'invalid') }
it 'does not authenticate' do
- expect(subject.current_user).to_not eq user
+ expect(subject.current_user).not_to eq user
end
it 'warns about invalid OTP code' do
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index a073a1f9d7c..675d9bd18b7 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -6,7 +6,7 @@ describe 'factories' do
let(:entity) { build(factory.name) }
it 'does not raise error when created' do
- expect { entity }.to_not raise_error
+ expect { entity }.not_to raise_error
end
it 'should be valid', if: factory.build_class < ActiveRecord::Base do
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index 26d03944b8a..8ebd4a6808e 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -79,7 +79,7 @@ describe "Admin Runners" do
end
it 'changes registration token' do
- expect(page_token).to_not eq token
+ expect(page_token).not_to eq token
end
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 6dee0cd8d47..96621843b30 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -152,7 +152,7 @@ describe "Admin::Users", feature: true do
it 'sees impersonation log out icon' do
icon = first('.fa.fa-user-secret')
- expect(icon).to_not eql nil
+ expect(icon).not_to eql nil
end
it 'can log out of impersonated user back to original user' do
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
index f83a78308e3..7a05d30e8b5 100644
--- a/spec/features/builds_spec.rb
+++ b/spec/features/builds_spec.rb
@@ -43,11 +43,10 @@ describe "Builds" do
end
it { expect(page).to have_selector('.nav-links li.active', text: 'All') }
- it { expect(page).to have_selector('.row-content-block', text: 'All builds from this project') }
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
- it { expect(page).to_not have_link 'Cancel running' }
+ it { expect(page).not_to have_link 'Cancel running' }
end
end
@@ -63,7 +62,7 @@ describe "Builds" do
it { expect(page).to have_content @build.short_sha }
it { expect(page).to have_content @build.ref }
it { expect(page).to have_content @build.name }
- it { expect(page).to_not have_link 'Cancel running' }
+ it { expect(page).not_to have_link 'Cancel running' }
end
describe "GET /:project/builds/:id" do
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
index dacaa96d760..20f0b27bcc1 100644
--- a/spec/features/commits_spec.rb
+++ b/spec/features/commits_spec.rb
@@ -137,8 +137,8 @@ describe 'Commits' do
expect(page).to have_content commit.git_commit_message
expect(page).to have_content commit.git_author_name
expect(page).to have_link('Download artifacts')
- expect(page).to_not have_link('Cancel running')
- expect(page).to_not have_link('Retry failed')
+ expect(page).not_to have_link('Cancel running')
+ expect(page).not_to have_link('Retry failed')
end
end
@@ -155,9 +155,9 @@ describe 'Commits' do
expect(page).to have_content commit.sha[0..7]
expect(page).to have_content commit.git_commit_message
expect(page).to have_content commit.git_author_name
- expect(page).to_not have_link('Download artifacts')
- expect(page).to_not have_link('Cancel running')
- expect(page).to_not have_link('Retry failed')
+ expect(page).not_to have_link('Download artifacts')
+ expect(page).not_to have_link('Cancel running')
+ expect(page).not_to have_link('Retry failed')
end
end
end
diff --git a/spec/features/issues/filter_issues_spec.rb b/spec/features/issues/filter_issues_spec.rb
index 192e3619375..1f0594e6b02 100644
--- a/spec/features/issues/filter_issues_spec.rb
+++ b/spec/features/issues/filter_issues_spec.rb
@@ -154,4 +154,144 @@ describe 'Filter issues', feature: true do
end
end
end
+
+ describe 'filter issues by text' do
+ before do
+ create(:issue, title: "Bug", project: project)
+
+ bug_label = create(:label, project: project, title: 'bug')
+ milestone = create(:milestone, title: "8", project: project)
+
+ issue = create(:issue,
+ title: "Bug 2",
+ project: project,
+ milestone: milestone,
+ author: user,
+ assignee: user)
+ issue.labels << bug_label
+
+ visit namespace_project_issues_path(project.namespace, project)
+ end
+
+ context 'only text', js: true do
+ it 'should filter issues by searched text' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+ end
+
+ it 'should not show any issues' do
+ fill_in 'issue_search', with: 'testing'
+
+ page.within '.issues-list' do
+ expect(page).not_to have_selector('.issue')
+ end
+ end
+ end
+
+ context 'text and dropdown options', js: true do
+ it 'should filter by text and label' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Label'
+ page.within '.labels-filter' do
+ click_link 'bug'
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+
+ it 'should filter by text and milestone' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Milestone'
+ page.within '.milestone-filter' do
+ click_link '8'
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+
+ it 'should filter by text and assignee' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Assignee'
+ page.within '.dropdown-menu-assignee' do
+ click_link user.name
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+
+ it 'should filter by text and author' do
+ fill_in 'issue_search', with: 'Bug'
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Author'
+ page.within '.dropdown-menu-author' do
+ click_link user.name
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 1)
+ end
+ end
+ end
+ end
+
+ describe 'filter issues and sort', js: true do
+ before do
+ bug_label = create(:label, project: project, title: 'bug')
+ bug_one = create(:issue, title: "Frontend", project: project)
+ bug_two = create(:issue, title: "Bug 2", project: project)
+
+ bug_one.labels << bug_label
+ bug_two.labels << bug_label
+
+ visit namespace_project_issues_path(project.namespace, project)
+ end
+
+ it 'should be able to filter and sort issues' do
+ click_button 'Label'
+ page.within '.labels-filter' do
+ click_link 'bug'
+ end
+
+ page.within '.issues-list' do
+ expect(page).to have_selector('.issue', count: 2)
+ end
+
+ click_button 'Last created'
+ page.within '.dropdown-menu-sort' do
+ click_link 'Oldest created'
+ end
+
+ page.within '.issues-list' do
+ expect(first('.issue')).to have_content('Frontend')
+ end
+ end
+ end
end
diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb
index b03dd0f666d..466a6f7dfa7 100644
--- a/spec/features/issues/update_issues_spec.rb
+++ b/spec/features/issues/update_issues_spec.rb
@@ -95,7 +95,7 @@ feature 'Multiple issue updating from issues#index', feature: true do
find('.dropdown-menu-milestone a', text: "No Milestone").click
click_update_issues_button
- expect(first('.issue')).to_not have_content milestone.title
+ expect(first('.issue')).not_to have_content milestone.title
end
end
diff --git a/spec/features/pipelines_spec.rb b/spec/features/pipelines_spec.rb
index 1d6f4485c81..bef0578a9bb 100644
--- a/spec/features/pipelines_spec.rb
+++ b/spec/features/pipelines_spec.rb
@@ -41,7 +41,7 @@ describe "Pipelines" do
context 'when canceling' do
before { click_link('Cancel') }
- it { expect(page).to_not have_link('Cancel') }
+ it { expect(page).not_to have_link('Cancel') }
it { expect(page).to have_selector('.ci-canceled') }
end
end
@@ -57,7 +57,7 @@ describe "Pipelines" do
context 'when retrying' do
before { click_link('Retry') }
- it { expect(page).to_not have_link('Retry') }
+ it { expect(page).not_to have_link('Retry') }
it { expect(page).to have_selector('.ci-pending') }
end
end
@@ -75,7 +75,7 @@ describe "Pipelines" do
context 'without artifacts' do
let!(:without_artifacts) { create(:ci_build, :success, commit: pipeline, name: 'rspec', stage: 'test') }
- it { expect(page).to_not have_selector('.build-artifacts') }
+ it { expect(page).not_to have_selector('.build-artifacts') }
end
end
end
@@ -104,23 +104,23 @@ describe "Pipelines" do
end
context 'retrying builds' do
- it { expect(page).to_not have_content('retried') }
+ it { expect(page).not_to have_content('retried') }
context 'when retrying' do
before { click_on 'Retry failed' }
- it { expect(page).to_not have_content('Retry failed') }
+ it { expect(page).not_to have_content('Retry failed') }
it { expect(page).to have_content('retried') }
end
end
context 'canceling builds' do
- it { expect(page).to_not have_selector('.ci-canceled') }
+ it { expect(page).not_to have_selector('.ci-canceled') }
context 'when canceling' do
before { click_on 'Cancel running' }
- it { expect(page).to_not have_content('Cancel running') }
+ it { expect(page).not_to have_content('Cancel running') }
it { expect(page).to have_selector('.ci-canceled') }
end
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index 49156130ad3..a5ed3595b0a 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -29,8 +29,8 @@ describe "Runners" do
end
before do
- expect(page).to_not have_content(@specific_runner3.display_name)
- expect(page).to_not have_content(@specific_runner3.display_name)
+ expect(page).not_to have_content(@specific_runner3.display_name)
+ expect(page).not_to have_content(@specific_runner3.display_name)
end
it "places runners in right places" do
diff --git a/spec/features/todos/target_state_spec.rb b/spec/features/todos/target_state_spec.rb
new file mode 100644
index 00000000000..72491ac7e61
--- /dev/null
+++ b/spec/features/todos/target_state_spec.rb
@@ -0,0 +1,65 @@
+require 'rails_helper'
+
+feature 'Todo target states', feature: true do
+ let(:user) { create(:user) }
+ let(:author) { create(:user) }
+ let(:project) { create(:project) }
+
+ before do
+ login_as user
+ end
+
+ scenario 'on a closed issue todo has closed label' do
+ issue_closed = create(:issue, state: 'closed')
+ create_todo issue_closed
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).to have_content('Closed')
+ end
+ end
+
+ scenario 'on an open issue todo does not have an open label' do
+ issue_open = create(:issue)
+ create_todo issue_open
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).not_to have_content('Open')
+ end
+ end
+
+ scenario 'on a merged merge request todo has merged label' do
+ mr_merged = create(:merge_request, :simple, author: user, state: 'merged')
+ create_todo mr_merged
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).to have_content('Merged')
+ end
+ end
+
+ scenario 'on a closed merge request todo has closed label' do
+ mr_closed = create(:merge_request, :simple, author: user, state: 'closed')
+ create_todo mr_closed
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).to have_content('Closed')
+ end
+ end
+
+ scenario 'on an open merge request todo does not have an open label' do
+ mr_open = create(:merge_request, :simple, author: user)
+ create_todo mr_open
+ visit dashboard_todos_path
+
+ page.within '.todos-list' do
+ expect(page).not_to have_content('Open')
+ end
+ end
+
+ def create_todo(target)
+ create(:todo, :mentioned, user: user, project: project, target: target, author: author)
+ end
+end
diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb
index 48e2dae4884..a2b8f7b6931 100644
--- a/spec/features/variables_spec.rb
+++ b/spec/features/variables_spec.rb
@@ -34,7 +34,7 @@ describe 'Project variables', js: true do
find('.btn-variable-delete').click
end
- expect(page).to_not have_selector('variables-table')
+ expect(page).not_to have_selector('variables-table')
end
it 'should edit variable' do
diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb
index 16fbb5dcecb..49ea4fa6d3e 100644
--- a/spec/helpers/auth_helper_spec.rb
+++ b/spec/helpers/auth_helper_spec.rb
@@ -36,7 +36,7 @@ describe AuthHelper do
)
expect(helper.enabled_button_based_providers).to include('twitter')
- expect(helper.enabled_button_based_providers).to_not include('github')
+ expect(helper.enabled_button_based_providers).not_to include('github')
end
end
end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index 600e1c4e9ec..8e7ed42e883 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -17,7 +17,7 @@ describe MergeRequestsHelper do
it 'does not include api credentials in a link' do
allow(ci_service).
to receive(:build_page).and_return("http://secretuser:secretpass@jenkins.example.com:8888/job/test1/scm/bySHA1/12d65c")
- expect(helper.ci_build_details_path(merge_request)).to_not match("secret")
+ expect(helper.ci_build_details_path(merge_request)).not_to match("secret")
end
end
diff --git a/spec/javascripts/fixtures/right_sidebar.html.haml b/spec/javascripts/fixtures/right_sidebar.html.haml
new file mode 100644
index 00000000000..95efaff4b69
--- /dev/null
+++ b/spec/javascripts/fixtures/right_sidebar.html.haml
@@ -0,0 +1,13 @@
+%div
+ %div.page-gutter.page-with-sidebar
+
+ %aside.right-sidebar
+ %div.block.issuable-sidebar-header
+ %a.gutter-toggle.pull-right.js-sidebar-toggle
+ %i.fa.fa-angle-double-left
+
+ %form.issuable-context-form
+ %div.block.labels
+ %div.sidebar-collapsed-icon
+ %i.fa.fa-tags
+ %span 1
diff --git a/spec/javascripts/right_sidebar_spec.js.coffee b/spec/javascripts/right_sidebar_spec.js.coffee
new file mode 100644
index 00000000000..2075cacdb67
--- /dev/null
+++ b/spec/javascripts/right_sidebar_spec.js.coffee
@@ -0,0 +1,69 @@
+#= require right_sidebar
+#= require jquery
+#= require jquery.cookie
+
+@sidebar = null
+$aside = null
+$toggle = null
+$icon = null
+$page = null
+$labelsIcon = null
+
+
+assertSidebarState = (state) ->
+
+ shouldBeExpanded = state is 'expanded'
+ shouldBeCollapsed = state is 'collapsed'
+
+ expect($aside.hasClass('right-sidebar-expanded')).toBe shouldBeExpanded
+ expect($page.hasClass('right-sidebar-expanded')).toBe shouldBeExpanded
+ expect($icon.hasClass('fa-angle-double-right')).toBe shouldBeExpanded
+
+ expect($aside.hasClass('right-sidebar-collapsed')).toBe shouldBeCollapsed
+ expect($page.hasClass('right-sidebar-collapsed')).toBe shouldBeCollapsed
+ expect($icon.hasClass('fa-angle-double-left')).toBe shouldBeCollapsed
+
+
+describe 'RightSidebar', ->
+
+ fixture.preload 'right_sidebar.html'
+
+ beforeEach ->
+ fixture.load 'right_sidebar.html'
+
+ @sidebar = new Sidebar
+ $aside = $ '.right-sidebar'
+ $page = $ '.page-with-sidebar'
+ $icon = $aside.find 'i'
+ $toggle = $aside.find '.js-sidebar-toggle'
+ $labelsIcon = $aside.find '.sidebar-collapsed-icon'
+
+
+ it 'should expand the sidebar when arrow is clicked', ->
+
+ $toggle.click()
+ assertSidebarState 'expanded'
+
+
+ it 'should collapse the sidebar when arrow is clicked', ->
+
+ $toggle.click()
+ assertSidebarState 'expanded'
+
+ $toggle.click()
+ assertSidebarState 'collapsed'
+
+
+ it 'should float over the page and when sidebar icons clicked', ->
+
+ $labelsIcon.click()
+ assertSidebarState 'expanded'
+
+
+ it 'should collapse when the icon arrow clicked while it is floating on page', ->
+
+ $labelsIcon.click()
+ assertSidebarState 'expanded'
+
+ $toggle.click()
+ assertSidebarState 'collapsed'
diff --git a/spec/lib/award_emoji_spec.rb b/spec/lib/award_emoji_spec.rb
index 88c22912950..c3098574292 100644
--- a/spec/lib/award_emoji_spec.rb
+++ b/spec/lib/award_emoji_spec.rb
@@ -5,7 +5,7 @@ describe AwardEmoji do
subject { AwardEmoji.urls }
it { is_expected.to be_an_instance_of(Array) }
- it { is_expected.to_not be_empty }
+ it { is_expected.not_to be_empty }
context 'every Hash in the Array' do
it 'has the correct keys and values' do
diff --git a/spec/lib/ci/ansi2html_spec.rb b/spec/lib/ci/ansi2html_spec.rb
index 04afbd06929..898f1e84ab0 100644
--- a/spec/lib/ci/ansi2html_spec.rb
+++ b/spec/lib/ci/ansi2html_spec.rb
@@ -175,5 +175,14 @@ describe Ci::Ansi2html, lib: true do
it_behaves_like 'stateable converter'
end
+
+ context 'with new line' do
+ let(:pre_text) { "Hello\r" }
+ let(:pre_html) { "Hello\r" }
+ let(:text) { "\nWorld" }
+ let(:html) { "<br>World" }
+
+ it_behaves_like 'stateable converter'
+ end
end
end
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index 9eef8ea0976..7375539cf17 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -619,19 +619,19 @@ module Ci
context 'no dependencies' do
let(:dependencies) { }
- it { expect { subject }.to_not raise_error }
+ it { expect { subject }.not_to raise_error }
end
context 'dependencies to builds' do
let(:dependencies) { ['build1', 'build2'] }
- it { expect { subject }.to_not raise_error }
+ it { expect { subject }.not_to raise_error }
end
context 'dependencies to builds defined as symbols' do
let(:dependencies) { [:build1, :build2] }
- it { expect { subject }.to_not raise_error }
+ it { expect { subject }.not_to raise_error }
end
context 'undefined dependency' do
diff --git a/spec/lib/container_registry/registry_spec.rb b/spec/lib/container_registry/registry_spec.rb
index 2638401ae6e..4f3f8b24fc4 100644
--- a/spec/lib/container_registry/registry_spec.rb
+++ b/spec/lib/container_registry/registry_spec.rb
@@ -10,7 +10,7 @@ describe ContainerRegistry::Registry do
it { is_expected.to respond_to(:uri) }
it { is_expected.to respond_to(:path) }
- it { expect(subject.repository('test')).to_not be_nil }
+ it { expect(subject.repository('test')).not_to be_nil }
context '#path' do
subject { registry.path }
diff --git a/spec/lib/container_registry/repository_spec.rb b/spec/lib/container_registry/repository_spec.rb
index e6d66b11e4e..279709521c9 100644
--- a/spec/lib/container_registry/repository_spec.rb
+++ b/spec/lib/container_registry/repository_spec.rb
@@ -6,7 +6,7 @@ describe ContainerRegistry::Repository do
it { expect(repository).to respond_to(:registry) }
it { expect(repository).to delegate_method(:client).to(:registry) }
- it { expect(repository.tag('test')).to_not be_nil }
+ it { expect(repository.tag('test')).not_to be_nil }
context '#path' do
subject { repository.path }
@@ -27,7 +27,7 @@ describe ContainerRegistry::Repository do
context '#manifest' do
subject { repository.manifest }
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
context '#valid?' do
@@ -39,7 +39,7 @@ describe ContainerRegistry::Repository do
context '#tags' do
subject { repository.tags }
- it { is_expected.to_not be_empty }
+ it { is_expected.not_to be_empty }
end
end
diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb
index 12cf91127ed..858cb0bb134 100644
--- a/spec/lib/container_registry/tag_spec.rb
+++ b/spec/lib/container_registry/tag_spec.rb
@@ -50,13 +50,13 @@ describe ContainerRegistry::Tag do
context '#config' do
subject { tag.config }
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
context '#created_at' do
subject { tag.created_at }
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
end
end
diff --git a/spec/lib/gitlab/bitbucket_import/client_spec.rb b/spec/lib/gitlab/bitbucket_import/client_spec.rb
index af839f42421..7718689e6d4 100644
--- a/spec/lib/gitlab/bitbucket_import/client_spec.rb
+++ b/spec/lib/gitlab/bitbucket_import/client_spec.rb
@@ -59,7 +59,7 @@ describe Gitlab::BitbucketImport::Client, lib: true do
bitbucket_access_token_secret: "test" } })
project.import_url = "ssh://git@bitbucket.org/test/test.git"
- expect { described_class.from_project(project) }.to_not raise_error
+ expect { described_class.from_project(project) }.not_to raise_error
end
end
end
diff --git a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
index 46a5b7fce65..711a3e1c7d4 100644
--- a/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
+++ b/spec/lib/gitlab/ci/build/artifacts/metadata/entry_spec.rb
@@ -122,7 +122,7 @@ describe Gitlab::Ci::Build::Artifacts::Metadata::Entry do
describe 'empty path', path: '' do
subject { |example| path(example) }
- it { is_expected.to_not have_parent }
+ it { is_expected.not_to have_parent }
describe '#children' do
subject { |example| path(example).children }
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 0a7ca3ec848..0af249d8690 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -33,8 +33,8 @@ describe Gitlab::Gfm::ReferenceRewriter do
end
it { is_expected.to include issue_first.to_reference(new_project) }
- it { is_expected.to_not include issue_second.to_reference(new_project) }
- it { is_expected.to_not include merge_request.to_reference(new_project) }
+ it { is_expected.not_to include issue_second.to_reference(new_project) }
+ it { is_expected.not_to include merge_request.to_reference(new_project) }
end
context 'description ambigous elements' do
diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
index eda956e6f0a..6eca33f9fee 100644
--- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb
@@ -32,13 +32,13 @@ describe Gitlab::Gfm::UploadsRewriter do
let(:new_paths) { new_files.map(&:path) }
it 'rewrites content' do
- expect(new_text).to_not eq text
+ expect(new_text).not_to eq text
expect(new_text.length).to eq text.length
end
it 'copies files' do
expect(new_files).to all(exist)
- expect(old_paths).to_not match_array new_paths
+ expect(old_paths).not_to match_array new_paths
expect(old_paths).to all(include(old_project.path_with_namespace))
expect(new_paths).to all(include(new_project.path_with_namespace))
end
@@ -48,8 +48,8 @@ describe Gitlab::Gfm::UploadsRewriter do
end
it 'generates a new secret for each file' do
- expect(new_paths).to_not include image_uploader.secret
- expect(new_paths).to_not include zip_uploader.secret
+ expect(new_paths).not_to include image_uploader.secret
+ expect(new_paths).not_to include zip_uploader.secret
end
end
diff --git a/spec/lib/gitlab/lfs/lfs_router_spec.rb b/spec/lib/gitlab/lfs/lfs_router_spec.rb
index 3325190789b..88814bc474d 100644
--- a/spec/lib/gitlab/lfs/lfs_router_spec.rb
+++ b/spec/lib/gitlab/lfs/lfs_router_spec.rb
@@ -368,7 +368,7 @@ describe Gitlab::Lfs::Router, lib: true do
expect(response['objects']).to be_kind_of(Array)
expect(response['objects'].first['oid']).to eq(sample_oid)
expect(response['objects'].first['size']).to eq(sample_size)
- expect(lfs_object.projects.pluck(:id)).to_not include(project.id)
+ expect(lfs_object.projects.pluck(:id)).not_to include(project.id)
expect(lfs_object.projects.pluck(:id)).to include(public_project.id)
expect(response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/#{sample_oid}/#{sample_size}")
expect(response['objects'].first['actions']['upload']['header']).to eq('Authorization' => @auth)
@@ -430,7 +430,7 @@ describe Gitlab::Lfs::Router, lib: true do
expect(response_body['objects'].last['oid']).to eq(sample_oid)
expect(response_body['objects'].last['size']).to eq(sample_size)
- expect(response_body['objects'].last).to_not have_key('actions')
+ expect(response_body['objects'].last).not_to have_key('actions')
end
end
end
diff --git a/spec/lib/gitlab/metrics/instrumentation_spec.rb b/spec/lib/gitlab/metrics/instrumentation_spec.rb
index 7b86450a223..220e86924a2 100644
--- a/spec/lib/gitlab/metrics/instrumentation_spec.rb
+++ b/spec/lib/gitlab/metrics/instrumentation_spec.rb
@@ -67,7 +67,7 @@ describe Gitlab::Metrics::Instrumentation do
allow(Gitlab::Metrics).to receive(:method_call_threshold).
and_return(100)
- expect(transaction).to_not receive(:add_metric)
+ expect(transaction).not_to receive(:add_metric)
@dummy.foo
end
@@ -147,7 +147,7 @@ describe Gitlab::Metrics::Instrumentation do
allow(Gitlab::Metrics).to receive(:method_call_threshold).
and_return(100)
- expect(transaction).to_not receive(:add_metric)
+ expect(transaction).not_to receive(:add_metric)
@dummy.new.bar
end
@@ -220,7 +220,7 @@ describe Gitlab::Metrics::Instrumentation do
described_class.instrument_methods(@dummy)
- expect(@dummy).to_not respond_to(:_original_kittens)
+ expect(@dummy).not_to respond_to(:_original_kittens)
end
it 'can take a block to determine if a method should be instrumented' do
@@ -228,7 +228,7 @@ describe Gitlab::Metrics::Instrumentation do
false
end
- expect(@dummy).to_not respond_to(:_original_foo)
+ expect(@dummy).not_to respond_to(:_original_foo)
end
end
diff --git a/spec/lib/gitlab/metrics/sampler_spec.rb b/spec/lib/gitlab/metrics/sampler_spec.rb
index 38da77adc9f..59db127674a 100644
--- a/spec/lib/gitlab/metrics/sampler_spec.rb
+++ b/spec/lib/gitlab/metrics/sampler_spec.rb
@@ -130,7 +130,7 @@ describe Gitlab::Metrics::Sampler do
100.times do
interval = sampler.sleep_interval
- expect(interval).to_not eq(last)
+ expect(interval).not_to eq(last)
last = interval
end
diff --git a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb
index e3293a01207..49699ffe28f 100644
--- a/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb
+++ b/spec/lib/gitlab/metrics/subscribers/active_record_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::Metrics::Subscribers::ActiveRecord do
describe 'without a current transaction' do
it 'simply returns' do
expect_any_instance_of(Gitlab::Metrics::Transaction).
- to_not receive(:increment)
+ not_to receive(:increment)
subscriber.sql(event)
end
diff --git a/spec/lib/gitlab/sherlock/collection_spec.rb b/spec/lib/gitlab/sherlock/collection_spec.rb
index de6bb86c5dd..2ae79b50e77 100644
--- a/spec/lib/gitlab/sherlock/collection_spec.rb
+++ b/spec/lib/gitlab/sherlock/collection_spec.rb
@@ -11,13 +11,13 @@ describe Gitlab::Sherlock::Collection, lib: true do
it 'adds a new transaction' do
collection.add(transaction)
- expect(collection).to_not be_empty
+ expect(collection).not_to be_empty
end
it 'is aliased as <<' do
collection << transaction
- expect(collection).to_not be_empty
+ expect(collection).not_to be_empty
end
end
@@ -47,7 +47,7 @@ describe Gitlab::Sherlock::Collection, lib: true do
it 'returns false for a collection with a transaction' do
collection.add(transaction)
- expect(collection).to_not be_empty
+ expect(collection).not_to be_empty
end
end
diff --git a/spec/lib/gitlab/sherlock/query_spec.rb b/spec/lib/gitlab/sherlock/query_spec.rb
index 05da915ccfd..0a620428138 100644
--- a/spec/lib/gitlab/sherlock/query_spec.rb
+++ b/spec/lib/gitlab/sherlock/query_spec.rb
@@ -85,7 +85,7 @@ FROM users;
frames = query.application_backtrace
expect(frames).to be_an_instance_of(Array)
- expect(frames).to_not be_empty
+ expect(frames).not_to be_empty
frames.each do |frame|
expect(frame.path).to start_with(Rails.root.to_s)
diff --git a/spec/lib/gitlab/sherlock/transaction_spec.rb b/spec/lib/gitlab/sherlock/transaction_spec.rb
index 7553f2a045f..9fe18f253f0 100644
--- a/spec/lib/gitlab/sherlock/transaction_spec.rb
+++ b/spec/lib/gitlab/sherlock/transaction_spec.rb
@@ -203,7 +203,7 @@ describe Gitlab::Sherlock::Transaction, lib: true do
end
it 'only tracks queries triggered from the transaction thread' do
- expect(transaction).to_not receive(:track_query)
+ expect(transaction).not_to receive(:track_query)
Thread.new { subscription.publish('test', time, time, nil, query_data) }.
join
@@ -226,7 +226,7 @@ describe Gitlab::Sherlock::Transaction, lib: true do
end
it 'only tracks views rendered from the transaction thread' do
- expect(transaction).to_not receive(:track_view)
+ expect(transaction).not_to receive(:track_view)
Thread.new { subscription.publish('test', time, time, nil, view_data) }.
join
diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb
index 0c3d3ea7019..18726754517 100644
--- a/spec/lib/json_web_token/rsa_token_spec.rb
+++ b/spec/lib/json_web_token/rsa_token_spec.rb
@@ -23,7 +23,7 @@ describe JSONWebToken::RSAToken do
subject { JWT.decode(rsa_encoded, rsa_key) }
- it { expect{subject}.to_not raise_error }
+ it { expect{subject}.not_to raise_error }
it { expect(subject.first).to include('key' => 'value') }
it do
expect(subject.second).to eq(
diff --git a/spec/mailers/previews/devise_mailer_preview.rb b/spec/mailers/previews/devise_mailer_preview.rb
new file mode 100644
index 00000000000..dc3062a4332
--- /dev/null
+++ b/spec/mailers/previews/devise_mailer_preview.rb
@@ -0,0 +1,11 @@
+class DeviseMailerPreview < ActionMailer::Preview
+ def confirmation_instructions_for_signup
+ user = User.new(name: 'Jane Doe', email: 'signup@example.com')
+ DeviseMailer.confirmation_instructions(user, 'faketoken', {})
+ end
+
+ def confirmation_instructions_for_new_email
+ user = User.last
+ DeviseMailer.confirmation_instructions(user, 'faketoken', {})
+ end
+end
diff --git a/spec/mailers/shared/notify.rb b/spec/mailers/shared/notify.rb
index 5a85cb501dd..93de5850ba2 100644
--- a/spec/mailers/shared/notify.rb
+++ b/spec/mailers/shared/notify.rb
@@ -146,8 +146,8 @@ shared_examples 'it should have Gmail Actions links' do
end
shared_examples 'it should not have Gmail Actions links' do
- it { is_expected.to_not have_body_text '<script type="application/ld+json">' }
- it { is_expected.to_not have_body_text /ViewAction/ }
+ it { is_expected.not_to have_body_text '<script type="application/ld+json">' }
+ it { is_expected.not_to have_body_text /ViewAction/ }
end
shared_examples 'it should show Gmail Actions View Issue link' do
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index abae3271a5c..55b7af441d6 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -90,7 +90,7 @@ describe Ci::Build, models: true do
build.update_attributes(trace: token)
end
- it { is_expected.to_not include(token) }
+ it { is_expected.not_to include(token) }
end
end
@@ -317,7 +317,7 @@ describe Ci::Build, models: true do
context 'when build does not have tags' do
subject { create(:ci_build, tag_list: []) }
- it { is_expected.to_not have_tags }
+ it { is_expected.not_to have_tags }
end
end
@@ -534,7 +534,7 @@ describe Ci::Build, models: true do
end
it 'should set erase date' do
- expect(build.erased_at).to_not be_falsy
+ expect(build.erased_at).not_to be_falsy
end
end
@@ -606,7 +606,7 @@ describe Ci::Build, models: true do
describe '#erase' do
it 'should not raise error' do
- expect { build.erase }.to_not raise_error
+ expect { build.erase }.not_to raise_error
end
end
end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index 1b5940ad5a8..22f8639e5ab 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -247,7 +247,7 @@ describe Ci::Commit, models: true do
expect(commit.builds.pluck(:status)).to contain_exactly('pending')
commit.builds.running_or_pending.each(&:success)
- expect(commit.builds.running_or_pending).to_not be_empty
+ expect(commit.builds.running_or_pending).not_to be_empty
expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 7c6e39419ed..5d04d8ffcff 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -140,7 +140,7 @@ describe Ci::Runner, models: true do
context 'when runner does not have tags' do
subject { create(:ci_runner, tag_list: []) }
- it { is_expected.to_not have_tags }
+ it { is_expected.not_to have_tags }
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 4a4cd093435..583827cdf42 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -114,6 +114,35 @@ describe Issue, "Issuable" do
end
end
+ describe "#sort" do
+ let(:project) { build_stubbed(:empty_project) }
+
+ context "by milestone due date" do
+ #Correct order is:
+ #Issues/MRs with milestones ordered by date
+ #Issues/MRs with milestones without dates
+ #Issues/MRs without milestones
+
+ let!(:issue) { create(:issue, project: project) }
+ let!(:early_milestone) { create(:milestone, project: project, due_date: 10.days.from_now) }
+ let!(:late_milestone) { create(:milestone, project: project, due_date: 30.days.from_now) }
+ let!(:issue1) { create(:issue, project: project, milestone: early_milestone) }
+ let!(:issue2) { create(:issue, project: project, milestone: late_milestone) }
+ let!(:issue3) { create(:issue, project: project) }
+
+ it "sorts desc" do
+ issues = project.issues.sort('milestone_due_desc')
+ expect(issues).to match_array([issue2, issue1, issue, issue3])
+ end
+
+ it "sorts asc" do
+ issues = project.issues.sort('milestone_due_asc')
+ expect(issues).to match_array([issue1, issue2, issue, issue3])
+ end
+ end
+ end
+
+
describe '#subscribed?' do
context 'user is not a participant in the issue' do
before { allow(issue).to receive(:participants).with(user).and_return([]) }
@@ -165,7 +194,7 @@ describe Issue, "Issuable" do
expect(data[:object_kind]).to eq("issue")
expect(data[:user]).to eq(user.hook_attrs)
expect(data[:object_attributes]).to eq(issue.hook_attrs)
- expect(data).to_not have_key(:assignee)
+ expect(data).not_to have_key(:assignee)
end
context "issue is assigned" do
diff --git a/spec/models/concerns/token_authenticatable_spec.rb b/spec/models/concerns/token_authenticatable_spec.rb
index b6adc2bf247..9e8ebc56a31 100644
--- a/spec/models/concerns/token_authenticatable_spec.rb
+++ b/spec/models/concerns/token_authenticatable_spec.rb
@@ -28,14 +28,14 @@ describe ApplicationSetting, 'TokenAuthenticatable' do
context 'token is not generated yet' do
describe 'token field accessor' do
subject { described_class.new.send(token_field) }
- it { is_expected.to_not be_blank }
+ it { is_expected.not_to be_blank }
end
describe 'ensured token' do
subject { described_class.new.send("ensure_#{token_field}") }
it { is_expected.to be_a String }
- it { is_expected.to_not be_blank }
+ it { is_expected.not_to be_blank }
end
describe 'ensured! token' do
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index 0caf5869c24..d0e02618b6b 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -27,13 +27,13 @@ describe GenericCommitStatus, models: true do
describe :context do
subject { generic_commit_status.context }
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
describe :stage do
subject { generic_commit_status.stage }
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 8ab00c70f9d..6540d77fbc0 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -192,7 +192,7 @@ describe Issue, models: true do
source_project: subject.project,
source_branch: "#{subject.iid}-branch" })
merge_request.create_cross_references!(user)
- expect(subject.referenced_merge_requests).to_not be_empty
+ expect(subject.referenced_merge_requests).not_to be_empty
expect(subject.related_branches(user)).to eq([subject.to_branch_name])
end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 6fb5cad5011..f887ed4bafc 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -303,7 +303,7 @@ describe HipchatService, models: true do
it "should notify only broken" do
hipchat.notify_only_broken_builds = true
hipchat.execute(data)
- expect(WebMock).to_not have_requested(:post, api_url).once
+ expect(WebMock).not_to have_requested(:post, api_url).once
end
end
end
diff --git a/spec/models/project_services/slack_service/build_message_spec.rb b/spec/models/project_services/slack_service/build_message_spec.rb
index 621c83c0cda..7fcfdf0eacd 100644
--- a/spec/models/project_services/slack_service/build_message_spec.rb
+++ b/spec/models/project_services/slack_service/build_message_spec.rb
@@ -15,7 +15,7 @@ describe SlackService::BuildMessage do
commit: {
status: status,
author_name: 'hacker',
- duration: 10,
+ duration: duration,
},
}
end
@@ -23,9 +23,10 @@ describe SlackService::BuildMessage do
context 'succeeded' do
let(:status) { 'success' }
let(:color) { 'good' }
-
+ let(:duration) { 10 }
+
it 'returns a message with information about succeeded build' do
- message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker passed in 10 second(s)'
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker passed in 10 seconds'
expect(subject.pretext).to be_empty
expect(subject.fallback).to eq(message)
expect(subject.attachments).to eq([text: message, color: color])
@@ -35,9 +36,23 @@ describe SlackService::BuildMessage do
context 'failed' do
let(:status) { 'failed' }
let(:color) { 'danger' }
+ let(:duration) { 10 }
it 'returns a message with information about failed build' do
- message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 10 second(s)'
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 10 seconds'
+ expect(subject.pretext).to be_empty
+ expect(subject.fallback).to eq(message)
+ expect(subject.attachments).to eq([text: message, color: color])
+ end
+ end
+
+ describe '#seconds_name' do
+ let(:status) { 'failed' }
+ let(:color) { 'danger' }
+ let(:duration) { 1 }
+
+ it 'returns seconds as singular when there is only one' do
+ message = '<somewhere.com|project_name>: Commit <somewhere.com/commit/97de212e80737a608d939f648d959671fb0a0142/builds|97de212e> of <somewhere.com/commits/develop|develop> branch by hacker failed in 1 second'
expect(subject.pretext).to be_empty
expect(subject.fallback).to eq(message)
expect(subject.attachments).to eq([text: message, color: color])
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 60e1ec43f2b..6c1b0393682 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -60,7 +60,7 @@ describe Project, models: true do
project2 = build(:project)
allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object)
expect(project2).not_to be_valid
- expect(project2.errors[:limit_reached].first).to match(/Your project limit is 0/)
+ expect(project2.errors[:limit_reached].first).to match(/Personal project creation is not allowed/)
end
end
@@ -791,7 +791,7 @@ describe Project, models: true do
subject { project.container_registry_repository }
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
describe '#container_registry_repository_url' do
@@ -809,7 +809,7 @@ describe Project, models: true do
}
end
- it { is_expected.to_not be_nil }
+ it { is_expected.not_to be_nil }
end
context 'for disabled registry' do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 583151023b6..8c2347992f1 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -443,7 +443,7 @@ describe Repository, models: true do
end
it 'does nothing' do
- expect(repository.raw_repository).to_not receive(:autocrlf=).
+ expect(repository.raw_repository).not_to receive(:autocrlf=).
with(:input)
repository.update_autocrlf_option
@@ -511,7 +511,7 @@ describe Repository, models: true do
it 'does not expire the emptiness caches for a non-empty repository' do
expect(repository).to receive(:empty?).and_return(false)
- expect(repository).to_not receive(:expire_emptiness_caches)
+ expect(repository).not_to receive(:expire_emptiness_caches)
repository.expire_cache
end
@@ -674,7 +674,7 @@ describe Repository, models: true do
end
it 'does not flush caches that depend on repository data' do
- expect(repository).to_not receive(:expire_cache)
+ expect(repository).not_to receive(:expire_cache)
repository.before_delete
end
@@ -829,18 +829,6 @@ describe Repository, models: true do
end
end
- describe "#main_language" do
- it 'shows the main language of the project' do
- expect(repository.main_language).to eq("Ruby")
- end
-
- it 'returns nil when the repository is empty' do
- allow(repository).to receive(:empty?).and_return(true)
-
- expect(repository.main_language).to be_nil
- end
- end
-
describe '#before_remove_tag' do
it 'flushes the tag cache' do
expect(repository).to receive(:expire_tag_count_cache)
@@ -951,7 +939,7 @@ describe Repository, models: true do
expect(repository.avatar).to eq('logo.png')
- expect(repository).to_not receive(:blob_at_branch)
+ expect(repository).not_to receive(:blob_at_branch)
expect(repository.avatar).to eq('logo.png')
end
end
@@ -1045,7 +1033,7 @@ describe Repository, models: true do
and_return(true)
repository.cache_keys.each do |key|
- expect(repository).to_not receive(key)
+ expect(repository).not_to receive(key)
end
repository.build_cache
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 37ddab83c30..7ecefce80d6 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -12,6 +12,7 @@ describe API::API, api: true do
let!(:group2) { create(:group, :private) }
let!(:project1) { create(:project, namespace: group1) }
let!(:project2) { create(:project, namespace: group2) }
+ let!(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
before do
group1.add_owner(user1)
@@ -147,9 +148,11 @@ describe API::API, api: true do
context "when authenticated as user" do
it "should return the group's projects" do
get api("/groups/#{group1.id}/projects", user1)
+
expect(response.status).to eq(200)
- expect(json_response.length).to eq(1)
- expect(json_response.first['name']).to eq(project1.name)
+ expect(json_response.length).to eq(2)
+ project_names = json_response.map { |proj| proj['name' ] }
+ expect(project_names).to match_array([project1.name, project3.name])
end
it "should not return a non existing group" do
@@ -162,6 +165,16 @@ describe API::API, api: true do
expect(response.status).to eq(404)
end
+
+ it "should only return projects to which user has access" do
+ project3.team << [user3, :developer]
+
+ get api("/groups/#{group1.id}/projects", user3)
+
+ expect(response.status).to eq(200)
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['name']).to eq(project3.name)
+ end
end
context "when authenticated as admin" do
@@ -181,8 +194,10 @@ describe API::API, api: true do
context 'when using group path in URL' do
it 'should return any existing group' do
get api("/groups/#{group1.path}/projects", admin)
+
expect(response.status).to eq(200)
- expect(json_response.first['name']).to eq(project1.name)
+ project_names = json_response.map { |proj| proj['name' ] }
+ expect(project_names).to match_array([project1.name, project3.name])
end
it 'should not return a non existing group' do
diff --git a/spec/requests/api/project_members_spec.rb b/spec/requests/api/project_members_spec.rb
index c112ca5e3ca..44b532b10e1 100644
--- a/spec/requests/api/project_members_spec.rb
+++ b/spec/requests/api/project_members_spec.rb
@@ -133,7 +133,7 @@ describe API::API, api: true do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
expect do
delete api("/projects/#{project.id}/members/#{user3.id}", user)
- end.to_not change { ProjectMember.count }
+ end.not_to change { ProjectMember.count }
expect(response.status).to eq(200)
end
diff --git a/spec/requests/api/system_hooks_spec.rb b/spec/requests/api/system_hooks_spec.rb
index 3e676515488..94eebc48ec8 100644
--- a/spec/requests/api/system_hooks_spec.rb
+++ b/spec/requests/api/system_hooks_spec.rb
@@ -49,7 +49,7 @@ describe API::API, api: true do
it "should not create new hook without url" do
expect do
post api("/hooks", admin)
- end.to_not change { SystemHook.count }
+ end.not_to change { SystemHook.count }
end
end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index 7ebf8e41f3b..e5124ea5ea7 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -253,13 +253,13 @@ describe Ci::API::API do
it "using token as parameter" do
post authorize_url, { token: build.token }, headers
expect(response.status).to eq(200)
- expect(json_response["TempPath"]).to_not be_nil
+ expect(json_response["TempPath"]).not_to be_nil
end
it "using token as header" do
post authorize_url, {}, headers_with_token
expect(response.status).to eq(200)
- expect(json_response["TempPath"]).to_not be_nil
+ expect(json_response["TempPath"]).not_to be_nil
end
end
diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb
index 3f4a1ced2b6..98ef9d21035 100644
--- a/spec/services/auth/container_registry_authentication_service_spec.rb
+++ b/spec/services/auth/container_registry_authentication_service_spec.rb
@@ -52,12 +52,12 @@ describe Auth::ContainerRegistryAuthenticationService, services: true do
shared_examples 'an unauthorized' do
it { is_expected.to include(http_status: 401) }
- it { is_expected.to_not include(:token) }
+ it { is_expected.not_to include(:token) }
end
shared_examples 'a forbidden' do
it { is_expected.to include(http_status: 403) }
- it { is_expected.to_not include(:token) }
+ it { is_expected.not_to include(:token) }
end
describe '#full_access_token' do
diff --git a/spec/services/create_commit_builds_service_spec.rb b/spec/services/create_commit_builds_service_spec.rb
index ea5dcfa068a..9ae8f31b372 100644
--- a/spec/services/create_commit_builds_service_spec.rb
+++ b/spec/services/create_commit_builds_service_spec.rb
@@ -78,7 +78,7 @@ describe CreateCommitBuildsService, services: true do
expect(commit).to be_persisted
expect(commit.builds.any?).to be false
expect(commit.status).to eq('failed')
- expect(commit.yaml_errors).to_not be_nil
+ expect(commit.yaml_errors).not_to be_nil
end
describe :ci_skip? do
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index eeab540c2fd..18692f1279a 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -158,49 +158,6 @@ describe GitPushService, services: true do
end
end
- describe "Updates main language" do
- context "before push" do
- it { expect(project.main_language).to eq(nil) }
- end
-
- context "after push" do
- def execute
- execute_service(project, user, @oldrev, @newrev, ref)
- end
-
- context "to master" do
- let(:ref) { @ref }
-
- context 'when main_language is nil' do
- it 'obtains the language from the repository' do
- expect(project.repository).to receive(:main_language)
- execute
- end
-
- it 'sets the project main language' do
- execute
- expect(project.main_language).to eq("Ruby")
- end
- end
-
- context 'when main_language is already set' do
- it 'does not check the repository' do
- execute # do an initial run to simulate lang being preset
- expect(project.repository).not_to receive(:main_language)
- execute
- end
- end
- end
-
- context "to other branch" do
- let(:ref) { 'refs/heads/feature/branch' }
-
- it { expect(project.main_language).to eq(nil) }
- end
- end
- end
-
-
describe "Updates git attributes" do
context "for default branch" do
it "calls the copy attributes method for the first push to the default branch" do
diff --git a/spec/services/groups/create_service_spec.rb b/spec/services/groups/create_service_spec.rb
index 6aefb48a4e8..a97ac3ead45 100644
--- a/spec/services/groups/create_service_spec.rb
+++ b/spec/services/groups/create_service_spec.rb
@@ -14,7 +14,7 @@ describe Groups::CreateService, services: true do
context "cannot create group with restricted visibility level" do
before { allow(current_application_settings).to receive(:restricted_visibility_levels).and_return([Gitlab::VisibilityLevel::PUBLIC]) }
- it { is_expected.to_not be_persisted }
+ it { is_expected.not_to be_persisted }
end
end
end
diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb
index 6aa0a89f893..1ee9f3aae4d 100644
--- a/spec/services/issues/create_service_spec.rb
+++ b/spec/services/issues/create_service_spec.rb
@@ -55,7 +55,7 @@ describe Issues::CreateService, services: true do
end
it 'does not assign label' do
- expect(issue.labels).to_not include label
+ expect(issue.labels).not_to include label
end
end
@@ -69,7 +69,7 @@ describe Issues::CreateService, services: true do
end
it 'does not assign milestone' do
- expect(issue.milestone).to_not eq milestone
+ expect(issue.milestone).not_to eq milestone
end
end
end
diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb
index c15e26189a5..95fe6c2400a 100644
--- a/spec/services/issues/move_service_spec.rb
+++ b/spec/services/issues/move_service_spec.rb
@@ -194,10 +194,10 @@ describe Issues::MoveService, services: true do
include_context 'issue move executed'
it 'rewrites uploads in description' do
- expect(new_issue.description).to_not eq description
+ expect(new_issue.description).not_to eq description
expect(new_issue.description)
.to match(/Text and #{FileUploader::MARKDOWN_PATTERN}/)
- expect(new_issue.description).to_not include uploader.secret
+ expect(new_issue.description).not_to include uploader.secret
end
end
end
@@ -231,7 +231,7 @@ describe Issues::MoveService, services: true do
context 'user is reporter in both projects' do
include_context 'user can move issue'
- it { expect { move }.to_not raise_error }
+ it { expect { move }.not_to raise_error }
end
context 'user is reporter only in new project' do
diff --git a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
index 52a302e0e1a..82247849814 100644
--- a/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
+++ b/spec/services/merge_requests/merge_when_build_succeeds_service_spec.rb
@@ -75,7 +75,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
allow(ci_commit).to receive(:success?).and_return(true)
allow(old_build).to receive(:sha).and_return('1234abcdef')
- expect(MergeWorker).to_not receive(:perform_async)
+ expect(MergeWorker).not_to receive(:perform_async)
service.trigger(old_build)
end
end
@@ -88,7 +88,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
it "doesn't merge a requests for status on other branch" do
allow(project.repository).to receive(:branch_names_contains).with(commit_status.sha).and_return([])
- expect(MergeWorker).to_not receive(:perform_async)
+ expect(MergeWorker).not_to receive(:perform_async)
service.trigger(commit_status)
end
@@ -122,7 +122,7 @@ describe MergeRequests::MergeWhenBuildSucceedsService do
end
it "doesn't merge if some stages failed" do
- expect(MergeWorker).to_not receive(:perform_async)
+ expect(MergeWorker).not_to receive(:perform_async)
build.success
test.drop
end
diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb
index d1ee60a0aea..31bb7120d84 100644
--- a/spec/services/projects/fork_service_spec.rb
+++ b/spec/services/projects/fork_service_spec.rb
@@ -42,6 +42,33 @@ describe Projects::ForkService, services: true do
expect(@to_project.builds_enabled?).to be_truthy
end
end
+
+ context "when project has restricted visibility level" do
+ context "and only one visibility level is restricted" do
+ before do
+ @from_project.update_attributes(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
+ end
+
+ it "creates fork with highest allowed level" do
+ forked_project = fork_project(@from_project, @to_user)
+
+ expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
+ end
+ end
+
+ context "and all visibility levels are restricted" do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE])
+ end
+
+ it "creates fork with private visibility levels" do
+ forked_project = fork_project(@from_project, @to_user)
+
+ expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
+ end
+ end
+ end
end
describe :fork_to_namespace do
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 8aeb013eec6..25da0917134 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -2,6 +2,8 @@ require 'spec_helper'
require 'rake'
describe 'gitlab:app namespace rake task' do
+ let(:enable_registry) { true }
+
before :all do
Rake.application.rake_require 'tasks/gitlab/task_helpers'
Rake.application.rake_require 'tasks/gitlab/backup'
@@ -15,6 +17,10 @@ describe 'gitlab:app namespace rake task' do
FileUtils.mkdir_p('public/uploads')
end
+ before do
+ stub_container_registry_config(enabled: enable_registry)
+ end
+
def run_rake_task(task_name)
Rake::Task[task_name].reenable
Rake.application.invoke_task task_name
@@ -143,6 +149,18 @@ describe 'gitlab:app namespace rake task' do
expect(temp_dirs).to be_empty
end
+
+ context 'registry disabled' do
+ let(:enable_registry) { false }
+
+ it 'should not create registry.tar.gz' do
+ tar_contents, exit_status = Gitlab::Popen.popen(
+ %W{tar -tvf #{@backup_tar}}
+ )
+ expect(exit_status).to eq(0)
+ expect(tar_contents).not_to match('registry.tar.gz')
+ end
+ end
end # backup_create task
describe "Skipping items" do
diff --git a/spec/tasks/gitlab/db_rake_spec.rb b/spec/tasks/gitlab/db_rake_spec.rb
new file mode 100644
index 00000000000..36d03a224e4
--- /dev/null
+++ b/spec/tasks/gitlab/db_rake_spec.rb
@@ -0,0 +1,62 @@
+require 'spec_helper'
+require 'rake'
+
+describe 'gitlab:db namespace rake task' do
+ before :all do
+ Rake.application.rake_require 'active_record/railties/databases'
+ Rake.application.rake_require 'tasks/seed_fu'
+ Rake.application.rake_require 'tasks/gitlab/db'
+
+ # empty task as env is already loaded
+ Rake::Task.define_task :environment
+ end
+
+ before do
+ # Stub out db tasks
+ allow(Rake::Task['db:migrate']).to receive(:invoke).and_return(true)
+ allow(Rake::Task['db:schema:load']).to receive(:invoke).and_return(true)
+ allow(Rake::Task['db:seed_fu']).to receive(:invoke).and_return(true)
+ end
+
+ describe 'configure' do
+ it 'should invoke db:migrate when schema has already been loaded' do
+ allow(ActiveRecord::Base.connection).to receive(:tables).and_return(['default'])
+ expect(Rake::Task['db:migrate']).to receive(:invoke)
+ expect(Rake::Task['db:schema:load']).not_to receive(:invoke)
+ expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
+ expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
+ end
+
+ it 'should invoke db:shema:load and db:seed_fu when schema is not loaded' do
+ allow(ActiveRecord::Base.connection).to receive(:tables).and_return([])
+ expect(Rake::Task['db:schema:load']).to receive(:invoke)
+ expect(Rake::Task['db:seed_fu']).to receive(:invoke)
+ expect(Rake::Task['db:migrate']).not_to receive(:invoke)
+ expect { run_rake_task('gitlab:db:configure') }.not_to raise_error
+ end
+
+ it 'should not invoke any other rake tasks during an error' do
+ allow(ActiveRecord::Base).to receive(:connection).and_raise(RuntimeError, 'error')
+ expect(Rake::Task['db:migrate']).not_to receive(:invoke)
+ expect(Rake::Task['db:schema:load']).not_to receive(:invoke)
+ expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
+ expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error')
+ # unstub connection so that the database cleaner still works
+ allow(ActiveRecord::Base).to receive(:connection).and_call_original
+ end
+
+ it 'should not invoke seed after a failed schema_load' do
+ allow(ActiveRecord::Base.connection).to receive(:tables).and_return([])
+ allow(Rake::Task['db:schema:load']).to receive(:invoke).and_raise(RuntimeError, 'error')
+ expect(Rake::Task['db:schema:load']).to receive(:invoke)
+ expect(Rake::Task['db:seed_fu']).not_to receive(:invoke)
+ expect(Rake::Task['db:migrate']).not_to receive(:invoke)
+ expect { run_rake_task('gitlab:db:configure') }.to raise_error(RuntimeError, 'error')
+ end
+ end
+
+ def run_rake_task(task_name)
+ Rake::Task[task_name].reenable
+ Rake.application.invoke_task task_name
+ end
+end
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index 2f465bcf1e3..20d3dfb42b3 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -61,7 +61,7 @@ describe PostReceive do
context "does not create a Ci::Commit" do
before { stub_ci_commit_yaml_file(nil) }
- it { expect{ subject }.to_not change{ Ci::Commit.count } }
+ it { expect{ subject }.not_to change{ Ci::Commit.count } }
end
end
end