Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-07-06 09:07:05 +00:00
parent 67d7b691b1
commit 22856b8780
21 changed files with 171 additions and 126 deletions

View File

@ -157,7 +157,7 @@ gem 'github-markup', '~> 1.7.0', require: 'github/markup'
gem 'commonmarker', '~> 0.21' gem 'commonmarker', '~> 0.21'
gem 'kramdown', '~> 2.3.1' gem 'kramdown', '~> 2.3.1'
gem 'RedCloth', '~> 4.3.2' gem 'RedCloth', '~> 4.3.2'
gem 'gitlab-rdoc', '~> 6.3.2', require: 'rdoc' # We need this fork until rdoc releases a new version. See https://gitlab.com/gitlab-org/gitlab/-/issues/334695 gem 'rdoc', '~> 6.3.2'
gem 'org-ruby', '~> 0.9.12' gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0' gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1' gem 'wikicloth', '0.8.1'
@ -197,7 +197,7 @@ gem 'acts-as-taggable-on', '~> 7.0'
# Background jobs # Background jobs
gem 'sidekiq', '~> 5.2.7' gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0' gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.7.0' gem 'redis-namespace', '~> 1.8.1'
gem 'gitlab-sidekiq-fetcher', '0.5.6', require: 'sidekiq-reliable-fetch' gem 'gitlab-sidekiq-fetcher', '0.5.6', require: 'sidekiq-reliable-fetch'
# Cron Parser # Cron Parser
@ -229,7 +229,7 @@ gem 'js_regex', '~> 3.4'
gem 'device_detector' gem 'device_detector'
# Redis # Redis
gem 'redis', '~> 4.0' gem 'redis', '~> 4.1.4'
gem 'connection_pool', '~> 2.0' gem 'connection_pool', '~> 2.0'
# Redis session store # Redis session store

View File

@ -499,7 +499,6 @@ GEM
openid_connect (~> 1.2) openid_connect (~> 1.2)
gitlab-pg_query (2.0.4) gitlab-pg_query (2.0.4)
google-protobuf (>= 3.17.1) google-protobuf (>= 3.17.1)
gitlab-rdoc (6.3.2)
gitlab-sidekiq-fetcher (0.5.6) gitlab-sidekiq-fetcher (0.5.6)
sidekiq (~> 5) sidekiq (~> 5)
gitlab-styles (6.2.0) gitlab-styles (6.2.0)
@ -1026,11 +1025,12 @@ GEM
msgpack (>= 0.4.3) msgpack (>= 0.4.3)
optimist (>= 3.0.0) optimist (>= 3.0.0)
rchardet (1.8.0) rchardet (1.8.0)
rdoc (6.3.2)
re2 (1.2.0) re2 (1.2.0)
recaptcha (4.13.1) recaptcha (4.13.1)
json json
recursive-open-struct (1.1.2) recursive-open-struct (1.1.2)
redis (4.1.3) redis (4.1.4)
redis-actionpack (5.2.0) redis-actionpack (5.2.0)
actionpack (>= 5, < 7) actionpack (>= 5, < 7)
redis-rack (>= 2.1.0, < 3) redis-rack (>= 2.1.0, < 3)
@ -1038,7 +1038,7 @@ GEM
redis-activesupport (5.2.0) redis-activesupport (5.2.0)
activesupport (>= 3, < 7) activesupport (>= 3, < 7)
redis-store (>= 1.3, < 2) redis-store (>= 1.3, < 2)
redis-namespace (1.7.0) redis-namespace (1.8.1)
redis (>= 3.0.4) redis (>= 3.0.4)
redis-rack (2.1.2) redis-rack (2.1.2)
rack (>= 2.0.8, < 3) rack (>= 2.0.8, < 3)
@ -1497,7 +1497,6 @@ DEPENDENCIES
gitlab-markup (~> 1.7.1) gitlab-markup (~> 1.7.1)
gitlab-net-dns (~> 0.9.1) gitlab-net-dns (~> 0.9.1)
gitlab-omniauth-openid-connect (~> 0.4.0) gitlab-omniauth-openid-connect (~> 0.4.0)
gitlab-rdoc (~> 6.3.2)
gitlab-sidekiq-fetcher (= 0.5.6) gitlab-sidekiq-fetcher (= 0.5.6)
gitlab-styles (~> 6.2.0) gitlab-styles (~> 6.2.0)
gitlab_chronic_duration (~> 0.10.6.2) gitlab_chronic_duration (~> 0.10.6.2)
@ -1607,10 +1606,11 @@ DEPENDENCIES
rainbow (~> 3.0) rainbow (~> 3.0)
rblineprof (~> 0.3.6) rblineprof (~> 0.3.6)
rbtrace (~> 0.4) rbtrace (~> 0.4)
rdoc (~> 6.3.2)
re2 (~> 1.2.0) re2 (~> 1.2.0)
recaptcha (~> 4.11) recaptcha (~> 4.11)
redis (~> 4.0) redis (~> 4.1.4)
redis-namespace (~> 1.7.0) redis-namespace (~> 1.8.1)
redis-rails (~> 5.0.2) redis-rails (~> 5.0.2)
request_store (~> 1.5) request_store (~> 1.5)
responders (~> 3.0) responders (~> 3.0)

