Commit f7dae0cd authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent b98fa9ef
......@@ -349,8 +349,8 @@ RSpec/HaveGitlabHttpStatus:
- 'ee/spec/requests/{groups,projects,repositories}/**/*'
- 'spec/requests/api/*/**/*.rb'
- 'ee/spec/requests/api/*/**/*.rb'
- 'spec/requests/api/[a-f]*.rb'
- 'ee/spec/requests/api/[a-f]*.rb'
- 'spec/requests/api/[a-l]*.rb'
- 'ee/spec/requests/api/[a-l]*.rb'
Style/MultilineWhenThen:
Enabled: false
......
......@@ -159,7 +159,7 @@ gem 'escape_utils', '~> 1.1'
gem 'icalendar'
# Diffs
gem 'diffy', '~> 3.1.0'
gem 'diffy', '~> 3.3'
gem 'diff_match_patch', '~> 0.1.0'
# Application server
......
......@@ -237,7 +237,7 @@ GEM
rotp (~> 2.0)
diff-lcs (1.3)
diff_match_patch (0.1.0)
diffy (3.1.0)
diffy (3.3.0)
discordrb-webhooks-blackst0ne (3.3.0)
rest-client (~> 2.0)
docile (1.3.1)
......@@ -1195,7 +1195,7 @@ DEPENDENCIES
devise (~> 4.6)
devise-two-factor (~> 3.1.0)
diff_match_patch (~> 0.1.0)
diffy (~> 3.1.0)
diffy (~> 3.3)
discordrb-webhooks-blackst0ne (~> 3.3)
doorkeeper (~> 5.0.2)
doorkeeper-openid_connect (~> 1.6.3)
......
import Vue from 'vue';
import ConfirmModal from '~/vue_shared/components/confirm_modal.vue';
const mountConfirmModal = button => {
const props = {
path: button.dataset.path,
method: button.dataset.method,
modalAttributes: JSON.parse(button.dataset.modalAttributes),
};
return new Vue({
render(h) {
return h(ConfirmModal, { props });
},
}).$mount();
};
export default () => {
document.getElementsByClassName('js-confirm-modal-button').forEach(button => {
button.addEventListener('click', e => {
e.preventDefault();
mountConfirmModal(button);
});
});
};
......@@ -259,8 +259,15 @@ export default function dropzoneInput(form) {
const insertToTextArea = (filename, url) => {
const $child = $(child);
$child.val((index, val) => val.replace(`{{${filename}}}`, url));
const textarea = $child.get(0);
const caretStart = textarea.selectionStart;
const caretEnd = textarea.selectionEnd;
const formattedText = `{{${filename}}}`;
$child.val((index, val) => val.replace(formattedText, url));
textarea.setSelectionRange(
caretStart - formattedText.length + url.length,
caretEnd - formattedText.length + url.length,
);
$child.trigger('change');
};
......
......@@ -175,6 +175,7 @@ export const localTimeAgo = ($timeagoEls, setTimeago = true) => {
function addTimeAgoTooltip() {
$timeagoEls.each((i, el) => {
// Recreate with custom template
el.setAttribute('title', formatDate(el.dateTime));
$(el).tooltip({
template:
'<div class="tooltip local-timeago" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>',
......
......@@ -169,6 +169,10 @@ const bindEvents = () => {
text: s__('ProjectTemplates|Go Micro'),
icon: '.template-option .icon-gomicro',
},
gatsby: {
text: s__('ProjectTemplates|Pages/Gatsby'),
icon: '.template-option .icon-gatsby',
},
hugo: {
text: s__('ProjectTemplates|Pages/Hugo'),
icon: '.template-option .icon-hugo',
......
<script>
import { GlModal } from '@gitlab/ui';
import csrf from '~/lib/utils/csrf';
export default {
components: {
GlModal,
},
props: {
modalAttributes: {
type: Object,
required: true,
},
path: {
type: String,
required: true,
},
method: {
type: String,
required: true,
},
},
data() {
return {
isDismissed: false,
};
},
mounted() {
this.openModal();
},
methods: {
openModal() {
this.$refs.modal.show();
},
submitModal() {
this.$refs.form.requestSubmit();
},
dismiss() {
this.isDismissed = true;
},
},
csrf,
};
</script>
<template>
<gl-modal
v-if="!isDismissed"
ref="modal"
v-bind="modalAttributes"
@primary="submitModal"
@canceled="dismiss"
>
<form ref="form" :action="path" method="post">
<!-- Rails workaround for <form method="delete" />
https://github.com/rails/rails/blob/master/actionview/app/assets/javascripts/rails-ujs/features/method.coffee
-->
<input type="hidden" name="_method" :value="method" />
<input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
<div>{{ modalAttributes.message }}</div>
</form>
</gl-modal>
</template>
......@@ -17,12 +17,6 @@
.tree-controls {
text-align: right;
> .btn,
.project-action-button > .btn,
.git-clone-holder > .btn {
margin-left: 8px;
}
.control {
float: left;
margin-left: 10px;
......
......@@ -45,6 +45,12 @@
.border-bottom-color-default { border-bottom-color: $border-color; }
.box-shadow-default { box-shadow: 0 2px 4px 0 $black-transparent; }
.gl-children-ml-sm-3 > * {
@include media-breakpoint-up(sm) {
@include gl-ml-3;
}
}
.mh-50vh { max-height: 50vh; }
.font-size-inherit { font-size: inherit; }
......
......@@ -17,7 +17,7 @@
- else
= link_to title, project_tree_path(@project, tree_join(@ref, path))
.tree-controls<
.tree-controls.gl-children-ml-sm-3<
= render 'projects/find_file_link'
-# only show normal/blame view links for text files
- if blob.readable_text?
......
......@@ -29,8 +29,7 @@
":title" => "buttonText",
":ref" => "'button'" }
= icon('spin spinner', 'v-if' => 'loading', class: 'loading', 'aria-hidden' => 'true', 'aria-label' => 'Loading')
%div{ 'v-else' => '' }
%div
%template{ 'v-if' => 'isResolved' }
= render 'shared/icons/icon_status_success_solid.svg'
%template{ 'v-else' => '' }
......@@ -40,7 +39,6 @@
- if note.emoji_awardable?
.note-actions-item
= button_tag title: 'Add reaction', class: "note-action-button note-emoji-button js-add-award js-note-emoji has-tooltip btn btn-transparent", data: { position: 'right', container: 'body' } do
= icon('spinner spin')
%span{ class: 'link-highlight award-control-icon-neutral' }= sprite_icon('slight-smile')
%span{ class: 'link-highlight award-control-icon-positive' }= sprite_icon('smiley')
%span{ class: 'link-highlight award-control-icon-super-positive' }= sprite_icon('smile')
......
......@@ -75,34 +75,35 @@
= link_to new_project_tag_path(@project) do
#{ _('New tag') }
.tree-controls{ class: ("gl-font-size-0" if vue_file_list_enabled?) }<
= render_if_exists 'projects/tree/lock_link'
- if vue_file_list_enabled?
#js-tree-history-link.d-inline-block{ data: { history_link: project_commits_path(@project, @ref) } }
- else
= link_to s_('Commits|History'), project_commits_path(@project, @id), class: 'btn'
= render 'projects/find_file_link'
- if can_collaborate || current_user&.already_forked?(@project)
.tree-controls
.d-block.d-sm-flex.flex-wrap.align-items-start.gl-children-ml-sm-3<
= render_if_exists 'projects/tree/lock_link'
- if vue_file_list_enabled?
#js-tree-web-ide-link.d-inline-block
#js-tree-history-link.d-inline-block{ data: { history_link: project_commits_path(@project, @ref) } }
- else
= link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default qa-web-ide-button' do
= link_to s_('Commits|History'), project_commits_path(@project, @id), class: 'btn'
= render 'projects/find_file_link'
- if can_collaborate || current_user&.already_forked?(@project)
- if vue_file_list_enabled?
#js-tree-web-ide-link.d-inline-block
- else
= link_to ide_edit_path(@project, @ref, @path), class: 'btn btn-default qa-web-ide-button' do
= _('Web IDE')
- elsif can_create_mr_from_fork
= link_to '#modal-confirm-fork', class: 'btn btn-default qa-web-ide-button', data: { target: '#modal-confirm-fork', toggle: 'modal'} do
= _('Web IDE')
- elsif can_create_mr_from_fork
= link_to '#modal-confirm-fork', class: 'btn btn-default qa-web-ide-button', data: { target: '#modal-confirm-fork', toggle: 'modal'} do
= _('Web IDE')
= render 'shared/confirm_fork_modal', fork_path: ide_fork_and_edit_path(@project, @ref, @path)
= render 'shared/confirm_fork_modal', fork_path: ide_fork_and_edit_path(@project, @ref, @path)
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline<
= render "projects/buttons/xcode_link"
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline<
= render "projects/buttons/xcode_link"
= render 'projects/buttons/download', project: @project, ref: @ref
= render 'projects/buttons/download', project: @project, ref: @ref
.project-clone-holder.d-block.d-md-none.mt-sm-2.mt-md-0>
= render "shared/mobile_clone_panel"
.project-clone-holder.d-none.d-md-inline-block>
= render "projects/buttons/clone", dropdown_class: 'dropdown-menu-right'
.project-clone-holder.d-none.d-md-inline-block>
= render "projects/buttons/clone", dropdown_class: 'dropdown-menu-right'
.project-clone-holder.d-block.d-md-none.mt-sm-2.mt-md-0.ml-sm-2>
= render "shared/mobile_clone_panel"
---
title: Fix Web IDE fork modal showing no text
merge_request: 25842
author:
type: fixed
---
title: Fix project setting approval input in non-sequential order
merge_request: 25391
author:
type: fixed
---
title: Remove spinner from app/views/projects/notes
merge_request: 25015
author: nuwe1
type: other
---
title: Add Project template for Gatsby
merge_request: 25486
author:
type: added
---
title: Fixes caret position after pasting an image 15011
merge_request: 21382
author: Carolina Carvalhosa
type: fixed
---
title: Fix timezones for popovers.
merge_request: 24942
author:
type: fixed
......@@ -200,11 +200,18 @@ by the `gitlab:artifacts:migrate` script.
### Migrating from object storage to local storage
**In Omnibus installations:**
In order to migrate back to local storage:
1. Set both `direct_upload` and `background_upload` to false under the artifacts object storage settings. Don't forget to restart GitLab.
1. Run `rake gitlab:artifacts:migrate_to_local` on your console.
1. Disable `object_storage` for artifacts in `gitlab.rb`. Remember to restart GitLab afterwards.
1. Set both `direct_upload` and `background_upload` to false in `gitlab.rb`, under the artifacts object storage settings.
1. [reconfigure GitLab][].
1. Run `gitlab-rake gitlab:artifacts:migrate_to_local`.
1. Disable object_storage for artifacts in `gitlab.rb`:
- Set `gitlab_rails['artifacts_object_store_enabled'] = false`.
- Comment out all other `artifacts_object_store` settings, including the entire
`artifacts_object_store_connection` section, including the closing `}`.
1. [reconfigure GitLab][].
## Expiring artifacts
......
......@@ -118,7 +118,31 @@ button.addEventListener('click', () => {
## Tests and test helpers
In Karma tests, you can use the following:
In Jest particularly in vue tests, you can use the following:
```javascript
import { mockTracking } from 'helpers/tracking_helper';
describe('MyTracking', () => {
let spy;
beforeEach(() => {
spy = mockTracking('_category_', wrapper.element, jest.spyOn);
});
it('tracks an event when clicked on feedback', () => {
wrapper.find('.discover-feedback-icon').trigger('click');
expect(spy).toHaveBeenCalledWith('_category_', 'click_button', {
label: 'security-discover-feedback-cta',
property: '0',
});
});
});
```
In obsolete Karma tests it's used as below:
```javascript
import { mockTracking, triggerEvent } from 'spec/helpers/tracking_helper';
......
......@@ -30,7 +30,7 @@ instances (GitLab Core, Starter, Premium, and Ultimate).
<div class="col-md-9">
<p style="margin-top: 18px;">
To publish a website with Pages, you can use any Static Site Generator (SSG),
such as Jekyll, Hugo, Middleman, Harp, Hexo, and Brunch, just to name a few. You can also
such as Gatsby, Jekyll, Hugo, Middleman, Harp, Hexo, and Brunch, just to name a few. You can also
publish any website written directly in plain HTML, CSS, and JavaScript.</p>
<p>Pages does <strong>not</strong> support dynamic server-side processing, for instance, as <code>.php</code> and <code>.asp</code> requires. See this article to learn more about
<a href="https://about.gitlab.com/blog/2016/06/03/ssg-overview-gitlab-pages-part-1-dynamic-x-static/">static websites vs dynamic websites</a>.</p>
......
......@@ -182,9 +182,14 @@ If **Public pipelines** is disabled:
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/9362) in GitLab 9.1.
If you want to auto-cancel all pending non-HEAD pipelines on branch, when
new pipeline will be created (after your Git push or manually from UI),
check **Auto-cancel pending pipelines** checkbox and save the changes.
If you want all pending non-HEAD pipelines on branches to auto-cancel each time
a new pipeline is created, such as after a Git push or manually from the UI,
you can enable this in the project settings:
1. Go to **{settings}** **Settings > CI / CD**.
1. Expand **General Pipelines**.
1. Check the **Auto-cancel redundant, pending pipelines** checkbox.
1. Click **Save changes**.
## Pipeline Badges
......
......@@ -44,6 +44,7 @@ module Gitlab
ProjectTemplate.new('dotnetcore', '.NET Core', _('A .NET Core console application template, customizable for any .NET Core project'), 'https://gitlab.com/gitlab-org/project-templates/dotnetcore', 'illustrations/logos/dotnet.svg'),
ProjectTemplate.new('android', 'Android', _('A ready-to-go template for use with Android apps.'), 'https://gitlab.com/gitlab-org/project-templates/android', 'illustrations/logos/android.svg'),
ProjectTemplate.new('gomicro', 'Go Micro', _('Go Micro is a framework for micro service development.'), 'https://gitlab.com/gitlab-org/project-templates/go-micro'),
ProjectTemplate.new('gatsby', 'Pages/Gatsby', _('Everything you need to create a GitLab Pages site using Gatsby.'), 'https://gitlab.com/pages/gatsby'),
ProjectTemplate.new('hugo', 'Pages/Hugo', _('Everything you need to create a GitLab Pages site using Hugo.'), 'https://gitlab.com/pages/hugo'),
ProjectTemplate.new('jekyll', 'Pages/Jekyll', _('Everything you need to create a GitLab Pages site using Jekyll.'), 'https://gitlab.com/pages/jekyll'),
ProjectTemplate.new('plainhtml', 'Pages/Plain HTML', _('Everything you need to create a GitLab Pages site using plain HTML.'), 'https://gitlab.com/pages/plain-html'),
......
......@@ -7924,6 +7924,9 @@ msgstr ""
msgid "Everything on your to-do list is marked as done."
msgstr ""
msgid "Everything you need to create a GitLab Pages site using Gatsby."
msgstr ""
msgid "Everything you need to create a GitLab Pages site using GitBook."
msgstr ""
......@@ -15206,6 +15209,9 @@ msgstr ""
msgid "ProjectTemplates|NodeJS Express"
msgstr ""
msgid "ProjectTemplates|Pages/Gatsby"
msgstr ""
msgid "ProjectTemplates|Pages/GitBook"
msgstr ""
......@@ -18558,6 +18564,9 @@ msgstr ""
msgid "Subscription deletion failed."
msgstr ""
msgid "Subscription successfully applied to \"%{group_name}\""
msgstr ""
msgid "Subscription successfully created."
msgstr ""
......
......@@ -37,6 +37,7 @@ describe 'Environments page', :js do
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
expect(page.all('.ic-stop').length).to eq(1)
end
end
......@@ -105,6 +106,7 @@ describe 'Environments page', :js do
expect(page).to have_css('.environments-container')
expect(page.all('.environment-name').length).to eq(1)
expect(page.all('.ic-stop').length).to eq(0)
end
end
end
......
import Vue from 'vue';
import initConfirmModal from '~/confirm_modal';
import { TEST_HOST } from 'helpers/test_constants';
describe('ConfirmModal', () => {
const buttons = [
{
path: `${TEST_HOST}/1`,
method: 'delete',
modalAttributes: {
modalId: 'geo-entry-removal-modal',
title: 'Remove tracking database entry',
message: 'Tracking database entry will be removed. Are you sure?',
okVariant: 'danger',
okTitle: 'Remove entry',
},
},
{
path: `${TEST_HOST}/1`,
method: 'post',
modalAttributes: {
modalId: 'geo-entry-removal-modal',
title: 'Update tracking database entry',
message: 'Tracking database entry will be updated. Are you sure?',
okVariant: 'success',
okTitle: 'Update entry',
},
},
];
beforeEach(() => {
const buttonContainer = document.createElement('div');
buttons.forEach(x => {
const button = document.createElement('button');
button.setAttribute('class', 'js-confirm-modal-button');
button.setAttribute('data-path', x.path);
button.setAttribute('data-method', x.method);
button.setAttribute('data-modal-attributes', JSON.stringify(x.modalAttributes));
button.innerHTML = 'Action';
buttonContainer.appendChild(button);
});
document.body.appendChild(buttonContainer);
});
afterEach(() => {
document.body.innerHTML = '';
});
const findJsHooks = () => document.querySelectorAll('.js-confirm-modal-button');
const findModal = () => document.querySelector('.gl-modal');
const findModalOkButton = (modal, variant) =>
modal.querySelector(`.modal-footer .btn-${variant}`);
const findModalCancelButton = modal => modal.querySelector('.modal-footer .btn-secondary');
const serializeModal = (modal, buttonIndex) => {
const { modalAttributes } = buttons[buttonIndex];
return {
path: modal.querySelector('form').action,
method: modal.querySelector('input[name="_method"]').value,
modalAttributes: {
modalId: modal.id,
title: modal.querySelector('.modal-title').innerHTML,
message: modal.querySelector('.modal-body div').innerHTML,
okVariant: [...findModalOkButton(modal, modalAttributes.okVariant).classList]
.find(x => x.match('btn-'))
.replace('btn-', ''),
okTitle: findModalOkButton(modal, modalAttributes.okVariant).innerHTML,
},
};
};
it('starts with only JsHooks', () => {
expect(findJsHooks()).toHaveLength(buttons.length);
expect(findModal()).not.toExist();
});
describe('when button clicked', () => {
beforeEach(() => {
initConfirmModal();
findJsHooks()
.item(0)
.click();
});
it('does not replace JsHook with GlModal', () => {
expect(findJsHooks()).toHaveLength(buttons.length);
});
describe('GlModal', () => {
it('is rendered', () => {
expect(findModal()).toExist();
});
describe('Cancel Button', () => {
beforeEach(() => {
findModalCancelButton(findModal()).click();
return Vue.nextTick();
});
it('closes the modal', () => {
expect(findModal()).not.toExist();
});
});
});
});
describe.each`
index
${0}
${1}
`(`when multiple buttons exist`, ({ index }) => {
beforeEach(() => {
initConfirmModal();
findJsHooks()
.item(index)
.click();
});
it('correct props are passed to gl-modal', () => {
expect(serializeModal(findModal(), index)).toEqual(buttons[index]);
});
});
});
import { __, s__ } from '~/locale';
import $ from 'jquery';
import '~/commons/bootstrap';
import * as datetimeUtility from '~/lib/utils/datetime_utility';
describe('Date time utils', () => {
......@@ -563,3 +565,23 @@ describe('approximateDuration', () => {
expect(datetimeUtility.approximateDuration(seconds)).toBe(approximation);
});
});
describe('localTimeAgo', () => {
beforeEach(() => {
document.body.innerHTML = `<time title="some time" datetime="2020-02-18T22:22:32Z">1 hour ago</time>`;
});
it.each`
timeagoArg | title | dataOriginalTitle
${false} | ${'some time'} | ${null}
${true} | ${''} | ${'Feb 18, 2020 10:22pm GMT+0000'}
`('converts $seconds seconds to $approximation', ({ timeagoArg, title, dataOriginalTitle }) => {
const element = document.querySelector('time');
datetimeUtility.localTimeAgo($(element), timeagoArg);
jest.runAllTimers();
expect(element.getAttribute('data-original-title')).toBe(dataOriginalTitle);
expect(element.getAttribute('title')).toBe(title);
});
});
import { shallowMount } from '@vue/test-utils';
import { GlModal } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import ConfirmModal from '~/vue_shared/components/confirm_modal.vue';
describe('vue_shared/components/confirm_modal', () => {
const testModalProps = {
path: `${TEST_HOST}/1`,
method: 'delete',
modalAttributes: {
modalId: 'test-confirm-modal',
title: 'Are you sure?',
message: 'This will remove item 1',
okVariant: 'danger',
okTitle: 'Remove item',
},
};
const actionSpies = {
openModal: jest.fn(),
};
let wrapper;
const createComponent = (props = {}) => {
wrapper = shallowMount(ConfirmModal, {
propsData: {
...testModalProps,
...props,
},
methods: {
...actionSpies,
},
});
};
afterEach(() => {
wrapper.destroy();
});
const findModal = () => wrapper.find(GlModal);
describe('template', () => {
beforeEach(() => {
createComponent();
});
it('calls openModal on mount', () => {
expect(actionSpies.openModal).toHaveBeenCalled();
});
it('renders GlModal', () => {
expect(findModal().exists()).toBeTruthy();
});
});
describe('methods', () => {
beforeEach(() => {
createComponent();
});
describe('submitModal', () => {
beforeEach(() => {
wrapper.vm.$refs.form.requestSubmit = jest.fn();
});
it('calls requestSubmit', () => {
wrapper.vm.submitModal();
expect(wrapper.vm.$refs.form.requestSubmit).toHaveBeenCalled();
});
});
describe('dismiss', () => {
it('removes gl-modal', () => {
expect(findModal().exists()).toBeTruthy();
wrapper.vm.dismiss();
return wrapper.vm.$nextTick(() => {
expect(findModal().exists()).toBeFalsy();
});
});
});
});
});
......@@ -13,6 +13,7 @@ describe Gitlab::ProjectTemplate do
described_class.new('dotnetcore', '.NET Core', 'A .NET Core console application template, customizable for any .NET Core project', 'https://gitlab.com/gitlab-org/project-templates/dotnetcore'),
described_class.new('android', 'Android', 'A ready-to-go template for use with Android apps.', 'https://gitlab.com/gitlab-org/project-templates/android'),
described_class.new('gomicro', 'Go Micro', 'Go Micro is a framework for micro service development.', 'https://gitlab.com/gitlab-org/project-templates/go-micro'),
described_class.new('gatsby', 'Pages/Gatsby', 'Everything you need to get started using a Gatsby site.', 'https://gitlab.com/pages/gatsby'),
described_class.new('hugo', 'Pages/Hugo', 'Everything you need to get started using a Hugo Pages site.', 'https://gitlab.com/pages/hugo'),
described_class.new('jekyll', 'Pages/Jekyll', 'Everything you need to get started using a Jekyll Pages site.', 'https://gitlab.com/pages/jekyll'),
described_class.new('plainhtml', 'Pages/Plain HTML', 'Everything you need to get started using a plain HTML Pages site.', 'https://gitlab.com/pages/plain-html'),
......
......@@ -58,7 +58,7 @@ describe 'GraphQL' do
it 'returns an error' do
post_graphql(query, variables: "This is not JSON")
expect(response).to have_gitlab_http_status(422)
expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response['errors'].first['message']).not_to be_nil
end
end
......@@ -114,7 +114,7 @@ describe 'GraphQL' do
post_graphql(query, headers: { 'PRIVATE-TOKEN' => token.token })
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(graphql_data['echo']).to eq('nil says: Hello world')
end
......
......@@ -50,7 +50,7 @@ describe API::GroupBoards do
post api(url, user), params: { label_id: project_label.id }
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
......@@ -26,7 +26,7 @@ describe API::GroupClusters do
it 'responds with 403' do
get api("/groups/#{group.id}/clusters", developer_user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -36,7 +36,7 @@ describe API::GroupClusters do
end
it 'responds with 200' do
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
end
it 'includes pagination headers' do
......@@ -70,7 +70,7 @@ describe API::GroupClusters do
it 'responds with 403' do
get api("/groups/#{group.id}/clusters/#{cluster_id}", developer_user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -140,7 +140,7 @@ describe API::GroupClusters do
let(:cluster_id) { 123 }
it 'returns 404' do
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......@@ -179,7 +179,7 @@ describe API::GroupClusters do
it 'responds with 403' do
post api("/groups/#{group.id}/clusters/user", developer_user), params: cluster_params
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -190,7 +190,7 @@ describe API::GroupClusters do
context 'with valid params' do
it 'responds with 201' do
expect(response).to have_gitlab_http_status(201)
expect(response).to have_gitlab_http_status(:created)
end
it 'creates a new Cluster::Cluster' do
......@@ -238,7 +238,7 @@ describe API::GroupClusters do
let(:api_url) { 'invalid_api_url' }
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'does not create a new Clusters::Cluster' do
......@@ -260,7 +260,7 @@ describe API::GroupClusters do
end
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['message']['base'].first).to eq(_('Instance does not support multiple Kubernetes clusters'))
end
end
......@@ -271,7 +271,7 @@ describe API::GroupClusters do
end
it 'responds with 403' do
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden')
end
......@@ -305,7 +305,7 @@ describe API::GroupClusters do
it 'responds with 403' do
put api("/groups/#{group.id}/clusters/#{cluster.id}", developer_user), params: update_params
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -320,7 +320,7 @@ describe API::GroupClusters do
context 'with valid params' do
it 'responds with 200' do
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
end
it 'updates cluster attributes' do
......@@ -333,7 +333,7 @@ describe API::GroupClusters do
let(:domain) { 'invalid domain' }
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'does not update cluster attributes' do
......@@ -350,7 +350,7 @@ describe API::GroupClusters do
let(:management_project_id) { create(:project).id }
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'returns validation errors' do
......@@ -368,7 +368,7 @@ describe API::GroupClusters do
end
it 'responds with 400' do
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
it 'returns validation error' do
......@@ -380,7 +380,7 @@ describe API::GroupClusters do
let(:domain) { 'new-domain.com' }
it 'responds with 200' do
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
end
end
end
......@@ -408,7 +408,7 @@ describe API::GroupClusters do
end
it 'responds with 200' do
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
end
it 'updates platform kubernetes attributes' do
......@@ -424,7 +424,7 @@ describe API::GroupClusters do
let(:cluster) { create(:cluster, :group, :provided_by_user) }
it 'responds with 404' do
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......@@ -442,7 +442,7 @@ describe API::GroupClusters do
it 'responds with 403' do
delete api("/groups/#{group.id}/clusters/#{cluster.id}", developer_user), params: cluster_params
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -452,7 +452,7 @@ describe API::GroupClusters do
end
it 'responds with 204' do
expect(response).to have_gitlab_http_status(204)
expect(response).to have_gitlab_http_status(:no_content)
end
it 'deletes the cluster' do
......@@ -463,7 +463,7 @@ describe API::GroupClusters do
let(:cluster) { create(:cluster, :group, :provided_by_user) }
it 'responds with 404' do
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......
......@@ -44,7 +44,7 @@ describe API::GroupExport do
it 'downloads exported group archive' do
get api(download_path, user)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
end
context 'when export_file.file does not exist' do
......@@ -57,7 +57,7 @@ describe API::GroupExport do
it 'returns 404' do
get api(download_path, user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......@@ -66,7 +66,7 @@ describe API::GroupExport do
it 'returns 404' do
get api(download_path, user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......@@ -79,7 +79,7 @@ describe API::GroupExport do
it 'responds with 404 Not Found' do
get api(download_path, user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......@@ -98,7 +98,7 @@ describe API::GroupExport do
it 'accepts download' do
post api(path, user)
expect(response).to have_gitlab_http_status(202)
expect(response).to have_gitlab_http_status(:accepted)
end
end
......@@ -110,7 +110,7 @@ describe API::GroupExport do
it 'forbids the request' do
post api(path, user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
......@@ -123,7 +123,7 @@ describe API::GroupExport do
it 'responds with 404 Not Found' do
post api(path, user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
......
......@@ -42,7 +42,7 @@ describe API::GroupImport do
it 'creates new group and accepts request' do
subject
expect(response).to have_gitlab_http_status(202)
expect(response).to have_gitlab_http_status(:accepted)
end
it 'creates private group' do
......@@ -63,7 +63,7 @@ describe API::GroupImport do
subject
expect(response).to have_gitlab_http_status(202)
expect(response).to have_gitlab_http_status(:accepted)
expect(group.children.count).to eq(1)
end
......@@ -81,7 +81,7 @@ describe API::GroupImport do
subject
expect(response).to have_gitlab_http_status(202)
expect(response).to have_gitlab_http_status(:accepted)
expect(public_parent_group.children.first.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
end
......@@ -90,7 +90,7 @@ describe API::GroupImport do
subject
expect(response).to have_gitlab_http_status(202)
expect(response).to have_gitlab_http_status(:accepted)
expect(internal_parent_group.children.first.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL)
end
end
......@@ -101,7 +101,7 @@ describe API::GroupImport do
expect { subject }.not_to change { Group.count }
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Group Not Found')
end
......@@ -111,7 +111,7 @@ describe API::GroupImport do
subject
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
expect(json_response['message']).to eq('403 Forbidden')
end
end
......@@ -128,7 +128,7 @@ describe API::GroupImport do
it 'returns 400 HTTP status' do
subject
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
end
end
......@@ -139,7 +139,7 @@ describe API::GroupImport do
it 'forbids the request' do
subject
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
end
......@@ -154,7 +154,7 @@ describe API::GroupImport do
post api('/groups/import', user), params: params, headers: workhorse_header
end.not_to change { Group.count }.from(1)
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq(error_message)
end
end
......
This diff is collapsed.
......@@ -17,7 +17,7 @@ describe API::GroupVariables do
it 'returns group variables' do
get api("/groups/#{group.id}/variables", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_a(Array)
end
end
......@@ -26,7 +26,7 @@ describe API::GroupVariables do
it 'does not return group variables' do
get api("/groups/#{group.id}/variables", user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -34,7 +34,7 @@ describe API::GroupVariables do
it 'does not return group variables' do
get api("/groups/#{group.id}/variables")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
......@@ -50,7 +50,7 @@ describe API::GroupVariables do
it 'returns group variable details' do
get api("/groups/#{group.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['value']).to eq(variable.value)
expect(json_response['protected']).to eq(variable.protected?)
expect(json_response['variable_type']).to eq(variable.variable_type)
......@@ -59,7 +59,7 @@ describe API::GroupVariables do
it 'responds with 404 Not Found if requesting non-existing variable' do
get api("/groups/#{group.id}/variables/non_existing_variable", user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
......@@ -67,7 +67,7 @@ describe API::GroupVariables do
it 'does not return group variable details' do
get api("/groups/#{group.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -75,7 +75,7 @@ describe API::GroupVariables do
it 'does not return group variable details' do
get api("/groups/#{group.id}/variables/#{variable.key}")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
......@@ -93,7 +93,7 @@ describe API::GroupVariables do
post api("/groups/#{group.id}/variables", user), params: { key: 'TEST_VARIABLE_2', value: 'PROTECTED_VALUE_2', protected: true, masked: true }
end.to change {group.variables.count}.by(1)
expect(response).to have_gitlab_http_status(201)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('PROTECTED_VALUE_2')
expect(json_response['protected']).to be_truthy
......@@ -106,7 +106,7 @@ describe API::GroupVariables do
post api("/groups/#{group.id}/variables", user), params: { variable_type: 'file', key: 'TEST_VARIABLE_2', value: 'VALUE_2' }
end.to change {group.variables.count}.by(1)
expect(response).to have_gitlab_http_status(201)
expect(response).to have_gitlab_http_status(:created)
expect(json_response['key']).to eq('TEST_VARIABLE_2')
expect(json_response['value']).to eq('VALUE_2')
expect(json_response['protected']).to be_falsey
......@@ -119,7 +119,7 @@ describe API::GroupVariables do
post api("/groups/#{group.id}/variables", user), params: { key: variable.key, value: 'VALUE_2' }
end.to change {group.variables.count}.by(0)
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
end
end
......@@ -127,7 +127,7 @@ describe API::GroupVariables do
it 'does not create variable' do
post api("/groups/#{group.id}/variables", user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -135,7 +135,7 @@ describe API::GroupVariables do
it 'does not create variable' do
post api("/groups/#{group.id}/variables")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
......@@ -156,7 +156,7 @@ describe API::GroupVariables do
updated_variable = group.variables.reload.first
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(value_before).to eq(variable.value)
expect(updated_variable.value).to eq('VALUE_1_UP')
expect(updated_variable).to be_protected
......@@ -167,7 +167,7 @@ describe API::GroupVariables do
it 'responds with 404 Not Found if requesting non-existing variable' do
put api("/groups/#{group.id}/variables/non_existing_variable", user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
end
......@@ -175,7 +175,7 @@ describe API::GroupVariables do
it 'does not update variable' do
put api("/groups/#{group.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -183,7 +183,7 @@ describe API::GroupVariables do
it 'does not update variable' do
put api("/groups/#{group.id}/variables/#{variable.key}")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
......@@ -200,14 +200,14 @@ describe API::GroupVariables do
expect do
delete api("/groups/#{group.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(204)
expect(response).to have_gitlab_http_status(:no_content)
end.to change {group.variables.count}.by(-1)
end
it 'responds with 404 Not Found if requesting non-existing variable' do
delete api("/groups/#{group.id}/variables/non_existing_variable", user)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
end
it_behaves_like '412 response' do
......@@ -219,7 +219,7 @@ describe API::GroupVariables do
it 'does not delete variable' do
delete api("/groups/#{group.id}/variables/#{variable.key}", user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
end
......@@ -227,7 +227,7 @@ describe API::GroupVariables do
it 'does not delete variable' do
delete api("/groups/#{group.id}/variables/#{variable.key}")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end
......
This diff is collapsed.
......@@ -269,7 +269,7 @@ describe API::Helpers do
# The 500 status is expected as we're testing a case where an exception
# is raised, but Grape shouldn't raise an additional exception
expect(response).to have_gitlab_http_status(500)
expect(response).to have_gitlab_http_status(:internal_server_error)
expect(json_response['message']).not_to include("undefined local variable or method `request'")
expect(json_response['message']).to start_with("\nRuntimeError (Runtime Error!):")
end
......
......@@ -36,7 +36,7 @@ describe API::ImportGithub do
personal_access_token: token,
repo_id: 1234
}
expect(response).to have_gitlab_http_status(201)
expect(response).to have_gitlab_http_status(:created)
expect(json_response).to be_a Hash
expect(json_response['name']).to eq(project.name)
end
......@@ -50,7 +50,7 @@ describe API::ImportGithub do
repo_id: 1234
}
expect(response).to have_gitlab_http_status(422)
expect(response).to have_gitlab_http_status(:unprocessable_entity)
end
end
end
This diff is collapsed.
......@@ -12,21 +12,21 @@ describe API::Keys do
context 'when unauthenticated' do
it 'returns authentication error' do
get api("/keys/#{key.id}")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
context 'when authenticated' do
it 'returns 404 for non-existing key' do
get api('/keys/0', admin)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Not found')
end
it 'returns single ssh key with user information' do
user.keys << key
get api("/keys/#{key.id}", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(key.title)
expect(json_response['user']['id']).to eq(user.id)
expect(json_response['user']['username']).to eq(user.username)
......@@ -44,27 +44,27 @@ describe API::Keys do
it 'returns authentication error' do
get api("/keys?fingerprint=#{key.fingerprint}")
expect(response).to have_gitlab_http_status(401)
expect(response).to have_gitlab_http_status(:unauthorized)
end
it 'returns authentication error when authenticated as user' do
get api("/keys?fingerprint=#{key.fingerprint}", user)
expect(response).to have_gitlab_http_status(403)
expect(response).to have_gitlab_http_status(:forbidden)
end
context 'when authenticated as admin' do
it 'returns 404 for non-existing SSH md5 fingerprint' do
get api("/keys?fingerprint=11:11:11:11:11:11:11:11:11:11:11:11:11:11:11:11", admin)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Key Not Found')
end
it 'returns 404 for non-existing SSH sha256 fingerprint' do
get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:nUhzNyftwADy8AH3wFY31tAKs7HufskYTte2aXo1lCg")}", admin)
expect(response).to have_gitlab_http_status(404)
expect(response).to have_gitlab_http_status(:not_found)
expect(json_response['message']).to eq('404 Key Not Found')
end
......@@ -73,7 +73,7 @@ describe API::Keys do
get api("/keys?fingerprint=#{key.fingerprint}", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(key.title)
expect(json_response['user']['id']).to eq(user.id)
expect(json_response['user']['username']).to eq(user.username)
......@@ -84,7 +84,7 @@ describe API::Keys do
get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:" + key.fingerprint_sha256)}", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(key.title)
expect(json_response['user']['id']).to eq(user.id)
expect(json_response['user']['username']).to eq(user.username)
......@@ -95,7 +95,7 @@ describe API::Keys do
get api("/keys?fingerprint=#{URI.encode_www_form_component("sha256:" + key.fingerprint_sha256)}", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(key.title)
expect(json_response['user']['id']).to eq(user.id)
expect(json_response['user']['username']).to eq(user.username)
......@@ -125,7 +125,7 @@ describe API::Keys do
get api("/keys?fingerprint=#{URI.encode_www_form_component("SHA256:" + deploy_key.fingerprint_sha256)}", admin)
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['title']).to eq(deploy_key.title)
expect(json_response['user']['id']).to eq(user.id)
......
This diff is collapsed.
......@@ -12,7 +12,7 @@ describe API::Lint do
it 'passes validation' do
post api('/ci/lint'), params: { content: yaml_content }
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to be_an Hash
expect(json_response['status']).to eq('valid')
expect(json_response['errors']).to eq([])
......@@ -23,7 +23,7 @@ describe API::Lint do
it 'responds with errors about invalid syntax' do
post api('/ci/lint'), params: { content: 'invalid content' }
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['status']).to eq('invalid')
expect(json_response['errors']).to eq(['Invalid configuration format'])
end
......@@ -31,7 +31,7 @@ describe API::Lint do
it "responds with errors about invalid configuration" do
post api('/ci/lint'), params: { content: '{ image: "ruby:2.1", services: ["postgres"] }' }
expect(response).to have_gitlab_http_status(200)
expect(response).to have_gitlab_http_status(:ok)
expect(json_response['status']).to eq('invalid')
expect(json_response['errors']).to eq(['jobs config should contain at least one visible job'])
end
......@@ -41,7 +41,7 @@ describe API::Lint do
it 'responds with validation error about missing content' do
post api('/ci/lint')
expect(response).to have_gitlab_http_status(400)
expect(response).to have_gitlab_http_status(:bad_request)
expect(json_response['error']).to eq('content is missing')
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