diff options
87 files changed, 845 insertions, 488 deletions
@@ -328,7 +328,7 @@ end gem 'newrelic_rpm', '~> 3.16' -gem 'octokit', '~> 4.3.0' +gem 'octokit', '~> 4.6.2' gem 'mail_room', '~> 0.9.0' diff --git a/Gemfile.lock b/Gemfile.lock index 1c192d2fc6e..5dcf3744d99 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -420,8 +420,8 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - octokit (4.3.0) - sawyer (~> 0.7.0, >= 0.5.3) + octokit (4.6.2) + sawyer (~> 0.8.0, >= 0.5.3) oj (2.17.4) omniauth (1.3.1) hashie (>= 1.2, < 4) @@ -650,9 +650,9 @@ GEM sprockets (>= 2.8, < 4.0) sprockets-rails (>= 2.0, < 4.0) tilt (>= 1.1, < 3) - sawyer (0.7.0) - addressable (>= 2.3.5, < 2.5) - faraday (~> 0.8, < 0.10) + sawyer (0.8.1) + addressable (>= 2.3.5, < 2.6) + faraday (~> 0.8, < 1.0) scss_lint (0.47.1) rake (>= 0.9, < 11) sass (~> 3.4.15) @@ -895,7 +895,7 @@ DEPENDENCIES newrelic_rpm (~> 3.16) nokogiri (~> 1.6.7, >= 1.6.7.2) oauth2 (~> 1.2.0) - octokit (~> 4.3.0) + octokit (~> 4.6.2) oj (~> 2.17.4) omniauth (~> 1.3.1) omniauth-auth0 (~> 1.4.1) diff --git a/app/assets/javascripts/compare_autocomplete.js.es6 b/app/assets/javascripts/compare_autocomplete.js.es6 index 45c974b2b68..251f2ded347 100644 --- a/app/assets/javascripts/compare_autocomplete.js.es6 +++ b/app/assets/javascripts/compare_autocomplete.js.es6 @@ -55,6 +55,13 @@ $('.dropdown-toggle-text', $dropdown).text(text); $dropdownContainer.removeClass('open'); }); + + $dropdownContainer.on('click', '.dropdown-content a', (e) => { + $dropdown.prop('title', e.target.text.replace(/_+?/g, '-')); + if ($dropdown.hasClass('has-tooltip')) { + $dropdown.tooltip('fixTitle'); + } + }); }); }; diff --git a/app/assets/javascripts/gfm_auto_complete.js.es6 b/app/assets/javascripts/gfm_auto_complete.js.es6 index 87c579ac757..6ca543c2b00 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.es6 +++ b/app/assets/javascripts/gfm_auto_complete.js.es6 @@ -48,6 +48,7 @@ }, DefaultOptions: { sorter: function(query, items, searchKey) { + this.setting.highlightFirst = query.length > 0; if (gl.GfmAutoComplete.isLoading(items)) { return items; } @@ -55,11 +56,9 @@ }, filter: function(query, data, searchKey) { if (gl.GfmAutoComplete.isLoading(data)) { - gl.GfmAutoComplete.togglePreventSelection.call(this, true); gl.GfmAutoComplete.fetchData(this.$inputor, this.at); return data; } else { - gl.GfmAutoComplete.togglePreventSelection.call(this, false); return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); } }, @@ -257,9 +256,9 @@ insertTpl: '${atwho-at}${title}', callbacks: { matcher: this.DefaultOptions.matcher, - sorter: this.DefaultOptions.sorter, beforeInsert: this.DefaultOptions.beforeInsert, filter: this.DefaultOptions.filter, + sorter: this.DefaultOptions.sorter, beforeSave: function(merges) { if (gl.GfmAutoComplete.isLoading(merges)) return merges; var sanitizeLabelTitle; @@ -370,11 +369,7 @@ if (!data || !data.length) return false; if (Array.isArray(data)) data = data[0]; return data === this.defaultLoadingData[0] || data.name === this.defaultLoadingData[0]; - }, - togglePreventSelection(isPrevented = !!this.setting.tabSelectsMatch) { - this.setting.tabSelectsMatch = !isPrevented; - this.setting.spaceSelectsMatch = !isPrevented; - }, + } }; }).call(this); diff --git a/app/assets/stylesheets/framework/awards.scss b/app/assets/stylesheets/framework/awards.scss index 9fc9bcebc44..49907417e26 100644 --- a/app/assets/stylesheets/framework/awards.scss +++ b/app/assets/stylesheets/framework/awards.scss @@ -97,8 +97,20 @@ padding: 5px 6px; outline: 0; - &:hover, + &.disabled { + cursor: default; + + &:hover, + &:focus, + &:active { + background-color: $white-light; + border-color: $border-color; + box-shadow: none; + } + } + &.active, + &:hover, &:active { background-color: $row-hover; border-color: $row-hover-border; diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 88ed0a4a17e..c51912b4ac4 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -182,3 +182,52 @@ span.idiff { border-bottom-right-radius: 2px; } } + +.file-stats { + ul { + list-style: none; + margin: 0; + padding: 10px 0; + + li { + padding: 3px 0; + line-height: 20px; + } + } + + .new-file { + a { + color: $gl-text-green; + } + } + + .renamed-file { + a { + color: $gl-text-orange; + } + } + + .deleted-file { + a { + color: $gl-text-red; + } + } + + .edit-file { + a { + color: $gl-text-color; + } + } + + a { + text-decoration: none; + + .new-file { + color: $notify-new-file; + } + + .deleted-file { + color: $notify-deleted-file; + } + } +} diff --git a/app/assets/stylesheets/framework/lists.scss b/app/assets/stylesheets/framework/lists.scss index 277d4202950..bffd0e6f0cd 100644 --- a/app/assets/stylesheets/framework/lists.scss +++ b/app/assets/stylesheets/framework/lists.scss @@ -234,14 +234,46 @@ ul.content-list { } } -.panel > .content-list > li { - padding: $gl-padding-top $gl-padding; +// Table list +.table-list { + display: table; + width: 100%; + + .table-list-row { + display: table-row; + } + + .table-list-cell { + display: table-cell; + vertical-align: top; + padding: 10px 16px; + border-bottom: 1px solid $gray-darker; - &.commit { - @media (min-width: $screen-sm-min) { - padding-left: 46px + $gl-padding; + &.avatar-cell { + width: 36px; + padding-right: 0; + + img { + margin-right: 0; + } } } + + &.table-wide { + .table-list-cell { + &:last-of-type { + padding-right: 0; + } + + &:first-of-type { + padding-left: 0; + } + } + } +} + +.panel > .content-list > li { + padding: $gl-padding-top $gl-padding; } ul.controls { diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss index 9d8d08dff88..efe93724013 100644 --- a/app/assets/stylesheets/framework/panels.scss +++ b/app/assets/stylesheets/framework/panels.scss @@ -48,3 +48,11 @@ line-height: inherit; } } + +.panel-default { + .table-list-row:last-child { + .table-list-cell { + border-bottom: 0; + } + } +} diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index b0c4a6edf57..dc211fc55a7 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -376,7 +376,6 @@ $callout-success-color: #3c763d; /* * Commit Page */ -$commit-committer-color: #999; $commit-max-width-marker-color: rgba(0, 0, 0, 0.0); $commit-message-text-area-bg: rgba(0, 0, 0, 0.0); diff --git a/app/assets/stylesheets/notify.scss b/app/assets/stylesheets/notify.scss index ddc382362f7..a81e5eb5ebf 100644 --- a/app/assets/stylesheets/notify.scss +++ b/app/assets/stylesheets/notify.scss @@ -18,15 +18,3 @@ p.details { pre.commit-message { white-space: pre-wrap; } - -.file-stats > a { - text-decoration: none; - - > .new-file { - color: $notify-new-file; - } - - > .deleted-file { - color: $notify-deleted-file; - } -} diff --git a/app/assets/stylesheets/pages/branches.scss b/app/assets/stylesheets/pages/branches.scss new file mode 100644 index 00000000000..8d671585b7a --- /dev/null +++ b/app/assets/stylesheets/pages/branches.scss @@ -0,0 +1,55 @@ +.divergence-graph { + padding: 12px 12px 0 0; + float: right; + + .graph-side { + position: relative; + width: 80px; + height: 22px; + padding: 5px 0 13px; + float: left; + + .bar { + position: absolute; + height: 4px; + background-color: $divergence-graph-bar-bg; + } + + .bar-behind { + right: 0; + border-radius: 3px 0 0 3px; + } + + .bar-ahead { + left: 0; + border-radius: 0 3px 3px 0; + } + + .count { + padding-top: 6px; + padding-bottom: 0; + font-size: 12px; + color: $gl-title-color; + display: block; + } + + .count-behind { + padding-right: 4px; + text-align: right; + } + + .count-ahead { + padding-left: 4px; + text-align: left; + } + } + + .graph-separator { + position: relative; + width: 1px; + height: 18px; + margin: 5px 0 0; + float: left; + background-color: $divergence-graph-separator-bg; + } +} diff --git a/app/assets/stylesheets/pages/commit.scss b/app/assets/stylesheets/pages/commit.scss deleted file mode 100644 index bf656d0e28e..00000000000 --- a/app/assets/stylesheets/pages/commit.scss +++ /dev/null @@ -1,132 +0,0 @@ -.commit-title { - display: block; -} - -.commit-author, -.commit-committer { - display: block; - color: $commit-committer-color; - font-weight: normal; - font-style: italic; -} - -.commit-author strong, -.commit-committer strong { - font-weight: bold; - font-style: normal; -} - -.commit-description { - background: none; - border: none; - margin: 0; - padding: 0; - margin-top: 10px; - word-break: normal; - white-space: pre-wrap; -} - -.js-details-expand { - &:hover { - text-decoration: none; - } -} - -.ci-status-link { - svg { - overflow: visible; - } -} - -.commit-box { - border-top: 1px solid $border-color; - padding: $gl-padding 0; - - .commit-title { - margin: 0; - font-size: 23px; - color: $gl-gray-dark; - } - - .commit-description { - margin-top: 15px; - } -} - -.commit-hash-full { - @media (max-width: $screen-sm-max) { - width: 80px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - display: inline-block; - vertical-align: bottom; - } -} - -.file-stats { - ul { - list-style: none; - margin: 0; - padding: 10px 0; - - li { - padding: 3px 0; - line-height: 20px; - } - } - - .new-file { - a { - color: $gl-text-green; - } - } - - .renamed-file { - a { - color: $gl-text-orange; - } - } - - .deleted-file { - a { - color: $gl-text-red; - } - } - - .edit-file { - a { - color: $gl-text-color; - } - } -} - -/* - * Commit message textarea for web editor and - * custom merge request message - */ -.commit-message-container { - background-color: $body-bg; - position: relative; - font-family: $monospace_font; - $left: 12px; - overflow: hidden; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987 - .max-width-marker { - width: 72ch; - color: $commit-max-width-marker-color; - font-family: inherit; - left: $left; - height: 100%; - border-right: 1px solid mix($input-border, $white-light); - position: absolute; - z-index: 1; - } - - > textarea { - background-color: $commit-message-text-area-bg; - font-family: inherit; - padding-left: $left; - position: relative; - z-index: 2; - } -} diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss index e76e1a73b25..d890cf3502b 100644 --- a/app/assets/stylesheets/pages/commits.scss +++ b/app/assets/stylesheets/pages/commits.scss @@ -1,6 +1,75 @@ +.commit-description { + background: none; + border: none; + padding: 0; + margin-top: 10px; + word-break: normal; + white-space: pre-wrap; +} + +.js-details-expand { + &:hover { + text-decoration: none; + } +} + +.commit-box { + border-top: 1px solid $border-color; + padding: $gl-padding 0; + + .commit-title { + margin: 0; + color: $gl-gray-dark; + } + + .commit-description { + margin-top: 15px; + } +} + +.commit-hash-full { + @media (max-width: $screen-sm-max) { + width: 80px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: inline-block; + vertical-align: bottom; + } +} + +/* + * Commit message textarea for web editor and + * custom merge request message + */ +.commit-message-container { + background-color: $body-bg; + position: relative; + font-family: $monospace_font; + $left: 12px; + overflow: hidden; // See https://gitlab.com/gitlab-org/gitlab-ce/issues/13987 + .max-width-marker { + width: 72ch; + color: $commit-max-width-marker-color; + font-family: inherit; + left: $left; + height: 100%; + border-right: 1px solid mix($input-border, $white-light); + position: absolute; + z-index: 1; + } + + textarea { + background-color: $commit-message-text-area-bg; + font-family: inherit; + padding-left: $left; + position: relative; + z-index: 2; + } +} + + .commits-compare-switch { - @include btn-default; - @include btn-white; float: left; margin-right: 9px; } @@ -8,7 +77,6 @@ .commit-header { padding: 5px 10px; background-color: $gray-light; - border-top: 1px solid $gray-darker; border-bottom: 1px solid $gray-darker; font-size: 14px; @@ -18,8 +86,6 @@ } .commit-row-title { - line-height: 1.35; - .notes_count { float: right; margin-right: 10px; @@ -32,7 +98,6 @@ .commit-row-message { color: $gl-dark-link-color; } - } .text-expander { @@ -54,9 +119,8 @@ .commit-actions { @media (min-width: $screen-sm-min) { - float: right; - margin-left: $gl-padding; - margin-top: 2px; + width: 300px; + text-align: right; font-size: 0; } @@ -86,16 +150,6 @@ .commit, .generic_commit_status { - padding: 10px 0; - position: relative; - - @media (min-width: $screen-sm-min) { - padding-left: 46px; - } - - &:not(:last-child) { - border-bottom: 1px solid $gray-darker; - } a, button { @@ -103,18 +157,6 @@ vertical-align: baseline; } - .avatar { - margin-left: -46px; - } - - .item-title { - display: inline-block; - - @media (min-width: $screen-sm-min) { - max-width: 70%; - } - } - .commit-row-description { font-size: 14px; border-left: 1px solid $white-normal; @@ -138,19 +180,6 @@ } } - .commit-row-info { - color: $gl-gray; - line-height: 1.35; - - a { - color: $gl-gray; - } - - .avatar { - margin-right: 8px; - } - } - &.inline-commit { .commit-row-title { font-size: 13px; @@ -186,59 +215,3 @@ color: $gl-gray; } } - -.divergence-graph { - padding: 12px 12px 0 0; - float: right; - - .graph-side { - position: relative; - width: 80px; - height: 22px; - padding: 5px 0 13px; - float: left; - - .bar { - position: absolute; - height: 4px; - background-color: $divergence-graph-bar-bg; - } - - .bar-behind { - right: 0; - border-radius: 3px 0 0 3px; - } - - .bar-ahead { - left: 0; - border-radius: 0 3px 3px 0; - } - - .count { - padding-top: 6px; - padding-bottom: 0; - font-size: 12px; - color: $gl-title-color; - display: block; - } - - .count-behind { - padding-right: 4px; - text-align: right; - } - - .count-ahead { - padding-left: 4px; - text-align: left; - } - } - - .graph-separator { - position: relative; - width: 1px; - height: 18px; - margin: 5px 0 0; - float: left; - background-color: $divergence-graph-separator-bg; - } -} diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss index 6b4d1f85564..42a3f5baed9 100644 --- a/app/assets/stylesheets/pages/issuable.scss +++ b/app/assets/stylesheets/pages/issuable.scss @@ -5,6 +5,12 @@ } } + .title { + padding: 0; + margin: 0; + border-bottom: none; + } + // Border around images in issue and MR descriptions. .description img:not(.emoji) { border: 1px solid $white-normal; diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 1b1126695a1..98d5967e76a 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -310,10 +310,6 @@ left: 0; top: 2px; } - - .commit-row-info { - line-height: 20px; - } } .btn-clipboard { diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 8f15775ee03..21d72791e81 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -43,7 +43,7 @@ ul.notes { } .system-note-message { - display: inline-block; + display: inline; &::first-letter { text-transform: lowercase; @@ -55,7 +55,7 @@ ul.notes { } p { - display: inline-block; + display: inline; margin: 0; &::first-letter { @@ -353,6 +353,14 @@ ul.notes { font-size: 14px; } +.note-headline-light { + display: inline; + + @media (max-width: $screen-xs-min) { + display: block; + } +} + .note-headline-light, .discussion-headline-light { color: $notes-light-color; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index b99be02ab0c..4a1bc560292 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -26,7 +26,7 @@ margin-bottom: 5px; } - &> .form-group { + & > .form-group { padding-left: 0; } } @@ -73,7 +73,7 @@ border: 1px solid $border-color; } - &+ .select2 a { + & + .select2 a { border-top-left-radius: 0; border-bottom-left-radius: 0; } @@ -618,7 +618,6 @@ pre.light-well { margin: 0; } - .activity-filter-block { .controls { padding-bottom: 7px; @@ -811,7 +810,31 @@ pre.light-well { .compare-form-group { .dropdown-menu { - width: 300px; + width: 100%; + + @media (min-width: $screen-sm-min) { + width: 300px; + } + } + + + .compare-ellipsis { + width: 100%; + vertical-align: middle; + text-align: center; + margin-top: -20px; + + @media (min-width: $screen-sm-min) { + margin-top: 0; + width: auto; + } + } + + .inline-input-group { + width: 100%; + + @media (min-width: $screen-sm-min) { + width: 250px; + } } } diff --git a/app/assets/stylesheets/pages/status.scss b/app/assets/stylesheets/pages/status.scss index 4acd17360c1..2f6f03e9877 100644 --- a/app/assets/stylesheets/pages/status.scss +++ b/app/assets/stylesheets/pages/status.scss @@ -135,3 +135,9 @@ left: 5px; } } + +.ci-status-link { + svg { + overflow: visible; + } +} diff --git a/app/assets/stylesheets/pages/tree.scss b/app/assets/stylesheets/pages/tree.scss index cad4e149845..fe4f08e4749 100644 --- a/app/assets/stylesheets/pages/tree.scss +++ b/app/assets/stylesheets/pages/tree.scss @@ -134,21 +134,18 @@ .blob-commit-info { list-style: none; - padding: $gl-padding; background: $gray-light; + padding: 6px 0; border: 1px solid $border-color; border-bottom: none; margin: 0; - .commit { - padding-top: 0; - padding-bottom: 0; + .table-list-cell { + border-bottom: none; + } - .commit-row-title { - .commit-row-message { - font-weight: normal; - } - } + .commit-actions { + width: 200px; } } diff --git a/app/controllers/projects/mattermosts_controller.rb b/app/controllers/projects/mattermosts_controller.rb index d87dff2a80e..01d99c7df35 100644 --- a/app/controllers/projects/mattermosts_controller.rb +++ b/app/controllers/projects/mattermosts_controller.rb @@ -30,7 +30,7 @@ class Projects::MattermostsController < Projects::ApplicationController def configure_params params.require(:mattermost).permit(:trigger, :team_id).merge( url: service_trigger_url(@service), - icon_url: asset_url('gitlab_logo.png')) + icon_url: asset_url('slash-command-logo.png')) end def teams diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index fc8a289d49d..6004e7d7115 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -98,7 +98,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController @start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha } unless @start_version - render_404 + @start_sha = @merge_request_diff.head_commit_sha + @start_version = @merge_request_diff end end diff --git a/app/controllers/registrations_controller.rb b/app/controllers/registrations_controller.rb index c45196cc3e9..bf27f3d4d51 100644 --- a/app/controllers/registrations_controller.rb +++ b/app/controllers/registrations_controller.rb @@ -7,17 +7,17 @@ class RegistrationsController < Devise::RegistrationsController end def create - if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha - # To avoid duplicate form fields on the login page, the registration form - # names fields using `new_user`, but Devise still wants the params in - # `user`. - if params["new_#{resource_name}"].present? && params[resource_name].blank? - params[resource_name] = params.delete(:"new_#{resource_name}") - end + # To avoid duplicate form fields on the login page, the registration form + # names fields using `new_user`, but Devise still wants the params in + # `user`. + if params["new_#{resource_name}"].present? && params[resource_name].blank? + params[resource_name] = params.delete(:"new_#{resource_name}") + end + if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha super else - flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code." + flash[:alert] = 'There was an error with the reCAPTCHA. Please re-solve the reCAPTCHA.' flash.delete :recaptcha_error render action: 'new' end @@ -57,7 +57,7 @@ class RegistrationsController < Devise::RegistrationsController end def sign_up_params - params.require(:user).permit(:username, :email, :name, :password, :password_confirmation) + params.require(:user).permit(:username, :email, :email_confirmation, :name, :password) end def resource_name diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb index eb435cc1783..6d365ea9251 100644 --- a/app/helpers/gitlab_markdown_helper.rb +++ b/app/helpers/gitlab_markdown_helper.rb @@ -110,6 +110,28 @@ module GitlabMarkdownHelper end end + # Returns the text necessary to reference `entity` across projects + # + # project - Project to reference + # entity - Object that responds to `to_reference` + # + # Examples: + # + # cross_project_reference(project, project.issues.first) + # # => 'namespace1/project1#123' + # + # cross_project_reference(project, project.merge_requests.first) + # # => 'namespace1/project1!345' + # + # Returns a String + def cross_project_reference(project, entity) + if entity.respond_to?(:to_reference) + entity.to_reference(project, full: true) + else + '' + end + end + private # Return +text+, truncated to +max_chars+ characters, excluding any HTML @@ -158,28 +180,6 @@ module GitlabMarkdownHelper end end - # Returns the text necessary to reference `entity` across projects - # - # project - Project to reference - # entity - Object that responds to `to_reference` - # - # Examples: - # - # cross_project_reference(project, project.issues.first) - # # => 'namespace1/project1#123' - # - # cross_project_reference(project, project.merge_requests.first) - # # => 'namespace1/project1!345' - # - # Returns a String - def cross_project_reference(project, entity) - if entity.respond_to?(:to_reference) - entity.to_reference(project) - else - '' - end - end - def markdown_toolbar_button(options = {}) data = options[:data].merge({ container: "body" }) content_tag :button, diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index a8a49e43b05..a2d21b67a77 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -58,13 +58,13 @@ module IssuesHelper end def status_box_class(item) - if item.respond_to?(:expired?) && item.expired? + if item.try(:expired?) 'status-box-expired' - elsif item.respond_to?(:merged?) && item.merged? + elsif item.try(:merged?) 'status-box-merged' elsif item.closed? 'status-box-closed' - elsif item.respond_to?(:upcoming?) && item.upcoming? + elsif item.try(:upcoming?) 'status-box-upcoming' else 'status-box-open' @@ -128,8 +128,10 @@ module IssuesHelper names.to_sentence end - def award_active_class(awards, current_user) - if current_user && awards.find { |a| a.user_id == current_user.id } + def award_state_class(awards, current_user) + if !current_user + "disabled" + elsif current_user && awards.find { |a| a.user_id == current_user.id } "active" else "" diff --git a/app/models/commit.rb b/app/models/commit.rb index 69cfc47f5bf..0b924b063a4 100644 --- a/app/models/commit.rb +++ b/app/models/commit.rb @@ -91,8 +91,8 @@ class Commit @link_reference_pattern ||= super("commit", /(?<commit>\h{7,40})/) end - def to_reference(from_project = nil) - commit_reference(from_project, id) + def to_reference(from_project = nil, full: false) + commit_reference(from_project, id, full: full) end def reference_link_text(from_project = nil) @@ -320,8 +320,8 @@ class Commit private - def commit_reference(from_project, referable_commit_id) - reference = project.to_reference(from_project) + def commit_reference(from_project, referable_commit_id, full: false) + reference = project.to_reference(from_project, full: full) if reference.present? "#{reference}#{self.class.reference_prefix}#{referable_commit_id}" diff --git a/app/models/commit_range.rb b/app/models/commit_range.rb index d9af7f6c139..84e2e8a5dd5 100644 --- a/app/models/commit_range.rb +++ b/app/models/commit_range.rb @@ -89,8 +89,8 @@ class CommitRange alias_method :id, :to_s - def to_reference(from_project = nil) - project_reference = project.to_reference(from_project) + def to_reference(from_project = nil, full: false) + project_reference = project.to_reference(from_project, full: full) if project_reference.present? project_reference + self.class.reference_prefix + self.id diff --git a/app/models/concerns/referable.rb b/app/models/concerns/referable.rb index 8ba009fe04f..da803c7f481 100644 --- a/app/models/concerns/referable.rb +++ b/app/models/concerns/referable.rb @@ -17,7 +17,7 @@ module Referable # Issue.last.to_reference(other_project) # => "cross-project#1" # # Returns a String - def to_reference(_from_project = nil) + def to_reference(_from_project = nil, full:) '' end diff --git a/app/models/external_issue.rb b/app/models/external_issue.rb index 91b508eb325..26712c19b5a 100644 --- a/app/models/external_issue.rb +++ b/app/models/external_issue.rb @@ -38,7 +38,7 @@ class ExternalIssue @reference_pattern ||= %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)} end - def to_reference(_from_project = nil) + def to_reference(_from_project = nil, full: nil) id end diff --git a/app/models/group.rb b/app/models/group.rb index 9888b242e98..99675ddb366 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -80,7 +80,7 @@ class Group < Namespace end end - def to_reference(_from_project = nil) + def to_reference(_from_project = nil, full: nil) "#{self.class.reference_prefix}#{name}" end diff --git a/app/models/group_label.rb b/app/models/group_label.rb index 68841ace2e6..92c83b54861 100644 --- a/app/models/group_label.rb +++ b/app/models/group_label.rb @@ -8,8 +8,4 @@ class GroupLabel < Label def subject_foreign_key 'group_id' end - - def to_reference(source_project = nil, target_project = nil, format: :id) - super(source_project, target_project, format: format) - end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 6825553512f..65638d9a299 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -97,10 +97,10 @@ class Issue < ActiveRecord::Base end end - def to_reference(from_project = nil) + def to_reference(from_project = nil, full: false) reference = "#{self.class.reference_prefix}#{iid}" - "#{project.to_reference(from_project)}#{reference}" + "#{project.to_reference(from_project, full: full)}#{reference}" end def referenced_merge_requests(current_user = nil) diff --git a/app/models/label.rb b/app/models/label.rb index d38c37344c9..5c01c15e5af 100644 --- a/app/models/label.rb +++ b/app/models/label.rb @@ -146,17 +146,17 @@ class Label < ActiveRecord::Base # # Label.first.to_reference # => "~1" # Label.first.to_reference(format: :name) # => "~\"bug\"" - # Label.first.to_reference(project, same_namespace_project) # => "gitlab-ce~1" - # Label.first.to_reference(project, another_namespace_project) # => "gitlab-org/gitlab-ce~1" + # Label.first.to_reference(project, target_project: same_namespace_project) # => "gitlab-ce~1" + # Label.first.to_reference(project, target_project: another_namespace_project) # => "gitlab-org/gitlab-ce~1" # # Returns a String # - def to_reference(source_project = nil, target_project = nil, format: :id) + def to_reference(from_project = nil, target_project: nil, format: :id, full: false) format_reference = label_format_reference(format) reference = "#{self.class.reference_prefix}#{format_reference}" - if source_project - "#{source_project.to_reference(target_project)}#{reference}" + if from_project + "#{from_project.to_reference(target_project, full: full)}#{reference}" else reference end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 61845bf4036..926944bc3b3 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -175,10 +175,10 @@ class MergeRequest < ActiveRecord::Base work_in_progress?(title) ? title : "WIP: #{title}" end - def to_reference(from_project = nil) + def to_reference(from_project = nil, full: false) reference = "#{self.class.reference_prefix}#{iid}" - "#{project.to_reference(from_project)}#{reference}" + "#{project.to_reference(from_project, full: full)}#{reference}" end def first_commit diff --git a/app/models/milestone.rb b/app/models/milestone.rb index 0dcfec89f14..8a11f47dd67 100644 --- a/app/models/milestone.rb +++ b/app/models/milestone.rb @@ -118,11 +118,11 @@ class Milestone < ActiveRecord::Base # Milestone.first.to_reference(cross_namespace_project) # => "gitlab-org/gitlab-ce%1" # Milestone.first.to_reference(same_namespace_project) # => "gitlab-ce%1" # - def to_reference(from_project = nil, format: :iid) + def to_reference(from_project = nil, format: :iid, full: false) format_reference = milestone_format_reference(format) reference = "#{self.class.reference_prefix}#{format_reference}" - "#{project.to_reference(from_project)}#{reference}" + "#{project.to_reference(from_project, full: full)}#{reference}" end def reference_link_text(from_project = nil) diff --git a/app/models/project.rb b/app/models/project.rb index e0ffa7e7af7..ec40def6fb1 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -589,8 +589,8 @@ class Project < ActiveRecord::Base end end - def to_reference(from_project = nil) - if cross_namespace_reference?(from_project) + def to_reference(from_project = nil, full: false) + if full || cross_namespace_reference?(from_project) path_with_namespace elsif cross_project_reference?(from_project) path @@ -609,10 +609,6 @@ class Project < ActiveRecord::Base Gitlab::Routing.url_helpers.namespace_project_url(self.namespace, self) end - def web_url_without_protocol - web_url.split('://')[1] - end - def new_issue_address(author) return unless Gitlab::IncomingEmail.supports_issue_creation? && author diff --git a/app/models/project_label.rb b/app/models/project_label.rb index 82f47f0e8fd..313815e5869 100644 --- a/app/models/project_label.rb +++ b/app/models/project_label.rb @@ -16,8 +16,8 @@ class ProjectLabel < Label 'project_id' end - def to_reference(target_project = nil, format: :id) - super(project, target_project, format: format) + def to_reference(target_project = nil, format: :id, full: false) + super(project, target_project: target_project, format: format, full: full) end private diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 98ccf5f331f..771a7350556 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -64,11 +64,11 @@ class Snippet < ActiveRecord::Base @link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/) end - def to_reference(from_project = nil) + def to_reference(from_project = nil, full: false) reference = "#{self.class.reference_prefix}#{id}" if project.present? - "#{project.to_reference(from_project)}#{reference}" + "#{project.to_reference(from_project, full: full)}#{reference}" else reference end diff --git a/app/models/user.rb b/app/models/user.rb index 899a89a4eaa..66a768d54bb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -99,6 +99,7 @@ class User < ActiveRecord::Base # # Note: devise :validatable above adds validations for :email and :password validates :name, presence: true + validates_confirmation_of :email validates :notification_email, presence: true validates :notification_email, email: true, if: ->(user) { user.notification_email != user.email } validates :public_email, presence: true, uniqueness: true, email: true, allow_blank: true @@ -332,7 +333,7 @@ class User < ActiveRecord::Base username end - def to_reference(_from_project = nil, _target_project = nil) + def to_reference(_from_project = nil, target_project: nil, full: nil) "#{self.class.reference_prefix}#{username}" end diff --git a/app/uploaders/avatar_uploader.rb b/app/uploaders/avatar_uploader.rb index a1ecb7bc00b..265cea2d2c6 100644 --- a/app/uploaders/avatar_uploader.rb +++ b/app/uploaders/avatar_uploader.rb @@ -10,4 +10,15 @@ class AvatarUploader < GitlabUploader def exists? model.avatar.file && model.avatar.file.exists? end + + # We set move_to_store and move_to_cache to 'false' to prevent stealing + # the avatar file from a project when forking it. + # https://gitlab.com/gitlab-org/gitlab-ce/issues/26158 + def move_to_store + false + end + + def move_to_cache + false + end end diff --git a/app/views/award_emoji/_awards_block.html.haml b/app/views/award_emoji/_awards_block.html.haml index d8912eda314..e3305e21e96 100644 --- a/app/views/award_emoji/_awards_block.html.haml +++ b/app/views/award_emoji/_awards_block.html.haml @@ -2,8 +2,7 @@ .awards.js-awards-block{ class: ("hidden" if !inline && grouped_emojis.empty?), data: { award_url: toggle_award_url(awardable) } } - awards_sort(grouped_emojis).each do |emoji, awards| %button.btn.award-control.js-emoji-btn.has-tooltip{ type: "button", - disabled: !current_user, - class: (award_active_class(awards, current_user)), + class: (award_state_class(awards, current_user)), data: { placement: "bottom", title: award_user_list(awards, current_user) } } = emoji_icon(emoji, sprite: false) %span.award-control-text.js-counter diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 545a938f4be..681eb303b49 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -15,6 +15,9 @@ .form-group = f.label :email = f.email_field :email, class: "form-control middle", required: true, title: "Please provide a valid email address." + %div.form-group + = f.label :email_confirmation + = f.email_field :email_confirmation, class: "form-control middle", required: true, title: "Please retype the email address." .form-group.append-bottom-20#password-strength = f.label :password = f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters." diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml index 350bdf5f836..f75f438ee4f 100644 --- a/app/views/projects/blob/_blob.html.haml +++ b/app/views/projects/blob/_blob.html.haml @@ -18,7 +18,7 @@ - else = link_to title, '#' -%ul.blob-commit-info.hidden-xs +%ul.blob-commit-info.table-list.hidden-xs - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path) = render blob_commit, project: @project, ref: @ref diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml index a940515fadf..3c6c50dce3c 100644 --- a/app/views/projects/commits/_commit.html.haml +++ b/app/views/projects/commits/_commit.html.haml @@ -9,33 +9,33 @@ - cache_key.push(commit.status(ref)) if commit.status(ref) = cache(cache_key, expires_in: 1.day) do - %li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" } - = author_avatar(commit, size: 36) + %li.commit.table-list-row.js-toggle-container{ id: "commit-#{commit.short_id}" } - .commit-info-block - .commit-row-title - %span.item-title - = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message" - %span.commit-row-message.visible-xs-inline - · - = commit.short_id - - if commit.status(ref) - .visible-xs-inline - = render_commit_status(commit, ref: ref) - - if commit.description? - %a.text-expander.hidden-xs.js-toggle-button ... + .table-list-cell.avatar-cell.hidden-xs + = author_avatar(commit, size: 36) - .commit-actions.hidden-xs - - if commit.status(ref) - = render_commit_status(commit, ref: ref) - = clipboard_button(clipboard_text: commit.id) - = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent" - = link_to_browse_code(project, commit) + .table-list-cell.commit-content + = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message item-title" + %span.commit-row-message.visible-xs-inline + · + = commit.short_id + - if commit.status(ref) + .visible-xs-inline + = render_commit_status(commit, ref: ref) + - if commit.description? + %a.text-expander.hidden-xs.js-toggle-button ... - if commit.description? %pre.commit-row-description.js-toggle-content = preserve(markdown(commit.description, pipeline: :single_line, author: commit.author)) + .commiter + = commit_author_link(commit, avatar: false, size: 24) + committed + #{time_ago_with_tooltip(commit.committed_date)} - = commit_author_link(commit, avatar: false, size: 24) - committed - #{time_ago_with_tooltip(commit.committed_date)} + .table-list-cell.commit-actions.hidden-xs + - if commit.status(ref) + = render_commit_status(commit, ref: ref) + = clipboard_button(clipboard_text: commit.id) + = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent" + = link_to_browse_code(project, commit) diff --git a/app/views/projects/commits/_commit_list.html.haml b/app/views/projects/commits/_commit_list.html.haml index 6f5835cb9be..64d93e4141c 100644 --- a/app/views/projects/commits/_commit_list.html.haml +++ b/app/views/projects/commits/_commit_list.html.haml @@ -11,4 +11,4 @@ %li.warning-row.unstyled #{number_with_delimiter(hidden)} additional commits have been omitted to prevent performance issues. - else - %ul.content-list= render commits, project: @project, ref: @ref + %ul.content-list.table-list= render commits, project: @project, ref: @ref diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml index 48756c68941..fcc367951ad 100644 --- a/app/views/projects/commits/_commits.html.haml +++ b/app/views/projects/commits/_commits.html.haml @@ -4,7 +4,7 @@ - commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits| %li.commit-header= "#{day.strftime('%d %b, %Y')} #{pluralize(commits.count, 'commit')}" %li.commits-row - %ul.list-unstyled.commit-list + %ul.content-list.commit-list.table-list.table-wide = render commits, project: project, ref: ref - if hidden > 0 diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml index 7bde20c3286..d76d48187cd 100644 --- a/app/views/projects/compare/_form.html.haml +++ b/app/views/projects/compare/_form.html.haml @@ -2,21 +2,21 @@ .clearfix - if params[:to] && params[:from] .compare-switch-container - = link_to icon('exchange'), {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has-tooltip', title: 'Switch base of comparison'} + = link_to icon('exchange'), {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has-tooltip btn btn-white', title: 'Switch base of comparison'} .form-group.dropdown.compare-form-group.from.js-compare-from-dropdown .input-group.inline-input-group %span.input-group-addon from = hidden_field_tag :from, params[:from] - = button_tag type: 'button', class: "form-control compare-dropdown-toggle js-compare-dropdown", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do - .dropdown-toggle-text= params[:from] || 'Select branch/tag' + = button_tag type: 'button', title: params[:from], class: "form-control compare-dropdown-toggle js-compare-dropdown has-tooltip", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-from-dropdown", selected: params[:from], field_name: :from } do + .dropdown-toggle-text.str-truncated= params[:from] || 'Select branch/tag' = render "ref_dropdown" .compare-ellipsis.inline ... .form-group.dropdown.compare-form-group.to.js-compare-to-dropdown .input-group.inline-input-group %span.input-group-addon to = hidden_field_tag :to, params[:to] - = button_tag type: 'button', class: "form-control compare-dropdown-toggle js-compare-dropdown", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to], field_name: :to } do - .dropdown-toggle-text= params[:to] || 'Select branch/tag' + = button_tag type: 'button', title: params[:to], class: "form-control compare-dropdown-toggle js-compare-dropdown has-tooltip", required: true, data: { refs_url: refs_namespace_project_path(@project.namespace, @project), toggle: "dropdown", target: ".js-compare-to-dropdown", selected: params[:to], field_name: :to } do + .dropdown-toggle-text.str-truncated= params[:to] || 'Select branch/tag' = render "ref_dropdown" = button_tag "Compare", class: "btn btn-create commits-compare-btn" diff --git a/app/views/projects/cycle_analytics/_empty_stage.html.haml b/app/views/projects/cycle_analytics/_empty_stage.html.haml index b200ce22970..c3f95860e92 100644 --- a/app/views/projects/cycle_analytics/_empty_stage.html.haml +++ b/app/views/projects/cycle_analytics/_empty_stage.html.haml @@ -2,6 +2,6 @@ .empty-stage .icon-no-data = custom_icon ('icon_no_data') - %h4 We don’t have enough data to show this stage. + %h4 We don't have enough data to show this stage. %p {{currentStage.emptyStageText}} diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index 89e2e162b5b..479ce44f378 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -28,8 +28,8 @@ .container-fluid .row .col-sm-3.col-xs-12.column{ "v-for" => "item in state.summary" } - %h3.header {{item.value}} - %p.text {{item.title}} + %h3.header {{ item.value }} + %p.text {{ item.title }} .col-sm-3.col-xs-12.column .dropdown.inline.js-ca-dropdown %button.dropdown-menu-toggle{ "data-toggle" => "dropdown", :type => "button" } diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 633701c6f40..d9a3220b002 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -42,7 +42,7 @@ = render "projects/merge_requests/widget/show.html.haml" - if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user) - .merge-manually.light.prepend-top-default.append-bottom-default + .merge-manually.light.prepend-top-default You can also accept this merge request manually using the = succeed '.' do = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" diff --git a/app/views/projects/merge_requests/show/_versions.html.haml b/app/views/projects/merge_requests/show/_versions.html.haml index ac4a03220b9..b0f3c86fd21 100644 --- a/app/views/projects/merge_requests/show/_versions.html.haml +++ b/app/views/projects/merge_requests/show/_versions.html.haml @@ -19,7 +19,7 @@ %ul - @merge_request_diffs.each do |merge_request_diff| %li - = link_to merge_request_version_path(@project, @merge_request, merge_request_diff), class: ('is-active' if merge_request_diff == @merge_request_diff) do + = link_to merge_request_version_path(@project, @merge_request, merge_request_diff, @start_sha), class: ('is-active' if merge_request_diff == @merge_request_diff) do %strong - if merge_request_diff.latest? latest version diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml index c45052e3954..6d7c2defe2b 100644 --- a/app/views/projects/services/slack_slash_commands/_help.html.haml +++ b/app/views/projects/services/slack_slash_commands/_help.html.haml @@ -50,7 +50,7 @@ .form-group = label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label' .col-sm-10.col-xs-12.text-block - = image_tag(asset_url('gitlab_logo.png'), width: 36, height: 36) + = image_tag(asset_url('slash-command-logo.png'), width: 36, height: 36) = link_to('Download image', asset_url('gitlab_logo.png'), class: 'btn btn-sm', target: '_blank') .form-group diff --git a/changelogs/unreleased/25580-trucate-dropdown-for-long-branch.yml b/changelogs/unreleased/25580-trucate-dropdown-for-long-branch.yml new file mode 100644 index 00000000000..18d3ac050ae --- /dev/null +++ b/changelogs/unreleased/25580-trucate-dropdown-for-long-branch.yml @@ -0,0 +1,4 @@ +--- +title: Resolves overflow in compare branch and tags dropdown +merge_request: 8118 +author: diff --git a/changelogs/unreleased/add_email_password_confirmation.yml b/changelogs/unreleased/add_email_password_confirmation.yml new file mode 100644 index 00000000000..92f9b9b7a6d --- /dev/null +++ b/changelogs/unreleased/add_email_password_confirmation.yml @@ -0,0 +1,4 @@ +--- +title: Add email confirmation field to registration form +merge_request: 7432 +author: diff --git a/changelogs/unreleased/additional-award-emoji-repositioning-fixes.yml b/changelogs/unreleased/additional-award-emoji-repositioning-fixes.yml new file mode 100644 index 00000000000..8d5a94c3aa8 --- /dev/null +++ b/changelogs/unreleased/additional-award-emoji-repositioning-fixes.yml @@ -0,0 +1,4 @@ +--- +title: Removed bottom padding from merge manually from CLI because of repositioning award emoji's +merge_request: +author: diff --git a/changelogs/unreleased/api-hooks-changelog-entry.yml b/changelogs/unreleased/api-hooks-changelog-entry.yml new file mode 100644 index 00000000000..7d0b515ddf1 --- /dev/null +++ b/changelogs/unreleased/api-hooks-changelog-entry.yml @@ -0,0 +1,4 @@ +--- +title: Rename wiki_events to wiki_page_events in project hooks API to avoid errors +merge_request: Robert Schilling +author: 8425 diff --git a/changelogs/unreleased/fix-cross-project-ref-path.yml b/changelogs/unreleased/fix-cross-project-ref-path.yml new file mode 100644 index 00000000000..91acc1db0a6 --- /dev/null +++ b/changelogs/unreleased/fix-cross-project-ref-path.yml @@ -0,0 +1,4 @@ +--- +title: Fix cross-project references copy to include the project reference +merge_request: +author: diff --git a/changelogs/unreleased/ldap_person_attributes.yml b/changelogs/unreleased/ldap_person_attributes.yml new file mode 100644 index 00000000000..d04b5dbe7e0 --- /dev/null +++ b/changelogs/unreleased/ldap_person_attributes.yml @@ -0,0 +1,4 @@ +--- +title: Gitlab::LDAP::Person uses LDAP attributes configuration +merge_request: 8418 +author: diff --git a/changelogs/unreleased/project-avatar-fork.yml b/changelogs/unreleased/project-avatar-fork.yml new file mode 100644 index 00000000000..6facffe7887 --- /dev/null +++ b/changelogs/unreleased/project-avatar-fork.yml @@ -0,0 +1,4 @@ +--- +title: Copy, don't move uploaded avatar files +merge_request: 8396 +author: diff --git a/changelogs/unreleased/recaptcha_500.yml b/changelogs/unreleased/recaptcha_500.yml new file mode 100644 index 00000000000..de9ef183d5e --- /dev/null +++ b/changelogs/unreleased/recaptcha_500.yml @@ -0,0 +1,4 @@ +--- +title: Properly handle failed reCAPTCHA on user registration +merge_request: 8403 +author: diff --git a/changelogs/unreleased/regression-note-headline-light.yml b/changelogs/unreleased/regression-note-headline-light.yml new file mode 100644 index 00000000000..f24d4cb014c --- /dev/null +++ b/changelogs/unreleased/regression-note-headline-light.yml @@ -0,0 +1,4 @@ +--- +title: Fixed regression of note-headline-light where it was always placed on 2 lines, even on wide viewports +merge_request: +author: diff --git a/doc/development/changelog.md b/doc/development/changelog.md index 6a97fae9cac..c71858c6a24 100644 --- a/doc/development/changelog.md +++ b/doc/development/changelog.md @@ -40,6 +40,15 @@ Its simplest usage is to provide the value for `title`: ```text $ bin/changelog 'Hey DZ, I added a feature to GitLab!' +``` + +The entry filename is based on the name of the current Git branch. If you run +the command above on a branch called `feature/hey-dz`, it will generate a +`changelogs/unreleased/feature-hey-dz.yml` file. + +The command will output the path of the generated file and its contents: + +```text create changelogs/unreleased/my-feature.yml --- title: Hey DZ, I added a feature to GitLab! @@ -47,10 +56,6 @@ merge_request: author: ``` -The entry filename is based on the name of the current Git branch. If you run -the command above on a branch called `feature/hey-dz`, it will generate a -`changelogs/unreleased/feature-hey-dz.yml` file. - ### Arguments | Argument | Shorthand | Purpose | @@ -139,7 +144,7 @@ Use the **`--git-username`** or **`-u`** argument to automatically fill in the $ git config user.name Jane Doe -$ bin/changelog --u 'Hey DZ, I added a feature to GitLab!' +$ bin/changelog -u 'Hey DZ, I added a feature to GitLab!' create changelogs/unreleased/feature-hey-dz.yml --- title: Hey DZ, I added a feature to GitLab! diff --git a/lib/api/issues.rb b/lib/api/issues.rb index 91f65882f47..54b97402426 100644 --- a/lib/api/issues.rb +++ b/lib/api/issues.rb @@ -5,28 +5,18 @@ module API before { authenticate! } helpers do - def filter_issues_state(issues, state) - case state - when 'opened' then issues.opened - when 'closed' then issues.closed - else issues - end - end - + # TODO: Remove in 9.0 and switch to IssueFinder-based label filtering def filter_issues_labels(issues, labels) issues.includes(:labels).where('labels.title' => labels.split(',')) end - def filter_issues_milestone(issues, milestone) - issues.includes(:milestone).where('milestones.title' => milestone) - end - params :issues_params do optional :labels, type: String, desc: 'Comma-separated list of label names' optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at', desc: 'Return issues ordered by `created_at` or `updated_at` fields.' optional :sort, type: String, values: %w[asc desc], default: 'desc', desc: 'Return issues sorted in `asc` or `desc` order.' + optional :milestone, type: String, desc: 'Return issues for a specific milestone' use :pagination end @@ -50,8 +40,7 @@ module API use :issues_params end get do - issues = current_user.issues.inc_notes_with_associations - issues = filter_issues_state(issues, params[:state]) + issues = IssuesFinder.new(current_user, scope: 'all', author_id: current_user.id, state: params[:state]).execute.inc_notes_with_associations issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = issues.reorder(params[:order_by] => params[:sort]) @@ -99,16 +88,14 @@ module API use :issues_params end get ":id/issues" do - issues = IssuesFinder.new(current_user, project_id: user_project.id).execute.inc_notes_with_associations - issues = filter_issues_state(issues, params[:state]) + issues = IssuesFinder.new(current_user, + project_id: user_project.id, + state: params[:state], + milestone_title: params[:milestone]).execute.inc_notes_with_associations issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil? - - unless params[:milestone].nil? - issues = filter_issues_milestone(issues, params[:milestone]) - end - issues = issues.reorder(params[:order_by] => params[:sort]) + present paginate(issues), with: Entities::Issue, current_user: current_user, project: user_project end diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb index dcc0fb7a911..cb679e6658a 100644 --- a/lib/api/project_hooks.rb +++ b/lib/api/project_hooks.rb @@ -15,7 +15,7 @@ module API optional :note_events, type: Boolean, desc: "Trigger hook on note(comment) events" optional :build_events, type: Boolean, desc: "Trigger hook on build events" optional :pipeline_events, type: Boolean, desc: "Trigger hook on pipeline events" - optional :wiki_events, type: Boolean, desc: "Trigger hook on wiki events" + optional :wiki_page_events, type: Boolean, desc: "Trigger hook on wiki events" optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook" optional :token, type: String, desc: "Secret token to validate received payloads; this will not be returned in the response" end diff --git a/lib/api/users.rb b/lib/api/users.rb index 4c22287b5c6..de07fbf59fc 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -16,7 +16,7 @@ module API optional :website_url, type: String, desc: 'The website of the user' optional :organization, type: String, desc: 'The organization of the user' optional :projects_limit, type: Integer, desc: 'The number of projects a user can create' - optional :extern_uid, type: Integer, desc: 'The external authentication provider UID' + optional :extern_uid, type: String, desc: 'The external authentication provider UID' optional :provider, type: String, desc: 'The external provider' optional :bio, type: String, desc: 'The biography of the user' optional :location, type: String, desc: 'The location of the user' diff --git a/lib/gitlab/chat_commands/deploy.rb b/lib/gitlab/chat_commands/deploy.rb index 0f70323810d..7127d2f6d04 100644 --- a/lib/gitlab/chat_commands/deploy.rb +++ b/lib/gitlab/chat_commands/deploy.rb @@ -49,9 +49,9 @@ module Gitlab end def url(subject) - project = subject.project - - namespace_project_build_url(project.namespace.becomes(Namespace), project, subject) + polymorphic_url( + [subject.project.namespace.becomes(Namespace), subject.project, subject] + ) end end end diff --git a/lib/gitlab/gfm/reference_rewriter.rb b/lib/gitlab/gfm/reference_rewriter.rb index a7c596dced0..b984492d369 100644 --- a/lib/gitlab/gfm/reference_rewriter.rb +++ b/lib/gitlab/gfm/reference_rewriter.rb @@ -76,7 +76,7 @@ module Gitlab if referable.respond_to?(:project) referable.to_reference(target_project) else - referable.to_reference(@source_project, target_project) + referable.to_reference(@source_project, target_project: target_project) end end diff --git a/lib/gitlab/ldap/person.rb b/lib/gitlab/ldap/person.rb index b81f3e8e8f5..333f170a484 100644 --- a/lib/gitlab/ldap/person.rb +++ b/lib/gitlab/ldap/person.rb @@ -28,7 +28,7 @@ module Gitlab end def name - entry.cn.first + attribute_value(:name) end def uid @@ -40,7 +40,7 @@ module Gitlab end def email - entry.try(:mail) + attribute_value(:email) end def dn @@ -56,6 +56,21 @@ module Gitlab def config @config ||= Gitlab::LDAP::Config.new(provider) end + + # Using the LDAP attributes configuration, find and return the first + # attribute with a value. For example, by default, when given 'email', + # this method looks for 'mail', 'email' and 'userPrincipalName' and + # returns the first with a value. + def attribute_value(attribute) + attributes = Array(config.attributes[attribute.to_sym]) + selected_attr = attributes.find { |attr| entry.respond_to?(attr) } + + return nil unless selected_attr + + # Some LDAP attributes return an array, + # even if it is a single value (like 'cn') + Array(entry.public_send(selected_attr)).first + end end end end diff --git a/public/slash-command-logo.png b/public/slash-command-logo.png Binary files differnew file mode 100644 index 00000000000..05c8b0d0ccf --- /dev/null +++ b/public/slash-command-logo.png diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 026f41c926b..42fbfe89368 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -2,30 +2,60 @@ require 'spec_helper' describe RegistrationsController do describe '#create' do - around(:each) do |example| - perform_enqueued_jobs do - example.run + let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } } + + context 'email confirmation' do + around(:each) do |example| + perform_enqueued_jobs do + example.run + end end - end - let(:user_params) { { user: { name: "new_user", username: "new_username", email: "new@user.com", password: "Any_password" } } } + context 'when send_user_confirmation_email is false' do + it 'signs the user in' do + allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(false) + + expect { post(:create, user_params) }.not_to change{ ActionMailer::Base.deliveries.size } + expect(subject.current_user).not_to be_nil + end + end - context 'when sending email confirmation' do - before { allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(false) } + context 'when send_user_confirmation_email is true' do + it 'does not authenticate user and sends confirmation email' do + allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true) - it 'logs user in directly' do - expect { post(:create, user_params) }.not_to change{ ActionMailer::Base.deliveries.size } - expect(subject.current_user).not_to be_nil + post(:create, user_params) + + expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email]) + expect(subject.current_user).to be_nil + end end end - context 'when not sending email confirmation' do - before { allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true) } + context 'when reCAPTCHA is enabled' do + before do + stub_application_setting(recaptcha_enabled: true) + end + + it 'displays an error when the reCAPTCHA is not solved' do + # Without this, `verify_recaptcha` arbitraily returns true in test env + Recaptcha.configuration.skip_verify_env.delete('test') - it 'does not authenticate user and sends confirmation email' do post(:create, user_params) - expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email]) - expect(subject.current_user).to be_nil + + expect(response).to render_template(:new) + expect(flash[:alert]).to include 'There was an error with the reCAPTCHA. Please re-solve the reCAPTCHA.' + end + + it 'redirects to the dashboard when the recaptcha is solved' do + # Avoid test ordering issue and ensure `verify_recaptcha` returns true + unless Recaptcha.configuration.skip_verify_env.include?('test') + Recaptcha.configuration.skip_verify_env << 'test' + end + + post(:create, user_params) + + expect(flash[:notice]).to include 'Welcome! You have signed up successfully.' end end end diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb new file mode 100644 index 00000000000..e48a2b0c92e --- /dev/null +++ b/spec/features/cycle_analytics_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +feature 'Cycle Analytics', feature: true, js: true do + include WaitForAjax + + let(:project) { create(:project) } + let(:user) { create(:user) } + let(:guest) { create(:user) } + let(:project) { create(:project) } + let(:issue) { create(:issue, project: project, created_at: 2.days.ago) } + let(:milestone) { create(:milestone, project: project) } + let(:mr) { create_merge_request_closing_issue(issue) } + let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr.source_branch, sha: mr.source_branch_sha) } + + context 'as an allowed user' do + context 'when project is new' do + before do + project.team << [user, :master] + login_as(user) + visit namespace_project_cycle_analytics_path(project.namespace, project) + wait_for_ajax + end + + it 'shows introductory message' do + expect(page).to have_content('Introducing Cycle Analytics') + end + + it 'shows active stage with empty message' do + expect(page).to have_selector('.stage-nav-item.active', text: 'Issue') + expect(page).to have_content("We don't have enough data to show this stage.") + end + end + + context "when there's cycle analytics data" do + before do + project.team << [user, :master] + + allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue]) + create_cycle + deploy_master + + login_as(user) + visit namespace_project_cycle_analytics_path(project.namespace, project) + end + + it 'shows data on each stage' do + expect_issue_to_be_present + + click_stage('Plan') + expect(find('.stage-events')).to have_content(mr.commits.last.title) + + click_stage('Code') + expect_merge_request_to_be_present + + click_stage('Test') + expect_build_to_be_present + + click_stage('Review') + expect_merge_request_to_be_present + + click_stage('Staging') + expect_build_to_be_present + + click_stage('Production') + expect_issue_to_be_present + end + end + end + + context "as a guest" do + before do + project.team << [guest, :guest] + + allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue]) + create_cycle + deploy_master + + login_as(guest) + visit namespace_project_cycle_analytics_path(project.namespace, project) + wait_for_ajax + end + + it 'needs permissions to see restricted stages' do + expect(find('.stage-events')).to have_content(issue.title) + + click_stage('Code') + expect(find('.stage-events')).to have_content('You need permission.') + + click_stage('Review') + expect(find('.stage-events')).to have_content('You need permission.') + end + end + + def expect_issue_to_be_present + expect(find('.stage-events')).to have_content(issue.title) + expect(find('.stage-events')).to have_content(issue.author.name) + expect(find('.stage-events')).to have_content("##{issue.iid}") + end + + def expect_build_to_be_present + expect(find('.stage-events')).to have_content(@build.ref) + expect(find('.stage-events')).to have_content(@build.short_sha) + expect(find('.stage-events')).to have_content("##{@build.id}") + end + + def expect_merge_request_to_be_present + expect(find('.stage-events')).to have_content(mr.title) + expect(find('.stage-events')).to have_content(mr.author.name) + expect(find('.stage-events')).to have_content("!#{mr.iid}") + end + + def create_cycle + issue.update(milestone: milestone) + pipeline.run + + @build = create(:ci_build, pipeline: pipeline, status: :success, author: user) + + merge_merge_requests_closing_issue(issue) + ProcessCommitWorker.new.perform(project.id, user.id, mr.commits.last.to_hash) + end + + def click_stage(stage_name) + find('.stage-nav li', text: stage_name).click + wait_for_ajax + end +end diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index efb53026449..73e43316dc7 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -76,7 +76,7 @@ describe 'Awards Emoji', feature: true do end it 'has disabled emoji button' do - expect(first('.award-control')[:disabled]).to be(true) + expect(first('.award-control')[:class]).to have_text('disabled') end end diff --git a/spec/features/merge_requests/merge_request_versions_spec.rb b/spec/features/merge_requests/merge_request_versions_spec.rb index cd2272dd38f..04e85ed3f73 100644 --- a/spec/features/merge_requests/merge_request_versions_spec.rb +++ b/spec/features/merge_requests/merge_request_versions_spec.rb @@ -81,4 +81,52 @@ feature 'Merge Request versions', js: true, feature: true do expect(page).to have_content '8 changed files' end end + + describe 'compare with same version' do + before do + page.within '.mr-version-compare-dropdown' do + find('.btn-default').click + click_link 'version 1' + end + end + + it 'should have 0 chages between versions' do + page.within '.mr-version-compare-dropdown' do + expect(page).to have_content 'version 1' + end + + page.within '.mr-version-dropdown' do + find('.btn-default').click + find(:link, 'version 1').trigger('click') + end + + expect(page).to have_content '0 changed files' + end + end + + describe 'compare with newer version' do + before do + page.within '.mr-version-compare-dropdown' do + find('.btn-default').click + click_link 'version 2' + end + end + + it 'should set the compared versions to be the same' do + page.within '.mr-version-compare-dropdown' do + expect(page).to have_content 'version 2' + end + + page.within '.mr-version-dropdown' do + find('.btn-default').click + find(:link, 'version 1').trigger('click') + end + + page.within '.mr-version-compare-dropdown' do + expect(page).to have_content 'version 1' + end + + expect(page).to have_content '0 changed files' + end + end end diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 274d50e7ce4..8de827447ff 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -49,4 +49,10 @@ feature 'Setup Mattermost slash commands', feature: true do end end end + + describe 'stable logo url' do + it 'shows a publicly available logo' do + expect(File.exist?(Rails.root.join('public/slash-command-logo.png'))) + end + end end diff --git a/spec/features/signup_spec.rb b/spec/features/signup_spec.rb index 65544f79eba..9fde8d6e5cf 100644 --- a/spec/features/signup_spec.rb +++ b/spec/features/signup_spec.rb @@ -10,10 +10,11 @@ feature 'Signup', feature: true do visit root_path - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: user.email - fill_in 'new_user_password', with: user.password + fill_in 'new_user_name', with: user.name + fill_in 'new_user_username', with: user.username + fill_in 'new_user_email', with: user.email + fill_in 'new_user_email_confirmation', with: user.email + fill_in 'new_user_password', with: user.password click_button "Register" expect(current_path).to eq users_almost_there_path @@ -29,10 +30,11 @@ feature 'Signup', feature: true do visit root_path - fill_in 'new_user_name', with: user.name - fill_in 'new_user_username', with: user.username - fill_in 'new_user_email', with: user.email - fill_in 'new_user_password', with: user.password + fill_in 'new_user_name', with: user.name + fill_in 'new_user_username', with: user.username + fill_in 'new_user_email', with: user.email + fill_in 'new_user_email_confirmation', with: user.email + fill_in 'new_user_password', with: user.password click_button "Register" expect(current_path).to eq dashboard_projects_path @@ -55,8 +57,9 @@ feature 'Signup', feature: true do click_button "Register" expect(current_path).to eq user_registration_path - expect(page).to have_content("error prohibited this user from being saved") + expect(page).to have_content("errors prohibited this user from being saved") expect(page).to have_content("Email has already been taken") + expect(page).to have_content("Email confirmation doesn't match") end it 'does not redisplay the password' do diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index afa98f3f715..2de0fbe7ab2 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -6,10 +6,11 @@ feature 'Users', feature: true, js: true do scenario 'GET /users/sign_in creates a new user account' do visit new_user_session_path click_link 'Register' - fill_in 'new_user_name', with: 'Name Surname' - fill_in 'new_user_username', with: 'Great' - fill_in 'new_user_email', with: 'name@mail.com' - fill_in 'new_user_password', with: 'password1234' + fill_in 'new_user_name', with: 'Name Surname' + fill_in 'new_user_username', with: 'Great' + fill_in 'new_user_email', with: 'name@mail.com' + fill_in 'new_user_email_confirmation', with: 'name@mail.com' + fill_in 'new_user_password', with: 'password1234' expect { click_button 'Register' }.to change { User.count }.by(1) end @@ -33,10 +34,11 @@ feature 'Users', feature: true, js: true do scenario 'Should show one error if email is already taken' do visit new_user_session_path click_link 'Register' - fill_in 'new_user_name', with: 'Another user name' - fill_in 'new_user_username', with: 'anotheruser' - fill_in 'new_user_email', with: user.email - fill_in 'new_user_password', with: '12341234' + fill_in 'new_user_name', with: 'Another user name' + fill_in 'new_user_username', with: 'anotheruser' + fill_in 'new_user_email', with: user.email + fill_in 'new_user_email_confirmation', with: user.email + fill_in 'new_user_password', with: '12341234' expect { click_button 'Register' }.to change { User.count }.by(0) expect(page).to have_text('Email has already been taken') expect(number_of_errors_on_page(page)).to be(1), 'errors on page:\n #{errors_on_page page}' diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 1d494edcd3b..810311e2b1a 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -170,4 +170,14 @@ describe GitlabMarkdownHelper do expect(doc.content).to eq "@#{user.username}, can you look at this?..." end end + + describe '#cross_project_reference' do + it 'shows the full MR reference' do + expect(helper.cross_project_reference(project, merge_request)).to include(project.path_with_namespace) + end + + it 'shows the full issue reference' do + expect(helper.cross_project_reference(project, issue)).to include(project.path_with_namespace) + end + end end diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index abe08d95ece..9c7e0ee2fe0 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -98,15 +98,15 @@ describe IssuesHelper do end end - describe '#award_active_class' do + describe '#award_state_class' do let!(:upvote) { create(:award_emoji) } - it "returns empty string for unauthenticated user" do - expect(award_active_class(AwardEmoji.all, nil)).to eq("") + it "returns disabled string for unauthenticated user" do + expect(award_state_class(AwardEmoji.all, nil)).to eq("disabled") end it "returns active string for author" do - expect(award_active_class(AwardEmoji.all, upvote.user)).to eq("active") + expect(award_state_class(AwardEmoji.all, upvote.user)).to eq("active") end end diff --git a/spec/lib/gitlab/ldap/person_spec.rb b/spec/lib/gitlab/ldap/person_spec.rb new file mode 100644 index 00000000000..60afe046788 --- /dev/null +++ b/spec/lib/gitlab/ldap/person_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe Gitlab::LDAP::Person do + include LdapHelpers + + let(:entry) { ldap_user_entry('john.doe') } + + before do + stub_ldap_config( + attributes: { + name: 'cn', + email: %w(mail email userPrincipalName) + } + ) + end + + describe '#name' do + it 'uses the configured name attribute and handles values as an array' do + name = 'John Doe' + entry['cn'] = [name] + person = Gitlab::LDAP::Person.new(entry, 'ldapmain') + + expect(person.name).to eq(name) + end + end + + describe '#email' do + it 'returns the value of mail, if present' do + mail = 'john@example.com' + entry['mail'] = mail + person = Gitlab::LDAP::Person.new(entry, 'ldapmain') + + expect(person.email).to eq(mail) + end + + it 'returns the value of userPrincipalName, if mail and email are not present' do + user_principal_name = 'john.doe@example.com' + entry['userPrincipalName'] = user_principal_name + person = Gitlab::LDAP::Person.new(entry, 'ldapmain') + + expect(person.email).to eq(user_principal_name) + end + end +end diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb index 668aa6fb357..555a876daeb 100644 --- a/spec/models/group_label_spec.rb +++ b/spec/models/group_label_spec.rb @@ -43,7 +43,7 @@ describe GroupLabel, models: true do let(:target_project) { build_stubbed(:empty_project, name: 'project-2', namespace: namespace) } it 'returns a String reference to the object' do - expect(label.to_reference(source_project, target_project)).to eq %(project-1~#{label.id}) + expect(label.to_reference(source_project, target_project: target_project)).to eq %(project-1~#{label.id}) end end diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index bb56e44db29..bfa36d92ac3 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -30,6 +30,10 @@ describe Issue, models: true do expect(issue.to_reference).to eq "#1" end + it 'returns a String reference with the full path' do + expect(issue.to_reference(full: true)).to eq(project.path_with_namespace + '#1') + end + it 'supports a cross-project reference' do another_project = build(:project, name: 'another-project', namespace: project.namespace) expect(issue.to_reference(another_project)).to eq "sample-project#1" diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 646e6c6dbb3..8d1385016fd 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -153,6 +153,10 @@ describe MergeRequest, models: true do another_project = build(:project, name: 'another-project', namespace: project.namespace) expect(merge_request.to_reference(another_project)).to eq "sample-project!1" end + + it 'returns a String reference with the full path' do + expect(merge_request.to_reference(full: true)).to eq(project.path_with_namespace + '!1') + end end describe '#raw_diffs' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index fb225eb7625..3ec7bb46686 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -362,14 +362,6 @@ describe Project, models: true do end end - describe "#web_url_without_protocol" do - let(:project) { create(:empty_project, path: "somewhere") } - - it 'returns the web URL without the protocol for this repo' do - expect(project.web_url_without_protocol).to eq("#{Gitlab.config.gitlab.url.split('://')[1]}/#{project.namespace.path}/somewhere") - end - end - describe "#new_issue_address" do let(:project) { create(:empty_project, path: "somewhere") } let(:user) { create(:user) } diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index a42cedae614..36fbcf088e7 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -86,7 +86,8 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do describe "POST /projects/:id/hooks" do it "adds hook to project" do expect do - post api("/projects/#{project.id}/hooks", user), url: "http://example.com", issues_events: true + post api("/projects/#{project.id}/hooks", user), + url: "http://example.com", issues_events: true, wiki_page_events: true end.to change {project.hooks.count}.by(1) expect(response).to have_http_status(201) @@ -98,7 +99,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do expect(json_response['note_events']).to eq(false) expect(json_response['build_events']).to eq(false) expect(json_response['pipeline_events']).to eq(false) - expect(json_response['wiki_page_events']).to eq(false) + expect(json_response['wiki_page_events']).to eq(true) expect(json_response['enable_ssl_verification']).to eq(true) expect(json_response).not_to include('token') end diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 9e317f3a7e9..45b7988a054 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -317,9 +317,9 @@ describe API::Users, api: true do end it 'updates user with new identity' do - put api("/users/#{user.id}", admin), provider: 'github', extern_uid: '67890' + put api("/users/#{user.id}", admin), provider: 'github', extern_uid: 'john' expect(response).to have_http_status(200) - expect(user.reload.identities.first.extern_uid).to eq('67890') + expect(user.reload.identities.first.extern_uid).to eq('john') expect(user.reload.identities.first.provider).to eq('github') end diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index 64d15c0523c..8e614211116 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -5,10 +5,12 @@ describe Projects::ForkService, services: true do before do @from_namespace = create(:namespace) @from_user = create(:user, namespace: @from_namespace ) + avatar = fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") @from_project = create(:project, creator_id: @from_user.id, namespace: @from_namespace, star_count: 107, + avatar: avatar, description: 'wow such project') @to_namespace = create(:namespace) @to_user = create(:user, namespace: @to_namespace) @@ -36,6 +38,17 @@ describe Projects::ForkService, services: true do it { expect(to_project.namespace).to eq(@to_user.namespace) } it { expect(to_project.star_count).to be_zero } it { expect(to_project.description).to eq(@from_project.description) } + it { expect(to_project.avatar.file).to be_exists } + + # This test is here because we had a bug where the from-project lost its + # avatar after being forked. + # https://gitlab.com/gitlab-org/gitlab-ce/issues/26158 + it "after forking the from-project still has its avatar" do + # If we do not fork the project first we cannot detect the bug. + expect(to_project).to be_persisted + + expect(@from_project.avatar.file).to be_exists + end end end diff --git a/spec/uploaders/avatar_uploader_spec.rb b/spec/uploaders/avatar_uploader_spec.rb index 1f0e8732587..76f5a4b42ed 100644 --- a/spec/uploaders/avatar_uploader_spec.rb +++ b/spec/uploaders/avatar_uploader_spec.rb @@ -5,14 +5,14 @@ describe AvatarUploader do subject { described_class.new(user) } describe '#move_to_cache' do - it 'is true' do - expect(subject.move_to_cache).to eq(true) + it 'is false' do + expect(subject.move_to_cache).to eq(false) end end describe '#move_to_store' do - it 'is true' do - expect(subject.move_to_store).to eq(true) + it 'is false' do + expect(subject.move_to_store).to eq(false) end end end diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index bc86adfef68..6a712e33c96 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -17,7 +17,7 @@ describe FileUploader do describe '#image_or_video?' do context 'given an image file' do before do - @uploader.store!(File.new(Rails.root.join('spec', 'fixtures', 'rails_sample.jpg'))) + @uploader.store!(fixture_file_upload(Rails.root.join('spec', 'fixtures', 'rails_sample.jpg'))) end it 'detects an image based on file extension' do @@ -27,7 +27,7 @@ describe FileUploader do context 'given an video file' do before do - video_file = File.new(Rails.root.join('spec', 'fixtures', 'video_sample.mp4')) + video_file = fixture_file_upload(Rails.root.join('spec', 'fixtures', 'video_sample.mp4')) @uploader.store!(video_file) end @@ -37,7 +37,7 @@ describe FileUploader do end it 'does not return image_or_video? for other types' do - @uploader.store!(File.new(Rails.root.join('spec', 'fixtures', 'doc_sample.txt'))) + @uploader.store!(fixture_file_upload(Rails.root.join('spec', 'fixtures', 'doc_sample.txt'))) expect(@uploader.image_or_video?).to be false end |