View File

@ -75,15 +75,6 @@ export default {
validProjectKey() { validProjectKey() {
return !this.enableJiraIssues || Boolean(this.projectKey) || !this.validated; return !this.enableJiraIssues || Boolean(this.projectKey) || !this.validated;
}, },
showJiraVulnerabilitiesOptions() {
return this.showJiraVulnerabilitiesIntegration;
},
showUltimateUpgrade() {
return this.showJiraIssuesIntegration && !this.showJiraVulnerabilitiesIntegration;
},
showPremiumUpgrade() {
return !this.showJiraIssuesIntegration;
},
}, },
created() { created() {
eventHub.$on('validateForm', this.validateForm); eventHub.$on('validateForm', this.validateForm);
@ -128,23 +119,30 @@ export default {
}} }}
</template> </template>
</gl-form-checkbox> </gl-form-checkbox>
<jira-issue-creation-vulnerabilities <template v-if="enableJiraIssues">
v-if="enableJiraIssues" <jira-issue-creation-vulnerabilities
:project-key="projectKey" :project-key="projectKey"
:initial-is-enabled="initialEnableJiraVulnerabilities" :initial-is-enabled="initialEnableJiraVulnerabilities"
:initial-issue-type-id="initialVulnerabilitiesIssuetype" :initial-issue-type-id="initialVulnerabilitiesIssuetype"
:show-full-feature="showJiraVulnerabilitiesOptions" :show-full-feature="showJiraVulnerabilitiesIntegration"
data-testid="jira-for-vulnerabilities" data-testid="jira-for-vulnerabilities"
@request-get-issue-types="getJiraIssueTypes" @request-get-issue-types="getJiraIssueTypes"
/> />
<jira-upgrade-cta
v-if="!showJiraVulnerabilitiesIntegration"
class="gl-mt-2 gl-ml-6"
data-testid="ultimate-upgrade-cta"
show-ultimate-message
:upgrade-plan-path="upgradePlanPath"
/>
</template>
</template> </template>
<jira-upgrade-cta <jira-upgrade-cta
v-if="showUltimateUpgrade || showPremiumUpgrade" v-else
class="gl-mt-2" class="gl-mt-2"
:class="{ 'gl-ml-6': showUltimateUpgrade }" data-testid="premium-upgrade-cta"
show-premium-message
:upgrade-plan-path="upgradePlanPath" :upgrade-plan-path="upgradePlanPath"
:show-ultimate-message="showUltimateUpgrade"
:show-premium-message="showPremiumUpgrade"
/> />
</div> </div>
</gl-form-group> </gl-form-group>

View File

