Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
3825437c53
commit
968e01a6dd
21 changed files with 397 additions and 109 deletions
|
@ -2,3 +2,4 @@
|
|||
|
||||
export const ESC_KEY = 'Escape';
|
||||
export const ESC_KEY_IE11 = 'Esc'; // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
|
||||
export const ENTER_KEY = 'Enter';
|
||||
|
|
|
@ -85,7 +85,7 @@ export default {
|
|||
saveButtonLabel() {
|
||||
return this.isExistingRelease ? __('Save changes') : __('Create release');
|
||||
},
|
||||
isSaveChangesDisabled() {
|
||||
isFormSubmissionDisabled() {
|
||||
return this.isUpdatingRelease || !this.isValid;
|
||||
},
|
||||
milestoneComboboxExtraLinks() {
|
||||
|
@ -116,13 +116,18 @@ export default {
|
|||
'updateReleaseNotes',
|
||||
'updateReleaseMilestones',
|
||||
]),
|
||||
submitForm() {
|
||||
if (!this.isFormSubmissionDisabled) {
|
||||
this.saveRelease();
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="d-flex flex-column">
|
||||
<p class="pt-3 js-subtitle-text" v-html="subtitleText"></p>
|
||||
<form v-if="showForm" @submit.prevent="saveRelease()">
|
||||
<form v-if="showForm" class="js-quick-submit" @submit.prevent="submitForm">
|
||||
<tag-field />
|
||||
<gl-form-group>
|
||||
<label for="release-title">{{ __('Release title') }}</label>
|
||||
|
@ -134,7 +139,7 @@ export default {
|
|||
class="form-control"
|
||||
/>
|
||||
</gl-form-group>
|
||||
<gl-form-group class="w-50">
|
||||
<gl-form-group class="w-50" @keydown.enter.prevent.capture>
|
||||
<label>{{ __('Milestones') }}</label>
|
||||
<div class="d-flex flex-column col-md-6 col-sm-10 pl-0">
|
||||
<milestone-combobox
|
||||
|
@ -163,8 +168,6 @@ export default {
|
|||
data-supports-quick-actions="false"
|
||||
:aria-label="__('Release notes')"
|
||||
:placeholder="__('Write your release notes or drag your files here…')"
|
||||
@keydown.meta.enter="saveRelease()"
|
||||
@keydown.ctrl.enter="saveRelease()"
|
||||
></textarea>
|
||||
</template>
|
||||
</markdown-field>
|
||||
|
@ -179,7 +182,7 @@ export default {
|
|||
category="primary"
|
||||
variant="success"
|
||||
type="submit"
|
||||
:disabled="isSaveChangesDisabled"
|
||||
:disabled="isFormSubmissionDisabled"
|
||||
data-testid="submit-button"
|
||||
>
|
||||
{{ saveButtonLabel }}
|
||||
|
|
|
@ -49,6 +49,12 @@ export default {
|
|||
this.removeAssetLink(linkId);
|
||||
this.ensureAtLeastOneLink();
|
||||
},
|
||||
updateUrl(link, newUrl) {
|
||||
this.updateAssetLinkUrl({ linkIdToUpdate: link.id, newUrl });
|
||||
},
|
||||
updateName(link, newName) {
|
||||
this.updateAssetLinkName({ linkIdToUpdate: link.id, newName });
|
||||
},
|
||||
hasDuplicateUrl(link) {
|
||||
return Boolean(this.getLinkErrors(link).isDuplicate);
|
||||
},
|
||||
|
@ -138,7 +144,9 @@ export default {
|
|||
type="text"
|
||||
class="form-control"
|
||||
:state="isUrlValid(link)"
|
||||
@change="updateAssetLinkUrl({ linkIdToUpdate: link.id, newUrl: $event })"
|
||||
@change="updateUrl(link, $event)"
|
||||
@keydown.ctrl.enter="updateUrl(link, $event.target.value)"
|
||||
@keydown.meta.enter="updateUrl(link, $event.target.value)"
|
||||
/>
|
||||
<template #invalid-feedback>
|
||||
<span v-if="hasEmptyUrl(link)" class="invalid-feedback d-inline">
|
||||
|
@ -175,7 +183,9 @@ export default {
|
|||
type="text"
|
||||
class="form-control"
|
||||
:state="isNameValid(link)"
|
||||
@change="updateAssetLinkName({ linkIdToUpdate: link.id, newName: $event })"
|
||||
@change="updateName(link, $event)"
|
||||
@keydown.ctrl.enter="updateName(link, $event.target.value)"
|
||||
@keydown.meta.enter="updateName(link, $event.target.value)"
|
||||
/>
|
||||
<template #invalid-feedback>
|
||||
<span v-if="hasEmptyName(link)" class="invalid-feedback d-inline">
|
||||
|
|
|
@ -32,5 +32,8 @@ export default {
|
|||
isMergeImmediatelyDangerous() {
|
||||
return false;
|
||||
},
|
||||
shouldRenderMergeTrainHelperText() {
|
||||
return false;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:merge_ref_head_comments, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:multiline_comments, @project)
|
||||
push_frontend_feature_flag(:multiline_comments, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:file_identifier_hash)
|
||||
push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true)
|
||||
push_frontend_feature_flag(:auto_expand_collapsed_diffs, @project, default_enabled: true)
|
||||
|
|
17
app/graphql/resolvers/ci_configuration/sast_resolver.rb
Normal file
17
app/graphql/resolvers/ci_configuration/sast_resolver.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "json"
|
||||
|
||||
module Resolvers
|
||||
module CiConfiguration
|
||||
class SastResolver < BaseResolver
|
||||
SAST_UI_SCHEMA_PATH = 'app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json'
|
||||
|
||||
type ::Types::CiConfiguration::Sast::Type, null: true
|
||||
|
||||
def resolve(**args)
|
||||
Gitlab::Json.parse(File.read(Rails.root.join(SAST_UI_SCHEMA_PATH)))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -175,6 +175,10 @@ module Types
|
|||
description: 'A single environment of the project',
|
||||
resolver: Resolvers::EnvironmentsResolver.single
|
||||
|
||||
field :sast_ci_configuration, ::Types::CiConfiguration::Sast::Type, null: true,
|
||||
description: 'SAST CI configuration for the project',
|
||||
resolver: ::Resolvers::CiConfiguration::SastResolver
|
||||
|
||||
field :issue,
|
||||
Types::IssueType,
|
||||
null: true,
|
||||
|
|
|
@ -4,43 +4,83 @@
|
|||
"field" : "SECURE_ANALYZERS_PREFIX",
|
||||
"label" : "Image prefix",
|
||||
"type": "string",
|
||||
"default_value": "",
|
||||
"value": "",
|
||||
"description": "Analyzer image's registry prefix (or Name of the registry providing the analyzers' image)"
|
||||
"default_value": "registry.gitlab.com/gitlab-org/security-products/analyzers",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"field" : "SAST_EXCLUDED_PATHS",
|
||||
"label" : "Excluded Paths",
|
||||
"type": "string",
|
||||
"default_value": "",
|
||||
"value": "",
|
||||
"description": "Comma-separated list of paths to be excluded from analyzer output. Patterns can be globs, file paths, or folder paths."
|
||||
"default_value": "spec, test, tests, tmp",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"field" : "SAST_ANALYZER_IMAGE_TAG",
|
||||
"label" : "Image tag",
|
||||
"type": "string",
|
||||
"default_value": "",
|
||||
"value": "",
|
||||
"description": "Analyzer image's tag"
|
||||
"options": [],
|
||||
"default_value": "2",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"field" : "SAST_DISABLED",
|
||||
"label" : "Disable SAST",
|
||||
"type": "options",
|
||||
"options": [
|
||||
{
|
||||
"value" :"true",
|
||||
"label" : "true (disables SAST)"
|
||||
},
|
||||
{
|
||||
"value":"false",
|
||||
"label":"false (enables SAST)"
|
||||
}
|
||||
],
|
||||
"default_value": "false",
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"pipeline": [
|
||||
{
|
||||
"field" : "stage",
|
||||
"label" : "Stage",
|
||||
"type": "string",
|
||||
"default_value": "",
|
||||
"value": "",
|
||||
"description": "Pipeline stage in which the scan jobs run"
|
||||
"type": "dropdown",
|
||||
"options": [
|
||||
{
|
||||
"value" :"test",
|
||||
"label" : "test"
|
||||
},
|
||||
{
|
||||
"value":"build",
|
||||
"label":"build"
|
||||
}
|
||||
],
|
||||
"default_value": "test",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"field" : "SEARCH_MAX_DEPTH",
|
||||
"label" : "Search maximum depth",
|
||||
"type": "string",
|
||||
"field" : "allow_failure",
|
||||
"label" : "Allow Failure",
|
||||
"type": "options",
|
||||
"options": [
|
||||
{
|
||||
"value" :"true",
|
||||
"label" : "Allows pipeline failure"
|
||||
},
|
||||
{
|
||||
"value": "false",
|
||||
"label": "Does not allow pipeline failure"
|
||||
}
|
||||
],
|
||||
"default_value": "true",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"field" : "rules",
|
||||
"label" : "Rules",
|
||||
"type": "multiline",
|
||||
"default_value": "",
|
||||
"value": "",
|
||||
"description": "Maximum depth of language and framework detection"
|
||||
"value": ""
|
||||
}
|
||||
],
|
||||
"analyzers": [
|
||||
|
|
5
changelogs/unreleased/jdb-mlc-enable-default.yml
Normal file
5
changelogs/unreleased/jdb-mlc-enable-default.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable Multiline Comments by default
|
||||
merge_request: 39370
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Improve submission behavior of the New/Edit Release page
|
||||
merge_request: 39145
|
||||
author:
|
||||
type: added
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
# Suggestion: gitlab.Contractions
|
||||
# Suggestion: gitlab.ContractionsDiscard
|
||||
#
|
||||
# Checks for use of common and uncommon contractions.
|
||||
# Suggests a list of agreed-upon contractions to discard.
|
||||
#
|
||||
# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
|
||||
extends: substitution
|
||||
|
@ -12,18 +12,6 @@ nonword: false
|
|||
ignorecase: true
|
||||
swap:
|
||||
|
||||
# Common contractions are ok
|
||||
it is: it's
|
||||
can not: can't
|
||||
cannot: can't
|
||||
do not: don't
|
||||
have not: haven't
|
||||
that is: that's
|
||||
we are: we're
|
||||
would not: wouldn't
|
||||
you are: you're
|
||||
you have: you've
|
||||
|
||||
# Uncommon contractions are not ok
|
||||
aren't: are not
|
||||
couldn't: could not
|
25
doc/.vale/gitlab/ContractionsKeep.yml
Normal file
25
doc/.vale/gitlab/ContractionsKeep.yml
Normal file
|
@ -0,0 +1,25 @@
|
|||
---
|
||||
# Suggestion: gitlab.ContractionsKeep
|
||||
#
|
||||
# Suggests a list of agreed-upon contractions to keep.
|
||||
#
|
||||
# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
|
||||
extends: substitution
|
||||
message: 'Use "%s" instead of "%s", for a friendly, informal tone.'
|
||||
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language
|
||||
level: suggestion
|
||||
nonword: false
|
||||
ignorecase: true
|
||||
swap:
|
||||
|
||||
# Common contractions are ok
|
||||
it is: it's
|
||||
can not: can't
|
||||
cannot: can't
|
||||
do not: don't
|
||||
have not: haven't
|
||||
that is: that's
|
||||
we are: we're
|
||||
would not: wouldn't
|
||||
you are: you're
|
||||
you have: you've
|
|
@ -80,6 +80,7 @@ Please note that the certificate [fingerprint algorithm](#additional-providers-a
|
|||
With this option enabled, users must go through your group's GitLab single sign-on URL. They may also be added via SCIM, if configured. Users cannot be added manually, and may only access project/group resources via the UI by signing in through the SSO URL.
|
||||
|
||||
However, users will not be prompted to sign in through SSO on each visit. GitLab will check whether a user has authenticated through SSO, and will only prompt the user to sign in via SSO if the session has expired.
|
||||
You can see more information about how long a session is valid in our [user profile documentation](../../profile/#why-do-i-keep-getting-signed-out).
|
||||
|
||||
We intend to add a similar SSO requirement for [Git and API activity](https://gitlab.com/gitlab-org/gitlab/-/issues/9152).
|
||||
|
||||
|
|
|
@ -151,11 +151,12 @@ in a Merge Request. To do so, click the **{comment}** **comment** icon in the gu
|
|||
### Commenting on multiple lines
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/ux-research/-/issues/870) in GitLab 13.2.
|
||||
> - It's deployed behind a feature flag, disabled by default.
|
||||
> - It's deployed behind a feature flag, enabled by default.
|
||||
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/221268) on GitLab 13.3.
|
||||
> - It's enabled on GitLab.com.
|
||||
> - It can be enabled or disabled per-project.
|
||||
> - It can be disabled or enabled per-project.
|
||||
> - It's recommended for production use.
|
||||
> - For GitLab self-managed instances, GitLab administrators can opt to [enable it](#enable-or-disable-multiline-comments-core-only). **(CORE ONLY)**
|
||||
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-multiline-comments-core-only). **(CORE ONLY)**
|
||||
|
||||
GitLab provides a way to select which lines of code a comment refers to. After starting a comment
|
||||
a dropdown selector is shown to select the first line that this comment refers to.
|
||||
|
@ -178,18 +179,18 @@ It is deployed behind a feature flag that is **disabled by default**.
|
|||
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||
can opt to enable it for your instance.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:multiline_comments)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:multiline_comments)
|
||||
```
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:multiline_comments)
|
||||
```
|
||||
|
||||
## Pipeline status in merge requests widgets
|
||||
|
||||
If you've set up [GitLab CI/CD](../../../ci/README.md) in your project,
|
||||
|
|
|
@ -36,7 +36,7 @@ RSpec.describe 'Global search' do
|
|||
end
|
||||
end
|
||||
|
||||
it 'closes the dropdown on blur', :js do
|
||||
it 'closes the dropdown on blur', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/201841' do
|
||||
fill_in 'search', with: "a"
|
||||
dropdown = find('.js-dashboard-search-options')
|
||||
|
||||
|
|
|
@ -83,11 +83,10 @@ describe('Release edit/new component', () => {
|
|||
});
|
||||
|
||||
const findSubmitButton = () => wrapper.find('button[type=submit]');
|
||||
const findForm = () => wrapper.find('form');
|
||||
|
||||
describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => {
|
||||
beforeEach(() => {
|
||||
factory();
|
||||
});
|
||||
beforeEach(factory);
|
||||
|
||||
it('calls initializeRelease when the component is created', () => {
|
||||
expect(actions.initializeRelease).toHaveBeenCalledTimes(1);
|
||||
|
@ -122,15 +121,14 @@ describe('Release edit/new component', () => {
|
|||
});
|
||||
|
||||
it('calls saveRelease when the form is submitted', () => {
|
||||
wrapper.find('form').trigger('submit');
|
||||
findForm().trigger('submit');
|
||||
|
||||
expect(actions.saveRelease).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => {
|
||||
beforeEach(() => {
|
||||
factory();
|
||||
});
|
||||
beforeEach(factory);
|
||||
|
||||
it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => {
|
||||
const cancelButton = wrapper.find('.js-cancel-button');
|
||||
|
@ -246,6 +244,12 @@ describe('Release edit/new component', () => {
|
|||
it('renders the submit button as disabled', () => {
|
||||
expect(findSubmitButton().attributes('disabled')).toBe('disabled');
|
||||
});
|
||||
|
||||
it('does not allow the form to be submitted', () => {
|
||||
findForm().trigger('submit');
|
||||
|
||||
expect(actions.saveRelease).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
|
|||
import AssetLinksForm from '~/releases/components/asset_links_form.vue';
|
||||
import { release as originalRelease } from '../mock_data';
|
||||
import * as commonUtils from '~/lib/utils/common_utils';
|
||||
import { ENTER_KEY } from '~/lib/utils/keys';
|
||||
import { ASSET_LINK_TYPE, DEFAULT_ASSET_LINK_TYPE } from '~/releases/constants';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
|
@ -91,42 +92,128 @@ describe('Release edit component', () => {
|
|||
expect(actions.removeAssetLink).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkUrl" store method when text is entered into the "URL" input field', () => {
|
||||
const linkIdToUpdate = release.assets.links[0].id;
|
||||
const newUrl = 'updated url';
|
||||
describe('URL input field', () => {
|
||||
let input;
|
||||
let linkIdToUpdate;
|
||||
let newUrl;
|
||||
|
||||
expect(actions.updateAssetLinkUrl).not.toHaveBeenCalled();
|
||||
beforeEach(() => {
|
||||
input = wrapper.find({ ref: 'urlInput' }).element;
|
||||
linkIdToUpdate = release.assets.links[0].id;
|
||||
newUrl = 'updated url';
|
||||
});
|
||||
|
||||
wrapper.find({ ref: 'urlInput' }).vm.$emit('change', newUrl);
|
||||
const expectStoreMethodNotToBeCalled = () => {
|
||||
expect(actions.updateAssetLinkUrl).not.toHaveBeenCalled();
|
||||
};
|
||||
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newUrl,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
const dispatchKeydowEvent = eventParams => {
|
||||
const event = new KeyboardEvent('keydown', eventParams);
|
||||
|
||||
input.dispatchEvent(event);
|
||||
};
|
||||
|
||||
const expectStoreMethodToBeCalled = () => {
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkUrl).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newUrl,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
};
|
||||
|
||||
it('calls the "updateAssetLinkUrl" store method when text is entered into the "URL" input field', () => {
|
||||
expectStoreMethodNotToBeCalled();
|
||||
|
||||
wrapper.find({ ref: 'urlInput' }).vm.$emit('change', newUrl);
|
||||
|
||||
expectStoreMethodToBeCalled();
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkUrl" store method when Ctrl+Enter is pressed inside the "URL" input field', () => {
|
||||
expectStoreMethodNotToBeCalled();
|
||||
|
||||
input.value = newUrl;
|
||||
|
||||
dispatchKeydowEvent({ key: ENTER_KEY, ctrlKey: true });
|
||||
|
||||
expectStoreMethodToBeCalled();
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkUrl" store method when Cmd+Enter is pressed inside the "URL" input field', () => {
|
||||
expectStoreMethodNotToBeCalled();
|
||||
|
||||
input.value = newUrl;
|
||||
|
||||
dispatchKeydowEvent({ key: ENTER_KEY, metaKey: true });
|
||||
|
||||
expectStoreMethodToBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkName" store method when text is entered into the "Link title" input field', () => {
|
||||
const linkIdToUpdate = release.assets.links[0].id;
|
||||
const newName = 'updated name';
|
||||
describe('Link title field', () => {
|
||||
let input;
|
||||
let linkIdToUpdate;
|
||||
let newName;
|
||||
|
||||
expect(actions.updateAssetLinkName).not.toHaveBeenCalled();
|
||||
beforeEach(() => {
|
||||
input = wrapper.find({ ref: 'nameInput' }).element;
|
||||
linkIdToUpdate = release.assets.links[0].id;
|
||||
newName = 'updated name';
|
||||
});
|
||||
|
||||
wrapper.find({ ref: 'nameInput' }).vm.$emit('change', newName);
|
||||
const expectStoreMethodNotToBeCalled = () => {
|
||||
expect(actions.updateAssetLinkUrl).not.toHaveBeenCalled();
|
||||
};
|
||||
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newName,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
const dispatchKeydowEvent = eventParams => {
|
||||
const event = new KeyboardEvent('keydown', eventParams);
|
||||
|
||||
input.dispatchEvent(event);
|
||||
};
|
||||
|
||||
const expectStoreMethodToBeCalled = () => {
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledTimes(1);
|
||||
expect(actions.updateAssetLinkName).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
{
|
||||
linkIdToUpdate,
|
||||
newName,
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
};
|
||||
|
||||
it('calls the "updateAssetLinkName" store method when text is entered into the "Link title" input field', () => {
|
||||
expectStoreMethodNotToBeCalled();
|
||||
|
||||
wrapper.find({ ref: 'nameInput' }).vm.$emit('change', newName);
|
||||
|
||||
expectStoreMethodToBeCalled();
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkName" store method when Ctrl+Enter is pressed inside the "Link title" input field', () => {
|
||||
expectStoreMethodNotToBeCalled();
|
||||
|
||||
input.value = newName;
|
||||
|
||||
dispatchKeydowEvent({ key: ENTER_KEY, ctrlKey: true });
|
||||
|
||||
expectStoreMethodToBeCalled();
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkName" store method when Cmd+Enter is pressed inside the "Link title" input field', () => {
|
||||
expectStoreMethodNotToBeCalled();
|
||||
|
||||
input.value = newName;
|
||||
|
||||
dispatchKeydowEvent({ key: ENTER_KEY, metaKey: true });
|
||||
|
||||
expectStoreMethodToBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('calls the "updateAssetLinkType" store method when an option is selected from the "Type" dropdown', () => {
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Resolvers::CiConfiguration::SastResolver do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject(:sast_config) { resolve(described_class, ctx: { current_user: user }, obj: project) }
|
||||
|
||||
it 'returns global variable informations related to SAST' do
|
||||
expect(sast_config['global'].first['field']).to eql("SECURE_ANALYZERS_PREFIX")
|
||||
expect(sast_config['global'].first['label']).to eql("Image prefix")
|
||||
expect(sast_config['global'].first['type']).to eql("string")
|
||||
|
||||
expect(sast_config['pipeline'].first['field']).to eql("stage")
|
||||
expect(sast_config['pipeline'].first['label']).to eql("Stage")
|
||||
expect(sast_config['pipeline'].first['type']).to eql("dropdown")
|
||||
|
||||
expect(sast_config['analyzers'].first['name']).to eql("brakeman")
|
||||
expect(sast_config['analyzers'].first['label']).to eql("Brakeman")
|
||||
expect(sast_config['analyzers'].first['enabled']).to be true
|
||||
end
|
||||
end
|
||||
end
|
|
@ -26,7 +26,7 @@ RSpec.describe GitlabSchema.types['Project'] do
|
|||
grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments
|
||||
environment boards jira_import_status jira_imports services releases release
|
||||
alert_management_alerts alert_management_alert alert_management_alert_status_counts
|
||||
container_expiration_policy service_desk_enabled service_desk_address
|
||||
container_expiration_policy sast_ci_configuration service_desk_enabled service_desk_address
|
||||
issue_status_counts
|
||||
]
|
||||
|
||||
|
@ -150,5 +150,93 @@ RSpec.describe GitlabSchema.types['Project'] do
|
|||
it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) }
|
||||
end
|
||||
|
||||
describe 'sast_ci_configuration' do
|
||||
let_it_be(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:query) do
|
||||
%(
|
||||
query {
|
||||
project(fullPath: "#{project.full_path}") {
|
||||
sastCiConfiguration {
|
||||
global {
|
||||
nodes {
|
||||
type
|
||||
options {
|
||||
nodes {
|
||||
label
|
||||
value
|
||||
}
|
||||
}
|
||||
field
|
||||
label
|
||||
defaultValue
|
||||
value
|
||||
}
|
||||
}
|
||||
pipeline {
|
||||
nodes {
|
||||
type
|
||||
options {
|
||||
nodes {
|
||||
label
|
||||
value
|
||||
}
|
||||
}
|
||||
field
|
||||
label
|
||||
defaultValue
|
||||
value
|
||||
}
|
||||
}
|
||||
analyzers {
|
||||
nodes {
|
||||
name
|
||||
label
|
||||
enabled
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
|
||||
|
||||
before do
|
||||
project.add_developer(user)
|
||||
end
|
||||
|
||||
it "returns the project's sast configuration for global variables" do
|
||||
query_result = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes')
|
||||
first_config = query_result.first
|
||||
fourth_config = query_result[3]
|
||||
expect(first_config['type']).to eq('string')
|
||||
expect(first_config['field']).to eq('SECURE_ANALYZERS_PREFIX')
|
||||
expect(first_config['label']).to eq('Image prefix')
|
||||
expect(first_config['defaultValue']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
|
||||
expect(first_config['value']).to eq('')
|
||||
expect(first_config['options']).to be_nil
|
||||
expect(fourth_config['options']['nodes']).to match([{ "value" => "true", "label" => "true (disables SAST)" },
|
||||
{ "value" => "false", "label" => "false (enables SAST)" }])
|
||||
end
|
||||
|
||||
it "returns the project's sast configuration for pipeline variables" do
|
||||
configuration = subject.dig('data', 'project', 'sastCiConfiguration', 'pipeline', 'nodes').first
|
||||
expect(configuration['type']).to eq('dropdown')
|
||||
expect(configuration['field']).to eq('stage')
|
||||
expect(configuration['label']).to eq('Stage')
|
||||
expect(configuration['defaultValue']).to eq('test')
|
||||
expect(configuration['value']).to eq('')
|
||||
end
|
||||
|
||||
it "returns the project's sast configuration for analyzer variables" do
|
||||
configuration = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
|
||||
expect(configuration['name']).to eq('brakeman')
|
||||
expect(configuration['label']).to eq('Brakeman')
|
||||
expect(configuration['enabled']).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'a GraphQL type with labels'
|
||||
end
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
include:
|
||||
- template: SAST.gitlab-ci.yml
|
||||
|
||||
variables:
|
||||
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
|
||||
SAST_EXCLUDED_PATHS: "spec, executables"
|
||||
|
||||
stages:
|
||||
- our_custom_security_stage
|
||||
sast:
|
||||
stage: our_custom_security_stage
|
||||
variables:
|
||||
SEARCH_MAX_DEPTH: 8
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_context 'read ci configuration for sast enabled project' do
|
||||
let_it_be(:gitlab_ci_yml_content) do
|
||||
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast.yml'))
|
||||
end
|
||||
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
end
|
Loading…
Reference in a new issue