diff options
143 files changed, 1233 insertions, 724 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 ebc83df0a40..4a38505eeea 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,15 +1,28 @@ 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 - -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 + - Use gitlab-shell v3.0.0 + - 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' + +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) @@ -88,6 +101,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/GITLAB_SHELL_VERSION b/GITLAB_SHELL_VERSION index 37c2961c243..4a36342fcab 100644 --- a/GITLAB_SHELL_VERSION +++ b/GITLAB_SHELL_VERSION @@ -1 +1 @@ -2.7.2 +3.0.0 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/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/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 afb0cd1a1e6..ee4f573f91b 100644 --- a/app/assets/stylesheets/framework/nav.scss +++ b/app/assets/stylesheets/framework/nav.scss @@ -119,7 +119,7 @@ } input { - height: 34px; + height: 35px; display: inline-block; position: relative; top: 2px; @@ -196,7 +196,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; 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/profile.scss b/app/assets/stylesheets/pages/profile.scss index 843379a3f54..8040dd0a1d8 100644 --- a/app/assets/stylesheets/pages/profile.scss +++ b/app/assets/stylesheets/pages/profile.scss @@ -134,14 +134,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/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/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/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/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/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/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/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/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/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 ... - - %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 8be124f387a..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,13 +40,13 @@ %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 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/_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/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/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/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/_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/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 - · created by #{link_to_member(@project, @snippet.author, size: 24)} - · + 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 - · = 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/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/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/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/integration/google.md b/doc/integration/google.md index f9a20dd840d..82978b68a34 100644 --- a/doc/integration/google.md +++ b/doc/integration/google.md @@ -11,9 +11,9 @@ To enable the Google OAuth2 OmniAuth provider you must register your application - Project ID: Must be unique to all Google Developer registered applications. Google provides a randomly generated Project ID by default. You can use the randomly generated ID or choose a new one. 1. Refresh the page. You should now see your new project in the list. Click on the project. -1. Select "APIs & auth" in the left menu. +1. Select the "Google APIs" tab in the Overview. -1. Select "APIs" in the submenu. +1. Select and enable the following Google APIs - listed under "Popular APIs" - Enable `Contacts API` - Enable `Google+ API` 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/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 << '<' + 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/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 090a941958f..7a05d30e8b5 100644 --- a/spec/features/builds_spec.rb +++ b/spec/features/builds_spec.rb @@ -46,7 +46,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 end @@ -62,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..bfbd06a29e2 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).to_not 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/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/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..92ec51eabd4 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 @@ -951,7 +951,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 +1045,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/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/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 |