@ -65,6 +65,9 @@ export default {
isLoadingLegacyViewer: false, isLoadingLegacyViewer: false,
activeViewerType: SIMPLE_BLOB_VIEWER, activeViewerType: SIMPLE_BLOB_VIEWER,
project: { project: {
userPermissions: {
pushCode: false,
},
repository: { repository: {
blobs: { blobs: {
nodes: [ nodes: [
@ -86,7 +89,6 @@ export default {
canLock: false, canLock: false,
isLocked: false, isLocked: false,
lockLink: '', lockLink: '',
canModifyBlob: true,
forkPath: '', forkPath: '',
simpleViewer: {}, simpleViewer: {},
richViewer: null, richViewer: null,
@ -168,7 +170,7 @@ export default {
:path="path" :path="path"
:name="blobInfo.name" :name="blobInfo.name"
:replace-path="blobInfo.replacePath" :replace-path="blobInfo.replacePath"
:can-push-code="blobInfo.canModifyBlob" :can-push-code="project.userPermissions.pushCode"
/> />
</template> </template>
</blob-header> </blob-header>

View File

@ -1,5 +1,8 @@
query getBlobInfo($projectPath: ID!, $filePath: String!) { query getBlobInfo($projectPath: ID!, $filePath: String!) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
userPermissions {
pushCode
}
repository { repository {
blobs(paths: [$filePath]) { blobs(paths: [$filePath]) {
nodes { nodes {
@ -15,7 +18,6 @@ query getBlobInfo($projectPath: ID!, $filePath: String!) {
storedExternally storedExternally
rawPath rawPath
replacePath replacePath
canModifyBlob
simpleViewer { simpleViewer {
fileType fileType
tooLarge tooLarge

View File

@ -56,24 +56,19 @@ $notification-box-shadow-color: rgba(0, 0, 0, 0.25);
} }
.flash-alert { .flash-alert {
background-color: $red-100; background-color: $red-50;
color: $red-700;
} }
.flash-notice { .flash-notice {
background-color: $blue-100; background-color: $blue-50;
color: $blue-700;
} }
.flash-success { .flash-success {
background-color: $theme-green-100; background-color: $green-50;
color: $green-700;
} }
.flash-warning { .flash-warning {
background-color: $orange-50; background-color: $orange-50;
color: $gray-900;
cursor: default;
} }
.flash-text, .flash-text,

View File

@ -84,11 +84,7 @@ module Repositories
return if Feature.enabled?(:disable_git_http_fetch_writes) return if Feature.enabled?(:disable_git_http_fetch_writes)
if Feature.enabled?(:project_statistics_sync, project, default_enabled: true) Projects::FetchStatisticsIncrementService.new(project).execute
Projects::FetchStatisticsIncrementService.new(project).execute
else
ProjectDailyStatisticsWorker.perform_async(project.id) # rubocop:disable CodeReuse/Worker
end
end end
def access def access

View File

@ -33,6 +33,7 @@ module Ci
secret_detection: 'gl-secret-detection-report.json', secret_detection: 'gl-secret-detection-report.json',
dependency_scanning: 'gl-dependency-scanning-report.json', dependency_scanning: 'gl-dependency-scanning-report.json',
container_scanning: 'gl-container-scanning-report.json', container_scanning: 'gl-container-scanning-report.json',
cluster_image_scanning: 'gl-cluster-image-scanning-report.json',
dast: 'gl-dast-report.json', dast: 'gl-dast-report.json',
license_scanning: 'gl-license-scanning-report.json', license_scanning: 'gl-license-scanning-report.json',
performance: 'performance.json', performance: 'performance.json',
@ -71,6 +72,7 @@ module Ci
secret_detection: :raw, secret_detection: :raw,
dependency_scanning: :raw, dependency_scanning: :raw,
container_scanning: :raw, container_scanning: :raw,
cluster_image_scanning: :raw,
dast: :raw, dast: :raw,
license_scanning: :raw, license_scanning: :raw,
@ -108,6 +110,7 @@ module Ci
sast sast
secret_detection secret_detection
requirements requirements
cluster_image_scanning
].freeze ].freeze
TYPE_AND_FORMAT_PAIRS = INTERNAL_TYPES.merge(REPORT_TYPES).freeze TYPE_AND_FORMAT_PAIRS = INTERNAL_TYPES.merge(REPORT_TYPES).freeze
@ -212,7 +215,8 @@ module Ci
coverage_fuzzing: 23, ## EE-specific coverage_fuzzing: 23, ## EE-specific
browser_performance: 24, ## EE-specific browser_performance: 24, ## EE-specific
load_performance: 25, ## EE-specific load_performance: 25, ## EE-specific
api_fuzzing: 26 ## EE-specific api_fuzzing: 26, ## EE-specific
cluster_image_scanning: 27 ## EE-specific
} }
# `file_location` indicates where actual files are stored. # `file_location` indicates where actual files are stored.

View File

@ -31,7 +31,8 @@ class UserCallout < ApplicationRecord
pipeline_needs_banner: 29, pipeline_needs_banner: 29,
pipeline_needs_hover_tip: 30, pipeline_needs_hover_tip: 30,
web_ide_ci_environments_guidance: 31, web_ide_ci_environments_guidance: 31,
security_configuration_upgrade_banner: 32 security_configuration_upgrade_banner: 32,
cloud_licensing_subscription_activation_banner: 33 # EE-only
} }
validates :user, presence: true validates :user, presence: true

View File

@ -3,7 +3,7 @@
%head %head
%meta{ content: "text/html; charset=utf-8", "http-equiv" => "Content-Type" } %meta{ content: "text/html; charset=utf-8", "http-equiv" => "Content-Type" }
%meta{ content: "width=device-width, initial-scale=1", name: "viewport" } %meta{ content: "width=device-width, initial-scale=1", name: "viewport" }
%link{ href: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600", rel: "stylesheet", type: "text/css" } %link{ href: "https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600", rel: "stylesheet", type: "text/css", data: { premailer: 'ignore' } }
%title= message.subject %title= message.subject
:css :css
/* CLIENT-SPECIFIC STYLES */ /* CLIENT-SPECIFIC STYLES */

View File

@ -1,8 +0,0 @@
---
name: project_statistics_sync
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29636
rollout_issue_url:
milestone: '12.10'
type: development
group: group::source code
default_enabled: true

View File

@ -9237,6 +9237,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
| <a id="groupcustomemoji"></a>`customEmoji` | [`CustomEmojiConnection`](#customemojiconnection) | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled. (see [Connections](#connections)) | | <a id="groupcustomemoji"></a>`customEmoji` | [`CustomEmojiConnection`](#customemojiconnection) | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled. (see [Connections](#connections)) |
| <a id="groupdescription"></a>`description` | [`String`](#string) | Description of the namespace. | | <a id="groupdescription"></a>`description` | [`String`](#string) | Description of the namespace. |
| <a id="groupdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. | | <a id="groupdescriptionhtml"></a>`descriptionHtml` | [`String`](#string) | The GitLab Flavored Markdown rendering of `description`. |
| <a id="groupdora"></a>`dora` | [`Dora`](#dora) | The group's DORA metrics. |
| <a id="groupemailsdisabled"></a>`emailsDisabled` | [`Boolean`](#boolean) | Indicates if a group has email notifications disabled. | | <a id="groupemailsdisabled"></a>`emailsDisabled` | [`Boolean`](#boolean) | Indicates if a group has email notifications disabled. |
| <a id="groupepicboards"></a>`epicBoards` | [`EpicBoardConnection`](#epicboardconnection) | Find epic boards. (see [Connections](#connections)) | | <a id="groupepicboards"></a>`epicBoards` | [`EpicBoardConnection`](#epicboardconnection) | Find epic boards. (see [Connections](#connections)) |
| <a id="groupepicsenabled"></a>`epicsEnabled` | [`Boolean`](#boolean) | Indicates if Epics are enabled for namespace. | | <a id="groupepicsenabled"></a>`epicsEnabled` | [`Boolean`](#boolean) | Indicates if Epics are enabled for namespace. |
@ -14681,6 +14682,7 @@ Iteration ID wildcard values.
| <a id="jobartifactfiletypearchive"></a>`ARCHIVE` | ARCHIVE job artifact file type. | | <a id="jobartifactfiletypearchive"></a>`ARCHIVE` | ARCHIVE job artifact file type. |
| <a id="jobartifactfiletypebrowser_performance"></a>`BROWSER_PERFORMANCE` | BROWSER PERFORMANCE job artifact file type. | | <a id="jobartifactfiletypebrowser_performance"></a>`BROWSER_PERFORMANCE` | BROWSER PERFORMANCE job artifact file type. |
| <a id="jobartifactfiletypecluster_applications"></a>`CLUSTER_APPLICATIONS` | CLUSTER APPLICATIONS job artifact file type. | | <a id="jobartifactfiletypecluster_applications"></a>`CLUSTER_APPLICATIONS` | CLUSTER APPLICATIONS job artifact file type. |
| <a id="jobartifactfiletypecluster_image_scanning"></a>`CLUSTER_IMAGE_SCANNING` | CLUSTER IMAGE SCANNING job artifact file type. |
| <a id="jobartifactfiletypecobertura"></a>`COBERTURA` | COBERTURA job artifact file type. | | <a id="jobartifactfiletypecobertura"></a>`COBERTURA` | COBERTURA job artifact file type. |
| <a id="jobartifactfiletypecodequality"></a>`CODEQUALITY` | CODE QUALITY job artifact file type. | | <a id="jobartifactfiletypecodequality"></a>`CODEQUALITY` | CODE QUALITY job artifact file type. |
| <a id="jobartifactfiletypecontainer_scanning"></a>`CONTAINER_SCANNING` | CONTAINER SCANNING job artifact file type. | | <a id="jobartifactfiletypecontainer_scanning"></a>`CONTAINER_SCANNING` | CONTAINER SCANNING job artifact file type. |
@ -15210,6 +15212,7 @@ Name of the feature that the callout is for.
| <a id="usercalloutfeaturenameenumactive_user_count_threshold"></a>`ACTIVE_USER_COUNT_THRESHOLD` | Callout feature name for active_user_count_threshold. | | <a id="usercalloutfeaturenameenumactive_user_count_threshold"></a>`ACTIVE_USER_COUNT_THRESHOLD` | Callout feature name for active_user_count_threshold. |
| <a id="usercalloutfeaturenameenumbuy_pipeline_minutes_notification_dot"></a>`BUY_PIPELINE_MINUTES_NOTIFICATION_DOT` | Callout feature name for buy_pipeline_minutes_notification_dot. | | <a id="usercalloutfeaturenameenumbuy_pipeline_minutes_notification_dot"></a>`BUY_PIPELINE_MINUTES_NOTIFICATION_DOT` | Callout feature name for buy_pipeline_minutes_notification_dot. |
| <a id="usercalloutfeaturenameenumcanary_deployment"></a>`CANARY_DEPLOYMENT` | Callout feature name for canary_deployment. | | <a id="usercalloutfeaturenameenumcanary_deployment"></a>`CANARY_DEPLOYMENT` | Callout feature name for canary_deployment. |
| <a id="usercalloutfeaturenameenumcloud_licensing_subscription_activation_banner"></a>`CLOUD_LICENSING_SUBSCRIPTION_ACTIVATION_BANNER` | Callout feature name for cloud_licensing_subscription_activation_banner. |
| <a id="usercalloutfeaturenameenumcluster_security_warning"></a>`CLUSTER_SECURITY_WARNING` | Callout feature name for cluster_security_warning. | | <a id="usercalloutfeaturenameenumcluster_security_warning"></a>`CLUSTER_SECURITY_WARNING` | Callout feature name for cluster_security_warning. |
| <a id="usercalloutfeaturenameenumcustomize_homepage"></a>`CUSTOMIZE_HOMEPAGE` | Callout feature name for customize_homepage. | | <a id="usercalloutfeaturenameenumcustomize_homepage"></a>`CUSTOMIZE_HOMEPAGE` | Callout feature name for customize_homepage. |
| <a id="usercalloutfeaturenameenumeoa_bronze_plan_banner"></a>`EOA_BRONZE_PLAN_BANNER` | Callout feature name for eoa_bronze_plan_banner. | | <a id="usercalloutfeaturenameenumeoa_bronze_plan_banner"></a>`EOA_BRONZE_PLAN_BANNER` | Callout feature name for eoa_bronze_plan_banner. |

View File

@ -3064,6 +3064,18 @@ as artifacts.
The collected coverage fuzzing report uploads to GitLab as an artifact and is summarized in merge The collected coverage fuzzing report uploads to GitLab as an artifact and is summarized in merge
requests and the pipeline view. It's also used to provide data for security dashboards. requests and the pipeline view. It's also used to provide data for security dashboards.
##### `artifacts:reports:cluster_image_scanning` **(ULTIMATE)**
> - Introduced in GitLab 14.1.
> - Requires GitLab Runner 14.1 and above.
The `cluster_image_scanning` report collects `CLUSTER_IMAGE_SCANNING` vulnerabilities
as artifacts.
The collected `CLUSTER_IMAGE_SCANNING` report uploads to GitLab as an artifact and
is summarized in the pipeline view. It's also used to provide data for security
dashboards.
##### `artifacts:reports:dast` **(ULTIMATE)** ##### `artifacts:reports:dast` **(ULTIMATE)**
> - Introduced in GitLab 11.5. > - Introduced in GitLab 11.5.

View File

@ -15,7 +15,7 @@ module Gitlab
%i[junit codequality sast secret_detection dependency_scanning container_scanning %i[junit codequality sast secret_detection dependency_scanning container_scanning
dast performance browser_performance load_performance license_scanning metrics lsif dast performance browser_performance load_performance license_scanning metrics lsif
dotenv cobertura terraform accessibility cluster_applications dotenv cobertura terraform accessibility cluster_applications
requirements coverage_fuzzing api_fuzzing].freeze requirements coverage_fuzzing api_fuzzing cluster_image_scanning].freeze
attributes ALLOWED_KEYS attributes ALLOWED_KEYS
@ -32,6 +32,7 @@ module Gitlab
validates :secret_detection, array_of_strings_or_string: true validates :secret_detection, array_of_strings_or_string: true
validates :dependency_scanning, array_of_strings_or_string: true validates :dependency_scanning, array_of_strings_or_string: true
validates :container_scanning, array_of_strings_or_string: true validates :container_scanning, array_of_strings_or_string: true
validates :cluster_image_scanning, array_of_strings_or_string: true
validates :dast, array_of_strings_or_string: true validates :dast, array_of_strings_or_string: true
validates :performance, array_of_strings_or_string: true validates :performance, array_of_strings_or_string: true
validates :browser_performance, array_of_strings_or_string: true validates :browser_performance, array_of_strings_or_string: true

View File

@ -34,18 +34,6 @@ RSpec.describe Repositories::GitHttpController do
end end
end end
context 'when project_statistics_sync feature flag is disabled' do
before do
stub_feature_flags(project_statistics_sync: false, disable_git_http_fetch_writes: false)
end
it 'updates project statistics async for projects' do
expect(ProjectDailyStatisticsWorker).to receive(:perform_async)
send_request
end
end
it 'updates project statistics sync for projects' do it 'updates project statistics sync for projects' do
stub_feature_flags(disable_git_http_fetch_writes: false) stub_feature_flags(disable_git_http_fetch_writes: false)

View File

@ -508,6 +508,14 @@ FactoryBot.define do
end end
end end
trait :cluster_image_scanning do
options do
{
artifacts: { reports: { cluster_image_scanning: 'gl-cluster-image-scanning-report.json' } }
}
end
end
trait :license_scanning do trait :license_scanning do
options do options do
{ {

View File

@ -2,7 +2,6 @@ import { GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended } from 'helpers/vue_test_utils_helper';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue'; import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import JiraUpgradeCta from '~/integrations/edit/components/jira_upgrade_cta.vue';
import eventHub from '~/integrations/edit/event_hub'; import eventHub from '~/integrations/edit/event_hub';
import { createStore } from '~/integrations/edit/store'; import { createStore } from '~/integrations/edit/store';
@ -14,6 +13,7 @@ describe('JiraIssuesFields', () => {
editProjectPath: '/edit', editProjectPath: '/edit',
showJiraIssuesIntegration: true, showJiraIssuesIntegration: true,
showJiraVulnerabilitiesIntegration: true, showJiraVulnerabilitiesIntegration: true,
upgradePlanPath: 'https://gitlab.com',
}; };
const createComponent = ({ isInheriting = false, props, ...options } = {}) => { const createComponent = ({ isInheriting = false, props, ...options } = {}) => {
@ -37,60 +37,79 @@ describe('JiraIssuesFields', () => {
const findEnableCheckboxDisabled = () => const findEnableCheckboxDisabled = () =>
findEnableCheckbox().find('[type=checkbox]').attributes('disabled'); findEnableCheckbox().find('[type=checkbox]').attributes('disabled');
const findProjectKey = () => wrapper.findComponent(GlFormInput); const findProjectKey = () => wrapper.findComponent(GlFormInput);
const findJiraUpgradeCta = () => wrapper.findComponent(JiraUpgradeCta); const findPremiumUpgradeCTA = () => wrapper.findByTestId('premium-upgrade-cta');
const findUltimateUpgradeCTA = () => wrapper.findByTestId('ultimate-upgrade-cta');
const findJiraForVulnerabilities = () => wrapper.findByTestId('jira-for-vulnerabilities'); const findJiraForVulnerabilities = () => wrapper.findByTestId('jira-for-vulnerabilities');
const setEnableCheckbox = async (isEnabled = true) => const setEnableCheckbox = async (isEnabled = true) =>
findEnableCheckbox().vm.$emit('input', isEnabled); findEnableCheckbox().vm.$emit('input', isEnabled);
describe('jira issues call to action', () => {
it('shows the premium message', () => {
createComponent({
props: { showJiraIssuesIntegration: false },
});
expect(findJiraUpgradeCta().props()).toMatchObject({
showPremiumMessage: true,
showUltimateMessage: false,
});
});
it('shows the ultimate message', () => {
createComponent({
props: {
showJiraIssuesIntegration: true,
showJiraVulnerabilitiesIntegration: false,
},
});
expect(findJiraUpgradeCta().props()).toMatchObject({
showPremiumMessage: false,
showUltimateMessage: true,
});
});
});
describe('template', () => { describe('template', () => {
describe('upgrade banner for non-Premium user', () => { describe.each`
beforeEach(() => { showJiraIssuesIntegration | showJiraVulnerabilitiesIntegration
createComponent({ props: { initialProjectKey: '', showJiraIssuesIntegration: false } }); ${false} | ${false}
}); ${false} | ${true}
${true} | ${false}
${true} | ${true}
`(
'when `showJiraIssuesIntegration` is $jiraIssues and `showJiraVulnerabilitiesIntegration` is $jiraVulnerabilities',
({ showJiraIssuesIntegration, showJiraVulnerabilitiesIntegration }) => {
beforeEach(() => {
createComponent({
props: {
showJiraIssuesIntegration,
showJiraVulnerabilitiesIntegration,
},
});
});
it('does not show checkbox and input field', () => { if (showJiraIssuesIntegration) {
expect(findEnableCheckbox().exists()).toBe(false); it('renders checkbox and input field', () => {
expect(findProjectKey().exists()).toBe(false); expect(findEnableCheckbox().exists()).toBe(true);
}); expect(findEnableCheckboxDisabled()).toBeUndefined();
}); expect(findProjectKey().exists()).toBe(true);
});
it('does not render the Premium CTA', () => {
expect(findPremiumUpgradeCTA().exists()).toBe(false);
});
if (!showJiraVulnerabilitiesIntegration) {
it.each`
scenario | enableJiraIssues
${'when "Enable Jira issues" is checked, renders Ultimate upgrade CTA'} | ${true}
${'when "Enable Jira issues" is unchecked, does not render Ultimate upgrade CTA'} | ${false}
`('$scenario', async ({ enableJiraIssues }) => {
if (enableJiraIssues) {
await setEnableCheckbox();
}
expect(findUltimateUpgradeCTA().exists()).toBe(enableJiraIssues);
});
}
} else {
it('does not render checkbox and input field', () => {
expect(findEnableCheckbox().exists()).toBe(false);
expect(findProjectKey().exists()).toBe(false);
});
it('renders the Premium CTA', () => {
const premiumUpgradeCTA = findPremiumUpgradeCTA();
expect(premiumUpgradeCTA.exists()).toBe(true);
expect(premiumUpgradeCTA.props('upgradePlanPath')).toBe(defaultProps.upgradePlanPath);
});
}
it('does not render the Ultimate CTA', () => {
expect(findUltimateUpgradeCTA().exists()).toBe(false);
});
},
);
describe('Enable Jira issues checkbox', () => { describe('Enable Jira issues checkbox', () => {
beforeEach(() => { beforeEach(() => {
createComponent({ props: { initialProjectKey: '' } }); createComponent({ props: { initialProjectKey: '' } });
}); });
it('renders enabled checkbox', () => {
expect(findEnableCheckbox().exists()).toBe(true);
expect(findEnableCheckboxDisabled()).toBeUndefined();
});
it('renders disabled project_key input', () => { it('renders disabled project_key input', () => {
const projectKey = findProjectKey(); const projectKey = findProjectKey();
@ -99,10 +118,6 @@ describe('JiraIssuesFields', () => {
expect(projectKey.attributes('required')).toBeUndefined(); expect(projectKey.attributes('required')).toBeUndefined();
}); });
it('does not show upgrade banner', () => {
expect(findJiraUpgradeCta().exists()).toBe(false);
});
// As per https://vuejs.org/v2/guide/forms.html#Checkbox-1, // As per https://vuejs.org/v2/guide/forms.html#Checkbox-1,
// browsers don't include unchecked boxes in form submissions. // browsers don't include unchecked boxes in form submissions.
it('includes issues_enabled as false even if unchecked', () => { it('includes issues_enabled as false even if unchecked', () => {

View File

@ -37,7 +37,6 @@ const simpleMockData = {
canLock: true, canLock: true,
isLocked: false, isLocked: false,
lockLink: 'some_file.js/lock', lockLink: 'some_file.js/lock',
canModifyBlob: true,
forkPath: 'some_file.js/fork', forkPath: 'some_file.js/fork',
simpleViewer: { simpleViewer: {
fileType: 'text', fileType: 'text',
@ -56,16 +55,26 @@ const richMockData = {
renderError: null, renderError: null,
}, },
}; };
const userPermissionsMockData = {
userPermissions: {
pushCode: true,
},
};
const localVue = createLocalVue(); const localVue = createLocalVue();
const mockAxios = new MockAdapter(axios); const mockAxios = new MockAdapter(axios);
const createComponentWithApollo = (mockData) => { const createComponentWithApollo = (mockData, mockPermissionData = true) => {
localVue.use(VueApollo); localVue.use(VueApollo);
const mockResolver = jest const mockResolver = jest.fn().mockResolvedValue({
.fn() data: {
.mockResolvedValue({ data: { project: { repository: { blobs: { nodes: [mockData] } } } } }); project: {
userPermissions: { pushCode: mockPermissionData },
repository: { blobs: { nodes: [mockData] } },
},
},
});
const fakeApollo = createMockApollo([[blobInfoQuery, mockResolver]]); const fakeApollo = createMockApollo([[blobInfoQuery, mockResolver]]);
@ -276,13 +285,16 @@ describe('Blob content viewer component', () => {
}); });
describe('BlobButtonGroup', () => { describe('BlobButtonGroup', () => {
const { name, path } = simpleMockData; const { name, path, replacePath } = simpleMockData;
const {
userPermissions: { pushCode },
} = userPermissionsMockData;
it('renders component', async () => { it('renders component', async () => {
window.gon.current_user_id = 1; window.gon.current_user_id = 1;
fullFactory({ fullFactory({
mockData: { blobInfo: simpleMockData }, mockData: { blobInfo: simpleMockData, project: userPermissionsMockData },
stubs: { stubs: {
BlobContent: true, BlobContent: true,
BlobButtonGroup: true, BlobButtonGroup: true,
@ -294,6 +306,8 @@ describe('Blob content viewer component', () => {
expect(findBlobButtonGroup().props()).toMatchObject({ expect(findBlobButtonGroup().props()).toMatchObject({
name, name,
path, path,
replacePath,
canPushCode: pushCode,
}); });
}); });

View File

@ -40,6 +40,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports do
:secret_detection | 'gl-secret-detection-report.json' :secret_detection | 'gl-secret-detection-report.json'
:dependency_scanning | 'gl-dependency-scanning-report.json' :dependency_scanning | 'gl-dependency-scanning-report.json'
:container_scanning | 'gl-container-scanning-report.json' :container_scanning | 'gl-container-scanning-report.json'
:cluster_image_scanning | 'gl-cluster-image-scanning-report.json'
:dast | 'gl-dast-report.json' :dast | 'gl-dast-report.json'
:license_scanning | 'gl-license-scanning-report.json' :license_scanning | 'gl-license-scanning-report.json'
:performance | 'performance.json' :performance | 'performance.json'

View File

@ -1969,6 +1969,19 @@ RSpec.describe Notify do
end end
end end
describe 'in product marketing', :mailer do
let_it_be(:group) { create(:group) }
let(:mail) { ActionMailer::Base.deliveries.last }
it 'does not raise error' do
described_class.in_product_marketing_email(user.id, group.id, :trial, 0).deliver
expect(mail.subject).to eq('Go farther with GitLab')
expect(mail.body.parts.first.to_s).to include('Start a GitLab Ultimate trial today in less than one minute, no credit card required.')
end
end
def expect_sender(user) def expect_sender(user)
sender = subject.header[:from].addrs[0] sender = subject.header[:from].addrs[0]
expect(sender.display_name).to eq("#{user.name} (@#{user.username})") expect(sender.display_name).to eq("#{user.name} (@#{user.username})")

View File

@ -39,7 +39,7 @@ RSpec.describe Ci::RetryBuildService do
erased_at auto_canceled_by job_artifacts job_artifacts_archive erased_at auto_canceled_by job_artifacts job_artifacts_archive
job_artifacts_metadata job_artifacts_trace job_artifacts_junit job_artifacts_metadata job_artifacts_trace job_artifacts_junit
job_artifacts_sast job_artifacts_secret_detection job_artifacts_dependency_scanning job_artifacts_sast job_artifacts_secret_detection job_artifacts_dependency_scanning
job_artifacts_container_scanning job_artifacts_dast job_artifacts_container_scanning job_artifacts_cluster_image_scanning job_artifacts_dast
job_artifacts_license_scanning job_artifacts_license_scanning
job_artifacts_performance job_artifacts_browser_performance job_artifacts_load_performance job_artifacts_performance job_artifacts_browser_performance job_artifacts_load_performance
job_artifacts_lsif job_artifacts_terraform job_artifacts_cluster_applications job_artifacts_lsif job_artifacts_terraform job_artifacts_cluster_applications