Skip to content
Snippets Groups Projects
Commit b304a723 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent b84eeb25
No related branches found
No related tags found
No related merge requests found
Showing
with 375 additions and 91 deletions
# frozen_string_literal: true
class MigrateSyncSecurityReportsToReportApprovalRulesSidekiqQueue < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
sidekiq_queue_migrate 'pipeline_default:sync_security_reports_to_report_approval_rules',
to: 'security_scans:sync_security_reports_to_report_approval_rules'
end
def down
sidekiq_queue_migrate 'security_scans:sync_security_reports_to_report_approval_rules',
to: 'pipeline_default:sync_security_reports_to_report_approval_rules'
end
end
Loading
Loading
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
 
ActiveRecord::Schema.define(version: 2020_02_13_204737) do
ActiveRecord::Schema.define(version: 2020_02_13_220211) do
 
# These are extensions that must be enabled in order to support this database
enable_extension "pg_trgm"
Loading
Loading
Loading
Loading
@@ -261,7 +261,10 @@ gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
# Configure the gitlab-shell API callback URL. Without this, `git push` will
# fail. This can be your 'front door' GitLab URL or an internal load
# balancer.
gitlab_rails['internal_api_url'] = 'https://gitlab.example.com'
# Possible values could be: 'http://10.23.101.53', 'https://gitlab.example.com',
# etc. Please replace GITLAB_SERVER_ADDRESS with proper value and change schema
# to 'https' in case you use encrypted connection.
gitlab_rails['internal_api_url'] = 'http://GITLAB_SERVER_ADDRESS'
 
