Commit cf6a3e7e authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 2a040e26
...@@ -10,6 +10,9 @@ import { ...@@ -10,6 +10,9 @@ import {
GlBadge, GlBadge,
GlAlert, GlAlert,
GlSprintf, GlSprintf,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { __, sprintf, n__ } from '~/locale'; import { __, sprintf, n__ } from '~/locale';
import LoadingButton from '~/vue_shared/components/loading_button.vue'; import LoadingButton from '~/vue_shared/components/loading_button.vue';
...@@ -36,6 +39,9 @@ export default { ...@@ -36,6 +39,9 @@ export default {
GlBadge, GlBadge,
GlAlert, GlAlert,
GlSprintf, GlSprintf,
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
}, },
directives: { directives: {
TrackEvent: TrackEventDirective, TrackEvent: TrackEventDirective,
...@@ -108,7 +114,7 @@ export default { ...@@ -108,7 +114,7 @@ export default {
return sprintf( return sprintf(
__('Reported %{timeAgo} by %{reportedBy}'), __('Reported %{timeAgo} by %{reportedBy}'),
{ {
reportedBy: `<strong>${this.error.culprit}</strong>`, reportedBy: `<strong class="error-details-meta-culprit">${this.error.culprit}</strong>`,
timeAgo: this.timeFormatted(this.stacktraceData.date_received), timeAgo: this.timeFormatted(this.stacktraceData.date_received),
}, },
false, false,
...@@ -144,6 +150,11 @@ export default { ...@@ -144,6 +150,11 @@ export default {
false, false,
); );
}, },
issueUpdateInProgress() {
return (
this.updatingIgnoreStatus || this.updatingResolveStatus || this.issueCreationInProgress
);
},
errorLevel() { errorLevel() {
return sprintf(__('level: %{level}'), { level: this.error.tags.level }); return sprintf(__('level: %{level}'), { level: this.error.tags.level });
}, },
...@@ -217,54 +228,90 @@ export default { ...@@ -217,54 +228,90 @@ export default {
</gl-sprintf> </gl-sprintf>
</gl-alert> </gl-alert>
<div class="top-area align-items-center justify-content-between py-3"> <div class="error-details-header d-flex py-2 justify-content-between">
<span v-if="!loadingStacktrace && stacktrace" v-html="reported"></span> <div class="error-details-meta my-auto">
<div class="d-inline-flex ml-lg-auto"> <span v-if="!loadingStacktrace && stacktrace" v-html="reported"></span>
<loading-button </div>
:label="ignoreBtnLabel" <div class="error-details-actions">
:loading="updatingIgnoreStatus" <div class="d-inline-flex bv-d-sm-down-none">
data-qa-selector="update_ignore_status_button" <loading-button
@click="onIgnoreStatusUpdate" :label="ignoreBtnLabel"
/> :loading="updatingIgnoreStatus"
<loading-button data-qa-selector="update_ignore_status_button"
class="btn-outline-info ml-2" @click="onIgnoreStatusUpdate"
:label="resolveBtnLabel"
:loading="updatingResolveStatus"
data-qa-selector="update_resolve_status_button"
@click="onResolveStatusUpdate"
/>
<gl-button
v-if="error.gitlabIssuePath"
class="ml-2"
data-qa-selector="view_issue_button"
:href="error.gitlabIssuePath"
variant="success"
>
{{ __('View issue') }}
</gl-button>
<form
ref="sentryIssueForm"
:action="projectIssuesPath"
method="POST"
class="d-inline-block ml-2"
>
<gl-form-input class="hidden" name="issue[title]" :value="issueTitle" />
<input name="issue[description]" :value="issueDescription" type="hidden" />
<gl-form-input
:value="error.sentryId"
class="hidden"
name="issue[sentry_issue_attributes][sentry_issue_identifier]"
/> />
<gl-form-input :value="csrfToken" class="hidden" name="authenticity_token" />
<loading-button <loading-button
class="btn-outline-info ml-2"
:label="resolveBtnLabel"
:loading="updatingResolveStatus"
data-qa-selector="update_resolve_status_button"
@click="onResolveStatusUpdate"
/>
<gl-button
v-if="error.gitlabIssuePath"
class="ml-2"
data-qa-selector="view_issue_button"
:href="error.gitlabIssuePath"
variant="success"
>
{{ __('View issue') }}
</gl-button>
<form
ref="sentryIssueForm"
:action="projectIssuesPath"
method="POST"
class="d-inline-block ml-2"
>
<gl-form-input class="hidden" name="issue[title]" :value="issueTitle" />
<input name="issue[description]" :value="issueDescription" type="hidden" />
<gl-form-input
:value="error.sentryId"
class="hidden"
name="issue[sentry_issue_attributes][sentry_issue_identifier]"
/>
<gl-form-input :value="csrfToken" class="hidden" name="authenticity_token" />
<loading-button
v-if="!error.gitlabIssuePath"
class="btn-success"
:label="__('Create issue')"
:loading="issueCreationInProgress"
data-qa-selector="create_issue_button"
@click="createIssue"
/>
</form>
</div>
<gl-dropdown
text="Options"
class="error-details-options d-md-none"
right
:disabled="issueUpdateInProgress"
>
<gl-dropdown-item
data-qa-selector="update_ignore_status_button"
@click="onIgnoreStatusUpdate"
>{{ ignoreBtnLabel }}</gl-dropdown-item
>
<gl-dropdown-item
data-qa-selector="update_resolve_status_button"
@click="onResolveStatusUpdate"
>{{ resolveBtnLabel }}</gl-dropdown-item
>
<gl-dropdown-divider />
<gl-dropdown-item
v-if="error.gitlabIssuePath"
data-qa-selector="view_issue_button"
:href="error.gitlabIssuePath"
variant="success"
>{{ __('View issue') }}</gl-dropdown-item
>
<gl-dropdown-item
v-if="!error.gitlabIssuePath" v-if="!error.gitlabIssuePath"
class="btn-success"
:label="__('Create issue')"
:loading="issueCreationInProgress" :loading="issueCreationInProgress"
data-qa-selector="create_issue_button" data-qa-selector="create_issue_button"
@click="createIssue" @click="createIssue"
/> >{{ __('Create issue') }}</gl-dropdown-item
</form> >
</gl-dropdown>
</div> </div>
</div> </div>
<div> <div>
...@@ -300,7 +347,6 @@ export default { ...@@ -300,7 +347,6 @@ export default {
<strong class="bold">{{ __('Sentry event') }}:</strong> <strong class="bold">{{ __('Sentry event') }}:</strong>
<gl-link <gl-link
v-track-event="trackClickErrorLinkToSentryOptions(error.externalUrl)" v-track-event="trackClickErrorLinkToSentryOptions(error.externalUrl)"
class="d-inline-flex align-items-center"
:href="error.externalUrl" :href="error.externalUrl"
target="_blank" target="_blank"
> >
......
...@@ -15,7 +15,7 @@ export default function notificationsDropdown() { ...@@ -15,7 +15,7 @@ export default function notificationsDropdown() {
.parents('.notification-form') .parents('.notification-form')
.first(); .first();
form.find('.js-notification-loading').toggleClass('fa-bell fa-spin fa-spinner'); form.find('.js-notification-loading').toggleClass('spinner');
if (form.hasClass('no-label')) { if (form.hasClass('no-label')) {
form.find('.js-notification-loading').toggleClass('hidden'); form.find('.js-notification-loading').toggleClass('hidden');
form.find('.js-notifications-icon').toggleClass('hidden'); form.find('.js-notifications-icon').toggleClass('hidden');
......
...@@ -7,6 +7,26 @@ ...@@ -7,6 +7,26 @@
color: $blue-500; color: $blue-500;
border-color: $blue-500; border-color: $blue-500;
} }
.error-details-header {
border-bottom: 1px solid $border-color;
@include media-breakpoint-down(xs) {
flex-flow: column;
.error-details-meta-culprit {
display: flex;
}
.error-details-options {
width: 100%;
.dropdown-toggle {
text-align: center;
}
}
}
}
} }
.stacktrace { .stacktrace {
......
...@@ -39,7 +39,7 @@ class SessionsController < Devise::SessionsController ...@@ -39,7 +39,7 @@ class SessionsController < Devise::SessionsController
# would cause the CSRF token to be cleared and then # would cause the CSRF token to be cleared and then
# RequestForgeryProtection#verify_authenticity_token would fail because of # RequestForgeryProtection#verify_authenticity_token would fail because of
# token mismatch. # token mismatch.
protect_from_forgery with: :exception, prepend: true protect_from_forgery with: :exception, prepend: true, except: :destroy
CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha' CAPTCHA_HEADER = 'X-GitLab-Show-Login-Captcha'
MAX_FAILED_LOGIN_ATTEMPTS = 5 MAX_FAILED_LOGIN_ATTEMPTS = 5
......
...@@ -226,6 +226,7 @@ class Commit ...@@ -226,6 +226,7 @@ class Commit
data = { data = {
id: id, id: id,
message: safe_message, message: safe_message,
title: title,
timestamp: committed_date.xmlschema, timestamp: committed_date.xmlschema,
url: Gitlab::UrlBuilder.build(self), url: Gitlab::UrlBuilder.build(self),
author: { author: {
......
...@@ -12,7 +12,6 @@ module ChatMessage ...@@ -12,7 +12,6 @@ module ChatMessage
attr_reader :user_avatar attr_reader :user_avatar
attr_reader :project_name attr_reader :project_name
attr_reader :project_url attr_reader :project_url
attr_reader :commit_message_html
def initialize(params) def initialize(params)
@markdown = params[:markdown] || false @markdown = params[:markdown] || false
...@@ -21,7 +20,6 @@ module ChatMessage ...@@ -21,7 +20,6 @@ module ChatMessage
@user_full_name = params.dig(:user, :name) || params[:user_full_name] @user_full_name = params.dig(:user, :name) || params[:user_full_name]
@user_name = params.dig(:user, :username) || params[:user_name] @user_name = params.dig(:user, :username) || params[:user_name]
@user_avatar = params.dig(:user, :avatar_url) || params[:user_avatar] @user_avatar = params.dig(:user, :avatar_url) || params[:user_avatar]
@commit_message_html = params[:commit_message_html] || false
end end
def user_combined_name def user_combined_name
......
...@@ -52,8 +52,7 @@ module ChatMessage ...@@ -52,8 +52,7 @@ module ChatMessage
end end
def commit_messages def commit_messages
linebreak_chars = commit_message_html ? "<br/>\n<br/>\n" : "\n\n" commits.map { |commit| compose_commit_message(commit) }.join("\n\n")
commits.map { |commit| compose_commit_message(commit) }.join(linebreak_chars)
end end
def commit_message_attachments def commit_message_attachments
...@@ -63,15 +62,11 @@ module ChatMessage ...@@ -63,15 +62,11 @@ module ChatMessage
def compose_commit_message(commit) def compose_commit_message(commit)
author = commit[:author][:name] author = commit[:author][:name]
id = Commit.truncate_sha(commit[:id]) id = Commit.truncate_sha(commit[:id])
message = commit[:message] title = commit[:title]
if commit_message_html
message = message.gsub(Gitlab::Regex.breakline_regex, "<br/>\n")
end
url = commit[:url] url = commit[:url]
"[#{id}](#{url}): #{message} - #{author}" "[#{id}](#{url}): #{title} - #{author}"
end end
def new_branch? def new_branch?
......
...@@ -58,6 +58,6 @@ class MicrosoftTeamsService < ChatNotificationService ...@@ -58,6 +58,6 @@ class MicrosoftTeamsService < ChatNotificationService
end end
def custom_data(data) def custom_data(data)
super(data).merge(markdown: true, commit_message_html: true) super(data).merge(markdown: true)
end end
end end
---
title: Use only the first line of the commit message on chat service notification
merge_request: 25224
author: Takuya Noguchi
type: changed
---
title: migrate fa spinner for notification_dropdown.js
merge_request: 25141
author: minghuan
type: other
---
title: Fix error details layout and alignment for mobile view
merge_request: 24390
author:
type: fixed
---
title: Disable CSRF protection on logout endpoint
merge_request: 25521
author: Diego Louzán
type: changed
...@@ -15,8 +15,8 @@ offline unless _absolutely necessary_. ...@@ -15,8 +15,8 @@ offline unless _absolutely necessary_.
When downtime is necessary the migration has to be approved by: When downtime is necessary the migration has to be approved by:
1. The VP of Engineering 1. The VP of Engineering
1. A Backend Lead 1. A Backend Maintainer
1. A Database Specialist 1. A Database Maintainer
An up-to-date list of people holding these titles can be found at An up-to-date list of people holding these titles can be found at
<https://about.gitlab.com/company/team/>. <https://about.gitlab.com/company/team/>.
...@@ -29,6 +29,10 @@ Please don't depend on GitLab-specific code since it can change in future ...@@ -29,6 +29,10 @@ Please don't depend on GitLab-specific code since it can change in future
versions. If needed copy-paste GitLab code into the migration to make it forward versions. If needed copy-paste GitLab code into the migration to make it forward
compatible. compatible.
For GitLab.com, please take into consideration that regular migrations (under `db/migrate`)
are run before [Canary is deployed](https://about.gitlab.com/handbook/engineering/infrastructure/library/canary/#configuration-and-deployment),
and post-deployment migrations (`db/post_migrate`) are run after the deployment to production has finished.
## Schema Changes ## Schema Changes
Migrations that make changes to the database schema (e.g. adding a column) can Migrations that make changes to the database schema (e.g. adding a column) can
......
...@@ -35,7 +35,8 @@ module Gitlab ...@@ -35,7 +35,8 @@ module Gitlab
commits: [ commits: [
{ {
id: "c5feabde2d8cd023215af4d2ceeb7a64839fc428", id: "c5feabde2d8cd023215af4d2ceeb7a64839fc428",
message: "Add simple search to projects in public area", message: "Add simple search to projects in public area\n\ncommit message body",
title: "Add simple search to projects in public area",
timestamp: "2013-05-13T18:18:08+00:00", timestamp: "2013-05-13T18:18:08+00:00",
url: "https://test.example.com/gitlab/gitlab/-/commit/c5feabde2d8cd023215af4d2ceeb7a64839fc428", url: "https://test.example.com/gitlab/gitlab/-/commit/c5feabde2d8cd023215af4d2ceeb7a64839fc428",
author: { author: {
......
...@@ -165,7 +165,7 @@ module QA ...@@ -165,7 +165,7 @@ module QA
# ls-remote is one command known to respond to Git protocol v2 so we use # ls-remote is one command known to respond to Git protocol v2 so we use
# it to get output including the version reported via Git tracing # it to get output including the version reported via Git tracing
output = run("git ls-remote #{uri}", "GIT_TRACE_PACKET=1") output = run("git ls-remote #{uri}", "GIT_TRACE_PACKET=1")
output[/git< version (\d+)/, 1] || 'unknown' output.response[/git< version (\d+)/, 1] || 'unknown'
end end
def try_add_credentials_to_netrc def try_add_credentials_to_netrc
......
...@@ -69,18 +69,20 @@ describe QA::Git::Repository do ...@@ -69,18 +69,20 @@ describe QA::Git::Repository do
end end
describe '#fetch_supported_git_protocol' do describe '#fetch_supported_git_protocol' do
Result = Struct.new(:response)
it "reports the detected version" do it "reports the detected version" do
expect(repository).to receive(:run).and_return("packet: git< version 2") expect(repository).to receive(:run).and_return(Result.new("packet: git< version 2"))
expect(repository.fetch_supported_git_protocol).to eq('2') expect(repository.fetch_supported_git_protocol).to eq('2')
end end
it 'reports unknown if version is unknown' do it 'reports unknown if version is unknown' do
expect(repository).to receive(:run).and_return("packet: git< version -1") expect(repository).to receive(:run).and_return(Result.new("packet: git< version -1"))
expect(repository.fetch_supported_git_protocol).to eq('unknown') expect(repository.fetch_supported_git_protocol).to eq('unknown')
end end
it 'reports unknown if content does not identify a version' do it 'reports unknown if content does not identify a version' do
expect(repository).to receive(:run).and_return("foo") expect(repository).to receive(:run).and_return(Result.new("foo"))
expect(repository.fetch_supported_git_protocol).to eq('unknown') expect(repository.fetch_supported_git_protocol).to eq('unknown')
end end
end end
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
/* global ListLabel */ /* global ListLabel */
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import _ from 'underscore';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import '~/boards/models/label'; import '~/boards/models/label';
import '~/boards/models/assignee'; import '~/boards/models/assignee';
...@@ -40,7 +39,7 @@ describe('List model', () => { ...@@ -40,7 +39,7 @@ describe('List model', () => {
list = new List({ list = new List({
title: 'test', title: 'test',
label: { label: {
id: _.random(10000), id: 1,
title: 'test', title: 'test',
color: 'red', color: 'red',
text_color: 'white', text_color: 'white',
...@@ -96,8 +95,8 @@ describe('List model', () => { ...@@ -96,8 +95,8 @@ describe('List model', () => {
const listDup = new List(listObjDuplicate); const listDup = new List(listObjDuplicate);
const issue = new ListIssue({ const issue = new ListIssue({
title: 'Testing', title: 'Testing',
id: _.random(10000), id: 1,
iid: _.random(10000), iid: 1,
confidential: false, confidential: false,
labels: [list.label, listDup.label], labels: [list.label, listDup.label],
assignees: [], assignees: [],
...@@ -129,8 +128,8 @@ describe('List model', () => { ...@@ -129,8 +128,8 @@ describe('List model', () => {
list.issues.push( list.issues.push(
new ListIssue({ new ListIssue({
title: 'Testing', title: 'Testing',
id: _.random(10000) + i, id: i,
iid: _.random(10000) + i, iid: i,
confidential: false, confidential: false,
labels: [list.label], labels: [list.label],
assignees: [], assignees: [],
...@@ -151,7 +150,7 @@ describe('List model', () => { ...@@ -151,7 +150,7 @@ describe('List model', () => {
list.issues.push( list.issues.push(
new ListIssue({ new ListIssue({
title: 'Testing', title: 'Testing',
id: _.random(10000), id: 1,
confidential: false, confidential: false,
labels: [list.label], labels: [list.label],
assignees: [], assignees: [],
...@@ -192,7 +191,7 @@ describe('List model', () => { ...@@ -192,7 +191,7 @@ describe('List model', () => {
list.issues.push( list.issues.push(
new ListIssue({ new ListIssue({
title: 'Testing', title: 'Testing',
id: _.random(10000), id: 1,
confidential: false, confidential: false,
labels: [new ListLabel(list.label)], labels: [new ListLabel(list.label)],
assignees: [], assignees: [],
...@@ -200,7 +199,7 @@ describe('List model', () => { ...@@ -200,7 +199,7 @@ describe('List model', () => {
); );
const dummyIssue = new ListIssue({ const dummyIssue = new ListIssue({
title: 'new issue', title: 'new issue',
id: _.random(10000), id: 2,
confidential: false, confidential: false,
labels: [new ListLabel(list.label)], labels: [new ListLabel(list.label)],
assignees: [user], assignees: [user],
......
...@@ -22,8 +22,14 @@ describe ChatMessage::PushMessage do ...@@ -22,8 +22,14 @@ describe ChatMessage::PushMessage do
context 'push' do context 'push' do
before do before do
args[:commits] = [ args[:commits] = [
{ message: 'message1', url: 'http://url1.com', id: 'abcdefghijkl', author: { name: 'author1' } }, { message: 'message1', title: 'message1', url: 'http://url1.com', id: 'abcdefghijkl', author: { name: 'author1' } },
{ message: "message2\nsecondline", url: 'http://url2.com', id: '123456789012', author: { name: 'author2' } } {
message: 'message2' + ' w' * 100 + "\nsecondline",
title: 'message2 w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w ...',
url: 'http://url2.com',
id: '123456789012',
author: { name: 'author2' }
}
] ]
end end
...@@ -34,7 +40,7 @@ describe ChatMessage::PushMessage do ...@@ -34,7 +40,7 @@ describe ChatMessage::PushMessage do
'<http://url.com|project_name> (<http://url.com/compare/before...after|Compare changes>)') '<http://url.com|project_name> (<http://url.com/compare/before...after|Compare changes>)')
expect(subject.attachments).to eq([{ expect(subject.attachments).to eq([{
text: "<http://url1.com|abcdefgh>: message1 - author1\n\n"\ text: "<http://url1.com|abcdefgh>: message1 - author1\n\n"\
"<http://url2.com|12345678>: message2\nsecondline - author2", "<http://url2.com|12345678>: message2 w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w ... - author2",
color: color color: color
}]) }])
end end
...@@ -49,27 +55,7 @@ describe ChatMessage::PushMessage do ...@@ -49,27 +55,7 @@ describe ChatMessage::PushMessage do
expect(subject.pretext).to eq( expect(subject.pretext).to eq(
'test.user pushed to branch [master](http://url.com/commits/master) of [project_name](http://url.com) ([Compare changes](http://url.com/compare/before...after))') 'test.user pushed to branch [master](http://url.com/commits/master) of [project_name](http://url.com) ([Compare changes](http://url.com/compare/before...after))')
expect(subject.attachments).to eq( expect(subject.attachments).to eq(
"[abcdefgh](http://url1.com): message1 - author1\n\n[12345678](http://url2.com): message2\nsecondline - author2") "[abcdefgh](http://url1.com): message1 - author1\n\n[12345678](http://url2.com): message2 w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w w ... - author2")
expect(subject.activity).to eq(
title: 'test.user pushed to branch [master](http://url.com/commits/master)',
subtitle: 'in [project_name](http://url.com)',
text: '[Compare changes](http://url.com/compare/before...after)',
image: 'http://someavatar.com'
)
end
end
context 'with markdown and commit message html' do
before do
args[:commit_message_html] = true
args[:markdown] = true
end
it 'returns a message regarding pushes' do
expect(subject.pretext).to eq(
'test.user pushed to branch [master](http://url.com/commits/master) of [project_name](http://url.com) ([Compare changes](http://url.com/compare/before...after))')
expect(subject.attachments).to eq(
"[abcdefgh](http://url1.com): message1 - author1<br/>\n<br/>\n[12345678](http://url2.com): message2<br/>\nsecondline - author2")
expect(subject.activity).to eq( expect(subject.activity).to eq(
title: 'test.user pushed to branch [master](http://url.com/commits/master)', title: 'test.user pushed to branch [master](http://url.com/commits/master)',
subtitle: 'in [project_name](http://url.com)', subtitle: 'in [project_name](http://url.com)',
......
# frozen_string_literal: true
require 'spec_helper'
describe 'Sessions' do
context 'authentication', :allow_forgery_protection do
let(:user) { create(:user) }
it 'logout does not require a csrf token' do
login_as(user)
post(destroy_user_session_path, headers: { 'X-CSRF-Token' => 'invalid' })
expect(response).to redirect_to(new_user_session_path)
end
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