Commit 2cf3ee30 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents e43a7eb7 a3083266
......@@ -207,11 +207,7 @@ class Projects::JobsController < Projects::ApplicationController
end
def find_job_as_processable
if ::Gitlab::Ci::Features.manual_bridges_enabled?(project)
@build = project.processables.find(params[:id])
else
find_job_as_build
end
@build = project.processables.find(params[:id])
end
def build_path(build)
......
......@@ -370,7 +370,7 @@ module SearchHelper
def highlight_and_truncate_issuable(issuable, search_term, _search_highlight)
return unless issuable.description.present?
simple_search_highlight_and_truncate(issuable.description, search_term, highlighter: '<span class="gl-text-black-normal gl-font-weight-bold">\1</span>')
simple_search_highlight_and_truncate(issuable.description, search_term, highlighter: '<span class="gl-text-gray-900 gl-font-weight-bold">\1</span>')
end
def show_user_search_tab?
......
......@@ -132,14 +132,10 @@ module Ci
end
def playable?
return false unless ::Gitlab::Ci::Features.manual_bridges_enabled?(project)
action? && !archived? && manual?
end
def action?
return false unless ::Gitlab::Ci::Features.manual_bridges_enabled?(project)
%w[manual].include?(self.when)
end
......
---
title: Global Search - Fix Dark Mode Font
merge_request: 48927
author:
type: fixed
---
name: ci_manual_bridges
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44011
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/263412
milestone: '13.5'
type: development
group: group::pipeline authoring
default_enabled: true
......@@ -2273,9 +2273,6 @@ You can use [protected branches](../../user/project/protected_branches.md) to mo
In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201938) and later, you
can use `when:manual` in the same job as [`trigger`](#trigger). In GitLab 13.4 and
earlier, using them together causes the error `jobs:#{job-name} when should be on_success, on_failure or always`.
It is deployed behind the `:ci_manual_bridges` [feature flag](../../user/feature_flags.md), which is **enabled by default**.
[GitLab administrators with access to the Rails console](../../administration/feature_flags.md)
can opt to disable it.
##### Protecting manual jobs **(PREMIUM)**
......@@ -3515,9 +3512,6 @@ hover over the downstream pipeline job.
In [GitLab 13.5](https://gitlab.com/gitlab-org/gitlab/-/issues/201938) and later, you
can use [`when:manual`](#whenmanual) in the same job as `trigger`. In GitLab 13.4 and
earlier, using them together causes the error `jobs:#{job-name} when should be on_success, on_failure or always`.
It is deployed behind the `:ci_manual_bridges` [feature flag](../../user/feature_flags.md), which is **enabled by default**.
[GitLab administrators with access to the Rails console](../../administration/feature_flags.md)
can opt to disable it.
#### Simple `trigger` syntax for multi-project pipelines
......
......@@ -47,3 +47,37 @@ To install the app in Jira:
You can also click **Getting Started** to open the configuration page rendered from your GitLab instance.
_Note that any changes to the app descriptor requires you to uninstall then reinstall the app._
### Troubleshooting
If the app install failed, you might need to delete `jira_connect_installations` from your database.
1. Open the [database console](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/howto/postgresql.md#access-postgresql).
1. Run `TRUNCATE TABLE jira_connect_installations CASCADE;`.
## Add a namespace
To add a [namespace](../../user/group/index.md#namespaces) to Jira:
1. Make sure you are logged in on your GitLab development instance.
1. On the GitLab app page in Jira, click **Get started**.
1. Open your browser's developer tools and navigate to the **Network** tab.
1. Try to add the namespace in Jira.
1. If the request fails with 401 "not authorized", copy the request as a cURL command
and paste it in your terminal.
![Example Vulnerability](img/copy_curl.png)
1. Go to your development instance (usually at: <http://localhost:3000>), open developer
tools, navigate to the Network tab and reload the page.
1. Copy all cookies from the first request.
![Example Vulnerability](img/copy_cookies.png)
1. Append the cookies to the cURL command in your terminal:
`--cookies "<cookies from the request>"`.
1. Submit the cURL request.
1. If the response is `{"success":true}`, the namespace was added.
1. Append the cookies to the cURL command in your terminal `--cookies "PASTE COOKIES HERE"`.
1. Submit the cURL request.
1. If the response is `{"success":true}` the namespace was added.
......@@ -324,7 +324,7 @@ whereas the `message` may repeat the location.
As a visual example, this screenshot highlights where these fields are used when viewing a
vulnerability as part of a pipeline view.
![Example Vulnerability](example_vuln.png)
![Example Vulnerability](img/example_vuln.png)
For instance, a `message` for a vulnerability
reported by Dependency Scanning gives information on the vulnerable dependency,
......
......@@ -7,7 +7,8 @@ type: reference, howto
# Static Application Security Testing (SAST)
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3775) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.3.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3775) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 10.3.
> - All open source (OSS) analyzers were moved to GitLab Core in GitLab 13.3.
NOTE: **Note:**
The whitepaper ["A Seismic Shift in Application Security"](https://about.gitlab.com/resources/whitepaper-seismic-shift-application-security/)
......
<script>
import { GlFormGroup, GlFormInput, GlFormCheckboxTree, GlModal, GlSprintf } from '@gitlab/ui';
import {
GlFormGroup,
GlFormInput,
GlFormCheckboxTree,
GlModal,
GlSprintf,
GlAlert,
} from '@gitlab/ui';
import { convertToGraphQLIds, TYPE_GROUP } from '~/graphql_shared/utils';
import * as Sentry from '~/sentry/wrapper';
import createDevopsAdoptionSegmentMutation from '../graphql/mutations/create_devops_adoption_segment.mutation.graphql';
import { DEVOPS_ADOPTION_STRINGS, DEVOPS_ADOPTION_SEGMENT_MODAL_ID } from '../constants';
export default {
......@@ -10,6 +20,7 @@ export default {
GlFormInput,
GlFormCheckboxTree,
GlSprintf,
GlAlert,
},
props: {
segmentId: {
......@@ -27,43 +38,109 @@ export default {
return {
name: '',
checkboxValues: [],
loading: false,
errors: [],
};
},
computed: {
checkboxOptions() {
return this.groups.map(({ id, full_name }) => ({ label: full_name, value: id }));
},
cancelOptions() {
return {
text: this.$options.i18n.cancel,
attributes: [{ disabled: this.loading }],
};
},
primaryOptions() {
return {
text: this.$options.i18n.button,
attributes: [
{
variant: 'info',
loading: this.loading,
disabled: !this.canSubmit,
},
],
};
},
canSubmit() {
return this.name.length && this.checkboxValues.length;
},
displayError() {
return this.errors[0];
},
},
methods: {
createSegment() {},
async createSegment() {
try {
this.loading = true;
const {
data: {
createDevopsAdoptionSegment: { errors },
},
} = await this.$apollo.mutate({
mutation: createDevopsAdoptionSegmentMutation,
variables: {
name: this.name,
groupIds: convertToGraphQLIds(TYPE_GROUP, this.checkboxValues),
},
});
if (errors.length) {
this.errors = errors;
} else {
this.name = '';
this.checkboxValues = [];
this.$refs.modal.hide();
}
} catch (error) {
this.errors.push(this.$options.i18n.error);
Sentry.captureException(error);
} finally {
this.loading = false;
}
},
clearErrors() {
this.errors = [];
},
},
devopsSegmentModalId: DEVOPS_ADOPTION_SEGMENT_MODAL_ID,
};
</script>
<template>
<gl-modal
ref="modal"
:modal-id="$options.devopsSegmentModalId"
:title="$options.i18n.title"
:ok-title="$options.i18n.button"
ok-variant="info"
size="sm"
scrollable
@ok="createSegment"
:action-primary="primaryOptions"
:action-cancel="cancelOptions"
@primary.prevent="createSegment"
>
<gl-form-group :label="$options.i18n.nameLabel" label-for="name" data-testid="name">
<gl-alert v-if="errors.length" variant="danger" class="gl-mb-3" @dismiss="clearErrors">
{{ displayError }}
</gl-alert>
<gl-form-group :label="$options.i18n.nameLabel" label-for="name">
<gl-form-input
id="name"
v-model="name"
data-testid="name"
type="text"
:placeholder="$options.i18n.namePlaceholder"
:required="true"
required
:disabled="loading"
/>
</gl-form-group>
<gl-form-group class="gl-mb-0" data-testid="groups">
<gl-form-group class="gl-mb-0">
<gl-form-checkbox-tree
v-model="checkboxValues"
data-testid="groups"
:options="checkboxOptions"
:hide-toggle-all="true"
:disabled="loading"
class="gl-p-3 gl-pb-0 gl-mb-2 gl-border-1 gl-border-solid gl-border-gray-100 gl-rounded-base"
/>
<div class="gl-text-gray-400" data-testid="groupsHelperText">
......
import { s__ } from '~/locale';
import { s__, __ } from '~/locale';
export const MAX_REQUEST_COUNT = 10;
......@@ -36,10 +36,12 @@ export const DEVOPS_ADOPTION_STRINGS = {
modal: {
title: s__('DevopsAdoption|New segment'),
button: s__('DevopsAdoption|Create new segment'),
cancel: __('Cancel'),
namePlaceholder: s__('DevopsAdoption|My segment'),
nameLabel: s__('DevopsAdoption|Name'),
selectedGroupsTextSingular: s__('DevopsAdoption|%{selectedCount} group selected (20 max)'),
selectedGroupsTextPlural: s__('DevopsAdoption|%{selectedCount} groups selected (20 max)'),
error: s__('DevopsAdoption|An error occured while saving the segment. Please try again.'),
},
};
......
mutation($name: String!, $groupIds: [GroupID!]!) {
createDevopsAdoptionSegment(input: { name: $name, groupIds: $groupIds }) {
segment {
id
name
groups {
id
}
}
errors
}
}
......@@ -77,7 +77,7 @@ module EE
# pre/post tags from Elasticsearch with highlighting, truncate, and mark as html_safe. HTML tags are not
# counted towards the character limit.
text = sanitize(search_highlight[issuable.id].description.first)
text.gsub!(::Elastic::Latest::GitClassProxy::HIGHLIGHT_START_TAG, '<span class="gl-text-black-normal gl-font-weight-bold">')
text.gsub!(::Elastic::Latest::GitClassProxy::HIGHLIGHT_START_TAG, '<span class="gl-text-gray-900 gl-font-weight-bold">')
text.gsub!(::Elastic::Latest::GitClassProxy::HIGHLIGHT_END_TAG, '</span>')
Truncato.truncate(text, count_tags: false, count_tail: false, max_length: 200).html_safe
end
......
import { ApolloMutation } from 'vue-apollo';
import { shallowMount } from '@vue/test-utils';
import { GlModal, GlFormInput, GlFormCheckboxTree, GlSprintf } from '@gitlab/ui';
import { GlModal, GlFormInput, GlSprintf, GlAlert } from '@gitlab/ui';
import { getByText } from '@testing-library/dom';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
import DevopsAdoptionSegmentModal from 'ee/admin/dev_ops_report/components/devops_adoption_segment_modal.vue';
import { DEVOPS_ADOPTION_SEGMENT_MODAL_ID } from 'ee/admin/dev_ops_report/constants';
import { groupNodes } from '../mock_data';
import * as Sentry from '~/sentry/wrapper';
import {
groupNodes,
groupIds,
groupGids,
segmentName,
genericErrorMessage,
dataErrorMessage,
} from '../mock_data';
const mockEvent = { preventDefault: jest.fn() };
const mutate = jest.fn().mockResolvedValue({
data: {
createDevopsAdoptionSegment: {
errors: [],
},
},
});
const mutateWithDataErrors = jest.fn().mockResolvedValue({
data: {
createDevopsAdoptionSegment: {
errors: [dataErrorMessage],
},
},
});
const mutateLoading = jest.fn().mockResolvedValue(new Promise(() => {}));
const mutateWithErrors = jest.fn().mockRejectedValue(genericErrorMessage);
describe('DevopsAdoptionSegmentModal', () => {
let wrapper;
const createComponent = () => {
const createComponent = ({ mutationMock = mutate } = {}) => {
const $apollo = {
mutate: mutationMock,
};
wrapper = shallowMount(DevopsAdoptionSegmentModal, {
propsData: {
groups: groupNodes,
},
stubs: {
GlSprintf,
ApolloMutation,
},
mocks: {
$apollo,
},
});
};
const findModal = () => wrapper.find(GlModal);
const findByTestId = testId => findModal().find(`[data-testid="${testId}"`);
const findByTestId = testId => findModal().find(`[data-testid="${testId}"]`);
const actionButtonDisabledState = () => findModal().props('actionPrimary').attributes[0].disabled;
const cancelButtonDisabledState = () => findModal().props('actionCancel').attributes[0].disabled;
const actionButtonLoadingState = () => findModal().props('actionPrimary').attributes[0].loading;
const findAlert = () => findModal().find(GlAlert);
const assertHelperText = text => expect(getByText(wrapper.element, text)).not.toBeNull();
beforeEach(() => createComponent());
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('contains the corrrect id', () => {
createComponent();
const modal = findModal();
expect(modal.exists()).toBe(true);
......@@ -40,6 +80,8 @@ describe('DevopsAdoptionSegmentModal', () => {
});
describe('displays the correct content', () => {
beforeEach(() => createComponent());
const isCorrectShape = option => {
const keys = Object.keys(option);
return keys.includes('label') && keys.includes('value');
......@@ -53,7 +95,7 @@ describe('DevopsAdoptionSegmentModal', () => {
});
it('contains the checkbox tree component', () => {
const checkboxes = findByTestId('groups').find(GlFormCheckboxTree);
const checkboxes = findByTestId('groups');
expect(checkboxes.exists()).toBe(true);
......@@ -84,5 +126,136 @@ describe('DevopsAdoptionSegmentModal', () => {
assertHelperText('2 groups selected (20 max)');
});
});
it('does not display an error', () => {
expect(findAlert().exists()).toBe(false);
});
});
it.each`
checkboxValues | name | disabled | values | state
${[]} | ${''} | ${true} | ${'checkbox and name'} | ${'disables'}
${[1]} | ${''} | ${true} | ${'checkbox'} | ${'disables'}
${[]} | ${segmentName} | ${true} | ${'name'} | ${'disables'}
${[1]} | ${segmentName} | ${false} | ${'nothing'} | ${'enables'}
`(
'$state the primary action if $values is missing',
async ({ checkboxValues, name, disabled }) => {
createComponent();
wrapper.setData({ checkboxValues, name });
await nextTick();
expect(actionButtonDisabledState()).toBe(disabled);
},
);
describe('submitting the form', () => {
describe('while waiting for the mutation', () => {
beforeEach(() => {
createComponent({ mutationMock: mutateLoading });
wrapper.setData({ checkboxValues: [1], name: segmentName });
});
it('disables the form inputs', async () => {
const checkboxes = findByTestId('groups');
const name = findByTestId('name');
expect(checkboxes.attributes('disabled')).not.toBeDefined();
expect(name.attributes('disabled')).not.toBeDefined();
findModal().vm.$emit('primary', mockEvent);
await waitForPromises();
expect(checkboxes.attributes('disabled')).toBeDefined();
expect(name.attributes('disabled')).toBeDefined();
});
it('disables the cancel button', async () => {
expect(cancelButtonDisabledState()).toBe(false);
findModal().vm.$emit('primary', mockEvent);
await waitForPromises();
expect(cancelButtonDisabledState()).toBe(true);
});
it('sets the action button state to loading', async () => {
expect(actionButtonLoadingState()).toBe(false);
findModal().vm.$emit('primary', mockEvent);
await waitForPromises();
expect(actionButtonLoadingState()).toBe(true);
});
});
describe('successful submission', () => {
beforeEach(async () => {
createComponent();
wrapper.setData({ checkboxValues: groupIds, name: segmentName });
wrapper.vm.$refs.modal.hide = jest.fn();
findModal().vm.$emit('primary', mockEvent);
await waitForPromises();
});
it('submits the correct request variables', async () => {
expect(mutate).toHaveBeenCalledWith(
expect.objectContaining({
variables: {
groupIds: groupGids,
name: segmentName,
},
}),
);
});
it('closes the modal after a successful mutation', async () => {
expect(wrapper.vm.$refs.modal.hide).toHaveBeenCalled();
});
});
describe('error handling', () => {
it.each`
errorType | errorLocation | mutationSpy | message
${'generic'} | ${'top level'} | ${mutateWithErrors} | ${genericErrorMessage}
${'specific'} | ${'data'} | ${mutateWithDataErrors} | ${dataErrorMessage}
`(
'displays a $errorType error if the mutation has a $errorLocation error',
async ({ mutationSpy, message }) => {
createComponent({ mutationMock: mutationSpy });
findModal().vm.$emit('primary', mockEvent);
await waitForPromises();
const alert = findAlert();
expect(alert.exists()).toBe(true);
expect(alert.props('variant')).toBe('danger');
expect(alert.text()).toBe(message);
},
);
it('calls sentry on top level error', async () => {
jest.spyOn(Sentry, 'captureException');
createComponent({ mutationMock: mutateWithErrors });
findModal().vm.$emit('primary', mockEvent);
await waitForPromises();
expect(Sentry.captureException.mock.calls[0][0]).toBe(genericErrorMessage);
});
});
});
});
......@@ -17,6 +17,10 @@ export const groupNodes = [
},
];
export const groupIds = ['foo', 'bar'];
export const groupGids = ['gid://gitlab/Group/foo', 'gid://gitlab/Group/bar'];
export const nextGroupNode = {
__typename: 'Group',
full_name: 'Baz',
......@@ -64,3 +68,9 @@ export const devopsAdoptionTableHeaders = [
'Scanning',
'',
];
export const segmentName = 'Foooo';
export const genericErrorMessage = 'An error occured while saving the segment. Please try again.';
export const dataErrorMessage = 'Name already taken.';
......@@ -227,11 +227,11 @@ RSpec.describe SearchHelper do
using RSpec::Parameterized::TableSyntax
where(:description, :search_highlight, :expected) do
'test' | { 1 => { description: ['gitlabelasticsearch→test←gitlabelasticsearch'] } } | "<span class='gl-text-black-normal gl-font-weight-bold'>test</span>"
'<span style="color: blue;">this test should not be blue</span>' | { 1 => { description: ['<span style="color: blue;">this gitlabelasticsearch→test←gitlabelasticsearch should not be blue</span>'] } } | "<span>this <span class='gl-text-black-normal gl-font-weight-bold'>test</span> should not be blue</span>"
'<a href="#" onclick="alert(\'XSS\')">Click Me test</a>' | { 1 => { description: ['<a href="#" onclick="alert(\'XSS\')">Click Me gitlabelasticsearch→test←gitlabelasticsearch</a>'] } } | "<a href='#'>Click Me <span class='gl-text-black-normal gl-font-weight-bold'>test</span></a>"
'<script type="text/javascript">alert(\'Another XSS\');</script> test' | { 1 => { description: ['<script type="text/javascript">alert(\'Another XSS\');</script> gitlabelasticsearch→test←gitlabelasticsearch'] } } | "alert(&apos;Another XSS&apos;); <span class='gl-text-black-normal gl-font-weight-bold'>test</span>"
'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.' | { 1 => { description: ['Lorem gitlabelasticsearch→test←gitlabelasticsearch ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.'] } } | "Lorem <span class='gl-text-black-normal gl-font-weight-bold'>test</span> ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Don..."
'test' | { 1 => { description: ['gitlabelasticsearch→test←gitlabelasticsearch'] } } | "<span class='gl-text-gray-900 gl-font-weight-bold'>test</span>"
'<span style="color: blue;">this test should not be blue</span>' | { 1 => { description: ['<span style="color: blue;">this gitlabelasticsearch→test←gitlabelasticsearch should not be blue</span>'] } } | "<span>this <span class='gl-text-gray-900 gl-font-weight-bold'>test</span> should not be blue</span>"
'<a href="#" onclick="alert(\'XSS\')">Click Me test</a>' | { 1 => { description: ['<a href="#" onclick="alert(\'XSS\')">Click Me gitlabelasticsearch→test←gitlabelasticsearch</a>'] } } | "<a href='#'>Click Me <span class='gl-text-gray-900 gl-font-weight-bold'>test</span></a>"
'<script type="text/javascript">alert(\'Another XSS\');</script> test' | { 1 => { description: ['<script type="text/javascript">alert(\'Another XSS\');</script> gitlabelasticsearch→test←gitlabelasticsearch'] } } | "alert(&apos;Another XSS&apos;); <span class='gl-text-gray-900 gl-font-weight-bold'>test</span>"
'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.' | { 1 => { description: ['Lorem gitlabelasticsearch→test←gitlabelasticsearch ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.'] } } | "Lorem <span class='gl-text-gray-900 gl-font-weight-bold'>test</span> ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Don..."
end
with_them do
......
......@@ -18,11 +18,11 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
let(:results) { described_class.new(user, 'hello world', limit_project_ids) }
where(:scope, :results_method, :expected) do
'projects' | :projects | { 1 => 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }
'milestones' | :milestones | { 1 => 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }
'notes' | :notes | { 1 => 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }
'issues' | :issues | { 1 => 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }
'merge_requests' | :merge_requests | { 1 => 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }
'projects' | :projects | { 1 => 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }
'milestones' | :milestones | { 1 => 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }
'notes' | :notes | { 1 => 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }
'issues' | :issues | { 1 => 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }
'merge_requests' | :merge_requests | { 1 => 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }
'blobs' | nil | nil
'wiki_blobs' | nil | nil
'commits' | nil | nil
......@@ -32,7 +32,7 @@ RSpec.describe Gitlab::Elastic::SearchResults, :elastic, :sidekiq_might_not_need
with_them do
it 'returns the expected highlight map' do
expect(results).to receive(results_method).and_return([{ _source: { id: 1 }, highlight: 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }]) if results_method
expect(results).to receive(results_method).and_return([{ _source: { id: 1 }, highlight: 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }]) if results_method
expect(results.highlight_map(scope)).to eq(expected)
end
end
......
......@@ -42,8 +42,8 @@ RSpec.describe Gitlab::Elastic::SnippetSearchResults, :elastic, :sidekiq_might_n
describe '#highlight_map' do
it 'returns the expected highlight map' do
expect(results).to receive(:snippet_titles).and_return([{ _source: { id: 1 }, highlight: 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' }])
expect(results.highlight_map('snippet_titles')).to eq({ 1 => 'test <span class="gl-text-black-normal gl-font-weight-bold">highlight</span>' })
expect(results).to receive(:snippet_titles).and_return([{ _source: { id: 1 }, highlight: 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' }])
expect(results.highlight_map('snippet_titles')).to eq({ 1 => 'test <span class="gl-text-gray-900 gl-font-weight-bold">highlight</span>' })
end
end
......
......@@ -55,10 +55,6 @@ module Gitlab
::Feature.enabled?(:ci_trace_log_invalid_chunks, project, type: :ops, default_enabled: false)
end
def self.manual_bridges_enabled?(project)
::Feature.enabled?(:ci_manual_bridges, project, default_enabled: true)
end
def self.auto_rollback_available?(project)
::Feature.enabled?(:cd_auto_rollback, project) && project&.feature_available?(:auto_rollback)
end
......
......@@ -9568,6 +9568,9 @@ msgstr ""
msgid "DevopsAdoption|Add new segment"
msgstr ""
msgid "DevopsAdoption|An error occured while saving the segment. Please try again."
msgstr ""
msgid "DevopsAdoption|Approvals"
msgstr ""
......
# frozen_string_literal: true
module QA
RSpec.describe 'Package', :orchestrated, :packages do
describe 'Generic Repository' do
let(:package_name) { 'my_package' }
let(:project) do
Resource::Project.fabricate_via_api! do |project|
project.name = 'generic-package-project'
end
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker
runner.project = project
end
end
let(:gitlab_ci_yaml) do
<<~YAML
image: curlimages/curl:latest
stages:
- upload
- download
upload:
stage: upload
script:
- 'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file file.txt ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt'
tags:
- "runner-for-#{project.name}"
download:
stage: download
script:
- 'wget --header="JOB-TOKEN: $CI_JOB_TOKEN" ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt -O file_downloaded.txt'
tags:
- "runner-for-#{project.name}"
YAML
end
let(:file_txt) do
<<~EOF
Hello, world!
EOF
end
before do
Flow::Login.sign_in
Resource::Repository::Commit.fabricate_via_api! do |commit|
commit.project = project
commit.commit_message = 'Add .gitlab-ci.yml'
commit.add_files([{
file_path: '.gitlab-ci.yml',
content: gitlab_ci_yaml
},
{
file_path: 'file.txt',
content: file_txt
}]
)
end
project.visit!
Page::Project::Menu.perform(&:click_ci_cd_pipelines)
Page::Project::Pipeline::Index.perform(&:click_on_latest_pipeline)
Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.click_job('upload')
end
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 800)
job.click_element(:pipeline_path)
end
Page::Project::Pipeline::Show.perform do |pipeline|
pipeline.click_job('download')
end
Page::Project::Job::Show.perform do |job|
expect(job).to be_successful(timeout: 800)
end
end
after do
runner.remove_via_api!
end
it 'uploads a generic package, downloads and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1108' do
Page::Project::Menu.perform(&:click_packages_link)
Page::Project::Packages::Index.perform do |index|
expect(index).to have_package(package_name)
index.click_package(package_name)
end
Page::Project::Packages::Show.perform do |package|
package.click_delete
end
Page::Project::Packages::Index.perform do |index|
aggregate_failures 'package deletion' do
expect(index).to have_content("Package deleted successfully")
expect(index).to have_no_package(package_name)
end
end
end
end
end
end
......@@ -854,18 +854,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do
expect(job.reload).to be_pending
end
context 'when FF ci_manual_bridges is disabled' do
before do
stub_feature_flags(ci_manual_bridges: false)
end
it 'returns 404' do
post_play
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
end
......
......@@ -533,11 +533,11 @@ RSpec.describe SearchHelper do
using RSpec::Parameterized::TableSyntax
where(:description, :expected) do
'test' | '<span class="gl-text-black-normal gl-font-weight-bold">test</span>'
'<span style="color: blue;">this test should not be blue</span>' | '<span>this <span class="gl-text-black-normal gl-font-weight-bold">test</span> should not be blue</span>'
'<a href="#" onclick="alert(\'XSS\')">Click Me test</a>' | '<a href="#">Click Me <span class="gl-text-black-normal gl-font-weight-bold">test</span></a>'
'<script type="text/javascript">alert(\'Another XSS\');</script> test' | ' <span class="gl-text-black-normal gl-font-weight-bold">test</span>'
'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.' | 'Lorem <span class="gl-text-black-normal gl-font-weight-bold">test</span> ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Don...'
'test' | '<span class="gl-text-gray-900 gl-font-weight-bold">test</span>'
'<span style="color: blue;">this test should not be blue</span>' | '<span>this <span class="gl-text-gray-900 gl-font-weight-bold">test</span> should not be blue</span>'
'<a href="#" onclick="alert(\'XSS\')">Click Me test</a>' | '<a href="#">Click Me <span class="gl-text-gray-900 gl-font-weight-bold">test</span></a>'
'<script type="text/javascript">alert(\'Another XSS\');</script> test' | ' <span class="gl-text-gray-900 gl-font-weight-bold">test</span>'
'Lorem test ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec.' | 'Lorem <span class="gl-text-gray-900 gl-font-weight-bold">test</span> ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Don...'
end
with_them do
......
......@@ -330,14 +330,6 @@ RSpec.describe Ci::Bridge do
subject { build_stubbed(:ci_bridge, :manual).playable? }
it { is_expected.to be_truthy }
context 'when FF ci_manual_bridges is disabled' do
before do
stub_feature_flags(ci_manual_bridges: false)
end
it { is_expected.to be_falsey }
end
end
context 'when build is not a manual action' do
......@@ -352,14 +344,6 @@ RSpec.describe Ci::Bridge do
subject { build_stubbed(:ci_bridge, :manual).action? }
it { is_expected.to be_truthy }
context 'when FF ci_manual_bridges is disabled' do
before do
stub_feature_flags(ci_manual_bridges: false)
end
it { is_expected.to be_falsey }
end
end
context 'when build is not a manual action' do
......
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