# Replace PRAEFECT_INTERNAL_TOKEN below with a real secret.
gitaly['auth_token'] = 'PRAEFECT_INTERNAL_TOKEN'
Loading
Loading
@@ -324,6 +327,12 @@ git_data_dirs({
 
# Replace GITLAB_SHELL_SECRET_TOKEN below with real secret
gitlab_shell['secret_token'] = 'GITLAB_SHELL_SECRET_TOKEN'
# Possible values could be: 'http://10.23.101.53', 'https://gitlab.example.com',
# etc. Please replace GITLAB_SERVER_ADDRESS with proper value and change schema
# to 'https' in case you use encrypted connection. For more info please refer
# to https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab
external_url "http://<GITLAB_SERVER_ADDRESS>"
```
 
Replace `GITLAB_SHELL_SECRET_TOKEN` and `PRAEFECT_EXTERNAL_TOKEN`
Loading
Loading
Loading
Loading
@@ -42,25 +42,25 @@ sprite_icon(icon_name, size: nil, css_class: '')
 
### Usage in Vue
 
We have a special Vue component for our sprite icons in `\vue_shared\components\icon.vue`.
[GitLab UI][gitlab-ui], our components library, provides a component to display sprite icons.
 
Sample usage :
 
```javascript
```html
<script>
import Icon from "~/vue_shared/components/icon.vue"
import { GlIcon } from "@gitlab/ui";
 
export default {
components: {
Icon,
GlIcon,
},
};
<script>
<template>
<icon
<gl-icon
name="issues"
:size="24"
class="icon-danger"
/>
</template>
```
Loading
Loading
@@ -95,7 +95,7 @@ To use an SVG illustrations in a template provide the path as a property and dis
 
Component:
 
```js
```html
<script>
export default {
props: {
Loading
Loading
@@ -106,6 +106,7 @@ export default {
},
};
<script>
<template>
<img :src="svgIllustrationPath" />
</template>
Loading
Loading
@@ -114,3 +115,4 @@ export default {
[npm]: https://www.npmjs.com/package/@gitlab/svgs
[gitlab-svgs]: https://gitlab.com/gitlab-org/gitlab-svgs
[svg-preview]: https://gitlab-org.gitlab.io/gitlab-svgs
[gitlab-ui]: https://gitlab-org.gitlab.io/gitlab-ui/
Loading
Loading
@@ -253,7 +253,6 @@ graph RL;
E[review-build-cng];
F[build-qa-image];
G[review-deploy];
G2["schedule:review-deploy<br/>(master only)"];
I["karma, jest, webpack-dev-server, static-analysis"];
I2["karma-foss, jest-foss<br/>(EE default refs only)"];
J["compile-assets pull-push-cache<br/>(master only)"];
Loading
Loading
@@ -297,19 +296,16 @@ subgraph "`post-test` stage"
 
subgraph "`review-prepare` stage"
E -.-> |needs| C;
E2["schedule:review-build-cng<br/>(master schedule only)"] -.-> |needs| C;
end
 
subgraph "`review` stage"
G --> |happens after| E
G2 --> |happens after| E2
G -.-> |needs| E
end
 
subgraph "`qa` stage"
Q -.-> |needs| C;
Q -.-> |needs| F;
QA1["review-qa-smoke, review-qa-all, review-performance, dast"] -.-> |needs and depends on| G;
QA2["schedule:review-performance<br/>(master only)"] -.-> |needs and depends on| G2;
QA1["review-qa-smoke, review-qa-all, review-performance, dast"] -.-> |needs| G;
end
 
subgraph "`post-qa` stage"
Loading
Loading
Loading
Loading
@@ -28,8 +28,6 @@ included_attributes:
excluded_attributes:
group:
- :id
- :name
- :path
- :owner_id
- :parent_id
- :created_at
Loading
Loading
Loading
Loading
@@ -7806,6 +7806,9 @@ msgstr ""
msgid "Events"
msgstr ""
 
msgid "Events in %{group_name}"
msgstr ""
msgid "Events in %{project_path}"
msgstr ""
 
Loading
Loading
@@ -9525,6 +9528,9 @@ msgstr ""
msgid "Group %{group_name} was successfully created."
msgstr ""
 
msgid "Group Audit Events"
msgstr ""
msgid "Group CI/CD settings"
msgstr ""
 
Loading
Loading
@@ -23123,6 +23129,9 @@ msgstr ""
msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB"
msgstr ""
 
msgid "mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd} %{addPipelineLinkStart}Add the .gitlab-ci.yml file%{addPipelineLinkEnd} to create one."
msgstr ""
msgid "mrWidget|Added to the merge train by"
msgstr ""
 
Loading
Loading
import { shallowMount } from '@vue/test-utils';
import DiffFileRow from '~/diffs/components/diff_file_row.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowStats from '~/diffs/components/file_row_stats.vue';
 
describe('Diff File Row component', () => {
let wrapper;
Loading
Loading
@@ -16,10 +17,42 @@ describe('Diff File Row component', () => {
});
 
it('renders file row component', () => {
createComponent({
const sharedProps = {
level: 4,
file: {},
};
const diffFileRowProps = {
hideFileStats: false,
};
createComponent({
...sharedProps,
...diffFileRowProps,
});
expect(wrapper.find(FileRow).props()).toEqual(
expect.objectContaining({
...sharedProps,
}),
);
});
describe('FileRowStats components', () => {
it.each`
type | hideFileStats | value | desc
${'blob'} | ${false} | ${true} | ${'is shown if file type is blob'}
${'tree'} | ${false} | ${false} | ${'is hidden if file is not blob'}
${'blob'} | ${true} | ${false} | ${'is hidden if hideFileStats is true'}
`('$desc', ({ type, value, hideFileStats }) => {
createComponent({
level: 4,
file: {
type,
},
hideFileStats,
});
expect(wrapper.find(FileRowStats).exists()).toEqual(value);
});
expect(wrapper.find(FileRow).exists()).toEqual(true);
});
});
Element.prototype.scrollIntoView = jest.fn();
import './element_scroll_into_view';
import './get_client_rects';
import './inner_text';
import './window_scroll_to';
import { shallowMount } from '@vue/test-utils';
import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import IdeFileRow from '~/ide/components/ide_file_row.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from '~/ide/components/file_row_extra.vue';
import { createStore } from '~/ide/stores';
const localVue = createLocalVue();
localVue.use(Vuex);
const TEST_EXTRA_PROPS = {
testattribute: 'abc',
};
const defaultComponentProps = (type = 'tree') => ({
level: 4,
file: {
type,
name: 'js',
},
});
 
describe('Ide File Row component', () => {
let wrapper;
 
const createComponent = (props = {}) => {
wrapper = shallowMount(IdeFileRow, {
propsData: { ...props },
const createComponent = (props = {}, options = {}) => {
wrapper = mount(IdeFileRow, {
propsData: {
...defaultComponentProps(),
...props,
},
store: createStore(),
localVue,
...options,
});
};
 
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
 
it('renders file row component', () => {
createComponent({
level: 4,
file: {},
const findFileRowExtra = () => wrapper.find(FileRowExtra);
const findFileRow = () => wrapper.find(FileRow);
const hasDropdownOpen = () => findFileRowExtra().props('dropdownOpen');
it('fileRow component has listeners', () => {
const toggleTreeOpen = jest.fn();
createComponent(
{},
{
listeners: {
toggleTreeOpen,
},
},
);
findFileRow().vm.$emit('toggleTreeOpen');
return wrapper.vm.$nextTick().then(() => {
expect(toggleTreeOpen).toHaveBeenCalled();
});
});
describe('default', () => {
beforeEach(() => {
createComponent(TEST_EXTRA_PROPS);
});
it('renders file row component', () => {
const fileRow = findFileRow();
expect(fileRow.props()).toEqual(expect.objectContaining(defaultComponentProps()));
expect(fileRow.attributes()).toEqual(expect.objectContaining(TEST_EXTRA_PROPS));
});
it('renders file row extra', () => {
const extra = findFileRowExtra();
expect(extra.exists()).toBe(true);
expect(extra.props()).toEqual({
file: defaultComponentProps().file,
dropdownOpen: false,
});
});
});
describe('with open dropdown', () => {
beforeEach(() => {
createComponent();
findFileRowExtra().vm.$emit('toggle', true);
return wrapper.vm.$nextTick();
});
it('shows open dropdown', () => {
expect(hasDropdownOpen()).toBe(true);
});
it('hides dropdown when mouseleave', () => {
findFileRow().vm.$emit('mouseleave');
return wrapper.vm.$nextTick().then(() => {
expect(hasDropdownOpen()).toEqual(false);
});
});
it('hides dropdown on toggle', () => {
findFileRowExtra().vm.$emit('toggle', false);
return wrapper.vm.$nextTick().then(() => {
expect(hasDropdownOpen()).toEqual(false);
});
});
expect(wrapper.find(FileRow).exists()).toEqual(true);
});
});
import { mount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import suggestPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue';
import MrWidgetIcon from '~/vue_merge_request_widget/components/mr_widget_icon.vue';
describe('MRWidgetHeader', () => {
let wrapper;
const pipelinePath = '/foo/bar/add/pipeline/path';
const iconName = 'status_notfound';
beforeEach(() => {
wrapper = mount(suggestPipelineComponent, {
propsData: { pipelinePath },
});
});
afterEach(() => {
wrapper.destroy();
});
describe('template', () => {
it('renders add pipeline file link', () => {
const link = wrapper.find(GlLink);
return wrapper.vm.$nextTick().then(() => {
expect(link.exists()).toBe(true);
expect(link.attributes().href).toBe(pipelinePath);
});
});
it('renders the expected text', () => {
const messageText = /\s*No pipeline\s*Add the .gitlab-ci.yml file\s*to create one./;
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.text()).toMatch(messageText);
});
});
it('renders widget icon', () => {
const icon = wrapper.find(MrWidgetIcon);
return wrapper.vm.$nextTick().then(() => {
expect(icon.exists()).toBe(true);
expect(icon.props()).toEqual(
expect.objectContaining({
name: iconName,
}),
);
});
});
});
});
Loading
Loading
@@ -16,6 +16,7 @@ export default {
updated_at: '2017-04-07T15:39:25.852Z',
time_estimate: 0,
total_time_spent: 0,
human_access: 'Maintainer',
human_time_estimate: null,
human_total_time_spent: null,
in_progress_merge_commit_sha: null,
Loading
Loading
@@ -34,6 +35,7 @@ export default {
target_branch: 'master',
target_project_id: 19,
target_project_full_path: '/group2/project2',
merge_request_add_ci_config_path: '/group2/project2/new/pipeline',
metrics: {
merged_by: {
name: 'Administrator',
Loading
Loading
Loading
Loading
@@ -94,6 +94,61 @@ describe('mrWidgetOptions', () => {
});
});
 
describe('shouldSuggestPipelines', () => {
describe('given suggestPipeline feature flag is enabled', () => {
beforeEach(() => {
gon.features = { suggestPipeline: true };
vm = mountComponent(MrWidgetOptions, {
mrData: { ...mockData },
});
});
afterEach(() => {
gon.features = {};
});
it('should suggest pipelines when none exist', () => {
vm.mr.mergeRequestAddCiConfigPath = 'some/path';
vm.mr.hasCI = false;
expect(vm.shouldSuggestPipelines).toBeTruthy();
});
it('should not suggest pipelines when they exist', () => {
vm.mr.mergeRequestAddCiConfigPath = null;
vm.mr.hasCI = false;
expect(vm.shouldSuggestPipelines).toBeFalsy();
});
it('should not suggest pipelines hasCI is true', () => {
vm.mr.mergeRequestAddCiConfigPath = 'some/path';
vm.mr.hasCI = true;
expect(vm.shouldSuggestPipelines).toBeFalsy();
});
});
describe('given suggestPipeline feature flag is not enabled', () => {
beforeEach(() => {
gon.features = { suggestPipeline: false };
vm = mountComponent(MrWidgetOptions, {
mrData: { ...mockData },
});
});
afterEach(() => {
gon.features = {};
});
it('should not suggest pipelines', () => {
vm.mr.mergeRequestAddCiConfigPath = null;
expect(vm.shouldSuggestPipelines).toBeFalsy();
});
});
});
describe('shouldRenderRelatedLinks', () => {
it('should return false for the initial data', () => {
expect(vm.shouldRenderRelatedLinks).toBeFalsy();
Loading
Loading
Loading
Loading
@@ -83,4 +83,18 @@ describe('MergeRequestStore', () => {
});
});
});
describe('setPaths', () => {
it('should set the add ci config path', () => {
store.setData({ ...mockData });
expect(store.mergeRequestAddCiConfigPath).toEqual('/group2/project2/new/pipeline');
});
it('should set humanAccess=Maintainer when user has that role', () => {
store.setData({ ...mockData });
expect(store.humanAccess).toEqual('Maintainer');
});
});
});
import Vue from 'vue';
import { file } from 'spec/ide/helpers';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from '~/ide/components/file_row_extra.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
 
describe('File row component', () => {
Loading
Loading
@@ -17,9 +16,6 @@ describe('File row component', () => {
vm.$destroy();
});
 
const findNewDropdown = () => vm.$el.querySelector('.ide-new-btn .dropdown');
const findNewDropdownButton = () => vm.$el.querySelector('.ide-new-btn .dropdown button');
it('renders name', () => {
createComponent({
file: file('t4'),
Loading
Loading
@@ -88,59 +84,4 @@ describe('File row component', () => {
 
expect(vm.$el.classList).toContain('js-file-row-header');
});
describe('new dropdown', () => {
beforeEach(() => {
createComponent({
file: file('t5'),
level: 1,
extraComponent: FileRowExtra,
});
});
it('renders in extra component', () => {
expect(findNewDropdown()).not.toBe(null);
});
it('is hidden at start', () => {
expect(findNewDropdown()).not.toHaveClass('show');
});
it('is opened when button is clicked', done => {
expect(vm.dropdownOpen).toBe(false);
findNewDropdownButton().dispatchEvent(new Event('click'));
vm.$nextTick()
.then(() => {
expect(vm.dropdownOpen).toBe(true);
expect(findNewDropdown()).toHaveClass('show');
})
.then(done)
.catch(done.fail);
});
describe('when opened', () => {
beforeEach(() => {
vm.dropdownOpen = true;
});
it('stays open when button triggers mouseout', () => {
findNewDropdownButton().dispatchEvent(new Event('mouseout'));
expect(vm.dropdownOpen).toBe(true);
});
it('stays open when button triggers mouseleave', () => {
findNewDropdownButton().dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(true);
});
it('closes when row triggers mouseleave', () => {
vm.$el.dispatchEvent(new Event('mouseleave'));
expect(vm.dropdownOpen).toBe(false);
});
});
});
});
Loading
Loading
@@ -82,8 +82,6 @@ describe Gitlab::ImportExport::GroupTreeRestorer do
shared_examples 'excluded attributes' do
excluded_attributes = %w[
id
name
path
owner_id
parent_id
created_at
Loading
Loading
Loading
Loading
@@ -160,8 +160,6 @@ describe Gitlab::ImportExport::GroupTreeSaver do
shared_examples 'excluded attributes' do
excluded_attributes = %w[
id
name
path
owner_id
parent_id
created_at
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200213220159_migrate_store_security_reports_sidekiq_queue.rb')
describe MigrateStoreSecurityReportsSidekiqQueue, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do
it 'migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_default:store_security_reports').perform_async(1, 5)
described_class.new.up
expect(sidekiq_queue_length('pipeline_default:store_security_reports')).to eq 0
expect(sidekiq_queue_length('security_scans:store_security_reports')).to eq 1
end
end
it 'migrates queue when migrating down' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'security_scans:store_security_reports').perform_async(1, 5)
described_class.new.down
expect(sidekiq_queue_length('pipeline_default:store_security_reports')).to eq 1
expect(sidekiq_queue_length('security_scans:store_security_reports')).to eq 0
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'post_migrate', '20200213220211_migrate_sync_security_reports_to_report_approval_rules_sidekiq_queue.rb')
describe MigrateSyncSecurityReportsToReportApprovalRulesSidekiqQueue, :redis do
include Gitlab::Database::MigrationHelpers
include StubWorker
context 'when there are jobs in the queue' do
it 'migrates queue when migrating up' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'pipeline_default:sync_security_reports_to_report_approval_rules').perform_async(1, 5)
described_class.new.up
expect(sidekiq_queue_length('pipeline_default:sync_security_reports_to_report_approval_rules')).to eq 0
expect(sidekiq_queue_length('security_scans:sync_security_reports_to_report_approval_rules')).to eq 1
end
end
it 'migrates queue when migrating down' do
Sidekiq::Testing.disable! do
stub_worker(queue: 'security_scans:sync_security_reports_to_report_approval_rules').perform_async(1, 5)
described_class.new.down
expect(sidekiq_queue_length('pipeline_default:sync_security_reports_to_report_approval_rules')).to eq 1
expect(sidekiq_queue_length('security_scans:sync_security_reports_to_report_approval_rules')).to eq 0
end
end
end
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment