Commit 1655824f authored by Regis's avatar Regis

Merge branch 'master' into auto-pipelines-vue

parents cf039f58 ec4fe443
...@@ -328,7 +328,7 @@ end ...@@ -328,7 +328,7 @@ end
gem 'newrelic_rpm', '~> 3.16' gem 'newrelic_rpm', '~> 3.16'
gem 'octokit', '~> 4.3.0' gem 'octokit', '~> 4.6.2'
gem 'mail_room', '~> 0.9.0' gem 'mail_room', '~> 0.9.0'
......
...@@ -420,8 +420,8 @@ GEM ...@@ -420,8 +420,8 @@ GEM
multi_json (~> 1.3) multi_json (~> 1.3)
multi_xml (~> 0.5) multi_xml (~> 0.5)
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
octokit (4.3.0) octokit (4.6.2)
sawyer (~> 0.7.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
oj (2.17.4) oj (2.17.4)
omniauth (1.3.1) omniauth (1.3.1)
hashie (>= 1.2, < 4) hashie (>= 1.2, < 4)
...@@ -650,9 +650,9 @@ GEM ...@@ -650,9 +650,9 @@ GEM
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0) sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3) tilt (>= 1.1, < 3)
sawyer (0.7.0) sawyer (0.8.1)
addressable (>= 2.3.5, < 2.5) addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 0.10) faraday (~> 0.8, < 1.0)
scss_lint (0.47.1) scss_lint (0.47.1)
rake (>= 0.9, < 11) rake (>= 0.9, < 11)
sass (~> 3.4.15) sass (~> 3.4.15)
...@@ -895,7 +895,7 @@ DEPENDENCIES ...@@ -895,7 +895,7 @@ DEPENDENCIES
newrelic_rpm (~> 3.16) newrelic_rpm (~> 3.16)
nokogiri (~> 1.6.7, >= 1.6.7.2) nokogiri (~> 1.6.7, >= 1.6.7.2)
oauth2 (~> 1.2.0) oauth2 (~> 1.2.0)
octokit (~> 4.3.0) octokit (~> 4.6.2)
oj (~> 2.17.4) oj (~> 2.17.4)
omniauth (~> 1.3.1) omniauth (~> 1.3.1)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
......
...@@ -55,6 +55,13 @@ ...@@ -55,6 +55,13 @@
$('.dropdown-toggle-text', $dropdown).text(text); $('.dropdown-toggle-text', $dropdown).text(text);
$dropdownContainer.removeClass('open'); $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');
}
});
}); });
}; };
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
}, },
DefaultOptions: { DefaultOptions: {
sorter: function(query, items, searchKey) { sorter: function(query, items, searchKey) {
this.setting.highlightFirst = query.length > 0;
if (gl.GfmAutoComplete.isLoading(items)) { if (gl.GfmAutoComplete.isLoading(items)) {
return items; return items;
} }
...@@ -55,11 +56,9 @@ ...@@ -55,11 +56,9 @@
}, },
filter: function(query, data, searchKey) { filter: function(query, data, searchKey) {
if (gl.GfmAutoComplete.isLoading(data)) { if (gl.GfmAutoComplete.isLoading(data)) {
gl.GfmAutoComplete.togglePreventSelection.call(this, true);
gl.GfmAutoComplete.fetchData(this.$inputor, this.at); gl.GfmAutoComplete.fetchData(this.$inputor, this.at);
return data; return data;
} else { } else {
gl.GfmAutoComplete.togglePreventSelection.call(this, false);
return $.fn.atwho["default"].callbacks.filter(query, data, searchKey); return $.fn.atwho["default"].callbacks.filter(query, data, searchKey);
} }
}, },
...@@ -257,9 +256,9 @@ ...@@ -257,9 +256,9 @@
insertTpl: '${atwho-at}${title}', insertTpl: '${atwho-at}${title}',
callbacks: { callbacks: {
matcher: this.DefaultOptions.matcher, matcher: this.DefaultOptions.matcher,
sorter: this.DefaultOptions.sorter,
beforeInsert: this.DefaultOptions.beforeInsert, beforeInsert: this.DefaultOptions.beforeInsert,
filter: this.DefaultOptions.filter, filter: this.DefaultOptions.filter,
sorter: this.DefaultOptions.sorter,
beforeSave: function(merges) { beforeSave: function(merges) {
if (gl.GfmAutoComplete.isLoading(merges)) return merges; if (gl.GfmAutoComplete.isLoading(merges)) return merges;
var sanitizeLabelTitle; var sanitizeLabelTitle;
...@@ -370,11 +369,7 @@ ...@@ -370,11 +369,7 @@
if (!data || !data.length) return false; if (!data || !data.length) return false;
if (Array.isArray(data)) data = data[0]; if (Array.isArray(data)) data = data[0];
return data === this.defaultLoadingData[0] || data.name === this.defaultLoadingData[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); }).call(this);
...@@ -97,8 +97,20 @@ ...@@ -97,8 +97,20 @@
padding: 5px 6px; padding: 5px 6px;
outline: 0; outline: 0;
&.disabled {
cursor: default;
&:hover, &:hover,
&:focus,
&:active {
background-color: $white-light;
border-color: $border-color;
box-shadow: none;
}
}
&.active, &.active,
&:hover,
&:active { &:active {
background-color: $row-hover; background-color: $row-hover;
border-color: $row-hover-border; border-color: $row-hover-border;
......
...@@ -182,3 +182,52 @@ span.idiff { ...@@ -182,3 +182,52 @@ span.idiff {
border-bottom-right-radius: 2px; 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;
}
}
}
...@@ -234,14 +234,46 @@ ul.content-list { ...@@ -234,14 +234,46 @@ ul.content-list {
} }
} }
.panel > .content-list > li { // Table list
padding: $gl-padding-top $gl-padding; .table-list {
display: table;
width: 100%;
&.commit { .table-list-row {
@media (min-width: $screen-sm-min) { display: table-row;
padding-left: 46px + $gl-padding; }
.table-list-cell {
display: table-cell;
vertical-align: top;
padding: 10px 16px;
border-bottom: 1px solid $gray-darker;
&.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 { ul.controls {
......
...@@ -48,3 +48,11 @@ ...@@ -48,3 +48,11 @@
line-height: inherit; line-height: inherit;
} }
} }
.panel-default {
.table-list-row:last-child {
.table-list-cell {
border-bottom: 0;
}
}
}
...@@ -376,7 +376,6 @@ $callout-success-color: #3c763d; ...@@ -376,7 +376,6 @@ $callout-success-color: #3c763d;
/* /*
* Commit Page * Commit Page
*/ */
$commit-committer-color: #999;
$commit-max-width-marker-color: rgba(0, 0, 0, 0.0); $commit-max-width-marker-color: rgba(0, 0, 0, 0.0);
$commit-message-text-area-bg: rgba(0, 0, 0, 0.0); $commit-message-text-area-bg: rgba(0, 0, 0, 0.0);
......
...@@ -18,15 +18,3 @@ p.details { ...@@ -18,15 +18,3 @@ p.details {
pre.commit-message { pre.commit-message {
white-space: pre-wrap; white-space: pre-wrap;
} }
.file-stats > a {
text-decoration: none;
> .new-file {
color: $notify-new-file;
}
> .deleted-file {
color: $notify-deleted-file;
}
}
.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;
}
}
.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;
}
}
.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 { .commits-compare-switch {
@include btn-default;
@include btn-white;
float: left; float: left;
margin-right: 9px; margin-right: 9px;
} }
...@@ -8,7 +77,6 @@ ...@@ -8,7 +77,6 @@
.commit-header { .commit-header {
padding: 5px 10px; padding: 5px 10px;
background-color: $gray-light; background-color: $gray-light;
border-top: 1px solid $gray-darker;
border-bottom: 1px solid $gray-darker; border-bottom: 1px solid $gray-darker;
font-size: 14px; font-size: 14px;
...@@ -18,8 +86,6 @@ ...@@ -18,8 +86,6 @@
} }
.commit-row-title { .commit-row-title {
line-height: 1.35;
.notes_count { .notes_count {
float: right; float: right;
margin-right: 10px; margin-right: 10px;
...@@ -32,7 +98,6 @@ ...@@ -32,7 +98,6 @@
.commit-row-message { .commit-row-message {
color: $gl-dark-link-color; color: $gl-dark-link-color;
} }
} }
.text-expander { .text-expander {
...@@ -54,9 +119,8 @@ ...@@ -54,9 +119,8 @@
.commit-actions { .commit-actions {
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
float: right; width: 300px;
margin-left: $gl-padding; text-align: right;
margin-top: 2px;
font-size: 0; font-size: 0;
} }
...@@ -86,16 +150,6 @@ ...@@ -86,16 +150,6 @@
.commit, .commit,
.generic_commit_status { .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, a,
button { button {
...@@ -103,18 +157,6 @@ ...@@ -103,18 +157,6 @@
vertical-align: baseline; vertical-align: baseline;
} }
.avatar {
margin-left: -46px;
}
.item-title {
display: inline-block;
@media (min-width: $screen-sm-min) {
max-width: 70%;
}
}
.commit-row-description { .commit-row-description {
font-size: 14px; font-size: 14px;
border-left: 1px solid $white-normal; border-left: 1px solid $white-normal;
...@@ -138,19 +180,6 @@ ...@@ -138,19 +180,6 @@
} }
} }
.commit-row-info {
color: $gl-gray;
line-height: 1.35;
a {
color: $gl-gray;
}
.avatar {
margin-right: 8px;
}
}
&.inline-commit { &.inline-commit {
.commit-row-title { .commit-row-title {
font-size: 13px; font-size: 13px;
...@@ -186,59 +215,3 @@ ...@@ -186,59 +215,3 @@
color: $gl-gray; 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;
}
}
...@@ -5,6 +5,12 @@ ...@@ -5,6 +5,12 @@
} }
} }
.title {
padding: 0;
margin: 0;
border-bottom: none;
}
// Border around images in issue and MR descriptions. // Border around images in issue and MR descriptions.
.description img:not(.emoji) { .description img:not(.emoji) {
border: 1px solid $white-normal; border: 1px solid $white-normal;
......
...@@ -310,10 +310,6 @@ ...@@ -310,10 +310,6 @@
left: 0; left: 0;
top: 2px; top: 2px;
} }
.commit-row-info {
line-height: 20px;
}
} }
.btn-clipboard { .btn-clipboard {
......
...@@ -43,7 +43,7 @@ ul.notes { ...@@ -43,7 +43,7 @@ ul.notes {
} }
.system-note-message { .system-note-message {
display: inline-block; display: inline;
&::first-letter { &::first-letter {
text-transform: lowercase; text-transform: lowercase;
...@@ -55,7 +55,7 @@ ul.notes { ...@@ -55,7 +55,7 @@ ul.notes {
} }
p { p {
display: inline-block; display: inline;
margin: 0; margin: 0;
&::first-letter { &::first-letter {
...@@ -353,6 +353,14 @@ ul.notes { ...@@ -353,6 +353,14 @@ ul.notes {
font-size: 14px; font-size: 14px;
} }
.note-headline-light {
display: inline;
@media (max-width: $screen-xs-min) {
display: block;
}
}
.note-headline-light, .note-headline-light,
.discussion-headline-light { .discussion-headline-light {
color: $notes-light-color; color: $notes-light-color;
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
margin-bottom: 5px; margin-bottom: 5px;
} }
&> .form-group { & > .form-group {
padding-left: 0; padding-left: 0;
} }
} }
...@@ -73,7 +73,7 @@ ...@@ -73,7 +73,7 @@
border: 1px solid $border-color; border: 1px solid $border-color;
} }
&+ .select2 a { & + .select2 a {
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }
...@@ -618,7 +618,6 @@ pre.light-well { ...@@ -618,7 +618,6 @@ pre.light-well {
margin: 0; margin: 0;
} }
.activity-filter-block { .activity-filter-block {
.controls { .controls {
padding-bottom: 7px; padding-bottom: 7px;
...@@ -811,8 +810,32 @@ pre.light-well { ...@@ -811,8 +810,32 @@ pre.light-well {
.compare-form-group { .compare-form-group {
.dropdown-menu { .dropdown-menu {
width: 100%;
@media (min-width: $screen-sm-min) {
width: 300px; 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;
}
}
} }
.clearable-input { .clearable-input {
......
...@@ -135,3 +135,9 @@ ...@@ -135,3 +135,9 @@
left: 5px; left: 5px;
} }
} }
.ci-status-link {
svg {
overflow: visible;
}
}
...@@ -134,21 +134,18 @@ ...@@ -134,21 +134,18 @@
.blob-commit-info { .blob-commit-info {
list-style: none; list-style: none;
padding: $gl-padding;
background: $gray-light; background: $gray-light;
padding: 6px 0;
border: 1px solid $border-color; border: 1px solid $border-color;
border-bottom: none; border-bottom: none;
margin: 0; margin: 0;
.commit { .table-list-cell {
padding-top: 0; border-bottom: none;
padding-bottom: 0;
.commit-row-title {
.commit-row-message {
font-weight: normal;
}
} }
.commit-actions {
width: 200px;
} }
} }
......
...@@ -30,7 +30,7 @@ class Projects::MattermostsController < Projects::ApplicationController ...@@ -30,7 +30,7 @@ class Projects::MattermostsController < Projects::ApplicationController
def configure_params def configure_params
params.require(:mattermost).permit(:trigger, :team_id).merge( params.require(:mattermost).permit(:trigger, :team_id).merge(
url: service_trigger_url(@service), url: service_trigger_url(@service),
icon_url: asset_url('gitlab_logo.png')) icon_url: asset_url('slash-command-logo.png'))
end end
def teams def teams
......
...@@ -98,7 +98,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -98,7 +98,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha } @start_version = @comparable_diffs.find { |diff| diff.head_commit_sha == @start_sha }
unless @start_version unless @start_version
render_404 @start_sha = @merge_request_diff.head_commit_sha
@start_version = @merge_request_diff
end end
end end
......
...@@ -7,7 +7,6 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -7,7 +7,6 @@ class RegistrationsController < Devise::RegistrationsController
end end
def create def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
# To avoid duplicate form fields on the login page, the registration form # To avoid duplicate form fields on the login page, the registration form
# names fields using `new_user`, but Devise still wants the params in # names fields using `new_user`, but Devise still wants the params in
# `user`. # `user`.
...@@ -15,9 +14,10 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -15,9 +14,10 @@ class RegistrationsController < Devise::RegistrationsController
params[resource_name] = params.delete(:"new_#{resource_name}") params[resource_name] = params.delete(:"new_#{resource_name}")
end end
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
super super
else 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 flash.delete :recaptcha_error
render action: 'new' render action: 'new'
end end
...@@ -57,7 +57,7 @@ class RegistrationsController < Devise::RegistrationsController ...@@ -57,7 +57,7 @@ class RegistrationsController < Devise::RegistrationsController
end end
def sign_up_params 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 end
def resource_name def resource_name
......
...@@ -110,6 +110,28 @@ module GitlabMarkdownHelper ...@@ -110,6 +110,28 @@ module GitlabMarkdownHelper
end end
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 private
# Return +text+, truncated to +max_chars+ characters, excluding any HTML # Return +text+, truncated to +max_chars+ characters, excluding any HTML
...@@ -158,28 +180,6 @@ module GitlabMarkdownHelper ...@@ -158,28 +180,6 @@ module GitlabMarkdownHelper
end end
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 = {}) def markdown_toolbar_button(options = {})
data = options[:data].merge({ container: "body" }) data = options[:data].merge({ container: "body" })
content_tag :button, content_tag :button,
......
...@@ -58,13 +58,13 @@ module IssuesHelper ...@@ -58,13 +58,13 @@ module IssuesHelper
end end
def status_box_class(item) def status_box_class(item)
if item.respond_to?(:expired?) && item.expired? if item.try(:expired?)
'status-box-expired' 'status-box-expired'
elsif item.respond_to?(:merged?) && item.merged? elsif item.try(:merged?)
'status-box-merged' 'status-box-merged'
elsif item.closed? elsif item.closed?
'status-box-closed' 'status-box-closed'
elsif item.respond_to?(:upcoming?) && item.upcoming? elsif item.try(:upcoming?)
'status-box-upcoming' 'status-box-upcoming'
else else
'status-box-open' 'status-box-open'
...@@ -128,8 +128,10 @@ module IssuesHelper ...@@ -128,8 +128,10 @@ module IssuesHelper
names.to_sentence names.to_sentence
end end
def award_active_class(awards, current_user) def award_state_class(awards, current_user)
if current_user && awards.find { |a| a.user_id == current_user.id } if !current_user
"disabled"
elsif current_user && awards.find { |a| a.user_id == current_user.id }
"active" "active"
else else
"" ""
......
...@@ -91,8 +91,8 @@ class Commit ...@@ -91,8 +91,8 @@ class Commit
@link_reference_pattern ||= super("commit", /(?<commit>\h{7,40})/) @link_reference_pattern ||= super("commit", /(?<commit>\h{7,40})/)
end end
def to_reference(from_project = nil) def to_reference(from_project = nil, full: false)
commit_reference(from_project, id) commit_reference(from_project, id, full: full)
end end
def reference_link_text(from_project = nil) def reference_link_text(from_project = nil)
...@@ -320,8 +320,8 @@ class Commit ...@@ -320,8 +320,8 @@ class Commit
private private
def commit_reference(from_project, referable_commit_id) def commit_reference(from_project, referable_commit_id, full: false)
reference = project.to_reference(from_project) reference = project.to_reference(from_project, full: full)
if reference.present? if reference.present?
"#{reference}#{self.class.reference_prefix}#{referable_commit_id}" "#{reference}#{self.class.reference_prefix}#{referable_commit_id}"
......
...@@ -89,8 +89,8 @@ class CommitRange ...@@ -89,8 +89,8 @@ class CommitRange
alias_method :id, :to_s alias_method :id, :to_s
def to_reference(from_project = nil) def to_reference(from_project = nil, full: false)
project_reference = project.to_reference(from_project) project_reference = project.to_reference(from_project, full: full)
if project_reference.present? if project_reference.present?
project_reference + self.class.reference_prefix + self.id project_reference + self.class.reference_prefix + self.id
......
...@@ -17,7 +17,7 @@ module Referable ...@@ -17,7 +17,7 @@ module Referable
# Issue.last.to_reference(other_project) # => "cross-project#1" # Issue.last.to_reference(other_project) # => "cross-project#1"
# #
# Returns a String # Returns a String
def to_reference(_from_project = nil) def to_reference(_from_project = nil, full:)
'' ''
end end
......
...@@ -38,7 +38,7 @@ class ExternalIssue ...@@ -38,7 +38,7 @@ class ExternalIssue
@reference_pattern ||= %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)} @reference_pattern ||= %r{(?<issue>\b([A-Z][A-Z0-9_]+-)\d+)}
end end
def to_reference(_from_project = nil) def to_reference(_from_project = nil, full: nil)
id id
end end
......
...@@ -80,7 +80,7 @@ class Group < Namespace ...@@ -80,7 +80,7 @@ class Group < Namespace
end end
end end
def to_reference(_from_project = nil) def to_reference(_from_project = nil, full: nil)
"#{self.class.reference_prefix}#{name}" "#{self.class.reference_prefix}#{name}"
end end
......
...@@ -8,8 +8,4 @@ class GroupLabel < Label ...@@ -8,8 +8,4 @@ class GroupLabel < Label
def subject_foreign_key def subject_foreign_key
'group_id' 'group_id'
end end
def to_reference(source_project = nil, target_project = nil, format: :id)
super(source_project, target_project, format: format)
end
end end
...@@ -97,10 +97,10 @@ class Issue < ActiveRecord::Base ...@@ -97,10 +97,10 @@ class Issue < ActiveRecord::Base
end end
end end
def to_reference(from_project = nil) def to_reference(from_project = nil, full: false)
reference = "#{self.class.reference_prefix}#{iid}" reference = "#{self.class.reference_prefix}#{iid}"
"#{project.to_reference(from_project)}#{reference}" "#{project.to_reference(from_project, full: full)}#{reference}"
end end
def referenced_merge_requests(current_user = nil) def referenced_merge_requests(current_user = nil)
......
...@@ -146,17 +146,17 @@ class Label < ActiveRecord::Base ...@@ -146,17 +146,17 @@ class Label < ActiveRecord::Base
# #
# Label.first.to_reference # => "~1" # Label.first.to_reference # => "~1"
# Label.first.to_reference(format: :name) # => "~\"bug\"" # Label.first.to_reference(format: :name) # => "~\"bug\""
# Label.first.to_reference(project, same_namespace_project) # => "gitlab-ce~1" # Label.first.to_reference(project, target_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: another_namespace_project) # => "gitlab-org/gitlab-ce~1"
# #
# Returns a String # 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) format_reference = label_format_reference(format)
reference = "#{self.class.reference_prefix}#{format_reference}" reference = "#{self.class.reference_prefix}#{format_reference}"
if source_project if from_project
"#{source_project.to_reference(target_project)}#{reference}" "#{from_project.to_reference(target_project, full: full)}#{reference}"
else else
reference reference
end end
......
...@@ -175,10 +175,10 @@ class MergeRequest < ActiveRecord::Base ...@@ -175,10 +175,10 @@ class MergeRequest < ActiveRecord::Base
work_in_progress?(title) ? title : "WIP: #{title}" work_in_progress?(title) ? title : "WIP: #{title}"
end end
def to_reference(from_project = nil) def to_reference(from_project = nil, full: false)
reference = "#{self.class.reference_prefix}#{iid}" reference = "#{self.class.reference_prefix}#{iid}"
"#{project.to_reference(from_project)}#{reference}" "#{project.to_reference(from_project, full: full)}#{reference}"
end end
def first_commit def first_commit
......
...@@ -118,11 +118,11 @@ class Milestone < ActiveRecord::Base ...@@ -118,11 +118,11 @@ class Milestone < ActiveRecord::Base
# Milestone.first.to_reference(cross_namespace_project) # => "gitlab-org/gitlab-ce%1" # Milestone.first.to_reference(cross_namespace_project) # => "gitlab-org/gitlab-ce%1"
# Milestone.first.to_reference(same_namespace_project) # => "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) format_reference = milestone_format_reference(format)
reference = "#{self.class.reference_prefix}#{format_reference}" reference = "#{self.class.reference_prefix}#{format_reference}"
"#{project.to_reference(from_project)}#{reference}" "#{project.to_reference(from_project, full: full)}#{reference}"
end end
def reference_link_text(from_project = nil) def reference_link_text(from_project = nil)
......
...@@ -589,8 +589,8 @@ class Project < ActiveRecord::Base ...@@ -589,8 +589,8 @@ class Project < ActiveRecord::Base
end end
end end
def to_reference(from_project = nil) def to_reference(from_project = nil, full: false)
if cross_namespace_reference?(from_project) if full || cross_namespace_reference?(from_project)
path_with_namespace path_with_namespace
elsif cross_project_reference?(from_project) elsif cross_project_reference?(from_project)
path path
...@@ -609,10 +609,6 @@ class Project < ActiveRecord::Base ...@@ -609,10 +609,6 @@ class Project < ActiveRecord::Base
Gitlab::Routing.url_helpers.namespace_project_url(self.namespace, self) Gitlab::Routing.url_helpers.namespace_project_url(self.namespace, self)
end end
def web_url_without_protocol
web_url.split('://')[1]
end
def new_issue_address(author) def new_issue_address(author)
return unless Gitlab::IncomingEmail.supports_issue_creation? && author return unless Gitlab::IncomingEmail.supports_issue_creation? && author
......
...@@ -16,8 +16,8 @@ class ProjectLabel < Label ...@@ -16,8 +16,8 @@ class ProjectLabel < Label
'project_id' 'project_id'
end end
def to_reference(target_project = nil, format: :id) def to_reference(target_project = nil, format: :id, full: false)
super(project, target_project, format: format) super(project, target_project: target_project, format: format, full: full)
end end
private private
......
...@@ -64,11 +64,11 @@ class Snippet < ActiveRecord::Base ...@@ -64,11 +64,11 @@ class Snippet < ActiveRecord::Base
@link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/) @link_reference_pattern ||= super("snippets", /(?<snippet>\d+)/)
end end
def to_reference(from_project = nil) def to_reference(from_project = nil, full: false)
reference = "#{self.class.reference_prefix}#{id}" reference = "#{self.class.reference_prefix}#{id}"
if project.present? if project.present?
"#{project.to_reference(from_project)}#{reference}" "#{project.to_reference(from_project, full: full)}#{reference}"
else else
reference reference
end end
......
...@@ -99,6 +99,7 @@ class User < ActiveRecord::Base ...@@ -99,6 +99,7 @@ class User < ActiveRecord::Base
# #
# Note: devise :validatable above adds validations for :email and :password # Note: devise :validatable above adds validations for :email and :password
validates :name, presence: true validates :name, presence: true
validates_confirmation_of :email
validates :notification_email, presence: true validates :notification_email, presence: true
validates :notification_email, email: true, if: ->(user) { user.notification_email != user.email } validates :notification_email, email: true, if: ->(user) { user.notification_email != user.email }
validates :public_email, presence: true, uniqueness: true, email: true, allow_blank: true validates :public_email, presence: true, uniqueness: true, email: true, allow_blank: true
...@@ -332,7 +333,7 @@ class User < ActiveRecord::Base ...@@ -332,7 +333,7 @@ class User < ActiveRecord::Base
username username
end 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}" "#{self.class.reference_prefix}#{username}"
end end
......
...@@ -10,4 +10,15 @@ class AvatarUploader < GitlabUploader ...@@ -10,4 +10,15 @@ class AvatarUploader < GitlabUploader
def exists? def exists?
model.avatar.file && model.avatar.file.exists? model.avatar.file && model.avatar.file.exists?
end 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 end
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
.awards.js-awards-block{ class: ("hidden" if !inline && grouped_emojis.empty?), data: { award_url: toggle_award_url(awardable) } } .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| - awards_sort(grouped_emojis).each do |emoji, awards|
%button.btn.award-control.js-emoji-btn.has-tooltip{ type: "button", %button.btn.award-control.js-emoji-btn.has-tooltip{ type: "button",
disabled: !current_user, class: (award_state_class(awards, current_user)),
class: (award_active_class(awards, current_user)),
data: { placement: "bottom", title: award_user_list(awards, current_user) } } data: { placement: "bottom", title: award_user_list(awards, current_user) } }
= emoji_icon(emoji, sprite: false) = emoji_icon(emoji, sprite: false)
%span.award-control-text.js-counter %span.award-control-text.js-counter
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
.form-group .form-group
= f.label :email = f.label :email
= f.email_field :email, class: "form-control middle", required: true, title: "Please provide a valid email address." = 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 .form-group.append-bottom-20#password-strength
= f.label :password = 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." = f.password_field :password, class: "form-control bottom", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters."
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
- else - else
= link_to title, '#' = 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) - blob_commit = @repository.last_commit_for_path(@commit.id, blob.path)
= render blob_commit, project: @project, ref: @ref = render blob_commit, project: @project, ref: @ref
......
...@@ -9,13 +9,13 @@ ...@@ -9,13 +9,13 @@
- cache_key.push(commit.status(ref)) if commit.status(ref) - cache_key.push(commit.status(ref)) if commit.status(ref)
= cache(cache_key, expires_in: 1.day) do = cache(cache_key, expires_in: 1.day) do
%li.commit.js-toggle-container{ id: "commit-#{commit.short_id}" } %li.commit.table-list-row.js-toggle-container{ id: "commit-#{commit.short_id}" }
.table-list-cell.avatar-cell.hidden-xs
= author_avatar(commit, size: 36) = author_avatar(commit, size: 36)
.commit-info-block .table-list-cell.commit-content
.commit-row-title = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message item-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 %span.commit-row-message.visible-xs-inline
&middot; &middot;
= commit.short_id = commit.short_id
...@@ -25,17 +25,17 @@ ...@@ -25,17 +25,17 @@
- if commit.description? - if commit.description?
%a.text-expander.hidden-xs.js-toggle-button ... %a.text-expander.hidden-xs.js-toggle-button ...
.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)
- if commit.description? - if commit.description?
%pre.commit-row-description.js-toggle-content %pre.commit-row-description.js-toggle-content
= preserve(markdown(commit.description, pipeline: :single_line, author: commit.author)) = preserve(markdown(commit.description, pipeline: :single_line, author: commit.author))
.commiter
= commit_author_link(commit, avatar: false, size: 24) = commit_author_link(commit, avatar: false, size: 24)
committed committed
#{time_ago_with_tooltip(commit.committed_date)} #{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)
...@@ -11,4 +11,4 @@ ...@@ -11,4 +11,4 @@
%li.warning-row.unstyled %li.warning-row.unstyled
#{number_with_delimiter(hidden)} additional commits have been omitted to prevent performance issues. #{number_with_delimiter(hidden)} additional commits have been omitted to prevent performance issues.
- else - else
%ul.content-list= render commits, project: @project, ref: @ref %ul.content-list.table-list= render commits, project: @project, ref: @ref
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
- commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits| - 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.commit-header= "#{day.strftime('%d %b, %Y')} #{pluralize(commits.count, 'commit')}"
%li.commits-row %li.commits-row
%ul.list-unstyled.commit-list %ul.content-list.commit-list.table-list.table-wide
= render commits, project: project, ref: ref = render commits, project: project, ref: ref
- if hidden > 0 - if hidden > 0
......
...@@ -2,21 +2,21 @@ ...@@ -2,21 +2,21 @@
.clearfix .clearfix
- if params[:to] && params[:from] - if params[:to] && params[:from]
.compare-switch-container .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 .form-group.dropdown.compare-form-group.from.js-compare-from-dropdown
.input-group.inline-input-group .input-group.inline-input-group
%span.input-group-addon from %span.input-group-addon from
= hidden_field_tag :from, params[: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 = 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= params[:from] || 'Select branch/tag' .dropdown-toggle-text.str-truncated= params[:from] || 'Select branch/tag'
= render "ref_dropdown" = render "ref_dropdown"
.compare-ellipsis.inline ... .compare-ellipsis.inline ...
.form-group.dropdown.compare-form-group.to.js-compare-to-dropdown .form-group.dropdown.compare-form-group.to.js-compare-to-dropdown
.input-group.inline-input-group .input-group.inline-input-group
%span.input-group-addon to %span.input-group-addon to
= hidden_field_tag :to, params[: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 = 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= params[:to] || 'Select branch/tag' .dropdown-toggle-text.str-truncated= params[:to] || 'Select branch/tag'
= render "ref_dropdown" = render "ref_dropdown"
&nbsp; &nbsp;
= button_tag "Compare", class: "btn btn-create commits-compare-btn" = button_tag "Compare", class: "btn btn-create commits-compare-btn"
......
...@@ -2,6 +2,6 @@ ...@@ -2,6 +2,6 @@
.empty-stage .empty-stage
.icon-no-data .icon-no-data
= custom_icon ('icon_no_data') = custom_icon ('icon_no_data')
%h4 We dont have enough data to show this stage. %h4 We don't have enough data to show this stage.
%p %p
{{currentStage.emptyStageText}} {{currentStage.emptyStageText}}
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
.container-fluid .container-fluid
.row .row
.col-sm-3.col-xs-12.column{ "v-for" => "item in state.summary" } .col-sm-3.col-xs-12.column{ "v-for" => "item in state.summary" }
%h3.header {{item.value}} %h3.header {{ item.value }}
%p.text {{item.title}} %p.text {{ item.title }}
.col-sm-3.col-xs-12.column .col-sm-3.col-xs-12.column
.dropdown.inline.js-ca-dropdown .dropdown.inline.js-ca-dropdown
%button.dropdown-menu-toggle{ "data-toggle" => "dropdown", :type => "button" } %button.dropdown-menu-toggle{ "data-toggle" => "dropdown", :type => "button" }
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
= render "projects/merge_requests/widget/show.html.haml" = 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) - 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 You can also accept this merge request manually using the
= succeed '.' do = succeed '.' do
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal" = link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
%ul %ul
- @merge_request_diffs.each do |merge_request_diff| - @merge_request_diffs.each do |merge_request_diff|
%li %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 %strong
- if merge_request_diff.latest? - if merge_request_diff.latest?
latest version latest version
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
.form-group .form-group
= label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label' = label_tag nil, 'Customize icon', class: 'col-sm-2 col-xs-12 control-label'
.col-sm-10.col-xs-12.text-block .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') = link_to('Download image', asset_url('gitlab_logo.png'), class: 'btn btn-sm', target: '_blank')
.form-group .form-group
......
---
title: Resolves overflow in compare branch and tags dropdown
merge_request: 8118
author:
---
title: Add email confirmation field to registration form
merge_request: 7432
author:
---
title: Removed bottom padding from merge manually from CLI because of repositioning award emoji's
merge_request:
author:
---
title: Rename wiki_events to wiki_page_events in project hooks API to avoid errors
merge_request: Robert Schilling
author: 8425
---
title: Fix cross-project references copy to include the project reference
merge_request:
author:
---
title: Gitlab::LDAP::Person uses LDAP attributes configuration
merge_request: 8418
author:
---
title: Copy, don't move uploaded avatar files
merge_request: 8396
author:
---
title: Properly handle failed reCAPTCHA on user registration
merge_request: 8403
author:
---
title: Fixed regression of note-headline-light where it was always placed on 2 lines, even on wide viewports
merge_request:
author:
...@@ -40,6 +40,15 @@ Its simplest usage is to provide the value for `title`: ...@@ -40,6 +40,15 @@ Its simplest usage is to provide the value for `title`:
```text ```text
$ bin/changelog 'Hey DZ, I added a feature to GitLab!' $ 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 create changelogs/unreleased/my-feature.yml
--- ---
title: Hey DZ, I added a feature to GitLab! title: Hey DZ, I added a feature to GitLab!
...@@ -47,10 +56,6 @@ merge_request: ...@@ -47,10 +56,6 @@ merge_request:
author: 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 ### Arguments
| Argument | Shorthand | Purpose | | Argument | Shorthand | Purpose |
...@@ -139,7 +144,7 @@ Use the **`--git-username`** or **`-u`** argument to automatically fill in the ...@@ -139,7 +144,7 @@ Use the **`--git-username`** or **`-u`** argument to automatically fill in the
$ git config user.name $ git config user.name
Jane Doe 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 create changelogs/unreleased/feature-hey-dz.yml
--- ---
title: Hey DZ, I added a feature to GitLab! title: Hey DZ, I added a feature to GitLab!
......
...@@ -5,28 +5,18 @@ module API ...@@ -5,28 +5,18 @@ module API
before { authenticate! } before { authenticate! }
helpers do helpers do
def filter_issues_state(issues, state) # TODO: Remove in 9.0 and switch to IssueFinder-based label filtering
case state
when 'opened' then issues.opened
when 'closed' then issues.closed
else issues
end
end
def filter_issues_labels(issues, labels) def filter_issues_labels(issues, labels)
issues.includes(:labels).where('labels.title' => labels.split(',')) issues.includes(:labels).where('labels.title' => labels.split(','))
end end
def filter_issues_milestone(issues, milestone)
issues.includes(:milestone).where('milestones.title' => milestone)
end
params :issues_params do params :issues_params do
optional :labels, type: String, desc: 'Comma-separated list of label names' 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', 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.' desc: 'Return issues ordered by `created_at` or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc', optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return issues sorted in `asc` or `desc` order.' desc: 'Return issues sorted in `asc` or `desc` order.'
optional :milestone, type: String, desc: 'Return issues for a specific milestone'
use :pagination use :pagination
end end
...@@ -50,8 +40,7 @@ module API ...@@ -50,8 +40,7 @@ module API
use :issues_params use :issues_params
end end
get do get do
issues = current_user.issues.inc_notes_with_associations issues = IssuesFinder.new(current_user, scope: 'all', author_id: current_user.id, state: params[:state]).execute.inc_notes_with_associations
issues = filter_issues_state(issues, params[:state])
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = issues.reorder(params[:order_by] => params[:sort]) issues = issues.reorder(params[:order_by] => params[:sort])
...@@ -99,16 +88,14 @@ module API ...@@ -99,16 +88,14 @@ module API
use :issues_params use :issues_params
end end
get ":id/issues" do get ":id/issues" do
issues = IssuesFinder.new(current_user, project_id: user_project.id).execute.inc_notes_with_associations issues = IssuesFinder.new(current_user,
issues = filter_issues_state(issues, params[:state]) 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_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = filter_by_iid(issues, params[:iid]) unless params[:iid].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]) issues = issues.reorder(params[:order_by] => params[:sort])
present paginate(issues), with: Entities::Issue, current_user: current_user, project: user_project present paginate(issues), with: Entities::Issue, current_user: current_user, project: user_project
end end
......
...@@ -15,7 +15,7 @@ module API ...@@ -15,7 +15,7 @@ module API
optional :note_events, type: Boolean, desc: "Trigger hook on note(comment) events" optional :note_events, type: Boolean, desc: "Trigger hook on note(comment) events"
optional :build_events, type: Boolean, desc: "Trigger hook on build events" optional :build_events, type: Boolean, desc: "Trigger hook on build events"
optional :pipeline_events, type: Boolean, desc: "Trigger hook on pipeline 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 :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" optional :token, type: String, desc: "Secret token to validate received payloads; this will not be returned in the response"
end end
......
...@@ -16,7 +16,7 @@ module API ...@@ -16,7 +16,7 @@ module API
optional :website_url, type: String, desc: 'The website of the user' optional :website_url, type: String, desc: 'The website of the user'
optional :organization, type: String, desc: 'The organization 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 :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 :provider, type: String, desc: 'The external provider'
optional :bio, type: String, desc: 'The biography of the user' optional :bio, type: String, desc: 'The biography of the user'
optional :location, type: String, desc: 'The location of the user' optional :location, type: String, desc: 'The location of the user'
......
...@@ -49,9 +49,9 @@ module Gitlab ...@@ -49,9 +49,9 @@ module Gitlab
end end
def url(subject) def url(subject)
project = subject.project polymorphic_url(
[subject.project.namespace.becomes(Namespace), subject.project, subject]
namespace_project_build_url(project.namespace.becomes(Namespace), project, subject) )
end end
end end
end end
......
...@@ -76,7 +76,7 @@ module Gitlab ...@@ -76,7 +76,7 @@ module Gitlab
if referable.respond_to?(:project) if referable.respond_to?(:project)
referable.to_reference(target_project) referable.to_reference(target_project)
else else
referable.to_reference(@source_project, target_project) referable.to_reference(@source_project, target_project: target_project)
end end
end end
......
...@@ -28,7 +28,7 @@ module Gitlab ...@@ -28,7 +28,7 @@ module Gitlab
end end
def name def name
entry.cn.first attribute_value(:name)
end end
def uid def uid
...@@ -40,7 +40,7 @@ module Gitlab ...@@ -40,7 +40,7 @@ module Gitlab
end end
def email def email
entry.try(:mail) attribute_value(:email)
end end
def dn def dn
...@@ -56,6 +56,21 @@ module Gitlab ...@@ -56,6 +56,21 @@ module Gitlab
def config def config
@config ||= Gitlab::LDAP::Config.new(provider) @config ||= Gitlab::LDAP::Config.new(provider)
end 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 end
end end
...@@ -2,31 +2,61 @@ require 'spec_helper' ...@@ -2,31 +2,61 @@ require 'spec_helper'
describe RegistrationsController do describe RegistrationsController do
describe '#create' do describe '#create' do
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| around(:each) do |example|
perform_enqueued_jobs do perform_enqueued_jobs do
example.run example.run
end 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
context 'when sending email confirmation' do allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(false)
before { allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(false) }
it 'logs user in directly' do
expect { post(:create, user_params) }.not_to change{ ActionMailer::Base.deliveries.size } expect { post(:create, user_params) }.not_to change{ ActionMailer::Base.deliveries.size }
expect(subject.current_user).not_to be_nil expect(subject.current_user).not_to be_nil
end end
end end
context 'when not sending email confirmation' do context 'when send_user_confirmation_email is true' do
before { allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(true) }
it 'does not authenticate user and sends confirmation email' 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)
post(:create, user_params) post(:create, user_params)
expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email]) expect(ActionMailer::Base.deliveries.last.to.first).to eq(user_params[:user][:email])
expect(subject.current_user).to be_nil expect(subject.current_user).to be_nil
end end
end end
end end
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')
post(:create, user_params)
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
end end
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
...@@ -76,7 +76,7 @@ describe 'Awards Emoji', feature: true do ...@@ -76,7 +76,7 @@ describe 'Awards Emoji', feature: true do
end end
it 'has disabled emoji button' do 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
end end
......
...@@ -81,4 +81,52 @@ feature 'Merge Request versions', js: true, feature: true do ...@@ -81,4 +81,52 @@ feature 'Merge Request versions', js: true, feature: true do
expect(page).to have_content '8 changed files' expect(page).to have_content '8 changed files'
end end
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 end
...@@ -49,4 +49,10 @@ feature 'Setup Mattermost slash commands', feature: true do ...@@ -49,4 +49,10 @@ feature 'Setup Mattermost slash commands', feature: true do
end end
end 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 end
...@@ -13,6 +13,7 @@ feature 'Signup', feature: true do ...@@ -13,6 +13,7 @@ feature 'Signup', feature: true do
fill_in 'new_user_name', with: user.name fill_in 'new_user_name', with: user.name
fill_in 'new_user_username', with: user.username fill_in 'new_user_username', with: user.username
fill_in 'new_user_email', with: user.email 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 fill_in 'new_user_password', with: user.password
click_button "Register" click_button "Register"
...@@ -32,6 +33,7 @@ feature 'Signup', feature: true do ...@@ -32,6 +33,7 @@ feature 'Signup', feature: true do
fill_in 'new_user_name', with: user.name fill_in 'new_user_name', with: user.name
fill_in 'new_user_username', with: user.username fill_in 'new_user_username', with: user.username
fill_in 'new_user_email', with: user.email 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 fill_in 'new_user_password', with: user.password
click_button "Register" click_button "Register"
...@@ -55,8 +57,9 @@ feature 'Signup', feature: true do ...@@ -55,8 +57,9 @@ feature 'Signup', feature: true do
click_button "Register" click_button "Register"
expect(current_path).to eq user_registration_path 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 has already been taken")
expect(page).to have_content("Email confirmation doesn't match")
end end
it 'does not redisplay the password' do it 'does not redisplay the password' do
......
...@@ -9,6 +9,7 @@ feature 'Users', feature: true, js: true do ...@@ -9,6 +9,7 @@ feature 'Users', feature: true, js: true do
fill_in 'new_user_name', with: 'Name Surname' fill_in 'new_user_name', with: 'Name Surname'
fill_in 'new_user_username', with: 'Great' fill_in 'new_user_username', with: 'Great'
fill_in 'new_user_email', with: 'name@mail.com' 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' fill_in 'new_user_password', with: 'password1234'
expect { click_button 'Register' }.to change { User.count }.by(1) expect { click_button 'Register' }.to change { User.count }.by(1)
end end
...@@ -36,6 +37,7 @@ feature 'Users', feature: true, js: true do ...@@ -36,6 +37,7 @@ feature 'Users', feature: true, js: true do
fill_in 'new_user_name', with: 'Another user name' fill_in 'new_user_name', with: 'Another user name'
fill_in 'new_user_username', with: 'anotheruser' fill_in 'new_user_username', with: 'anotheruser'
fill_in 'new_user_email', with: user.email fill_in 'new_user_email', with: user.email
fill_in 'new_user_email_confirmation', with: user.email
fill_in 'new_user_password', with: '12341234' fill_in 'new_user_password', with: '12341234'
expect { click_button 'Register' }.to change { User.count }.by(0) expect { click_button 'Register' }.to change { User.count }.by(0)
expect(page).to have_text('Email has already been taken') expect(page).to have_text('Email has already been taken')
......
...@@ -170,4 +170,14 @@ describe GitlabMarkdownHelper do ...@@ -170,4 +170,14 @@ describe GitlabMarkdownHelper do
expect(doc.content).to eq "@#{user.username}, can you look at this?..." expect(doc.content).to eq "@#{user.username}, can you look at this?..."
end end
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 end
...@@ -98,15 +98,15 @@ describe IssuesHelper do ...@@ -98,15 +98,15 @@ describe IssuesHelper do
end end
end end
describe '#award_active_class' do describe '#award_state_class' do
let!(:upvote) { create(:award_emoji) } let!(:upvote) { create(:award_emoji) }
it "returns empty string for unauthenticated user" do it "returns disabled string for unauthenticated user" do
expect(award_active_class(AwardEmoji.all, nil)).to eq("") expect(award_state_class(AwardEmoji.all, nil)).to eq("disabled")
end end
it "returns active string for author" do 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
end end
......
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
...@@ -43,7 +43,7 @@ describe GroupLabel, models: true do ...@@ -43,7 +43,7 @@ describe GroupLabel, models: true do
let(:target_project) { build_stubbed(:empty_project, name: 'project-2', namespace: namespace) } let(:target_project) { build_stubbed(:empty_project, name: 'project-2', namespace: namespace) }
it 'returns a String reference to the object' do 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
end end
......
...@@ -30,6 +30,10 @@ describe Issue, models: true do ...@@ -30,6 +30,10 @@ describe Issue, models: true do
expect(issue.to_reference).to eq "#1" expect(issue.to_reference).to eq "#1"
end 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 it 'supports a cross-project reference' do
another_project = build(:project, name: 'another-project', namespace: project.namespace) another_project = build(:project, name: 'another-project', namespace: project.namespace)
expect(issue.to_reference(another_project)).to eq "sample-project#1" expect(issue.to_reference(another_project)).to eq "sample-project#1"
......
...@@ -153,6 +153,10 @@ describe MergeRequest, models: true do ...@@ -153,6 +153,10 @@ describe MergeRequest, models: true do
another_project = build(:project, name: 'another-project', namespace: project.namespace) another_project = build(:project, name: 'another-project', namespace: project.namespace)
expect(merge_request.to_reference(another_project)).to eq "sample-project!1" expect(merge_request.to_reference(another_project)).to eq "sample-project!1"
end 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 end
describe '#raw_diffs' do describe '#raw_diffs' do
......
...@@ -362,14 +362,6 @@ describe Project, models: true do ...@@ -362,14 +362,6 @@ describe Project, models: true do
end end
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 describe "#new_issue_address" do
let(:project) { create(:empty_project, path: "somewhere") } let(:project) { create(:empty_project, path: "somewhere") }
let(:user) { create(:user) } let(:user) { create(:user) }
......
...@@ -86,7 +86,8 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do ...@@ -86,7 +86,8 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do
describe "POST /projects/:id/hooks" do describe "POST /projects/:id/hooks" do
it "adds hook to project" do it "adds hook to project" do
expect 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) end.to change {project.hooks.count}.by(1)
expect(response).to have_http_status(201) expect(response).to have_http_status(201)
...@@ -98,7 +99,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do ...@@ -98,7 +99,7 @@ describe API::ProjectHooks, 'ProjectHooks', api: true do
expect(json_response['note_events']).to eq(false) expect(json_response['note_events']).to eq(false)
expect(json_response['build_events']).to eq(false) expect(json_response['build_events']).to eq(false)
expect(json_response['pipeline_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['enable_ssl_verification']).to eq(true)
expect(json_response).not_to include('token') expect(json_response).not_to include('token')
end end
......
...@@ -317,9 +317,9 @@ describe API::Users, api: true do ...@@ -317,9 +317,9 @@ describe API::Users, api: true do
end end
it 'updates user with new identity' do 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(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') expect(user.reload.identities.first.provider).to eq('github')
end end
......
...@@ -5,10 +5,12 @@ describe Projects::ForkService, services: true do ...@@ -5,10 +5,12 @@ describe Projects::ForkService, services: true do
before do before do
@from_namespace = create(:namespace) @from_namespace = create(:namespace)
@from_user = create(:user, namespace: @from_namespace ) @from_user = create(:user, namespace: @from_namespace )
avatar = fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")
@from_project = create(:project, @from_project = create(:project,
creator_id: @from_user.id, creator_id: @from_user.id,
namespace: @from_namespace, namespace: @from_namespace,
star_count: 107, star_count: 107,
avatar: avatar,
description: 'wow such project') description: 'wow such project')
@to_namespace = create(:namespace) @to_namespace = create(:namespace)
@to_user = create(:user, namespace: @to_namespace) @to_user = create(:user, namespace: @to_namespace)
...@@ -36,6 +38,17 @@ describe Projects::ForkService, services: true do ...@@ -36,6 +38,17 @@ describe Projects::ForkService, services: true do
it { expect(to_project.namespace).to eq(@to_user.namespace) } it { expect(to_project.namespace).to eq(@to_user.namespace) }
it { expect(to_project.star_count).to be_zero } it { expect(to_project.star_count).to be_zero }
it { expect(to_project.description).to eq(@from_project.description) } 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
end end
......
...@@ -5,14 +5,14 @@ describe AvatarUploader do ...@@ -5,14 +5,14 @@ describe AvatarUploader do
subject { described_class.new(user) } subject { described_class.new(user) }
describe '#move_to_cache' do describe '#move_to_cache' do
it 'is true' do it 'is false' do
expect(subject.move_to_cache).to eq(true) expect(subject.move_to_cache).to eq(false)
end end
end end
describe '#move_to_store' do describe '#move_to_store' do
it 'is true' do it 'is false' do
expect(subject.move_to_store).to eq(true) expect(subject.move_to_store).to eq(false)
end end
end end
end end
...@@ -17,7 +17,7 @@ describe FileUploader do ...@@ -17,7 +17,7 @@ describe FileUploader do
describe '#image_or_video?' do describe '#image_or_video?' do
context 'given an image file' do context 'given an image file' do
before 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 end
it 'detects an image based on file extension' do it 'detects an image based on file extension' do
...@@ -27,7 +27,7 @@ describe FileUploader do ...@@ -27,7 +27,7 @@ describe FileUploader do
context 'given an video file' do context 'given an video file' do
before 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) @uploader.store!(video_file)
end end
...@@ -37,7 +37,7 @@ describe FileUploader do ...@@ -37,7 +37,7 @@ describe FileUploader do
end end
it 'does not return image_or_video? for other types' do 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 expect(@uploader.image_or_video?).to be false
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment