diff options
author | Douglas Barbosa Alexandre <dbalexandre@gmail.com> | 2016-04-11 10:34:49 -0300 |
---|---|---|
committer | Douglas Barbosa Alexandre <dbalexandre@gmail.com> | 2016-04-11 10:34:49 -0300 |
commit | 9a44d6977ad27a443538b2b6c34b3fdd722e9bd6 (patch) | |
tree | 487aa6ad827b903aa2c78542d9252d056d9e1238 | |
parent | 73fdd4b83d76998fef9770dbeaf05981d4500b8c (diff) | |
parent | 15cbbd09fbd05cfd2447dfb43d66d7a96a708f82 (diff) | |
download | gitlab-ce-9a44d6977ad27a443538b2b6c34b3fdd722e9bd6.tar.gz |
Merge branch 'master' into decouple-member-notification
119 files changed, 1169 insertions, 588 deletions
diff --git a/CHANGELOG b/CHANGELOG index eae6cb90700..314d2eb1dfa 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Please view this file on the master branch, on stable branches it's out of date. v 8.7.0 (unreleased) + - Enable gzip for assets, makes the page size significantly smaller. !3544 / !3632 (Connor Shea) + - Load award emoji images separately unless opening the full picker. Saves several hundred KBs of data for most pages. (Connor Shea) - All images in discussions and wikis now link to their source files !3464 (Connor Shea). - Return status code 303 after a branch DELETE operation to avoid project deletion (Stan Hu) - Improved Markdown rendering performance !3389 (Yorick Peterse) @@ -45,6 +47,7 @@ v 8.6.5 v 8.6.4 - Don't attempt to fetch any tags from a forked repo (Stan Hu) + - Redesign the Labels page v 8.6.3 - Mentions on confidential issues doesn't create todos for non-members. !3374 @@ -1,6 +1,6 @@ source "https://rubygems.org" -gem 'rails', '4.2.5.2' +gem 'rails', '4.2.6' gem 'rails-deprecated_sanitizer', '~> 1.0.3' # Responders respond_to and respond_with @@ -8,7 +8,7 @@ gem 'responders', '~> 2.0' # Specify a sprockets version due to increased performance # See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069 -gem 'sprockets', '~> 3.3.5' +gem 'sprockets', '~> 3.6.0' # Default values for AR models gem "default_value_for", "~> 3.0.0" @@ -149,6 +149,10 @@ gem 'version_sorter', '~> 2.0.0' # Cache gem "redis-rails", '~> 4.0.0' +# Redis +gem 'redis', '~> 3.2' +gem 'connection_pool', '~> 2.0' + # Campfire integration gem 'tinder', '~> 1.10.0' @@ -229,14 +233,13 @@ group :metrics do gem 'allocations', '~> 1.0', require: false, platform: :mri gem 'method_source', '~> 0.8', require: false gem 'influxdb', '~> 0.2', require: false - gem 'connection_pool', '~> 2.0', require: false end group :development do gem "foreman" gem 'brakeman', '~> 3.2.0', require: false - gem "annotate", "~> 2.6.0" + gem "annotate", "~> 2.7.0" gem "letter_opener", '~> 1.1.2' gem 'quiet_assets', '~> 1.0.2' gem 'rerun', '~> 0.11.0' diff --git a/Gemfile.lock b/Gemfile.lock index 1ba8d748db1..9da44a46583 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,41 +4,41 @@ GEM CFPropertyList (2.3.2) RedCloth (4.2.9) ace-rails-ap (2.0.1) - actionmailer (4.2.5.2) - actionpack (= 4.2.5.2) - actionview (= 4.2.5.2) - activejob (= 4.2.5.2) + actionmailer (4.2.6) + actionpack (= 4.2.6) + actionview (= 4.2.6) + activejob (= 4.2.6) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.5.2) - actionview (= 4.2.5.2) - activesupport (= 4.2.5.2) + actionpack (4.2.6) + actionview (= 4.2.6) + activesupport (= 4.2.6) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.5.2) - activesupport (= 4.2.5.2) + actionview (4.2.6) + activesupport (= 4.2.6) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.5.2) - activesupport (= 4.2.5.2) + activejob (4.2.6) + activesupport (= 4.2.6) globalid (>= 0.3.0) - activemodel (4.2.5.2) - activesupport (= 4.2.5.2) + activemodel (4.2.6) + activesupport (= 4.2.6) builder (~> 3.1) - activerecord (4.2.5.2) - activemodel (= 4.2.5.2) - activesupport (= 4.2.5.2) + activerecord (4.2.6) + activemodel (= 4.2.6) + activesupport (= 4.2.6) arel (~> 6.0) activerecord-deprecated_finders (1.0.4) activerecord-session_store (0.1.2) actionpack (>= 4.0.0, < 5) activerecord (>= 4.0.0, < 5) railties (>= 4.0.0, < 5) - activesupport (4.2.5.2) + activesupport (4.2.6) i18n (~> 0.7) json (~> 1.7, >= 1.7.7) minitest (~> 5.1) @@ -51,8 +51,8 @@ GEM activerecord (>= 3.0) akismet (2.0.0) allocations (1.0.4) - annotate (2.6.10) - activerecord (>= 3.2, <= 4.3) + annotate (2.7.0) + activerecord (>= 3.2, < 6.0) rake (~> 10.4) arel (6.0.3) asana (0.4.0) @@ -145,7 +145,7 @@ GEM crack (0.4.3) safe_yaml (~> 1.0.0) creole (0.5.0) - css_parser (1.3.7) + css_parser (1.4.1) addressable d3_rails (3.5.11) railties (>= 3.1.0) @@ -459,8 +459,8 @@ GEM nokogiri (>= 1.5.9) macaddr (1.7.1) systemu (~> 2.6.2) - mail (2.6.3) - mime-types (>= 1.16, < 3) + mail (2.6.4) + mime-types (>= 1.16, < 4) mail_room (0.6.1) method_source (0.8.2) mime-types (1.25.1) @@ -559,8 +559,8 @@ GEM premailer (1.8.6) css_parser (>= 1.3.6) htmlentities (>= 4.0.0) - premailer-rails (1.9.0) - actionmailer (>= 3, < 5) + premailer-rails (1.9.2) + actionmailer (>= 3, < 6) premailer (~> 1.7, >= 1.7.9) pry (0.10.3) coderay (~> 1.1.0) @@ -589,16 +589,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.5.2) - actionmailer (= 4.2.5.2) - actionpack (= 4.2.5.2) - actionview (= 4.2.5.2) - activejob (= 4.2.5.2) - activemodel (= 4.2.5.2) - activerecord (= 4.2.5.2) - activesupport (= 4.2.5.2) + rails (4.2.6) + actionmailer (= 4.2.6) + actionpack (= 4.2.6) + actionview (= 4.2.6) + activejob (= 4.2.6) + activemodel (= 4.2.6) + activerecord (= 4.2.6) + activesupport (= 4.2.6) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.5.2) + railties (= 4.2.6) sprockets-rails rails-deprecated_sanitizer (1.0.3) activesupport (>= 4.2.0.alpha) @@ -608,9 +608,9 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (4.2.5.2) - actionpack (= 4.2.5.2) - activesupport (= 4.2.5.2) + railties (4.2.6) + actionpack (= 4.2.6) + activesupport (= 4.2.6) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.1.0) @@ -776,12 +776,13 @@ GEM spring (>= 0.9.1) spring-commands-teaspoon (0.0.2) spring (>= 0.9.1) - sprockets (3.3.5) + sprockets (3.6.0) + concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (2.3.3) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) + sprockets-rails (3.0.4) + actionpack (>= 4.0) + activesupport (>= 4.0) + sprockets (>= 3.0.0) state_machines (0.4.0) state_machines-activemodel (0.3.0) activemodel (~> 4.1) @@ -887,7 +888,7 @@ DEPENDENCIES after_commit_queue akismet (~> 2.0) allocations (~> 1.0) - annotate (~> 2.6.0) + annotate (~> 2.7.0) asana (~> 0.4.0) asciidoctor (~> 1.5.2) attr_encrypted (~> 1.3.4) @@ -992,13 +993,14 @@ DEPENDENCIES rack-attack (~> 4.3.1) rack-cors (~> 0.4.0) rack-oauth2 (~> 1.2.1) - rails (= 4.2.5.2) + rails (= 4.2.6) rails-deprecated_sanitizer (~> 1.0.3) raphael-rails (~> 2.1.2) rblineprof rdoc (~> 3.6) recaptcha redcarpet (~> 3.3.3) + redis (~> 3.2) redis-namespace redis-rails (~> 4.0.0) request_store (~> 1.3.0) @@ -1032,7 +1034,7 @@ DEPENDENCIES spring-commands-rspec (~> 1.0.4) spring-commands-spinach (~> 1.0.0) spring-commands-teaspoon (~> 0.0.2) - sprockets (~> 3.3.5) + sprockets (~> 3.6.0) state_machines-activerecord (~> 0.3.0) task_list (~> 1.0.2) teaspoon (~> 1.1.0) diff --git a/app/assets/javascripts/awards_handler.coffee b/app/assets/javascripts/awards_handler.coffee index 6a670d5e887..af4462ece38 100644 --- a/app/assets/javascripts/awards_handler.coffee +++ b/app/assets/javascripts/awards_handler.coffee @@ -22,8 +22,19 @@ class @AwardsHandler emoji = $(this) .find(".icon") .data "emoji" + + if emoji is "thumbsup" and awards_handler.didUserClickEmoji $(this), "thumbsdown" + awards_handler.addAward "thumbsdown" + + else if emoji is "thumbsdown" and awards_handler.didUserClickEmoji $(this), "thumbsup" + awards_handler.addAward "thumbsup" + awards_handler.addAward emoji + didUserClickEmoji: (that, emoji) -> + if $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title") + $(that).siblings("button:has([data-emoji=#{emoji}])").attr("data-original-title").indexOf('me') > -1 + showEmojiMenu: -> if $(".emoji-menu").length if $(".emoji-menu").is ".is-visible" @@ -105,7 +116,7 @@ class @AwardsHandler if origTitle authors = origTitle.split(', ') authors.push("me") - award_block.attr("title", authors.join(", ")) + award_block.attr("data-original-title", authors.join(", ")) @resetTooltip(award_block) resetTooltip: (award) -> @@ -122,7 +133,7 @@ class @AwardsHandler nodes = [] nodes.push( - "<button class='btn award-control js-emoji-btn has-tooltip active' title='me'>", + "<button class='btn award-control js-emoji-btn has-tooltip active' data-original-title='me'>", "<div class='icon emoji-icon #{emojiCssClass}' data-emoji='#{emoji}'></div>", "<span class='award-control-text js-counter'>1</span>", "</button>" diff --git a/app/assets/javascripts/compare.js.coffee b/app/assets/javascripts/compare.js.coffee new file mode 100644 index 00000000000..f20992ead3e --- /dev/null +++ b/app/assets/javascripts/compare.js.coffee @@ -0,0 +1,67 @@ +class @Compare + constructor: (@opts) -> + @source_loading = $ ".js-source-loading" + @target_loading = $ ".js-target-loading" + + $('.js-compare-dropdown').each (i, dropdown) => + $dropdown = $(dropdown) + + $dropdown.glDropdown( + selectable: true + fieldName: $dropdown.data 'field-name' + filterable: true + id: (obj, $el) -> + $el.data 'id' + toggleLabel: (obj, $el) -> + $el.text().trim() + clicked: (e, el) => + if $dropdown.is '.js-target-branch' + @getTargetHtml() + else if $dropdown.is '.js-source-branch' + @getSourceHtml() + else if $dropdown.is '.js-target-project' + @getTargetProject() + ) + + @initialState() + + initialState: -> + @getSourceHtml() + @getTargetHtml() + + getTargetProject: -> + $.ajax( + url: @opts.targetProjectUrl + data: + target_project_id: $("input[name='merge_request[target_project_id]']").val() + beforeSend: -> + $('.mr_target_commit').empty() + success: (html) -> + $('.js-target-branch-dropdown .dropdown-content').html html + ) + + getSourceHtml: -> + @sendAjax(@opts.sourceBranchUrl, @source_loading, '.mr_source_commit', + ref: $("input[name='merge_request[source_branch]']").val() + ) + + getTargetHtml: -> + @sendAjax(@opts.targetBranchUrl, @target_loading, '.mr_target_commit', + target_project_id: $("input[name='merge_request[target_project_id]']").val() + ref: $("input[name='merge_request[target_branch]']").val() + ) + + sendAjax: (url, loading, target, data) -> + $target = $(target) + + $.ajax( + url: url + data: data + beforeSend: -> + loading.show() + $target.empty() + success: (html) -> + loading.hide() + $target.html html + $('.js-timeago', $target).timeago() + ) diff --git a/app/assets/javascripts/gl_dropdown.js.coffee b/app/assets/javascripts/gl_dropdown.js.coffee index e8d25591f63..ee1d0fad289 100644 --- a/app/assets/javascripts/gl_dropdown.js.coffee +++ b/app/assets/javascripts/gl_dropdown.js.coffee @@ -57,14 +57,30 @@ class GitLabDropdownFilter filter: (search_text) -> data = @options.data() - results = data - if search_text isnt "" - results = fuzzaldrinPlus.filter(data, search_text, - key: @options.keys - ) + if data? + results = data - @options.callback results + if search_text isnt '' + results = fuzzaldrinPlus.filter(data, search_text, + key: @options.keys + ) + + @options.callback results + else + elements = @options.elements() + + if search_text + elements.each -> + $el = $(@) + matches = fuzzaldrinPlus.match($el.text().trim(), search_text) + + if matches.length + $el.show() + else + $el.hide() + else + elements.show() class GitLabDropdownRemote constructor: (@dataEndpoint, @options) -> @@ -123,7 +139,7 @@ class GitLabDropdown if _.isString(@filterInput) @filterInput = @getElement(@filterInput) - search_fields = if @options.search then @options.search.fields else []; + searchFields = if @options.search then @options.search.fields else []; if @options.data # If data is an array @@ -147,7 +163,14 @@ class GitLabDropdown filterInputBlur: @filterInputBlur remote: @options.filterRemote query: @options.data - keys: @options.search.fields + keys: searchFields + elements: => + selector = '.dropdown-content li:not(.divider)' + + if @dropdown.find('.dropdown-toggle-page').length + selector = ".dropdown-page-one #{selector}" + + return $(selector) data: => return @fullData callback: (data) => @@ -376,7 +399,7 @@ class GitLabDropdown # Toggle the dropdown label if @options.toggleLabel - $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject) + $(@el).find(".dropdown-toggle-text").text @options.toggleLabel(selectedObject, el) if value? if !field.length and fieldName # Create hidden input for form diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee index 839e6ec2c08..9946249adbf 100644 --- a/app/assets/javascripts/merge_request_tabs.js.coffee +++ b/app/assets/javascripts/merge_request_tabs.js.coffee @@ -73,7 +73,8 @@ class @MergeRequestTabs @expandView() else if action == 'diffs' @loadDiff($target.attr('href')) - @shrinkView() + if bp? and bp.getBreakpointSize() isnt 'lg' + @shrinkView() else if action == 'builds' @loadBuilds($target.attr('href')) @expandView() diff --git a/app/assets/javascripts/subscription.js.coffee b/app/assets/javascripts/subscription.js.coffee index 084f0e0dc65..e4b7a3172ec 100644 --- a/app/assets/javascripts/subscription.js.coffee +++ b/app/assets/javascripts/subscription.js.coffee @@ -10,10 +10,10 @@ class @Subscription btn = $(event.currentTarget) action = btn.find('span').text() current_status = @subscription_status.attr('data-status') - btn.prop('disabled', true) + btn.addClass('disabled') $.post @url, => - btn.prop('disabled', false) + btn.removeClass('disabled') status = if current_status == 'subscribed' then 'unsubscribed' else 'subscribed' @subscription_status.attr('data-status', status) action = if status == 'subscribed' then 'Unsubscribe' else 'Subscribe' diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss index 657c5f033c7..e8c0172680d 100644 --- a/app/assets/stylesheets/framework/buttons.scss +++ b/app/assets/stylesheets/framework/buttons.scss @@ -7,6 +7,7 @@ &:focus, &:active { outline: none; + background-color: $btn-active-gray; @include box-shadow($gl-btn-active-background); } } @@ -27,7 +28,8 @@ color: $color; } - &:active { + &:active, + &.active { @include box-shadow ($gl-btn-active-background); background-color: $dark; @@ -61,7 +63,7 @@ } @mixin btn-white { - @include btn-color($white-light, $border-white-light, $white-normal, $border-white-normal, $white-dark, $border-white-dark, #313236); + @include btn-color($white-light, $border-color, $white-normal, $border-white-normal, $white-dark, $border-white-dark, $btn-white-active); } .btn { @@ -218,3 +220,26 @@ margin-right: 5px; } } + +.btn-text-field { + width: 100%; + text-align: left; + padding: 6px 16px; + border-color: $border-color; + color: $btn-placeholder-gray; + background-color: $background-color; + + &:hover, + &:active, + &:focus { + cursor: text; + box-shadow: none; + border-color: $border-color; + color: $btn-placeholder-gray; + background-color: $background-color; + } +} + +.btn-file-option { + background: linear-gradient(180deg, $white-light 25%, $gray-light 100%); +} diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index 82dc1acbd01..ba6c7930cdc 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -248,7 +248,7 @@ .dropdown-title { position: relative; - padding: 0 0 15px; + padding: 0 25px 15px; margin: 0 10px 10px; font-weight: 600; line-height: 1; @@ -275,7 +275,7 @@ } .dropdown-menu-close { - right: 7px; + right: 5px; width: 20px; height: 20px; top: -1px; diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index b15f4e7bd5e..789df42fb66 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -15,12 +15,13 @@ .file-title { position: relative; - background: $background-color; + background-color: $background-color; border-bottom: 1px solid $border-color; margin: 0; text-align: left; padding: 10px $gl-padding; word-wrap: break-word; + border-radius: 3px 3px 0 0; .file-actions { float: right; @@ -49,7 +50,7 @@ } } - a { + a:not(.btn) { color: $gl-dark-link-color; } diff --git a/app/assets/stylesheets/framework/timeline.scss b/app/assets/stylesheets/framework/timeline.scss index aa244fe548d..b91f2f6f898 100644 --- a/app/assets/stylesheets/framework/timeline.scss +++ b/app/assets/stylesheets/framework/timeline.scss @@ -14,10 +14,6 @@ background: $row-hover; } - &:last-child { - border-bottom: none; - } - .avatar { margin-right: 15px; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 8d3ad934a50..1ebbd9b0e57 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -10,10 +10,10 @@ $gutter_inner_width: 258px; /* * UI elements */ -$border-color: #efeff1; +$border-color: #e5e5e5; $focus-border-color: #3aabf0; $table-border-color: #eef0f2; -$background-color: #faf9f9; +$background-color: #fafafa; /* * Text @@ -81,7 +81,7 @@ $provider-btn-not-active-color: #4688f1; $white-light: #fff; $white-normal: #ededed; -$white-dark: #ededed; +$white-dark: #ececec; $gray-light: #faf9f9; $gray-normal: #f5f5f5; @@ -108,6 +108,8 @@ $red-light: #e52c5a; $red-normal: #d22852; $red-dark: darken($red-normal, 5%); +$black-transparent: rgba(0, 0, 0, 0.3); + $border-white-light: #f1f2f4; $border-white-normal: #d6dae2; $border-white-dark: #c6cacf; @@ -150,15 +152,22 @@ $gl-success: $green-normal; $gl-info: $blue-normal; $gl-warning: $orange-normal; $gl-danger: $red-normal; -$gl-btn-active-background: rgba(0, 0, 0, 0.12); -$gl-btn-active-gradient: inset 0 0 4px $gl-btn-active-background; +$gl-btn-active-background: rgba(0, 0, 0, 0.16); +$gl-btn-active-gradient: inset 0 2px 3px $gl-btn-active-background; /* * Commit Diff Colors */ $added: #63c363; $deleted: #f77; - +$line-added: #ecfdf0; +$line-added-dark: #c7f0d2; +$line-removed: #fbe9eb; +$line-removed-dark: #fac5cd; +$line-number-old: #f9d7dc; +$line-number-new: #ddfbe6; +$match-line: #fafafa; +$table-border-gray: #f0f0f0; /* * Fonts */ @@ -192,6 +201,13 @@ $dropdown-toggle-icon-color: #c4c4c4; $dropdown-toggle-hover-icon-color: $dropdown-toggle-hover-border-color; /* +* Buttons +*/ +$btn-active-gray: #ececec; +$btn-placeholder-gray: #c7c7c7; +$btn-white-active: #848484; + +/* * Award emoji */ $award-emoji-menu-bg: #fff; diff --git a/app/assets/stylesheets/highlight/solarized_light.scss b/app/assets/stylesheets/highlight/solarized_light.scss index b90c95c62d1..c482a1258f7 100644 --- a/app/assets/stylesheets/highlight/solarized_light.scss +++ b/app/assets/stylesheets/highlight/solarized_light.scss @@ -6,7 +6,7 @@ } .diff-line-num, .diff-line-num a { - color: rgba(0, 0, 0, 0.3); + color: $black-transparent; } // Code itself @@ -30,7 +30,7 @@ } .line_content.match { - color: rgba(0, 0, 0, 0.3); + color: $black-transparent; background: rgba(255, 255, 255, 0.4); } } diff --git a/app/assets/stylesheets/highlight/white.scss b/app/assets/stylesheets/highlight/white.scss index 8c1b0cd84ec..28331f59754 100644 --- a/app/assets/stylesheets/highlight/white.scss +++ b/app/assets/stylesheets/highlight/white.scss @@ -6,12 +6,12 @@ } .diff-line-num, .diff-line-num a { - color: rgba(0, 0, 0, 0.3); + color: $black-transparent; } // Code itself pre.code, .diff-line-num { - border-color: $border-color; + border-color: $table-border-gray; } &, pre.code, .line_holder .line_content { @@ -23,36 +23,36 @@ .line_holder { .diff-line-num { &.old { - background: #fdd; - border-color: #f1c0c0; + background-color: $line-number-old; + border-color: $line-removed-dark; } &.new { - background: #dbffdb; - border-color: #c1e9c1; + background-color: $line-number-new; + border-color: $line-added-dark; } } .line_content { &.old { - background: #ffecec; + background: $line-removed; span.idiff { - background-color: #f8cbcb; + background-color: $line-removed-dark; } } &.new { - background: #eaffea; + background-color: $line-added; span.idiff { - background-color: #a6f3a6; + background-color: $line-added-dark; } } &.match { - color: rgba(0, 0, 0, 0.3); - background: #fafafa; + color: $black-transparent; + background: $match-line; } } } diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index 8272615768d..6453c91d955 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -47,6 +47,7 @@ li.commit { .commit_short_id { min-width: 65px; + color: $gl-dark-link-color; font-family: $monospace_font; } @@ -88,6 +89,10 @@ li.commit { padding: 0; margin: 0; } + + a { + color: $gl-dark-link-color; + } } .commit-row-info { diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 97f4485beb8..d0855f66911 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -2,6 +2,7 @@ .diff-file { border: 1px solid $border-color; margin-bottom: $gl-padding; + border-radius: 3px; .diff-header { position: relative; @@ -10,6 +11,7 @@ padding: 10px 16px; color: #555; z-index: 10; + border-radius: 3px 3px 0 0; .diff-title { font-family: $monospace_font; @@ -31,6 +33,7 @@ overflow-y: hidden; background: #fff; color: #333; + border-radius: 0 0 3px 3px; .unfold { cursor: pointer; @@ -325,6 +328,16 @@ float: right; } +.diffs { + .content-block { + border-bottom: none; + } +} + +.files-changed { + border-bottom: none; +} + // Mobile @media (max-width: 480px) { .diff-title { diff --git a/app/assets/stylesheets/pages/labels.scss b/app/assets/stylesheets/pages/labels.scss index 4e02ec4e891..3e0a3140be7 100644 --- a/app/assets/stylesheets/pages/labels.scss +++ b/app/assets/stylesheets/pages/labels.scss @@ -49,6 +49,15 @@ } .label-row { + .label-name { + display: inline-block; + width: 200px; + + @media (max-width: $screen-xs-min) { + display: block; + } + } + .label { padding: 9px; font-size: 14px; @@ -69,3 +78,52 @@ background-color: $gl-danger; color: $white-light; } + +.manage-labels-list { + + .prepend-left-10 { + display: inline-block; + width: 40%; + vertical-align: middle; + + @media (max-width: $screen-xs-min) { + display: block; + width: 100%; + margin-left: 0; + padding: 10px 0; + } + } + + .pull-info-right { + float: right; + + @media (max-width: $screen-xs-min) { + float: none; + } + + .action-buttons { + border-color: transparent; + padding: 6px; + color: $gl-text-color; + + &.subscribe-button { + padding-left: 0; + } + } + + i { + color: $gl-text-color; + } + + .append-right-20 { + a { + color: $gl-text-color; + } + + @media (max-width: $screen-xs-min) { + display: block; + margin-bottom: 10px; + } + } + } +} diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 1c6a4208974..b79335eab91 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -123,6 +123,8 @@ .mr_source_commit, .mr_target_commit { + margin-bottom: 0; + .commit { margin: 0; padding: 2px 0; @@ -174,10 +176,6 @@ display: none; } -.merge-request-form .select2-container { - width: 250px !important; -} - #modal_merge_info .modal-dialog { width: 600px; @@ -200,3 +198,76 @@ overflow-x: scroll; } } + +.panel-new-merge-request { + .panel-heading { + padding: 5px 10px; + font-weight: 600; + line-height: 25px; + } + + .panel-body { + padding: 10px 5px; + } + + .panel-footer { + padding: 5px 10px; + } + + .commit { + .commit-row-title { + margin-bottom: 4px; + } + + .avatar { + width: 20px; + height: 20px; + margin-right: 5px; + } + + .commit-row-info { + line-height: 20px; + } + } + + .btn-clipboard { + margin-right: 5px; + padding: 0; + background: transparent; + } + + .ci-status-link { + margin-right: 5px; + } +} + +.merge-request-select { + padding-left: 5px; + padding-right: 5px; + margin-bottom: 10px; + + &:last-child { + margin-bottom: 0; + } + + @media (min-width: $screen-sm-min) { + float: left; + width: 50%; + margin-bottom: 0; + } + + .dropdown-menu-toggle { + width: 100%; + } + + .dropdown-menu { + left: 5px; + right: 5px; + width: auto; + } +} + +.issuable-form-select-holder { + display: inline-block; + width: 250px; +} diff --git a/app/assets/stylesheets/pages/note_form.scss b/app/assets/stylesheets/pages/note_form.scss index a909776b437..4d4d508396d 100644 --- a/app/assets/stylesheets/pages/note_form.scss +++ b/app/assets/stylesheets/pages/note_form.scss @@ -1,10 +1,10 @@ /** * Note Form */ -.reply-btn { - @extend .btn-primary; - margin: 10px $gl-padding; +.comment-btn { + @extend .btn-create; } + .diff-file .diff-content { tr.line_holder:hover > td .line_note_link { opacity: 1.0; @@ -113,13 +113,12 @@ .discussion-body, .diff-file { .notes .note { - border-color: #ddd; padding: 10px 15px; } .discussion-reply-holder { - background: $background-color; - border-top: 1px solid $border-color; + background-color: $white-light; + padding: 10px 16px; } } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index aca86457c70..7295fe51121 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -58,6 +58,7 @@ ul.notes { .note { display: block; position: relative; + border-bottom: 1px solid $table-border-gray; &.is-editting { .note-header, @@ -117,9 +118,6 @@ ul.notes { padding-bottom: 3px; } - &:last-child { - border-bottom: 1px solid $border-color; - } } } @@ -137,14 +135,14 @@ ul.notes { font-family: $regular_font; td { - border: 1px solid #ddd; + border: 1px solid $table-border-gray; border-left: none; &.notes_line { vertical-align: middle; text-align: center; padding: 10px 0; - background: #fff; + background: $background-color; color: $text-color; } &.notes_line2 { @@ -175,9 +173,6 @@ ul.notes { } } - .author_link { - font-weight: 600; - } } .note-headline-light, @@ -203,14 +198,26 @@ ul.notes { line-height: 24px; .fa { + color: $notes-action-color; position: relative; top: 1px; font-size: 17px; } - .fa-trash-o { - top: 0; - font-size: 16px; + &.js-note-delete { + i { + &:hover { + color: $gl-text-red; + } + } + } + + &.js-note-edit { + i { + &:hover { + color: $gl-link-color; + } + } } } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c81cb85dc1b..97d53acde94 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -47,6 +47,16 @@ class ApplicationController < ActionController::Base email: current_user.email, username: current_user.username, ) + + Raven.tags_context(program: sentry_program_context) + end + end + + def sentry_program_context + if Sidekiq.server? + 'sidekiq' + else + 'rails' end end diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 49064f5d505..ae613f5e093 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -207,20 +207,20 @@ class Projects::MergeRequestsController < Projects::ApplicationController #This is always source @source_project = @merge_request.nil? ? @project : @merge_request.source_project @commit = @repository.commit(params[:ref]) if params[:ref].present? + render layout: false end def branch_to @target_project = selected_target_project @commit = @target_project.commit(params[:ref]) if params[:ref].present? + render layout: false end def update_branches @target_project = selected_target_project @target_branches = @target_project.repository.branch_names - respond_to do |format| - format.js - end + render layout: false end def ci_status diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 820d69c230b..9e59a295fc4 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -27,9 +27,9 @@ module BlobHelper link_opts) if !on_top_of_branch?(project, ref) - button_tag "Edit", class: "btn btn-default disabled has-tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' } + button_tag "Edit", class: "btn disabled has-tooltip btn-file-option", title: "You can only edit files when you are on a branch", data: { container: 'body' } elsif can_edit_blob?(blob, project, ref) - link_to "Edit", edit_path, class: 'btn' + link_to "Edit", edit_path, class: 'btn btn-file-option' elsif can?(current_user, :fork_project, project) continue_params = { to: edit_path, @@ -38,7 +38,7 @@ module BlobHelper } fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) - link_to "Edit", fork_path, class: 'btn', method: :post + link_to "Edit", fork_path, class: 'btn btn-file-option', method: :post end end diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb index bde0799f3de..35ba543cef1 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -28,7 +28,7 @@ module CommitsHelper def commit_to_html(commit, project, inline = true) template = inline ? "inline_commit" : "commit" - escape_javascript(render "projects/commits/#{template}", commit: commit, project: project) unless commit.nil? + render "projects/commits/#{template}", commit: commit, project: project unless commit.nil? end # Breadcrumb links for a Project and, if applicable, a tree path @@ -117,7 +117,7 @@ module CommitsHelper end end link_to( - "Browse Files »", + "Browse Files", namespace_project_tree_path(project.namespace, project, commit), class: "pull-right" ) @@ -197,7 +197,7 @@ module CommitsHelper link_to( namespace_project_blob_path(project.namespace, project, tree_join(commit_sha, diff.new_path)), - class: 'btn view-file js-view-file' + class: 'btn view-file js-view-file btn-file-option' ) do raw('View file @') + content_tag(:span, commit_sha[0..6], class: 'commit-short-id') diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb new file mode 100644 index 00000000000..6a43be2cf3e --- /dev/null +++ b/app/helpers/form_helper.rb @@ -0,0 +1,18 @@ +module FormHelper + def form_errors(model) + return unless model.errors.any? + + pluralized = 'error'.pluralize(model.errors.count) + headline = "The form contains the following #{pluralized}:" + + content_tag(:div, class: 'alert alert-danger', id: 'error_explanation') do + content_tag(:h4, headline) << + content_tag(:ul) do + model.errors.full_messages. + map { |msg| content_tag(:li, msg) }. + join. + html_safe + end + end + end +end diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index 2f760af02fd..3a45205563e 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -116,29 +116,6 @@ module GitlabMarkdownHelper end end - MARKDOWN_TIPS = [ - "End a line with two or more spaces for a line-break, or soft-return", - "Inline code can be denoted by `surrounding it with backticks`", - "Blocks of code can be denoted by three backticks ``` or four leading spaces", - "Emoji can be added by :emoji_name:, for example :thumbsup:", - "Notify other participants using @user_name", - "Notify a specific group using @group_name", - "Notify the entire team using @all", - "Reference an issue using a hash, for example issue #123", - "Reference a merge request using an exclamation point, for example MR !123", - "Italicize words or phrases using *asterisks* or _underscores_", - "Bold words or phrases using **double asterisks** or __double underscores__", - "Strikethrough words or phrases using ~~two tildes~~", - "Make a bulleted list using + pluses, - minuses, or * asterisks", - "Denote blockquotes using > at the beginning of a line", - "Make a horizontal line using three or more hyphens ---, asterisks ***, or underscores ___" - ].freeze - - # Returns a random markdown tip for use as a textarea placeholder - def random_markdown_tip - MARKDOWN_TIPS.sample - end - private # Return +text+, truncated to +max_chars+ characters, excluding any HTML diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 24b90fef4fe..bcf8639c829 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -115,17 +115,32 @@ module IssuesHelper icon('eye-slash') if issue.confidential? end - def emoji_icon(name, unicode = nil, aliases = []) + def emoji_icon(name, unicode = nil, aliases = [], sprite: true) unicode ||= Emoji.emoji_filename(name) rescue "" - content_tag :div, "", - class: "icon emoji-icon emoji-#{unicode}", - title: name, - data: { - aliases: aliases.join(' '), - emoji: name, - unicode_name: unicode - } + data = { + aliases: aliases.join(" "), + emoji: name, + unicode_name: unicode + } + + if sprite + # Emoji icons for the emoji menu, these use a spritesheet. + content_tag :div, "", + class: "icon emoji-icon emoji-#{unicode}", + title: name, + data: data + else + # Emoji icons displayed separately, used for the awards already given + # to an issue or merge request. + content_tag :img, "", + class: "icon emoji", + title: name, + height: "20px", + width: "20px", + src: url_to_image("#{unicode}.png"), + data: data + end end def emoji_author_list(notes, current_user) diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb index 698f90cb27a..95072b5373f 100644 --- a/app/helpers/notes_helper.rb +++ b/app/helpers/notes_helper.rb @@ -69,10 +69,7 @@ module NotesHelper line_type: line_type } - button_tag class: 'btn btn-nr reply-btn js-discussion-reply-button', - data: data, title: 'Add a reply' do - link_text = icon('comment') - link_text << ' Reply' - end + button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button', + data: data, title: 'Add a reply' end end diff --git a/app/views/abuse_reports/new.html.haml b/app/views/abuse_reports/new.html.haml index 3bc1b24b5e2..06be1a53318 100644 --- a/app/views/abuse_reports/new.html.haml +++ b/app/views/abuse_reports/new.html.haml @@ -3,11 +3,9 @@ %p Please use this form to report users who create spam issues, comments or behave inappropriately. %hr = form_for @abuse_report, html: { class: 'form-horizontal js-quick-submit js-requires-input'} do |f| + = form_errors(@abuse_report) + = f.hidden_field :user_id - - if @abuse_report.errors.any? - .alert.alert-danger - - @abuse_report.errors.full_messages.each do |msg| - %p= msg .form-group = f.label :user_id, class: 'control-label' .col-sm-10 diff --git a/app/views/admin/appearances/_form.html.haml b/app/views/admin/appearances/_form.html.haml index 6f325914d14..d88f3ad314d 100644 --- a/app/views/admin/appearances/_form.html.haml +++ b/app/views/admin/appearances/_form.html.haml @@ -1,8 +1,5 @@ = form_for @appearance, url: admin_appearances_path, html: { class: 'form-horizontal'} do |f| - - if @appearance.errors.any? - .alert.alert-danger - - @appearance.errors.full_messages.each do |msg| - %p= msg + = form_errors(@appearance) %fieldset.sign-in %legend diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml index de86dacbb12..a8cca1a81cb 100644 --- a/app/views/admin/application_settings/_form.html.haml +++ b/app/views/admin/application_settings/_form.html.haml @@ -1,9 +1,5 @@ = form_for @application_setting, url: admin_application_settings_path, html: { class: 'form-horizontal fieldset-form' } do |f| - - if @application_setting.errors.any? - #error_explanation - .alert.alert-danger - - @application_setting.errors.full_messages.each do |msg| - %p= msg + = form_errors(@application_setting) %fieldset %legend Visibility and Access Controls diff --git a/app/views/admin/applications/_form.html.haml b/app/views/admin/applications/_form.html.haml index e18f7b499dd..4aacbb8cd77 100644 --- a/app/views/admin/applications/_form.html.haml +++ b/app/views/admin/applications/_form.html.haml @@ -1,9 +1,6 @@ = form_for [:admin, @application], url: @url, html: {class: 'form-horizontal', role: 'form'} do |f| - - if application.errors.any? - .alert.alert-danger - %button{ type: "button", class: "close", "data-dismiss" => "alert"} × - - application.errors.full_messages.each do |msg| - %p= msg + = form_errors(application) + = content_tag :div, class: 'form-group' do = f.label :name, class: 'col-sm-2 control-label' .col-sm-10 diff --git a/app/views/admin/broadcast_messages/_form.html.haml b/app/views/admin/broadcast_messages/_form.html.haml index b748460a9f7..6b157abf842 100644 --- a/app/views/admin/broadcast_messages/_form.html.haml +++ b/app/views/admin/broadcast_messages/_form.html.haml @@ -4,10 +4,8 @@ = render_broadcast_message(@broadcast_message.message.presence || "Your message here") = form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-quick-submit js-requires-input'} do |f| - -if @broadcast_message.errors.any? - .alert.alert-danger - - @broadcast_message.errors.full_messages.each do |msg| - %p= msg + = form_errors(@broadcast_message) + .form-group = f.label :message, class: 'control-label' .col-sm-10 diff --git a/app/views/admin/deploy_keys/new.html.haml b/app/views/admin/deploy_keys/new.html.haml index 5b46b3222a9..15aa059c93d 100644 --- a/app/views/admin/deploy_keys/new.html.haml +++ b/app/views/admin/deploy_keys/new.html.haml @@ -4,11 +4,7 @@ %div = form_for [:admin, @deploy_key], html: { class: 'deploy-key-form form-horizontal' } do |f| - -if @deploy_key.errors.any? - .alert.alert-danger - %ul - - @deploy_key.errors.full_messages.each do |msg| - %li= msg + = form_errors(@deploy_key) .form-group = f.label :title, class: "control-label" diff --git a/app/views/admin/groups/_form.html.haml b/app/views/admin/groups/_form.html.haml index 7f2b1cd235d..0cc405401cf 100644 --- a/app/views/admin/groups/_form.html.haml +++ b/app/views/admin/groups/_form.html.haml @@ -1,8 +1,5 @@ = form_for [:admin, @group], html: { class: "form-horizontal" } do |f| - - if @group.errors.any? - .alert.alert-danger - %span= @group.errors.full_messages.first - + = form_errors(@group) = render 'shared/group_form', f: f .form-group.group-description-holder diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index 53b3cd04c68..ad952052f25 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -10,10 +10,8 @@ = form_for @hook, as: :hook, url: admin_hooks_path, html: { class: 'form-horizontal' } do |f| - -if @hook.errors.any? - .alert.alert-danger - - @hook.errors.full_messages.each do |msg| - %p= msg + = form_errors(@hook) + .form-group = f.label :url, "URL:", class: 'control-label' .col-sm-10 diff --git a/app/views/admin/identities/_form.html.haml b/app/views/admin/identities/_form.html.haml index 3a788558226..112a201fafa 100644 --- a/app/views/admin/identities/_form.html.haml +++ b/app/views/admin/identities/_form.html.haml @@ -1,9 +1,5 @@ = form_for [:admin, @user, @identity], html: { class: 'form-horizontal fieldset-form' } do |f| - - if @identity.errors.any? - #error_explanation - .alert.alert-danger - - @identity.errors.full_messages.each do |msg| - %p= msg + = form_errors(@identity) .form-group = f.label :provider, class: 'control-label' diff --git a/app/views/admin/labels/_form.html.haml b/app/views/admin/labels/_form.html.haml index 8c6b389bf15..448aa953548 100644 --- a/app/views/admin/labels/_form.html.haml +++ b/app/views/admin/labels/_form.html.haml @@ -1,11 +1,5 @@ = form_for [:admin, @label], html: { class: 'form-horizontal label-form js-requires-input' } do |f| - -if @label.errors.any? - .row - .col-sm-offset-2.col-sm-10 - .alert.alert-danger - - @label.errors.full_messages.each do |msg| - %span= msg - %br + = form_errors(@label) .form-group = f.label :title, class: 'control-label' diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index d2527ede995..b05fdbd5552 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -1,10 +1,6 @@ .user_new = form_for [:admin, @user], html: { class: 'form-horizontal fieldset-form' } do |f| - -if @user.errors.any? - #error_explanation - .alert.alert-danger - - @user.errors.full_messages.each do |msg| - %p= msg + = form_errors(@user) %fieldset %legend Account diff --git a/app/views/doorkeeper/applications/_form.html.haml b/app/views/doorkeeper/applications/_form.html.haml index 906b0676150..5c98265727a 100644 --- a/app/views/doorkeeper/applications/_form.html.haml +++ b/app/views/doorkeeper/applications/_form.html.haml @@ -1,9 +1,5 @@ = form_for application, url: doorkeeper_submit_path(application), html: {role: 'form'} do |f| - - if application.errors.any? - .alert.alert-danger - %ul - - application.errors.full_messages.each do |msg| - %li= msg + = form_errors(application) .form-group = f.label :name, class: 'label-light' diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index ea5a0358392..a698cbbe9db 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -5,9 +5,7 @@ Group settings .panel-body = form_for @group, html: { multipart: true, class: "form-horizontal" }, authenticity_token: true do |f| - - if @group.errors.any? - .alert.alert-danger - %span= @group.errors.full_messages.first + = form_errors(@group) = render 'shared/group_form', f: f .form-group diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 30ab8aeba13..2b8bc269e64 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -6,10 +6,7 @@ %hr = form_for @group, html: { class: 'group-form form-horizontal' } do |f| - - if @group.errors.any? - .alert.alert-danger - %span= @group.errors.full_messages.first - + = form_errors(@group) = render 'shared/group_form', f: f, autofocus: true .form-group.group-description-holder diff --git a/app/views/profiles/keys/_form.html.haml b/app/views/profiles/keys/_form.html.haml index 4d78215ed3c..b3ed59a1a4a 100644 --- a/app/views/profiles/keys/_form.html.haml +++ b/app/views/profiles/keys/_form.html.haml @@ -1,10 +1,6 @@ %div = form_for [:profile, @key], html: { class: 'js-requires-input' } do |f| - - if @key.errors.any? - .alert.alert-danger - %ul - - @key.errors.full_messages.each do |msg| - %li= msg + = form_errors(@key) .form-group = f.label :key, class: 'label-light' diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index 44d758dceb3..5ac8a8b9d09 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -13,11 +13,8 @@ - unless @user.password_automatically_set? or recover your current one = form_for @user, url: profile_password_path, method: :put, html: {class: "update-password"} do |f| - -if @user.errors.any? - .alert.alert-danger - %ul - - @user.errors.full_messages.each do |msg| - %li= msg + = form_errors(@user) + - unless @user.password_automatically_set? .form-group = f.label :current_password, class: 'label-light' diff --git a/app/views/profiles/passwords/new.html.haml b/app/views/profiles/passwords/new.html.haml index d165f758c81..2eb9fac57c3 100644 --- a/app/views/profiles/passwords/new.html.haml +++ b/app/views/profiles/passwords/new.html.haml @@ -7,11 +7,8 @@ Please set a new password before proceeding. %br After a successful password update you will be redirected to login screen. - -if @user.errors.any? - .alert.alert-danger - %ul - - @user.errors.full_messages.each do |msg| - %li= msg + + = form_errors(@user) - unless @user.password_automatically_set? .form-group diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index dcb3be9585d..f59d27f7ed0 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -1,9 +1,6 @@ = form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit-user prepend-top-default" }, authenticity_token: true do |f| - -if @user.errors.any? - %div.alert.alert-danger - %ul - - @user.errors.full_messages.each do |msg| - %li= msg + = form_errors(@user) + .row .col-lg-3.profile-settings-sidebar %h4.prepend-top-0 diff --git a/app/views/projects/_errors.html.haml b/app/views/projects/_errors.html.haml index 7c8bb33ed7e..2dba22d3be6 100644 --- a/app/views/projects/_errors.html.haml +++ b/app/views/projects/_errors.html.haml @@ -1,4 +1 @@ -- if @project.errors.any? - .alert.alert-danger - %button{ type: "button", class: "close", "data-dismiss" => "alert"} × - = @project.errors.full_messages.first += form_errors(@project) diff --git a/app/views/projects/_md_preview.html.haml b/app/views/projects/_md_preview.html.haml index 4920910fee1..7a78d61a611 100644 --- a/app/views/projects/_md_preview.html.haml +++ b/app/views/projects/_md_preview.html.haml @@ -2,13 +2,13 @@ .md-header %ul.nav-links %li.active - %a.js-md-write-button{ href: "#md-write-holder" } + %a.js-md-write-button{ href: "#md-write-holder", tabindex: -1 } Write %li - %a.js-md-preview-button{ href: "#md-preview-holder" } + %a.js-md-preview-button{ href: "#md-preview-holder", tabindex: -1 } Preview %li.pull-right - %button.zen-cotrol.zen-control-full.js-zen-enter{ type: 'button' } + %button.zen-cotrol.zen-control-full.js-zen-enter{ type: 'button', tabindex: -1 } Go full screen .md-write-holder diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index 7f2903589a9..7da89231243 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -19,24 +19,17 @@ .pull-right - if ci_commit = render_ci_status(ci_commit) - = clipboard_button(clipboard_text: commit.id) = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id" - .notes_count - - if note_count > 0 - %span.light - %i.fa.fa-comments - = note_count - - if commit.description? .commit-row-description.js-toggle-content %pre = preserve(markdown(escape_once(commit.description), pipeline: :single_line)) .commit-row-info + by = commit_author_link(commit, avatar: true, size: 24) - authored .committed_ago #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} = link_to_browse_code(project, commit) diff --git a/app/views/projects/deploy_keys/_form.html.haml b/app/views/projects/deploy_keys/_form.html.haml index 5e182af2669..f6565f85836 100644 --- a/app/views/projects/deploy_keys/_form.html.haml +++ b/app/views/projects/deploy_keys/_form.html.haml @@ -1,10 +1,6 @@ %div = form_for [@project.namespace.becomes(Namespace), @project, @key], url: namespace_project_deploy_keys_path, html: { class: 'deploy-key-form form-horizontal js-requires-input' } do |f| - -if @key.errors.any? - .alert.alert-danger - %ul - - @key.errors.full_messages.each do |msg| - %li= msg + = form_errors(@key) .form-group = f.label :title, class: "control-label" diff --git a/app/views/projects/diffs/_diffs.html.haml b/app/views/projects/diffs/_diffs.html.haml index 2e1a37aa06d..eaab99973a4 100644 --- a/app/views/projects/diffs/_diffs.html.haml +++ b/app/views/projects/diffs/_diffs.html.haml @@ -3,7 +3,7 @@ - diff_files = safe_diff_files(diffs, diff_refs) -.content-block.oneline-block +.content-block.oneline-block.files-changed .inline-parallel-buttons .btn-group = inline_diff_btn diff --git a/app/views/projects/diffs/_file.html.haml b/app/views/projects/diffs/_file.html.haml index 698ed02ea0e..83a8d7ae9bf 100644 --- a/app/views/projects/diffs/_file.html.haml +++ b/app/views/projects/diffs/_file.html.haml @@ -3,7 +3,7 @@ - if diff_file.diff.submodule? %span = icon('archive fw') - %strong + %span = submodule_link(blob, @commit.id, project.repository) - else = blob_icon blob.mode, blob.name @@ -11,13 +11,13 @@ = link_to "#diff-#{i}" do - if diff_file.renamed_file - old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path) - %strong.filename.old + .filename.old = old_path → - %strong.filename.new + .filename.new = new_path - else - %strong + %span = diff_file.new_path - if diff_file.deleted_file deleted @@ -28,8 +28,8 @@ .file-actions.hidden-xs - if blob_text_viewable?(blob) - = link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip', title: "Toggle comments for this file" do - = icon('comments') + = link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip btn-file-option', title: "Toggle comments for this file" do + = icon('comment') \ - if editable_diff?(diff_file) diff --git a/app/views/projects/hooks/index.html.haml b/app/views/projects/hooks/index.html.haml index 67d016bd871..e39224d86c6 100644 --- a/app/views/projects/hooks/index.html.haml +++ b/app/views/projects/hooks/index.html.haml @@ -9,10 +9,8 @@ %hr.clearfix = form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: namespace_project_hooks_path(@project.namespace, @project), html: { class: 'form-horizontal' } do |f| - -if @hook.errors.any? - .alert.alert-danger - - @hook.errors.full_messages.each do |msg| - %p= msg + = form_errors(@hook) + .form-group = f.label :url, "URL", class: 'control-label' .col-sm-10 diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml index be7a0bb5628..aa143e54ffe 100644 --- a/app/views/projects/labels/_form.html.haml +++ b/app/views/projects/labels/_form.html.haml @@ -1,11 +1,5 @@ = form_for [@project.namespace.becomes(Namespace), @project, @label], html: { class: 'form-horizontal label-form js-quick-submit js-requires-input' } do |f| - -if @label.errors.any? - .row - .col-sm-offset-2.col-sm-10 - .alert.alert-danger - - @label.errors.full_messages.each do |msg| - %span= msg - %br + = form_errors(@label) .form-group = f.label :title, class: 'control-label' diff --git a/app/views/projects/labels/_label.html.haml b/app/views/projects/labels/_label.html.haml index 0612863296a..097a65969a6 100644 --- a/app/views/projects/labels/_label.html.haml +++ b/app/views/projects/labels/_label.html.haml @@ -1,24 +1,27 @@ %li{id: dom_id(label)} = render "shared/label_row", label: label - .pull-right - %strong.append-right-20 + .pull-info-right + %span.append-right-20 = link_to_label(label, type: :merge_request) do - = pluralize label.open_merge_requests_count, 'open merge request' + = pluralize label.open_merge_requests_count, 'merge request' - %strong.append-right-20 + %span.append-right-20 = link_to_label(label) do = pluralize label.open_issues_count(current_user), 'open issue' - if current_user .label-subscription{data: {url: toggle_subscription_namespace_project_label_path(@project.namespace, @project, label)}} .subscription-status{data: {status: label_subscription_status(label)}} - %button.btn.btn-sm.btn-info.subscribe-button + + %a.subscribe-button.btn.action-buttons{data: {toggle: "tooltip"}} %span= label_subscription_toggle_button_text(label) - if can? current_user, :admin_label, @project - = link_to 'Edit', edit_namespace_project_label_path(@project.namespace, @project, label), class: 'btn btn-sm' - = link_to 'Delete', namespace_project_label_path(@project.namespace, @project, label), class: 'btn btn-sm btn-remove remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?"} + = link_to edit_namespace_project_label_path(@project.namespace, @project, label), title: "Edit", class: 'btn action-buttons', data: {toggle: "tooltip"} do + %i.fa.fa-pencil-square-o + = link_to namespace_project_label_path(@project.namespace, @project, label), title: "Delete", class: 'btn action-buttons remove-row', method: :delete, remote: true, data: {confirm: "Remove this label? Are you sure?", toggle: "tooltip"} do + %i.fa.fa-trash-o - if current_user :javascript diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml index 01dc7519bee..7d7c487e970 100644 --- a/app/views/projects/merge_requests/_new_compare.html.haml +++ b/app/views/projects/merge_requests/_new_compare.html.haml @@ -5,33 +5,74 @@ .hide.alert.alert-danger.mr-compare-errors .merge-request-branches.row .col-md-6 - .panel.panel-default + .panel.panel-default.panel-new-merge-request .panel-heading - %strong Source branch - .panel-body - = f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted?, required: true }) - - = f.select(:source_branch, @merge_request.source_branches, { include_blank: true }, { class: 'source_branch select2 span2', required: true, data: { placeholder: "Select source branch" } }) + Source branch + .panel-body.clearfix + .merge-request-select.dropdown + = f.hidden_field :source_project_id + = dropdown_toggle @merge_request.source_project_path, { toggle: "dropdown", field_name: "#{f.object_name}[source_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-source-project" } + .dropdown-menu.dropdown-menu-selectable.dropdown-source-project + = dropdown_title("Select source project") + = dropdown_filter("Search projects") + = dropdown_content do + - is_active = f.object.source_project_id == @merge_request.source_project.id + %ul + %li + %a{ href: "#", class: "#{("is-active" if is_active)}", data: { id: @merge_request.source_project.id } } + = @merge_request.source_project_path + .merge-request-select.dropdown + = f.hidden_field :source_branch + = dropdown_toggle "Select source branch", { toggle: "dropdown", field_name: "#{f.object_name}[source_branch]" }, { toggle_class: "js-compare-dropdown js-source-branch" } + .dropdown-menu.dropdown-menu-selectable.dropdown-source-branch + = dropdown_title("Select source branch") + = dropdown_filter("Search branches") + = dropdown_content do + %ul + - @merge_request.source_branches.each do |branch| + %li + %a{ href: "#", class: "#{("is-active" if f.object.source_branch == branch)}", data: { id: branch } } + = branch .panel-footer - .mr_source_commit + = icon('spinner spin', class: 'js-source-loading') + %ul.list-unstyled.mr_source_commit .col-md-6 - .panel.panel-default + .panel.panel-default.panel-new-merge-request .panel-heading - %strong Target branch - .panel-body + Target branch + .panel-body.clearfix - projects = @project.forked_from_project.nil? ? [@project] : [@project, @project.forked_from_project] - = f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace', f.object.target_project_id), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted?, required: true }) - - = f.select(:target_branch, @merge_request.target_branches, { include_blank: true }, { class: 'target_branch select2 span2', required: true, data: { placeholder: "Select target branch" } }) + .merge-request-select.dropdown + = f.hidden_field :target_project_id + = dropdown_toggle f.object.target_project.path_with_namespace, { toggle: "dropdown", field_name: "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" } + .dropdown-menu.dropdown-menu-selectable.dropdown-target-project + = dropdown_title("Select target project") + = dropdown_filter("Search projects") + = dropdown_content do + %ul + - projects.each do |project| + %li + %a{ href: "#", class: "#{("is-active" if f.object.target_project_id == project.id)}", data: { id: project.id } } + = project.path_with_namespace + .merge-request-select.dropdown + = f.hidden_field :target_branch + = dropdown_toggle f.object.target_branch, { toggle: "dropdown", field_name: "#{f.object_name}[target_branch]" }, { toggle_class: "js-compare-dropdown js-target-branch" } + .dropdown-menu.dropdown-menu-selectable.dropdown-target-branch.js-target-branch-dropdown + = dropdown_title("Select target branch") + = dropdown_filter("Search branches") + = dropdown_content do + %ul + - @merge_request.target_branches.each do |branch| + %li + %a{ href: "#", class: "#{("is-active" if f.object.target_branch == branch)}", data: { id: branch } } + = branch .panel-footer - .mr_target_commit + = icon('spinner spin', class: "js-target-loading") + %ul.list-unstyled.mr_target_commit - if @merge_request.errors.any? - .alert.alert-danger - - @merge_request.errors.full_messages.each do |msg| - %div= msg - + = form_errors(@merge_request) - elsif @merge_request.source_branch.present? && @merge_request.target_branch.present? .light-well.append-bottom-default .center @@ -45,40 +86,11 @@ and %span.label-branch #{@merge_request.target_branch} are the same. - - - .form-actions - = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn" - -:javascript - var source_branch = $("#merge_request_source_branch") - , target_branch = $("#merge_request_target_branch") - , target_project = $("#merge_request_target_project_id"); - - $.get("#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {ref: source_branch.val() }); - $.get("#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: target_project.val(),ref: target_branch.val() }); - - target_project.on("change", function() { - $.get("#{update_branches_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: $(this).val() }); - }); - source_branch.on("change", function() { - $.get("#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {ref: $(this).val() }); - $(".mr-compare-errors").fadeOut(); - $(".mr-compare-btn").enable(); - }); - target_branch.on("change", function() { - $.get("#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", {target_project_id: target_project.val(),ref: $(this).val() }); - $(".mr-compare-errors").fadeOut(); - $(".mr-compare-btn").enable(); - }); - + = f.submit 'Compare branches and continue', class: "btn btn-new mr-compare-btn" :javascript - $(".merge-request-form").on('submit', function () { - if ($("#merge_request_source_branch").val() === "" || $('#merge_request_target_branch').val() === "") { - $(".mr-compare-errors").html("You must select source and target branch to proceed"); - $(".mr-compare-errors").fadeIn(); - event.preventDefault(); - return; - } + new Compare({ + targetProjectUrl: "#{update_branches_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", + sourceBranchUrl: "#{branch_from_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}", + targetBranchUrl: "#{branch_to_namespace_project_merge_requests_path(@source_project.namespace, @source_project)}" }); diff --git a/app/views/projects/merge_requests/branch_from.html.haml b/app/views/projects/merge_requests/branch_from.html.haml new file mode 100644 index 00000000000..4f90dde6fa8 --- /dev/null +++ b/app/views/projects/merge_requests/branch_from.html.haml @@ -0,0 +1 @@ += commit_to_html(@commit, @source_project, false) diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml deleted file mode 100644 index 9210798f39c..00000000000 --- a/app/views/projects/merge_requests/branch_from.js.haml +++ /dev/null @@ -1,3 +0,0 @@ -:plain - $(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}"); - $('.js-timeago').timeago() diff --git a/app/views/projects/merge_requests/branch_to.html.haml b/app/views/projects/merge_requests/branch_to.html.haml new file mode 100644 index 00000000000..67a7a6bcec9 --- /dev/null +++ b/app/views/projects/merge_requests/branch_to.html.haml @@ -0,0 +1 @@ += commit_to_html(@commit, @target_project, false) diff --git a/app/views/projects/merge_requests/branch_to.js.haml b/app/views/projects/merge_requests/branch_to.js.haml deleted file mode 100644 index 32fe2d535f3..00000000000 --- a/app/views/projects/merge_requests/branch_to.js.haml +++ /dev/null @@ -1,3 +0,0 @@ -:plain - $(".mr_target_commit").html("#{commit_to_html(@commit, @target_project, false)}"); - $('.js-timeago').timeago() diff --git a/app/views/projects/merge_requests/update_branches.html.haml b/app/views/projects/merge_requests/update_branches.html.haml new file mode 100644 index 00000000000..1b93188a10c --- /dev/null +++ b/app/views/projects/merge_requests/update_branches.html.haml @@ -0,0 +1,5 @@ +%ul + - @target_branches.each do |branch| + %li + %a{ href: "#", class: "#{("is-active" if "a" == branch)}", data: { id: branch } } + = branch diff --git a/app/views/projects/merge_requests/update_branches.js.haml b/app/views/projects/merge_requests/update_branches.js.haml deleted file mode 100644 index ca21b3bc0de..00000000000 --- a/app/views/projects/merge_requests/update_branches.js.haml +++ /dev/null @@ -1,9 +0,0 @@ -:plain - $(".target_branch").html("#{escape_javascript(options_for_select(@target_branches))}"); - - $('select.target_branch').select2({ - width: 'resolve', - dropdownAutoWidth: true - }); - - $(".mr_target_commit").html(""); diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml index 23f2bca7baf..b2dae1c70ee 100644 --- a/app/views/projects/milestones/_form.html.haml +++ b/app/views/projects/milestones/_form.html.haml @@ -1,9 +1,6 @@ = form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'form-horizontal milestone-form gfm-form js-quick-submit js-requires-input'} do |f| - -if @milestone.errors.any? - .alert.alert-danger - %ul - - @milestone.errors.full_messages.each do |msg| - %li= msg + = form_errors(@milestone) + .row .col-md-6 .form-group diff --git a/app/views/projects/notes/_diff_notes_with_reply.html.haml b/app/views/projects/notes/_diff_notes_with_reply.html.haml index 11f9859a90f..39be072855a 100644 --- a/app/views/projects/notes/_diff_notes_with_reply.html.haml +++ b/app/views/projects/notes/_diff_notes_with_reply.html.haml @@ -3,9 +3,6 @@ - if !defined?(line) || line == note.diff_line %tr.notes_holder %td.notes_line{ colspan: 2 } - %span.discussion-notes-count - %i.fa.fa-comment - = notes.count %td.notes_content %ul.notes{ data: { discussion_id: note.discussion_id } } = render notes diff --git a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml index bb761ed2f94..f8aa5e2fa7d 100644 --- a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml +++ b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml @@ -4,9 +4,6 @@ %tr.notes_holder - if note1 %td.notes_line.old - %span.btn.disabled - %i.fa.fa-comment - = notes_left.count %td.notes_content.parallel.old %ul.notes{ data: { discussion_id: note1.discussion_id } } = render notes_left @@ -19,9 +16,6 @@ - if note2 %td.notes_line.new - %span.btn.disabled - %i.fa.fa-comment - = notes_right.count %td.notes_content.parallel.new %ul.notes{ data: { discussion_id: note2.discussion_id } } = render notes_right diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index a681d6dece4..5c42423541e 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -17,8 +17,8 @@ %span.note-role = access = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do - = icon('pencil-square-o') - = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete' do + = icon('pencil') + = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete danger' do = icon('trash-o') .note-body{class: note_editable?(note) ? 'js-task-list-container' : ''} .note-text diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index cfd7e1534ca..653b02da4db 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -13,11 +13,7 @@ - if can? current_user, :admin_project, @project = form_for [@project.namespace.becomes(Namespace), @project, @protected_branch], html: { class: 'form-horizontal' } do |f| - -if @protected_branch.errors.any? - .alert.alert-danger - %ul - - @protected_branch.errors.full_messages.each do |msg| - %li= msg + = form_errors(@protected_branch) .form-group = f.label :name, "Branch", class: 'control-label' diff --git a/app/views/projects/variables/show.html.haml b/app/views/projects/variables/show.html.haml index efe1e6f24c2..ca284b84d39 100644 --- a/app/views/projects/variables/show.html.haml +++ b/app/views/projects/variables/show.html.haml @@ -13,13 +13,7 @@ = nested_form_for @project, url: url_for(controller: 'projects/variables', action: 'update'), html: { class: 'form-horizontal' } do |f| - - if @project.errors.any? - #error_explanation - %p.lead= "#{pluralize(@project.errors.count, "error")} prohibited this project from being saved:" - .alert.alert-error - %ul - - @project.errors.full_messages.each do |msg| - %li= msg + = form_errors(@project) = f.fields_for :variables do |variable_form| .form-group diff --git a/app/views/projects/wikis/_form.html.haml b/app/views/projects/wikis/_form.html.haml index f0d1932e23c..812876e2835 100644 --- a/app/views/projects/wikis/_form.html.haml +++ b/app/views/projects/wikis/_form.html.haml @@ -1,9 +1,5 @@ = form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form gfm-form prepend-top-default js-quick-submit' } do |f| - -if @page.errors.any? - #error_explanation - .alert.alert-danger - - @page.errors.full_messages.each do |msg| - %p= msg + = form_errors(@page) = f.hidden_field :title, value: @page.title .form-group diff --git a/app/views/shared/_label_row.html.haml b/app/views/shared/_label_row.html.haml index 4b47b0291be..b38c5e18efb 100644 --- a/app/views/shared/_label_row.html.haml +++ b/app/views/shared/_label_row.html.haml @@ -1,4 +1,5 @@ %span.label-row - = link_to_label(label, tooltip: false) + %span.label-name + = link_to_label(label, tooltip: false) %span.prepend-left-10 = markdown(label.description, pipeline: :single_line) diff --git a/app/views/shared/_service_settings.html.haml b/app/views/shared/_service_settings.html.haml index 5a60ff5a5da..fc935166bf6 100644 --- a/app/views/shared/_service_settings.html.haml +++ b/app/views/shared/_service_settings.html.haml @@ -1,9 +1,4 @@ -- if @service.errors.any? - #error_explanation - .alert.alert-danger - %ul - - @service.errors.full_messages.each do |msg| - %li= msg += form_errors(@service) - if @service.help.present? .well diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index e2a9e5bfb92..757a3812deb 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -1,10 +1,5 @@ -- if issuable.errors.any? - .row - .col-sm-offset-2.col-sm-10 - .alert.alert-danger - - issuable.errors.full_messages.each do |msg| - %span= msg - %br += form_errors(issuable) + .form-group = f.label :title, class: 'control-label' .col-sm-10 @@ -53,10 +48,11 @@ .issue-assignee = f.label :assignee_id, "Assignee", class: 'control-label' .col-sm-10 - = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]", - placeholder: 'Select assignee', class: 'custom-form-control', null_user: true, - selected: issuable.assignee_id, project: @target_project || @project, - first_user: true, current_user: true, include_blank: true) + .issuable-form-select-holder + = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]", + placeholder: 'Select assignee', class: 'custom-form-control', null_user: true, + selected: issuable.assignee_id, project: @target_project || @project, + first_user: true, current_user: true, include_blank: true) = link_to 'Assign to me', '#', class: 'btn assign-to-me-link' .form-group @@ -64,8 +60,9 @@ = f.label :milestone_id, "Milestone", class: 'control-label' .col-sm-10 - if milestone_options(issuable).present? - = f.select(:milestone_id, milestone_options(issuable), - { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } }) + .issuable-form-select-holder + = f.select(:milestone_id, milestone_options(issuable), + { include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } }) - else .prepend-top-10 %span.light No open milestones available. diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml index 1041eccd1df..47ec09f62c6 100644 --- a/app/views/shared/snippets/_form.html.haml +++ b/app/views/shared/snippets/_form.html.haml @@ -1,10 +1,6 @@ .snippet-form-holder = form_for @snippet, url: url, html: { class: "form-horizontal snippet-form js-requires-input" } do |f| - - if @snippet.errors.any? - .alert.alert-danger - %ul - - @snippet.errors.full_messages.each do |msg| - %li= msg + = form_errors(@snippet) .form-group = f.label :title, class: 'control-label' diff --git a/app/views/users/calendar.html.haml b/app/views/users/calendar.html.haml index 7f29918dba3..1de71f37d1a 100644 --- a/app/views/users/calendar.html.haml +++ b/app/views/users/calendar.html.haml @@ -7,4 +7,4 @@ '#{user_calendar_activities_path}' ); -.calendar-hint Summary of issues, merge requests and push events +.calendar-hint Summary of issues, merge requests, and push events diff --git a/app/views/votes/_votes_block.html.haml b/app/views/votes/_votes_block.html.haml index 8ffcdc4a327..dc249155b92 100644 --- a/app/views/votes/_votes_block.html.haml +++ b/app/views/votes/_votes_block.html.haml @@ -1,7 +1,7 @@ .awards.votes-block - awards_sort(votable.notes.awards.grouped_awards).each do |emoji, notes| - %button.btn.award-control.js-emoji-btn.has-tooltip{class: (note_active_class(notes, current_user)), title: emoji_author_list(notes, current_user), data: {placement: "top"}} - = emoji_icon(emoji) + %button.btn.award-control.js-emoji-btn.has-tooltip{class: (note_active_class(notes, current_user)), data: {placement: "top", original_title: emoji_author_list(notes, current_user)}} + = emoji_icon(emoji, sprite: false) %span.award-control-text.js-counter = notes.count diff --git a/config/application.rb b/config/application.rb index 5a0ac70aa2a..2e2ed48db07 100644 --- a/config/application.rb +++ b/config/application.rb @@ -4,11 +4,9 @@ require 'rails/all' require 'devise' I18n.config.enforce_available_locales = false Bundler.require(:default, Rails.env) -require_relative '../lib/gitlab/redis_config' +require_relative '../lib/gitlab/redis' module Gitlab - REDIS_CACHE_NAMESPACE = 'cache:gitlab' - class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers @@ -69,8 +67,8 @@ module Gitlab end end - redis_config_hash = Gitlab::RedisConfig.redis_store_options - redis_config_hash[:namespace] = REDIS_CACHE_NAMESPACE + redis_config_hash = Gitlab::Redis.redis_store_options + redis_config_hash[:namespace] = Gitlab::Redis::CACHE_NAMESPACE redis_config_hash[:expires_in] = 2.weeks # Cache should not grow forever config.cache_store = :redis_store, redis_config_hash diff --git a/config/environments/production.rb b/config/environments/production.rb index 909526605a1..a9d8ac4b6d4 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -21,6 +21,9 @@ Rails.application.configure do # Generate digests for assets URLs config.assets.digest = true + # Enable compression of compiled assets using gzip. + config.assets.compress = true + # Defaults to nil and saved in location specified by config.assets.prefix # config.assets.manifest = YOUR_PATH diff --git a/config/environments/test.rb b/config/environments/test.rb index f96ac6f9753..a703c0934f7 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -8,6 +8,7 @@ Rails.application.configure do config.cache_classes = false # Configure static asset server for tests with Cache-Control for performance + config.assets.digest = false config.serve_static_files = true config.static_cache_control = "public, max-age=3600" diff --git a/config/initializers/metrics.rb b/config/initializers/metrics.rb index 3e1deb8d306..a9fc38fb04a 100644 --- a/config/initializers/metrics.rb +++ b/config/initializers/metrics.rb @@ -7,6 +7,7 @@ if Gitlab::Metrics.enabled? # ActiveSupport. require 'gitlab/metrics/subscribers/action_view' require 'gitlab/metrics/subscribers/active_record' + require 'gitlab/metrics/subscribers/rails_cache' Gitlab::Application.configure do |config| config.middleware.use(Gitlab::Metrics::RackMiddleware) diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 3da5d46be92..70285255877 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -13,7 +13,7 @@ end if Rails.env.test? Gitlab::Application.config.session_store :cookie_store, key: "_gitlab_session" else - redis_config = Gitlab::RedisConfig.redis_store_options + redis_config = Gitlab::Redis.redis_store_options redis_config[:namespace] = 'session:gitlab' Gitlab::Application.config.session_store( diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index cc83137745a..9182d929809 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -2,7 +2,7 @@ SIDEKIQ_REDIS_NAMESPACE = 'resque:gitlab' Sidekiq.configure_server do |config| config.redis = { - url: Gitlab::RedisConfig.url, + url: Gitlab::Redis.url, namespace: SIDEKIQ_REDIS_NAMESPACE } @@ -29,7 +29,7 @@ end Sidekiq.configure_client do |config| config.redis = { - url: Gitlab::RedisConfig.url, + url: Gitlab::Redis.url, namespace: SIDEKIQ_REDIS_NAMESPACE } end diff --git a/config/mail_room.yml b/config/mail_room.yml index 60257329f3e..761a32adb9e 100644 --- a/config/mail_room.yml +++ b/config/mail_room.yml @@ -2,7 +2,7 @@ <% require "yaml" require "json" -require_relative "lib/gitlab/redis_config" +require_relative "lib/gitlab/redis" rails_env = ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" @@ -18,7 +18,7 @@ if File.exists?(config_file) config['mailbox'] = "inbox" if config['mailbox'].nil? if config['enabled'] && config['address'] - redis_url = Gitlab::RedisConfig.new(rails_env).url + redis_url = Gitlab::Redis.new(rails_env).url %> - :host: <%= config['host'].to_json %> diff --git a/db/fixtures/development/07_milestones.rb b/db/fixtures/development/07_milestones.rb index e028ac82ba3..540e4e68259 100644 --- a/db/fixtures/development/07_milestones.rb +++ b/db/fixtures/development/07_milestones.rb @@ -4,7 +4,7 @@ Gitlab::Seeder.quiet do milestone_params = { title: "v#{i}.0", description: FFaker::Lorem.sentence, - state: ['opened', 'closed'].sample, + state: [:active, :closed].sample, } milestone = Milestones::CreateService.new( diff --git a/db/migrate/20130315124931_user_color_scheme.rb b/db/migrate/20130315124931_user_color_scheme.rb index fe139e32ea7..56c9a31ee3c 100644 --- a/db/migrate/20130315124931_user_color_scheme.rb +++ b/db/migrate/20130315124931_user_color_scheme.rb @@ -1,7 +1,9 @@ class UserColorScheme < ActiveRecord::Migration + include Gitlab::Database + def up add_column :users, :color_scheme_id, :integer, null: false, default: 1 - User.where(dark_scheme: true).update_all(color_scheme_id: 2) + execute("UPDATE users SET color_scheme_id = 2 WHERE dark_scheme = #{true_value}") remove_column :users, :dark_scheme end diff --git a/db/migrate/20130403003950_add_last_activity_column_into_project.rb b/db/migrate/20130403003950_add_last_activity_column_into_project.rb index 2a036bd9993..85e31608d79 100644 --- a/db/migrate/20130403003950_add_last_activity_column_into_project.rb +++ b/db/migrate/20130403003950_add_last_activity_column_into_project.rb @@ -3,14 +3,16 @@ class AddLastActivityColumnIntoProject < ActiveRecord::Migration add_column :projects, :last_activity_at, :datetime add_index :projects, :last_activity_at - Project.find_each do |project| - last_activity_date = if project.last_activity - project.last_activity.created_at - else - project.updated_at - end + select_all('SELECT id, updated_at FROM projects').each do |project| + project_id = project['id'] + update_date = project['updated_at'] + event = select_one("SELECT created_at FROM events WHERE project_id = #{project_id} ORDER BY created_at DESC LIMIT 1") - project.update_attribute(:last_activity_at, last_activity_date) + if event && event['created_at'] + update_date = event['created_at'] + end + + execute("UPDATE projects SET last_activity_at = '#{update_date}' WHERE id = #{project_id}") end end diff --git a/db/migrate/20131112220935_add_visibility_level_to_projects.rb b/db/migrate/20131112220935_add_visibility_level_to_projects.rb index cf1e9f912a0..89421cbedad 100644 --- a/db/migrate/20131112220935_add_visibility_level_to_projects.rb +++ b/db/migrate/20131112220935_add_visibility_level_to_projects.rb @@ -1,13 +1,15 @@ class AddVisibilityLevelToProjects < ActiveRecord::Migration + include Gitlab::Database + def self.up add_column :projects, :visibility_level, :integer, :default => 0, :null => false - Project.where(public: true).update_all(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + execute("UPDATE projects SET visibility_level = #{Gitlab::VisibilityLevel::PUBLIC} WHERE public = #{true_value}") remove_column :projects, :public end def self.down add_column :projects, :public, :boolean, :default => false, :null => false - Project.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).update_all(public: true) + execute("UPDATE projects SET public = #{true_value} WHERE visibility_level = #{Gitlab::VisibilityLevel::PUBLIC}") remove_column :projects, :visibility_level end end diff --git a/db/migrate/20140313092127_migrate_already_imported_projects.rb b/db/migrate/20140313092127_migrate_already_imported_projects.rb index f4392c0f05e..0a9f73a5758 100644 --- a/db/migrate/20140313092127_migrate_already_imported_projects.rb +++ b/db/migrate/20140313092127_migrate_already_imported_projects.rb @@ -1,12 +1,14 @@ class MigrateAlreadyImportedProjects < ActiveRecord::Migration + include Gitlab::Database + def up - Project.where(imported: true).update_all(import_status: "finished") - Project.where(imported: false).update_all(import_status: "none") + execute("UPDATE projects SET import_status = 'finished' WHERE imported = #{true_value}") + execute("UPDATE projects SET import_status = 'none' WHERE imported = #{false_value}") remove_column :projects, :imported end def down add_column :projects, :imported, :boolean, default: false - Project.where(import_status: 'finished').update_all(imported: true) + execute("UPDATE projects SET imported = #{true_value} WHERE import_status = 'finished'") end end diff --git a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb index 7f125acb5d1..93826185e8b 100644 --- a/db/migrate/20141007100818_add_visibility_level_to_snippet.rb +++ b/db/migrate/20141007100818_add_visibility_level_to_snippet.rb @@ -1,9 +1,11 @@ class AddVisibilityLevelToSnippet < ActiveRecord::Migration + include Gitlab::Database + def up add_column :snippets, :visibility_level, :integer, :default => 0, :null => false - Snippet.where(private: true).update_all(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - Snippet.where(private: false).update_all(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + execute("UPDATE snippets SET visibility_level = #{Gitlab::VisibilityLevel::PRIVATE} WHERE private = #{true_value}") + execute("UPDATE snippets SET visibility_level = #{Gitlab::VisibilityLevel::INTERNAL} WHERE private = #{false_value}") add_index :snippets, :visibility_level @@ -12,10 +14,10 @@ class AddVisibilityLevelToSnippet < ActiveRecord::Migration def down add_column :snippets, :private, :boolean, :default => false, :null => false - - Snippet.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).update_all(private: false) - Snippet.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).update_all(private: true) - + + execute("UPDATE snippets SET private = #{false_value} WHERE visibility_level = #{Gitlab::VisibilityLevel::INTERNAL}") + execute("UPDATE snippets SET private = #{true_value} WHERE visibility_level = #{Gitlab::VisibilityLevel::PRIVATE}") + remove_column :snippets, :visibility_level end end diff --git a/db/schema.rb b/db/schema.rb index a66274dc5a1..44482de467e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -44,7 +44,6 @@ ActiveRecord::Schema.define(version: 20160331223143) do t.datetime "updated_at" t.string "home_page_url" t.integer "default_branch_protection", default: 2 - t.boolean "twitter_sharing_enabled", default: true t.text "restricted_visibility_levels" t.boolean "version_check_enabled", default: true t.integer "max_attachment_size", default: 10, null: false diff --git a/doc/ci/build_artifacts/README.md b/doc/ci/build_artifacts/README.md index 71db5aa5dc8..9553bb11e9d 100644 --- a/doc/ci/build_artifacts/README.md +++ b/doc/ci/build_artifacts/README.md @@ -1,7 +1,10 @@ # Introduction to build artifacts Artifacts is a list of files and directories which are attached to a build -after it completes successfully. +after it completes successfully. This feature is enabled by default in all GitLab installations. + +_If you are searching for ways to use artifacts, jump to +[Defining artifacts in `.gitlab-ci.yml`](#defining-artifacts-in-gitlab-ciyml)._ Since GitLab 8.2 and [GitLab Runner] 0.7.0, build artifacts that are created by GitLab Runner are uploaded to GitLab and are downloadable as a single archive @@ -16,13 +19,9 @@ The artifacts browser will be available only for new artifacts that are sent to GitLab using GitLab Runner version 1.0 and up. It will not be possible to browse old artifacts already uploaded to GitLab. -## Enabling build artifacts - -_If you are searching for ways to use artifacts, jump to -[Defining artifacts in `.gitlab-ci.yml`](#defining-artifacts-in-gitlab-ciyml)._ +## Disabling build artifacts -The artifacts feature is enabled by default in all GitLab installations. -To disable it site-wide, follow the steps below. +To disable artifacts site-wide, follow the steps below. --- diff --git a/doc/development/README.md b/doc/development/README.md index 2f4e7845ccc..3f3ef068f96 100644 --- a/doc/development/README.md +++ b/doc/development/README.md @@ -2,6 +2,8 @@ - [Architecture](architecture.md) of GitLab - [CI setup](ci_setup.md) for testing GitLab +- [Code review guidelines](code_review.md) for reviewing code and having code + reviewed. - [Gotchas](gotchas.md) to avoid - [How to dump production data to staging](db_dump.md) - [Instrumentation](instrumentation.md) diff --git a/doc/development/code_review.md b/doc/development/code_review.md new file mode 100644 index 00000000000..40ae55ab905 --- /dev/null +++ b/doc/development/code_review.md @@ -0,0 +1,78 @@ +# Code Review Guidelines + +This guide contains advice and best practices for performing code review, and +having your code reviewed. + +All merge requests for GitLab CE and EE, whether written by a GitLab team member +or a volunteer contributor, must go through a code review process to ensure the +code is effective, understandable, and maintainable. + +Any developer can, and is encouraged to, perform code review on merge requests +of colleagues and contributors. However, the final decision to accept a merge +request is up to one of our merge request "endbosses", denoted on the +[team page](https://about.gitlab.com/team). + +## Everyone + +- Accept that many programming decisions are opinions. Discuss tradeoffs, which + you prefer, and reach a resolution quickly. +- Ask questions; don't make demands. ("What do you think about naming this + `:user_id`?") +- Ask for clarification. ("I didn't understand. Can you clarify?") +- Avoid selective ownership of code. ("mine", "not mine", "yours") +- Avoid using terms that could be seen as referring to personal traits. ("dumb", + "stupid"). Assume everyone is attractive, intelligent, and well-meaning. +- Be explicit. Remember people don't always understand your intentions online. +- Be humble. ("I'm not sure - let's look it up.") +- Don't use hyperbole. ("always", "never", "endlessly", "nothing") +- Be careful about the use of sarcasm. Everything we do is public; what seems + like good-natured ribbing to you and a long-time colleague might come off as + mean and unwelcoming to a person new to the project. +- Consider one-on-one chats or video calls if there are too many "I didn't + understand" or "Alternative solution:" comments. Post a follow-up comment + summarizing one-on-one discussion. + +## Having your code reviewed + +- The first reviewer of your code is _you_. Before you perform that first push + of your shiny new branch, read through the entire diff. Does it make sense? + Did you include something unrelated to the overall purpose of the changes? Did + you forget to remove any debugging code? +- Be grateful for the reviewer's suggestions. ("Good call. I'll make that + change.") +- Don't take it personally. The review is of the code, not of you. +- Explain why the code exists. ("It's like that because of these reasons. Would + it be more clear if I rename this class/file/method/variable?") +- Extract unrelated changes and refactorings into future merge requests/issues. +- Seek to understand the reviewer's perspective. +- Try to respond to every comment. +- Push commits based on earlier rounds of feedback as isolated commits to the + branch. Do not squash until the branch is ready to merge. Reviewers should be + able to read individual updates based on their earlier feedback. + +## Reviewing code + +Understand why the change is necessary (fixes a bug, improves the user +experience, refactors the existing code). Then: + +- Communicate which ideas you feel strongly about and those you don't. +- Identify ways to simplify the code while still solving the problem. +- Offer alternative implementations, but assume the author already considered + them. ("What do you think about using a custom validator here?") +- Seek to understand the author's perspective. +- If you don't understand a piece of code, _say so_. There's a good chance + someone else would be confused by it as well. +- After a round of line notes, it can be helpful to post a summary note such as + "LGTM :thumbsup:", or "Just a couple things to address." +- Avoid accepting a merge request before the build succeeds ("Merge when build + succeeds" is fine). + +## Credits + +Largely based on the [thoughtbot code review guide]. + +[thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review + +--- + +[Return to Development documentation](README.md) diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md index c0192bd6709..c1cf2e77c26 100644 --- a/doc/development/instrumentation.md +++ b/doc/development/instrumentation.md @@ -2,36 +2,35 @@ GitLab Performance Monitoring allows instrumenting of custom blocks of Ruby code. This can be used to measure the time spent in a specific part of a larger -chunk of code. The resulting data is written to a separate series. +chunk of code. The resulting data is stored as a field in the transaction that +executed the block. -To start measuring a block of Ruby code you should use -`Gitlab::Metrics.measure` and give it a name for the series to store the data -in: +To start measuring a block of Ruby code you should use `Gitlab::Metrics.measure` +and give it a name: ```ruby -Gitlab::Metrics.measure(:user_logins) do +Gitlab::Metrics.measure(:foo) do ... end ``` -The first argument of this method is the series name and should be plural. This -name will be prefixed with `rails_` or `sidekiq_` depending on whether the code -was run in the Rails application or one of the Sidekiq workers. In the -above example the final series names would be as follows: +3 values are measured for a block: -- rails_user_logins -- sidekiq_user_logins +1. The real time elapsed, stored in NAME_real_time. +2. The CPU time elapsed, stored in NAME_cpu_time. +3. The call count, stored in NAME_call_count. -Series names should be plural as this keeps the naming style in line with the -other series names. +Both the real and CPU timings are measured in milliseconds. -By default metrics measured using a block contain a single value, "duration", -which contains the number of milliseconds it took to execute the block. Custom -values can be added by passing a Hash as the 2nd argument. Custom tags can be -added by passing a Hash as the 3rd argument. A simple example is as follows: +Multiple calls to the same block will result in the final values being the sum +of all individual values. Take this code for example: ```ruby -Gitlab::Metrics.measure(:example_series, { number: 10 }, { class: self.class.to_s }) do - ... +3.times do + Gitlab::Metrics.measure(:sleep) do + sleep 1 + end end ``` + +Here the final value of `sleep_real_time` will be `3`, _not_ `1`. diff --git a/doc/development/testing.md b/doc/development/testing.md index 23417845f16..672e3fb4649 100644 --- a/doc/development/testing.md +++ b/doc/development/testing.md @@ -16,16 +16,18 @@ GitLab uses [factory_girl] as a test fixture replacement. - Factory definitions live in `spec/factories/`, named using the pluralization of their corresponding model (`User` factories are defined in `users.rb`). - There should be only one top-level factory definition per file. -- Make use of [Traits] to clean up definitions and usages. +- FactoryGirl methods are mixed in to all RSpec groups. This means you can (and + should) call `create(...)` instead of `FactoryGirl.create(...)`. +- Make use of [traits] to clean up definitions and usages. - When defining a factory, don't define attributes that are not required for the resulting record to pass validation. -- When instantiating from a factory, don't supply extraneous attributes that - aren't required by the test. +- When instantiating from a factory, don't supply attributes that aren't + required by the test. - Factories don't have to be limited to `ActiveRecord` objects. [See example](https://gitlab.com/gitlab-org/gitlab-ce/commit/0b8cefd3b2385a21cfed779bd659978c0402766d). [factory_girl]: https://github.com/thoughtbot/factory_girl -[Traits]: http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md#Traits +[traits]: http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md#Traits ## JavaScript @@ -40,9 +42,9 @@ the command line via `bundle exec teaspoon`, or via a web browser at `spec/javascripts/fixtures`. They should contain the bare minimum amount of markup necessary for the test. - > **Warning:** Keep in mind that a Rails view may change and - invalidate your test, but everything will still pass because your fixture - doesn't reflect the latest view. + > **Warning:** Keep in mind that a Rails view may change and + invalidate your test, but everything will still pass because your fixture + doesn't reflect the latest view. - Keep in mind that in a CI environment, these tests are run in a headless browser and you will not have access to certain APIs, such as @@ -102,7 +104,7 @@ Here are some things to keep in mind regarding test performance: - Don't `create` an object when `build`, `build_stubbed`, `attributes_for`, `spy`, or `double` will do. Database persistence is slow! - Use `create(:empty_project)` instead of `create(:project)` when you don't need - the underlying repository. Filesystem operations are slow! + the underlying Git repository. Filesystem operations are slow! - Don't mark a feature as requiring JavaScript (through `@javascript` in Spinach or `js: true` in RSpec) unless it's _actually_ required for the test to be valid. Headless browser testing is slow! diff --git a/doc/integration/README.md b/doc/integration/README.md index 7c8f785a61f..6fe04aa2a06 100644 --- a/doc/integration/README.md +++ b/doc/integration/README.md @@ -19,26 +19,15 @@ See the documentation below for details on how to configure these services. GitLab Enterprise Edition contains [advanced Jenkins support][jenkins]. +[jenkins]: http://doc.gitlab.com/ee/integration/jenkins.html + + ## Project services Integration with services such as Campfire, Flowdock, Gemnasium, HipChat, Pivotal Tracker, and Slack are available in the form of a [Project Service][]. -You can find these within GitLab in the Services page under Project Settings if -you are at least a master on the project. -Project Services are a bit like plugins in that they allow a lot of freedom in -adding functionality to GitLab. For example there is also a service that can -send an email every time someone pushes new commits. -Because GitLab is open source we can ship with the code and tests for all -plugins. This allows the community to keep the plugins up to date so that they -always work in newer GitLab versions. - -For an overview of what projects services are available without logging in, -please see the [project_services directory][projects-code]. - -[jenkins]: http://doc.gitlab.com/ee/integration/jenkins.html [Project Service]: ../project_services/project_services.md -[projects-code]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/models/project_services ## SSL certificate errors diff --git a/doc/project_services/project_services.md b/doc/project_services/project_services.md index 3fea2cff0b9..a5af620d9be 100644 --- a/doc/project_services/project_services.md +++ b/doc/project_services/project_services.md @@ -1,7 +1,24 @@ # Project Services Project services allow you to integrate GitLab with other applications. Below -is list of the currently supported ones. Click on the service links to see +is list of the currently supported ones. + +You can find these within GitLab in the Services page under Project Settings if +you are at least a master on the project. +Project Services are a bit like plugins in that they allow a lot of freedom in +adding functionality to GitLab. For example there is also a service that can +send an email every time someone pushes new commits. + +Because GitLab is open source we can ship with the code and tests for all +plugins. This allows the community to keep the plugins up to date so that they +always work in newer GitLab versions. + +For an overview of what projects services are available without logging in, +please see the [project_services directory][projects-code]. + +[projects-code]: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/models/project_services + +Click on the service links to see further configuration instructions and details. Contributions are welcome. ## Services diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature index 10bd6fec803..67f1e117f7f 100644 --- a/features/project/forked_merge_requests.feature +++ b/features/project/forked_merge_requests.feature @@ -4,6 +4,7 @@ Feature: Project Forked Merge Requests And I am a member of project "Shop" And I have a project forked off of "Shop" called "Forked Shop" + @javascript Scenario: I submit new unassigned merge request to a forked project Given I visit project "Forked Shop" merge requests page And I click link "New Merge Request" diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature index 823658b4f24..ecda4ea8240 100644 --- a/features/project/merge_requests.feature +++ b/features/project/merge_requests.feature @@ -70,6 +70,7 @@ Feature: Project Merge Requests When I click link "Reopen" Then I should see reopened merge request "Bug NS-04" + @javascript Scenario: I submit new unassigned merge request Given I click link "New Merge Request" And I submit new merge request "Wiki Feature" diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb index 7e4425ff662..612bb8fd8b1 100644 --- a/features/steps/project/forked_merge_requests.rb +++ b/features/steps/project/forked_merge_requests.rb @@ -34,10 +34,14 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps end step 'I fill out a "Merge Request On Forked Project" merge request' do - select @forked_project.path_with_namespace, from: "merge_request_source_project_id" - select @project.path_with_namespace, from: "merge_request_target_project_id" - select "fix", from: "merge_request_source_branch" - select "master", from: "merge_request_target_branch" + first('.js-source-project').click + first('.dropdown-source-project a', text: @forked_project.path_with_namespace) + + first('.js-target-project').click + first('.dropdown-target-project a', text: @project.path_with_namespace) + + first('.js-source-branch').click + first('.dropdown-source-branch .dropdown-content a', text: 'fix').click click_button "Compare branches and continue" @@ -115,10 +119,10 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps end step 'I fill out an invalid "Merge Request On Forked Project" merge request' do - expect(find(:select, "merge_request_source_project_id", {}).value).to eq @forked_project.id.to_s - expect(find(:select, "merge_request_target_project_id", {}).value).to eq @project.id.to_s - expect(find(:select, "merge_request_source_branch", {}).value).to eq "" - expect(find(:select, "merge_request_target_branch", {}).value).to eq "master" + expect(find_by_id("merge_request_source_project_id", visible: false).value).to eq @forked_project.id.to_s + expect(find_by_id("merge_request_target_project_id", visible: false).value).to eq @project.id.to_s + expect(find_by_id("merge_request_source_branch", visible: false).value).to eq nil + expect(find_by_id("merge_request_target_branch", visible: false).value).to eq "master" click_button "Compare branches" end @@ -127,7 +131,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps end step 'the target repository should be the original repository' do - expect(page).to have_select("merge_request_target_project_id", selected: @project.path_with_namespace) + expect(find_by_id("merge_request_target_project_id").value).to eq "#{@project.id}" end step 'I click "Assign to" dropdown"' do diff --git a/features/steps/project/issues/labels.rb b/features/steps/project/issues/labels.rb index 2ab8956867b..0ca2d6257c3 100644 --- a/features/steps/project/issues/labels.rb +++ b/features/steps/project/issues/labels.rb @@ -15,7 +15,7 @@ class Spinach::Features::ProjectIssuesLabels < Spinach::FeatureSteps step 'I delete all labels' do page.within '.labels' do - page.all('.btn-remove').each do |remove| + page.all('.remove-row').each do |remove| remove.click sleep 0.05 end diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index a4f02b590ea..f0af0d097fa 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -93,8 +93,12 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps end step 'I submit new merge request "Wiki Feature"' do - select "fix", from: "merge_request_source_branch" - select "feature", from: "merge_request_target_branch" + find('.js-source-branch').click + find('.dropdown-source-branch .dropdown-content a', text: 'fix').click + + find('.js-target-branch').click + first('.dropdown-target-branch .dropdown-content a', text: 'feature').click + click_button "Compare branches" fill_in "merge_request_title", with: "Wiki Feature" click_button "Submit merge request" diff --git a/features/steps/project/source/browse_files.rb b/features/steps/project/source/browse_files.rb index 243469b8e7d..e072505e5d7 100644 --- a/features/steps/project/source/browse_files.rb +++ b/features/steps/project/source/browse_files.rb @@ -213,13 +213,12 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps end step 'I see Browse file link' do - expect(page).to have_link 'Browse File »' - expect(page).not_to have_link 'Browse Files »' + expect(page).to have_link 'Browse File' + expect(page).not_to have_link 'Browse Files' end step 'I see Browse code link' do - expect(page).to have_link 'Browse Files »' - expect(page).not_to have_link 'Browse File »' + expect(page).to have_link 'Browse Files' expect(page).not_to have_link 'Browse Directory »' end diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb index 32c3e99f450..1448c3f44cc 100644 --- a/features/steps/shared/diff_note.rb +++ b/features/steps/shared/diff_note.rb @@ -155,7 +155,7 @@ module SharedDiffNote step 'I should see a discussion reply button' do page.within(diff_file_selector) do - expect(page).to have_button('Reply') + expect(page).to have_button('Reply...') end end diff --git a/lib/gitlab/exclusive_lease.rb b/lib/gitlab/exclusive_lease.rb index c73eca832d7..c2260a5f7ac 100644 --- a/lib/gitlab/exclusive_lease.rb +++ b/lib/gitlab/exclusive_lease.rb @@ -43,7 +43,9 @@ module Gitlab # false if the lease is already taken. def try_obtain # Performing a single SET is atomic - !!redis.set(redis_key, '1', nx: true, ex: @timeout) + Gitlab::Redis.with do |redis| + !!redis.set(redis_key, '1', nx: true, ex: @timeout) + end end # No #cancel method. See comments above! diff --git a/lib/gitlab/metrics.rb b/lib/gitlab/metrics.rb index 4a3f47b5a95..2a0a5629be5 100644 --- a/lib/gitlab/metrics.rb +++ b/lib/gitlab/metrics.rb @@ -74,24 +74,32 @@ module Gitlab # # Example: # - # Gitlab::Metrics.measure(:find_by_username_timings) do + # Gitlab::Metrics.measure(:find_by_username_duration) do # User.find_by_username(some_username) # end # - # series - The name of the series to store the data in. - # values - A Hash containing extra values to add to the metric. - # tags - A Hash containing extra tags to add to the metric. + # name - The name of the field to store the execution time in. # # Returns the value yielded by the supplied block. - def self.measure(series, values = {}, tags = {}) - return yield unless Transaction.current + def self.measure(name) + trans = current_transaction + + return yield unless trans + + real_start = Time.now.to_f + cpu_start = System.cpu_time - start = Time.now.to_f retval = yield - duration = (Time.now.to_f - start) * 1000.0 - values = values.merge(duration: duration) - Transaction.current.add_metric(series, values, tags) + cpu_stop = System.cpu_time + real_stop = Time.now.to_f + + real_time = (real_stop - real_start) * 1000.0 + cpu_time = cpu_stop - cpu_start + + trans.increment("#{name}_real_time", real_time) + trans.increment("#{name}_cpu_time", cpu_time) + trans.increment("#{name}_call_count", 1) retval end @@ -107,5 +115,11 @@ module Gitlab new(udp: { host: host, port: port }) end end + + private + + def self.current_transaction + Transaction.current + end end end diff --git a/lib/gitlab/metrics/subscribers/rails_cache.rb b/lib/gitlab/metrics/subscribers/rails_cache.rb new file mode 100644 index 00000000000..49e5f86e6e6 --- /dev/null +++ b/lib/gitlab/metrics/subscribers/rails_cache.rb @@ -0,0 +1,39 @@ +module Gitlab + module Metrics + module Subscribers + # Class for tracking the total time spent in Rails cache calls + class RailsCache < ActiveSupport::Subscriber + attach_to :active_support + + def cache_read(event) + increment(:cache_read_duration, event.duration) + end + + def cache_write(event) + increment(:cache_write_duration, event.duration) + end + + def cache_delete(event) + increment(:cache_delete_duration, event.duration) + end + + def cache_exist?(event) + increment(:cache_exists_duration, event.duration) + end + + def increment(key, duration) + return unless current_transaction + + current_transaction.increment(:cache_duration, duration) + current_transaction.increment(key, duration) + end + + private + + def current_transaction + Transaction.current + end + end + end + end +end diff --git a/lib/gitlab/metrics/system.rb b/lib/gitlab/metrics/system.rb index 83371265278..a7d183b2f94 100644 --- a/lib/gitlab/metrics/system.rb +++ b/lib/gitlab/metrics/system.rb @@ -30,6 +30,17 @@ module Gitlab 0 end end + + # THREAD_CPUTIME is not supported on OS X + if Process.const_defined?(:CLOCK_THREAD_CPUTIME_ID) + def self.cpu_time + Process.clock_gettime(Process::CLOCK_THREAD_CPUTIME_ID, :millisecond) + end + else + def self.cpu_time + Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond) + end + end end end end diff --git a/lib/gitlab/redis.rb b/lib/gitlab/redis.rb new file mode 100644 index 00000000000..319447669dc --- /dev/null +++ b/lib/gitlab/redis.rb @@ -0,0 +1,48 @@ +module Gitlab + class Redis + CACHE_NAMESPACE = 'cache:gitlab' + + attr_reader :url + + # To be thread-safe we must be careful when writing the class instance + # variables @url and @pool. Because @pool depends on @url we need two + # mutexes to prevent deadlock. + URL_MUTEX = Mutex.new + POOL_MUTEX = Mutex.new + private_constant :URL_MUTEX, :POOL_MUTEX + + def self.url + @url || URL_MUTEX.synchronize { @url = new.url } + end + + def self.with + if @pool.nil? + POOL_MUTEX.synchronize do + @pool = ConnectionPool.new { ::Redis.new(url: url) } + end + end + @pool.with { |redis| yield redis } + end + + def self.redis_store_options + url = new.url + redis_config_hash = ::Redis::Store::Factory.extract_host_options_from_uri(url) + # Redis::Store does not handle Unix sockets well, so let's do it for them + redis_uri = URI.parse(url) + if redis_uri.scheme == 'unix' + redis_config_hash[:path] = redis_uri.path + end + redis_config_hash + end + + def initialize(rails_env=nil) + rails_env ||= Rails.env + config_file = File.expand_path('../../../config/resque.yml', __FILE__) + + @url = "redis://localhost:6379" + if File.exists?(config_file) + @url =YAML.load_file(config_file)[rails_env] + end + end + end +end diff --git a/lib/gitlab/redis_config.rb b/lib/gitlab/redis_config.rb deleted file mode 100644 index 4949c6db539..00000000000 --- a/lib/gitlab/redis_config.rb +++ /dev/null @@ -1,30 +0,0 @@ -module Gitlab - class RedisConfig - attr_reader :url - - def self.url - new.url - end - - def self.redis_store_options - url = new.url - redis_config_hash = Redis::Store::Factory.extract_host_options_from_uri(url) - # Redis::Store does not handle Unix sockets well, so let's do it for them - redis_uri = URI.parse(url) - if redis_uri.scheme == 'unix' - redis_config_hash[:path] = redis_uri.path - end - redis_config_hash - end - - def initialize(rails_env=nil) - rails_env ||= Rails.env - config_file = File.expand_path('../../../config/resque.yml', __FILE__) - - @url = "redis://localhost:6379" - if File.exists?(config_file) - @url =YAML.load_file(config_file)[rails_env] - end - end - end -end diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake index 51e746ef923..2214f855200 100644 --- a/lib/tasks/cache.rake +++ b/lib/tasks/cache.rake @@ -4,18 +4,19 @@ namespace :cache do desc "GitLab | Clear redis cache" task :clear => :environment do - redis = Redis.new(url: Gitlab::RedisConfig.url) - cursor = REDIS_SCAN_START_STOP - loop do - cursor, keys = redis.scan( - cursor, - match: "#{Gitlab::REDIS_CACHE_NAMESPACE}*", - count: CLEAR_BATCH_SIZE - ) - - redis.del(*keys) if keys.any? - - break if cursor == REDIS_SCAN_START_STOP + Gitlab::Redis.with do |redis| + cursor = REDIS_SCAN_START_STOP + loop do + cursor, keys = redis.scan( + cursor, + match: "#{Gitlab::Redis::CACHE_NAMESPACE}*", + count: CLEAR_BATCH_SIZE + ) + + redis.del(*keys) if keys.any? + + break if cursor == REDIS_SCAN_START_STOP + end end end end diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb new file mode 100644 index 00000000000..41af789aae2 --- /dev/null +++ b/spec/features/issues/award_emoji_spec.rb @@ -0,0 +1,64 @@ +require 'rails_helper' + +describe 'Awards Emoji', feature: true do + let!(:project) { create(:project) } + let!(:user) { create(:user) } + + before do + project.team << [user, :master] + login_as(user) + end + + describe 'Click award emoji from issue#show' do + let!(:issue) do + create(:issue, + author: @user, + assignee: @user, + project: project) + end + + before do + visit namespace_project_issue_path(project.namespace, project, issue) + end + + it 'should increment the thumbsdown emoji', js: true do + find('[data-emoji="thumbsdown"]').click + sleep 2 + expect(thumbsdown_emoji).to have_text("1") + end + + context 'click the thumbsup emoji' do + + it 'should increment the thumbsup emoji', js: true do + find('[data-emoji="thumbsup"]').click + sleep 2 + expect(thumbsup_emoji).to have_text("1") + end + + it 'should decrement the thumbsdown emoji', js: true do + expect(thumbsdown_emoji).to have_text("0") + end + end + + context 'click the thumbsdown emoji' do + + it 'should increment the thumbsdown emoji', js: true do + find('[data-emoji="thumbsdown"]').click + sleep 2 + expect(thumbsdown_emoji).to have_text("1") + end + + it 'should decrement the thumbsup emoji', js: true do + expect(thumbsup_emoji).to have_text("0") + end + end + end + + def thumbsup_emoji + page.all('span.js-counter').first + end + + def thumbsdown_emoji + page.all('span.js-counter').last + end +end diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index fd02d584848..00b60bd0e75 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Create New Merge Request', feature: true, js: false do +feature 'Create New Merge Request', feature: true, js: true do let(:user) { create(:user) } let(:project) { create(:project, :public) } @@ -13,9 +13,12 @@ feature 'Create New Merge Request', feature: true, js: false do it 'generates a diff for an orphaned branch' do click_link 'New Merge Request' - select "orphaned-branch", from: "merge_request_source_branch" - select "master", from: "merge_request_target_branch" + + first('.js-source-branch').click + first('.dropdown-source-branch .dropdown-content a', text: 'orphaned-branch').click + click_button "Compare branches" + click_link "Changes" expect(page).to have_content "README.md" expect(page).to have_content "wm.png" @@ -23,6 +26,8 @@ feature 'Create New Merge Request', feature: true, js: false do fill_in "merge_request_title", with: "Orphaned MR test" click_button "Submit merge request" + click_link "Check out branch" + expect(page).to have_content 'git checkout -b orphaned-branch origin/orphaned-branch' end end diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index 70d0864783d..5f855ccc701 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -210,7 +210,7 @@ describe 'Comments', feature: true do is_expected.to have_content('Another comment on line 10') is_expected.to have_css('.notes_holder') is_expected.to have_css('.notes_holder .note', count: 1) - is_expected.to have_button('Reply') + is_expected.to have_button('Reply...') end end end diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb new file mode 100644 index 00000000000..b20373a96fb --- /dev/null +++ b/spec/helpers/form_helper_spec.rb @@ -0,0 +1,46 @@ +require 'rails_helper' + +describe FormHelper do + describe 'form_errors' do + it 'returns nil when model has no errors' do + model = double(errors: []) + + expect(helper.form_errors(model)).to be_nil + end + + it 'renders an alert div' do + model = double(errors: errors_stub('Error 1')) + + expect(helper.form_errors(model)). + to include('<div class="alert alert-danger" id="error_explanation">') + end + + it 'contains a summary message' do + single_error = double(errors: errors_stub('A')) + multi_errors = double(errors: errors_stub('A', 'B', 'C')) + + expect(helper.form_errors(single_error)). + to include('<h4>The form contains the following error:') + expect(helper.form_errors(multi_errors)). + to include('<h4>The form contains the following errors:') + end + + it 'renders each message' do + model = double(errors: errors_stub('Error 1', 'Error 2', 'Error 3')) + + errors = helper.form_errors(model) + + aggregate_failures do + expect(errors).to include('<li>Error 1</li>') + expect(errors).to include('<li>Error 2</li>') + expect(errors).to include('<li>Error 3</li>') + end + end + + def errors_stub(*messages) + ActiveModel::Errors.new(double).tap do |errors| + messages.each { |msg| errors.add(:base, msg) } + end + end + end +end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 9adcd916ced..13de88e2f21 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -150,13 +150,6 @@ describe GitlabMarkdownHelper do end end - describe 'random_markdown_tip' do - it 'returns a random Markdown tip' do - stub_const("#{described_class}::MARKDOWN_TIPS", ['Random tip']) - expect(random_markdown_tip).to eq 'Random tip' - end - end - describe '#first_line_in_markdown' do let(:text) { "@#{user.username}, can you look at this?\nHello world\n"} diff --git a/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb b/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb new file mode 100644 index 00000000000..e01b0b4bd21 --- /dev/null +++ b/spec/lib/gitlab/metrics/subscribers/rails_cache_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe Gitlab::Metrics::Subscribers::RailsCache do + let(:transaction) { Gitlab::Metrics::Transaction.new } + let(:subscriber) { described_class.new } + + let(:event) { double(:event, duration: 15.2) } + + describe '#cache_read' do + it 'increments the cache_read duration' do + expect(subscriber).to receive(:increment). + with(:cache_read_duration, event.duration) + + subscriber.cache_read(event) + end + end + + describe '#cache_write' do + it 'increments the cache_write duration' do + expect(subscriber).to receive(:increment). + with(:cache_write_duration, event.duration) + + subscriber.cache_write(event) + end + end + + describe '#cache_delete' do + it 'increments the cache_delete duration' do + expect(subscriber).to receive(:increment). + with(:cache_delete_duration, event.duration) + + subscriber.cache_delete(event) + end + end + + describe '#cache_exist?' do + it 'increments the cache_exists duration' do + expect(subscriber).to receive(:increment). + with(:cache_exists_duration, event.duration) + + subscriber.cache_exist?(event) + end + end + + describe '#increment' do + context 'without a transaction' do + it 'returns' do + expect(transaction).not_to receive(:increment) + + subscriber.increment(:foo, 15.2) + end + end + + context 'with a transaction' do + before do + allow(subscriber).to receive(:current_transaction). + and_return(transaction) + end + + it 'increments the total and specific cache duration' do + expect(transaction).to receive(:increment). + with(:cache_duration, event.duration) + + expect(transaction).to receive(:increment). + with(:cache_delete_duration, event.duration) + + subscriber.increment(:cache_delete_duration, event.duration) + end + end + end +end diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb index f8c1d956ca1..d6ae54e25e8 100644 --- a/spec/lib/gitlab/metrics/system_spec.rb +++ b/spec/lib/gitlab/metrics/system_spec.rb @@ -26,4 +26,10 @@ describe Gitlab::Metrics::System do end end end + + describe '.cpu_time' do + it 'returns a Fixnum' do + expect(described_class.cpu_time).to be_an_instance_of(Fixnum) + end + end end diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb index 8f63a5f2043..3dee13e27f4 100644 --- a/spec/lib/gitlab/metrics_spec.rb +++ b/spec/lib/gitlab/metrics_spec.rb @@ -74,24 +74,21 @@ describe Gitlab::Metrics do let(:transaction) { Gitlab::Metrics::Transaction.new } before do - allow(Gitlab::Metrics::Transaction).to receive(:current). + allow(Gitlab::Metrics).to receive(:current_transaction). and_return(transaction) end it 'adds a metric to the current transaction' do - expect(transaction).to receive(:add_metric). - with(:foo, { duration: a_kind_of(Numeric) }, { tag: 'value' }) + expect(transaction).to receive(:increment). + with('foo_real_time', a_kind_of(Numeric)) - Gitlab::Metrics.measure(:foo, {}, tag: 'value') { 10 } - end - - it 'supports adding of custom values' do - values = { duration: a_kind_of(Numeric), number: 10 } + expect(transaction).to receive(:increment). + with('foo_cpu_time', a_kind_of(Numeric)) - expect(transaction).to receive(:add_metric). - with(:foo, values, { tag: 'value' }) + expect(transaction).to receive(:increment). + with('foo_call_count', 1) - Gitlab::Metrics.measure(:foo, { number: 10 }, tag: 'value') { 10 } + Gitlab::Metrics.measure(:foo) { 10 } end it 'returns the return value of the block' do |