Commit 79a14458 authored by Olena Horal-Koretska's avatar Olena Horal-Koretska

Merge branch '255603-add-http-multiple-mvc-3' into 'master'

Resolve "Add new HTTP endpoint"

See merge request gitlab-org/gitlab!46647
parents 92cdedd4 7470b22a
5783f980c3c83022dd5a0173186fba4158948062
89e94b4b16d9bac60bfa5efe4773c270a69ddf4e
import Vue from 'vue';
import DevopsAdoptionApp from './components/devops_adoption_app.vue';
export default () => {
const el = document.querySelector('.js-devops-adoption');
if (!el) return false;
const { emptyStateSvgPath } = el.dataset;
return new Vue({
el,
provide: {
emptyStateSvgPath,
},
render(h) {
return h(DevopsAdoptionApp);
},
});
};
// EE-specific feature. Find the implementation in the `ee/`-folder
export default () => {};
......@@ -12,11 +12,19 @@ import { getLocationHash } from '../lib/utils/url_utility';
$(() => {
function toggleContainer(container, toggleState) {
const $container = $(container);
$container
.find('.js-toggle-button .fa-chevron-up, .js-toggle-button .fa-chevron-down')
.toggleClass('fa-chevron-up', toggleState)
.toggleClass('fa-chevron-down', toggleState !== undefined ? !toggleState : undefined);
const isExpanded = $container.data('is-expanded');
const $collapseIcon = $container.find('.js-sidebar-collapse');
const $expandIcon = $container.find('.js-sidebar-expand');
if (isExpanded && !toggleState) {
$container.data('is-expanded', false);
$collapseIcon.addClass('hidden');
$expandIcon.removeClass('hidden');
} else {
$container.data('is-expanded', true);
$expandIcon.addClass('hidden');
$collapseIcon.removeClass('hidden');
}
$container.find('.js-toggle-content').toggle(toggleState);
}
......
......@@ -27,7 +27,7 @@ export default {
rolloutUserListLabel: s__('FeatureFlag|User List'),
rolloutUserListDescription: s__('FeatureFlag|Select a user list'),
rolloutUserListNoListError: s__('FeatureFlag|There are no configured user lists'),
defaultDropdownText: s__('FeatureFlags|Select a user list'),
defaultDropdownText: s__('FeatureFlags|No user list selected'),
},
computed: {
...mapGetters(['hasUserLists', 'isLoading', 'hasError', 'userListOptions']),
......@@ -36,7 +36,7 @@ export default {
return this.strategy?.userList?.id ?? '';
},
dropdownText() {
return this.strategy?.userList?.name ?? this.$options.defaultDropdownText;
return this.strategy?.userList?.name ?? this.$options.translations.defaultDropdownText;
},
},
mounted() {
......
......@@ -116,7 +116,7 @@ export default {
<gl-dropdown
v-if="displayFilters"
id="discussion-filter-dropdown"
class="gl-mr-3 full-width-mobile discussion-filter-container js-discussion-filter-container qa-discussion-filter"
class="gl-mr-3 full-width-mobile discussion-filter-container js-discussion-filter-container"
data-qa-selector="discussion_filter_dropdown"
:text="currentFilter.title"
>
......
......@@ -65,8 +65,8 @@ export default {
};
},
computed: {
toggleChevronClass() {
return this.expanded ? 'fa-chevron-up' : 'fa-chevron-down';
toggleChevronIconName() {
return this.expanded ? 'chevron-up' : 'chevron-down';
},
noteTimestampLink() {
return this.noteId ? `#note_${this.noteId}` : undefined;
......@@ -133,7 +133,7 @@ export default {
type="button"
@click="handleToggle"
>
<i ref="chevronIcon" :class="toggleChevronClass" class="fa" aria-hidden="true"></i>
<gl-icon ref="chevronIcon" :name="toggleChevronIconName" aria-hidden="true" />
{{ __('Toggle thread') }}
</button>
</div>
......
import initDevopAdoption from 'ee_else_ce/admin/dev_ops_report/devops_adoption';
import initDevOpsScoreEmptyState from '~/admin/dev_ops_report/devops_score_empty_state';
import initDevopAdoption from '~/admin/dev_ops_report/devops_adoption';
initDevOpsScoreEmptyState();
initDevopAdoption();
......@@ -109,10 +109,6 @@
content: '\f0da';
}
.fa-chevron-up::before {
content: '\f077';
}
.fa-exclamation-circle::before {
content: '\f06a';
}
......
......@@ -32,7 +32,7 @@ module FinderWithCrossProjectAccess
end
override :execute
def execute(*args)
def execute(*args, **kwargs)
check = Gitlab::CrossProjectAccess.find_check(self)
original = -> { super }
......
......@@ -4,17 +4,7 @@
.container
.gl-mt-3
- if Feature.enabled?(:devops_adoption)
%h2
= _('DevOps Report')
%ul.nav-links.nav-tabs.nav.js-devops-tabs{ role: 'tablist' }
= render 'tab', active: true, title: _('DevOps Score'), target: '#devops_score_pane'
= render 'tab', active: false, title: _('Adoption'), target: '#devops_adoption_pane'
.tab-content
.tab-pane.active#devops_score_pane
= render 'report'
.tab-pane#devops_adoption_pane
.js-devops-adoption{ data: { empty_state_svg_path: image_path('illustrations/monitoring/getting_started.svg') } }
= render_if_exists 'admin/dev_ops_report/devops_tabs'
- else
= render 'report'
......@@ -2,17 +2,15 @@
%li.note.note-discussion.timeline-entry.unstyled-comments
.timeline-entry-inner
.timeline-content
.discussion.js-toggle-container{ data: { discussion_id: discussion.id } }
.discussion.js-toggle-container{ data: { discussion_id: discussion.id, is_expanded: expanded.to_s } }
.discussion-header
.timeline-icon
= link_to user_path(discussion.author) do
= image_tag avatar_icon_for_user(discussion.author), class: "avatar s40"
.discussion-actions
%button.note-action-button.discussion-toggle-button.js-toggle-button{ type: "button", class: ("js-toggle-lazy-diff" unless expanded) }
- if expanded
= icon("chevron-up")
- else
= icon("chevron-down")
= sprite_icon('chevron-up', css_class: "js-sidebar-collapse #{'hidden' unless expanded}")
= sprite_icon('chevron-down', css_class: "js-sidebar-expand #{'hidden' if expanded}")
= _('Toggle thread')
= link_to_member(@project, discussion.author, avatar: false)
......
---
title: Add EC2 to AutoDevOps template
merge_request: 45651
author:
type: changed
---
title: Replace fa-chevron-up with GitLab SVG icon
merge_request: 46118
author:
type: changed
---
title: Remove all records from `security_findings` table
merge_request: 44312
author:
type: fixed
---
title: Fix compliance framework database migration on CE instances
merge_request: 46761
author:
type: fixed
---
title: Show "No user list selected" in feature flags
merge_request: 46790
author:
type: fixed
---
title: Add total projects imported usage ping
merge_request: 46541
author:
type: added
......@@ -52,8 +52,6 @@ class MigrateComplianceFrameworkEnumToDatabaseFrameworkRecord < ActiveRecord::Mi
end
def up
return unless Gitlab.ee?
TmpComplianceFramework.reset_column_information
TmpProjectSettings.reset_column_information
......
# frozen_string_literal: true
class TruncateSecurityFindingsTable < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
return unless Gitlab.dev_env_or_com?
with_lock_retries do
connection.execute('TRUNCATE security_findings RESTART IDENTITY')
end
end
def down
# no-op
end
end
55ffd18d5f55ee0fd51a31d50cf2d51595740c72ca23d5134d93e2da3fc186ff
\ No newline at end of file
......@@ -282,6 +282,32 @@ When running your project pipeline at this point:
on the related JSON object's content. The deployment job finishes whenever the deployment to EC2
is done or has failed.
#### Custom build job for Auto DevOps
To leverage [Auto DevOps](../../topics/autodevops/index.md) for your project when deploying to
AWS EC2, you must specify a job for the `build` stage.
To do so, you must reference the `Auto-DevOps.gitlab-ci.yml` template and include a job named
`build_artifact` in your `.gitlab-ci.yml` file. For example:
```yaml
# .gitlab-ci.yml
include:
- template: Auto-DevOps.gitlab-ci.yml
variables:
- AUTO_DEVOPS_PLATFORM_TARGET: EC2
build_artifact:
stage: build
script:
- <your build script goes here>
artifacts:
paths:
- <built artifact>
```
### Deploy to Amazon EKS
- [How to deploy your application to a GitLab-managed Amazon EKS cluster with Auto DevOps](https://about.gitlab.com/blog/2020/05/05/deploying-application-eks/)
......
......@@ -133,6 +133,7 @@ from:
- [Approval Rules](approval_rules.md)
- [Feature categorization](feature_categorization/index.md)
- [Wikis development guide](wikis.md)
- [Newlines style guide](newlines_styleguide.md)
## Performance guides
......
......@@ -530,7 +530,10 @@ To remove a group and its contents:
This action either:
- Removes the group, and also queues a background job to delete all projects in that group.
- Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium or Silver](https://about.gitlab.com/pricing/premium/) or higher tiers, marks a group for deletion. The deletion will happen 7 days later by default, but this can be changed in the [instance settings](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
- Since [GitLab 12.8](https://gitlab.com/gitlab-org/gitlab/-/issues/33257), on [Premium or Silver](https://about.gitlab.com/pricing/premium/) or higher tiers, this action adds a background job to mark a group for deletion. By default, the job schedules the deletion 7 days in the future. You can modify this waiting period through the [instance settings](../admin_area/settings/visibility_and_access_controls.md#default-deletion-delay).
Since [GitLab 13.6](https://gitlab.com/gitlab-org/gitlab/-/issues/39504), if the user who sets up the deletion leaves or is otherwise removed from the group before the
actual deletion happens, the job is cancelled, and the group is no longer scheduled for deletion.
### Restore a group **(PREMIUM)**
......
import Vue from 'vue';
import DevopsAdoptionApp from './components/devops_adoption_app.vue';
export default () => {
const el = document.querySelector('.js-devops-adoption');
if (!el) return false;
const { emptyStateSvgPath } = el.dataset;
return new Vue({
el,
provide: {
emptyStateSvgPath,
},
render(h) {
return h(DevopsAdoptionApp);
},
});
};
......@@ -13,6 +13,7 @@ module EE
end
cleanup_group_identity(member)
cleanup_group_deletion_schedule(member) if member.source&.is_a?(Group)
end
private
......@@ -40,6 +41,14 @@ module EE
saml_provider.identities.for_user(member.user).delete_all
end
def cleanup_group_deletion_schedule(member)
deletion_schedule = member.source&.deletion_schedule
return unless deletion_schedule
deletion_schedule.destroy if deletion_schedule.deleting_user == member.user
end
end
end
end
......@@ -19,6 +19,8 @@ module Security
end
def execute
return security_scan unless Feature.enabled?(:store_security_findings, project)
StoreFindingsMetadataService.execute(security_scan, security_report)
deduplicate_findings? ? update_deduplicated_findings : register_finding_keys
......
%h2
= _('DevOps Report')
%ul.nav-links.nav-tabs.nav.js-devops-tabs{ role: 'tablist' }
= render 'tab', active: true, title: _('DevOps Score'), target: '#devops_score_pane'
= render 'tab', active: false, title: _('Adoption'), target: '#devops_adoption_pane'
.tab-content
.tab-pane.active#devops_score_pane
= render_ce 'admin/dev_ops_report/report'
.tab-pane#devops_adoption_pane
.js-devops-adoption{ data: { empty_state_svg_path: image_path('illustrations/monitoring/getting_started.svg') } }
......@@ -17,10 +17,10 @@
= f.hidden_field :data, value: license_key
%a#hide-license.hide-license{ href: '#hide-license' }
Show license key
= icon('chevron-down')
= sprite_icon('chevron-down')
%a#show-license.show-license{ href: '#show-license' }
Hide license key
= icon('chevron-up')
= sprite_icon('chevron-up')
.card.trial-license-preview.gl-mt-5
= license_key
.modal-footer.form-actions
......
......@@ -15,7 +15,8 @@
= s_('Promotions|This feature is locked.')
%a.btn-link.js-toggle-button.js-weight-sidebar-callout{ href: '#', data: { track_event: 'click_callout' }.merge(tracking_options) }
= s_('Promotions|Learn more')
= icon('chevron-down')
= sprite_icon('chevron-up', css_class: 'js-sidebar-collapse hidden')
= sprite_icon('chevron-down', css_class: 'js-sidebar-expand')
.js-toggle-content{ style:'display: none' }
%div
%h4
......
---
title: Unschedule group deletion on deleting member removal
merge_request: 45715
author:
type: changed
---
name: store_security_findings
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44312
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/276011
milestone: '13.6'
type: development
group: group::threat insights
default_enabled: false
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'DevOps Report page', :js do
tabs_selector = '.js-devops-tabs'
tab_item_selector = '.js-devops-tab-item'
active_tab_selector = '.nav-link.active'
before do
sign_in(create(:admin))
end
context 'with devops_adoption feature flag disabled' do
before do
stub_feature_flags(devops_adoption: false)
end
it 'does not show the tabbed layout' do
visit admin_dev_ops_report_path
expect(page).not_to have_selector tabs_selector
end
end
context 'with devops_adoption feature flag enabled' do
it 'shows the tabbed layout' do
visit admin_dev_ops_report_path
expect(page).to have_selector tabs_selector
end
it 'shows the correct tabs' do
visit admin_dev_ops_report_path
within tabs_selector do
expect(page.all(:css, tab_item_selector).length).to be(2)
expect(page).to have_text 'DevOps Score Adoption'
end
end
it 'defaults to the DevOps Score tab' do
visit admin_dev_ops_report_path
within tabs_selector do
expect(page).to have_selector active_tab_selector, text: 'DevOps Score'
end
end
it 'displays the Adoption tab content when selected' do
visit admin_dev_ops_report_path
click_link 'Adoption'
within tabs_selector do
expect(page).to have_selector active_tab_selector, text: 'Adoption'
end
end
context 'the devops score tab' do
it 'has dismissable intro callout' do
visit admin_dev_ops_report_path
expect(page).to have_content 'Introducing Your DevOps Report'
find('.js-close-callout').click
expect(page).not_to have_content 'Introducing Your DevOps Report'
end
context 'when usage ping is disabled' do
before do
stub_application_setting(usage_ping_enabled: false)
end
it 'shows empty state' do
visit admin_dev_ops_report_path
expect(page).to have_selector(".js-empty-state")
end
it 'hides the intro callout' do
visit admin_dev_ops_report_path
expect(page).not_to have_content 'Introducing Your DevOps Report'
end
end
context 'when there is no data to display' do
it 'shows empty state' do
stub_application_setting(usage_ping_enabled: true)
visit admin_dev_ops_report_path
expect(page).to have_content('Data is still calculating')
end
end
context 'when there is data to display' do
it 'shows numbers for each metric' do
stub_application_setting(usage_ping_enabled: true)
create(:dev_ops_report_metric)
visit admin_dev_ops_report_path
expect(page).to have_content(
'Issues created per active user 1.2 You 9.3 Lead 13.3%'
)
end
end
end
end
end
import { shallowMount } from '@vue/test-utils';
import DevopsAdoptionApp from '~/admin/dev_ops_report/components/devops_adoption_app.vue';
import DevopsAdoptionEmptyState from '~/admin/dev_ops_report/components/devops_adoption_empty_state.vue';
import DevopsAdoptionApp from 'ee/admin/dev_ops_report/components/devops_adoption_app.vue';
import DevopsAdoptionEmptyState from 'ee/admin/dev_ops_report/components/devops_adoption_empty_state.vue';
describe('DevopsAdoptionApp', () => {
let wrapper;
......
import { shallowMount } from '@vue/test-utils';
import { GlEmptyState, GlButton } from '@gitlab/ui';
import DevopsAdoptionEmptyState from '~/admin/dev_ops_report/components/devops_adoption_empty_state.vue';
import { DEVOPS_ADOPTION_STRINGS } from '~/admin/dev_ops_report/constants';
import DevopsAdoptionEmptyState from 'ee/admin/dev_ops_report/components/devops_adoption_empty_state.vue';
import { DEVOPS_ADOPTION_STRINGS } from 'ee/admin/dev_ops_report/constants';
const emptyStateSvgPath = 'illustrations/monitoring/getting_started.svg';
......
......@@ -57,6 +57,30 @@ RSpec.describe Members::DestroyService do
expect(details[:reason]).to be_nil
end
end
context 'group deletion schedule' do
context 'when member user has a scheduled deletion for the group' do
let!(:group_deletion_schedule) { create(:group_deletion_schedule, group: group, user_id: member_user.id, marked_for_deletion_on: 2.days.ago) }
it 'deletes the group deletion schedule' do
expect(group.reload.deletion_schedule).to eq(group_deletion_schedule)
subject.execute(member)
expect(group.reload.deletion_schedule).to be nil
end
end
context 'when scheduled deletion for the group belongs to different user' do
let!(:group_deletion_schedule) { create(:group_deletion_schedule, group: group, user_id: current_user.id, marked_for_deletion_on: 2.days.ago) }
it 'does not delete the group deletion schedule' do
subject.execute(member)
expect(group.reload.deletion_schedule).to eq(group_deletion_schedule)
end
end
end
end
context 'when current user is not present' do # ie, when the system initiates the destroy
......
......@@ -41,89 +41,121 @@ RSpec.describe Security::StoreScanService do
known_keys.add(finding_key)
end
it 'calls the `Security::StoreFindingsMetadataService` to store findings' do
store_scan
context 'when the `store_security_findings` feature is not enabled' do
before do
stub_feature_flags(store_security_findings: false)
end
expect(Security::StoreFindingsMetadataService).to have_received(:execute)
end
it 'does not call the `Security::StoreFindingsMetadataService`' do
store_scan
context 'when the security scan already exists for the artifact' do
let_it_be(:security_scan) { create(:security_scan, build: artifact.job, scan_type: :sast) }
let_it_be(:unique_security_finding) do
create(:security_finding,
scan: security_scan,
position: 0)
expect(Security::StoreFindingsMetadataService).not_to have_received(:execute)
end
let_it_be(:duplicated_security_finding) do
create(:security_finding,
scan: security_scan,
position: 5)
end
context 'when the security scan already exists for the artifact' do
let_it_be(:security_scan) { create(:security_scan, build: artifact.job, scan_type: :sast) }
it 'does not create a new security scan' do
expect { store_scan }.not_to change { artifact.job.security_scans.count }
it 'does not create a new security scan' do
expect { store_scan }.not_to change { artifact.job.security_scans.count }
end
end
context 'when the `deduplicate` param is set as false' do
it 'does not change the deduplicated flag of duplicated finding' do
expect { store_scan }.not_to change { duplicated_security_finding.reload.deduplicated }.from(false)
context 'when the security scan does not exist for the artifact' do
it 'creates a new security scan' do
expect { store_scan }.to change { artifact.job.security_scans.sast.count }.by(1)
end
end
end
it 'does not change the deduplicated flag of unique finding' do
expect { store_scan }.not_to change { unique_security_finding.reload.deduplicated }.from(false)
end
context 'when the `store_security_findings` feature is enabled' do
before do
stub_feature_flags(store_security_findings: true)
end
context 'when the `deduplicate` param is set as true' do
let(:deduplicate) { true }
it 'calls the `Security::StoreFindingsMetadataService` to store findings' do
store_scan
expect(Security::StoreFindingsMetadataService).to have_received(:execute)
end
it 'does not change the deduplicated flag of duplicated finding false' do
expect { store_scan }.not_to change { duplicated_security_finding.reload.deduplicated }.from(false)
context 'when the security scan already exists for the artifact' do
let_it_be(:security_scan) { create(:security_scan, build: artifact.job, scan_type: :sast) }
let_it_be(:unique_security_finding) do
create(:security_finding,
scan: security_scan,
position: 0)
end
it 'sets the deduplicated flag of unique finding as true' do
expect { store_scan }.to change { unique_security_finding.reload.deduplicated }.to(true)
let_it_be(:duplicated_security_finding) do
create(:security_finding,
scan: security_scan,
position: 5)
end
end
end
context 'when the security scan does not exist for the artifact' do
let(:unique_finding_attribute) do
-> { Security::Finding.by_position(0).first&.deduplicated }
end
it 'does not create a new security scan' do
expect { store_scan }.not_to change { artifact.job.security_scans.count }
end
let(:duplicated_finding_attribute) do
-> { Security::Finding.by_position(5).first&.deduplicated }
end
context 'when the `deduplicate` param is set as false' do
it 'does not change the deduplicated flag of duplicated finding' do
expect { store_scan }.not_to change { duplicated_security_finding.reload.deduplicated }.from(false)
end
before do
allow(Security::StoreFindingsMetadataService).to receive(:execute).and_call_original
end
it 'does not change the deduplicated flag of unique finding' do
expect { store_scan }.not_to change { unique_security_finding.reload.deduplicated }.from(false)
end
end
it 'creates a new security scan' do
expect { store_scan }.to change { artifact.job.security_scans.sast.count }.by(1)
context 'when the `deduplicate` param is set as true' do
let(:deduplicate) { true }
it 'does not change the deduplicated flag of duplicated finding false' do
expect { store_scan }.not_to change { duplicated_security_finding.reload.deduplicated }.from(false)
end
it 'sets the deduplicated flag of unique finding as true' do
expect { store_scan }.to change { unique_security_finding.reload.deduplicated }.to(true)
end
end
end
context 'when the `deduplicate` param is set as false' do
it 'sets the deduplicated flag of duplicated finding as false' do
expect { store_scan }.to change { duplicated_finding_attribute.call }.to(false)
context 'when the security scan does not exist for the artifact' do
let(:unique_finding_attribute) do
-> { Security::Finding.by_position(0).first&.deduplicated }
end
it 'sets the deduplicated flag of unique finding as true' do
expect { store_scan }.to change { unique_finding_attribute.call }.to(true)
let(:duplicated_finding_attribute) do
-> { Security::Finding.by_position(5).first&.deduplicated }
end
end
context 'when the `deduplicate` param is set as true' do
let(:deduplicate) { true }
before do
allow(Security::StoreFindingsMetadataService).to receive(:execute).and_call_original
end
it 'sets the deduplicated flag of duplicated finding false' do
expect { store_scan }.to change { duplicated_finding_attribute.call }.to(false)
it 'creates a new security scan' do
expect { store_scan }.to change { artifact.job.security_scans.sast.count }.by(1)
end
it 'sets the deduplicated flag of unique finding as true' do
expect { store_scan }.to change { unique_finding_attribute.call }.to(true)
context 'when the `deduplicate` param is set as false' do
it 'sets the deduplicated flag of duplicated finding as false' do
expect { store_scan }.to change { duplicated_finding_attribute.call }.to(false)
end
it 'sets the deduplicated flag of unique finding as true' do
expect { store_scan }.to change { unique_finding_attribute.call }.to(true)
end
end
context 'when the `deduplicate` param is set as true' do
let(:deduplicate) { true }
it 'sets the deduplicated flag of duplicated finding false' do
expect { store_scan }.to change { duplicated_finding_attribute.call }.to(false)
end
it 'sets the deduplicated flag of unique finding as true' do
expect { store_scan }.to change { unique_finding_attribute.call }.to(true)
end
end
end
end
......
......@@ -163,6 +163,7 @@ include:
- template: Jobs/Code-Intelligence.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Code-Intelligence.gitlab-ci.yml
- template: Jobs/Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
- template: Jobs/Deploy/ECS.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy/ECS.gitlab-ci.yml
- template: Jobs/Deploy/EC2.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Deploy/EC2.gitlab-ci.yml
- template: Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/DAST-Default-Branch-Deploy.gitlab-ci.yml
- template: Jobs/Browser-Performance-Testing.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Jobs/Browser-Performance-Testing.gitlab-ci.yml
- template: Security/DAST.gitlab-ci.yml # https://gitlab.com/gitlab-org/gitlab/blob/master/lib/gitlab/ci/templates/Security/DAST.gitlab-ci.yml
......
......@@ -16,4 +16,14 @@ build:
fi
- /build/build.sh
rules:
- if: '$AUTO_DEVOPS_PLATFORM_TARGET == "EC2"'
when: never
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
build_artifact:
stage: build
script:
- printf "To build your project, please create a build_artifact job into your .gitlab-ci.yml file.\nMore information at https://docs.gitlab.com/ee/ci/cloud_deployment\n"
- exit 1
rules:
- if: '$AUTO_DEVOPS_PLATFORM_TARGET == "EC2"'
......@@ -589,6 +589,7 @@ module Gitlab
gitlab: distinct_count(::BulkImport.where(time_period, source_type: :gitlab), :user_id)
},
projects_imported: {
total: count(Project.where(time_period).where.not(import_type: nil)),
gitlab_project: projects_imported_count('gitlab_project', time_period),
gitlab: projects_imported_count('gitlab', time_period),
github: projects_imported_count('github', time_period),
......
......@@ -11497,6 +11497,9 @@ msgstr ""
msgid "FeatureFlags|New user list"
msgstr ""
msgid "FeatureFlags|No user list selected"
msgstr ""
msgid "FeatureFlags|Percent of users"
msgstr ""
......@@ -11521,9 +11524,6 @@ msgstr ""
msgid "FeatureFlags|Rollout Strategy"
msgstr ""
msgid "FeatureFlags|Select a user list"
msgstr ""
msgid "FeatureFlags|Set the Unleash client application name to the name of the environment your application runs in. This value is used to match environment scopes. See the %{linkStart}example client configuration%{linkEnd}."
msgstr ""
......
......@@ -7,6 +7,7 @@ module QA
module Epic
class Show < QA::Page::Base
include QA::Page::Component::Issuable::Common
include QA::Page::Component::Note
view 'ee/app/assets/javascripts/epic/components/epic_header.vue' do
element :close_reopen_epic_button
......@@ -41,11 +42,6 @@ module QA
click_element :add_issue_button
end
def add_comment_to_epic(comment)
fill_element :comment_field, comment
click_element :comment_button
end
def remove_issue_from_epic
click_element :remove_issue_button
# Capybara code is used below due to the modal being defined in the @gitlab/ui project
......
......@@ -73,7 +73,7 @@ module QA
def has_no_assignee_named?(username)
within_element(:assignee_block) do
has_no_text?(username)
has_no_text?(username, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
end
......
......@@ -13,20 +13,35 @@ module QA
element :toggle_comments_button
end
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :comment_button
element :comment_field
element :discussion_menu_item
element :note_dropdown
end
base.view 'app/assets/javascripts/notes/components/discussion_actions.vue' do
element :discussion_reply_tab
element :resolve_discussion_button
end
base.view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :note_dropdown
element :discussion_menu_item
base.view 'app/assets/javascripts/notes/components/discussion_filter.vue' do
element :discussion_filter_dropdown, required: true
element :filter_menu_item
end
base.view 'app/assets/javascripts/notes/components/discussion_filter_note.vue' do
element :discussion_filter_container
end
base.view 'app/assets/javascripts/notes/components/noteable_discussion.vue' do
element :discussion_content
end
base.view 'app/assets/javascripts/notes/components/noteable_note.vue' do
element :noteable_note_container
end
base.view 'app/assets/javascripts/notes/components/note_actions.vue' do
element :note_edit_button
end
......@@ -36,6 +51,10 @@ module QA
element :reply_comment_button
end
base.view 'app/assets/javascripts/notes/components/note_header.vue' do
element :system_note_content
end
base.view 'app/assets/javascripts/notes/components/toggle_replies_widget.vue' do
element :expand_replies_button
element :collapse_replies_button
......@@ -44,12 +63,30 @@ module QA
base.view 'app/assets/javascripts/vue_shared/components/notes/skeleton_note.vue' do
element :skeleton_note_placeholder
end
base.view 'app/views/shared/notes/_form.html.haml' do
element :new_note_form, 'new-note' # rubocop:disable QA/ElementWithPattern
element :new_note_form, 'attr: :note' # rubocop:disable QA/ElementWithPattern
end
end
def collapse_replies
click_element :collapse_replies_button
end
# Attachment option should be an absolute path
def comment(text, attachment: nil, filter: :all_activities)
method("select_#{filter}_filter").call
fill_element :comment_field, "#{text}\n"
unless attachment.nil?
QA::Page::Component::Dropzone.new(self, '.new-note')
.attach_file(attachment)
end
click_element :comment_button
end
def edit_comment(text)
click_element :note_edit_button
fill_element :reply_field, text
......@@ -60,6 +97,18 @@ module QA
click_element :expand_replies_button
end
def has_comment?(comment_text)
has_element?(:noteable_note_container, text: comment_text, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
def has_system_note?(note_text)
has_element?(:system_note_content, text: note_text, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
def noteable_note_item
find_element(:noteable_note_container)
end
def reply_to_discussion(position, reply_text)
type_reply_to_discussion(position, reply_text)
click_element :reply_comment_button
......@@ -71,6 +120,26 @@ module QA
end
end
def select_all_activities_filter
select_filter_with_text('Show all activity')
end
def select_comments_only_filter
select_filter_with_text('Show comments only')
wait_until do
has_no_element?(:system_note_content)
end
end
def select_history_only_filter
select_filter_with_text('Show history only')
wait_until do
has_element?(:discussion_filter_container) && has_no_element?(:noteable_note_container)
end
end
def start_discussion(text)
fill_element :comment_field, text
click_element :note_dropdown
......@@ -90,6 +159,18 @@ module QA
def wait_for_loading
has_no_element?(:skeleton_note_placeholer)
end
private
def select_filter_with_text(text)
retry_on_exception do
click_element(:title)
click_element :discussion_filter_dropdown
find_element(:filter_menu_item, text: text).click
wait_for_loading
end
end
end
end
end
......
......@@ -10,28 +10,6 @@ module QA
include Page::Component::DesignManagement
include Page::Component::Issuable::Sidebar
view 'app/assets/javascripts/notes/components/comment_form.vue' do
element :comment_button
element :comment_field
end
view 'app/assets/javascripts/notes/components/discussion_filter.vue' do
element :discussion_filter_dropdown, required: true
element :filter_menu_item
end
view 'app/assets/javascripts/notes/components/discussion_filter_note.vue' do
element :discussion_filter_container
end
view 'app/assets/javascripts/notes/components/noteable_note.vue' do
element :noteable_note_container
end
view 'app/assets/javascripts/notes/components/note_header.vue' do
element :system_note_content
end
view 'app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue' do
element :remove_related_issue_button
end
......@@ -41,11 +19,6 @@ module QA
element :reopen_issue_button
end
view 'app/views/shared/notes/_form.html.haml' do
element :new_note_form, 'new-note' # rubocop:disable QA/ElementWithPattern
element :new_note_form, 'attr: :note' # rubocop:disable QA/ElementWithPattern
end
view 'app/assets/javascripts/related_issues/components/add_issuable_form.vue' do
element :add_issue_button
end
......@@ -88,67 +61,9 @@ module QA
click_element :close_issue_button
end
# Adds a comment to an issue
# attachment option should be an absolute path
def comment(text, attachment: nil, filter: :all_activities)
method("select_#{filter}_filter").call
fill_element :comment_field, "#{text}\n"
unless attachment.nil?
QA::Page::Component::Dropzone.new(self, '.new-note')
.attach_file(attachment)
end
click_element :comment_button
end
def has_comment?(comment_text)
has_element?(:noteable_note_container, text: comment_text, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
def has_system_note?(note_text)
has_element?(:system_note_content, text: note_text, wait: QA::Support::Repeater::DEFAULT_MAX_WAIT_TIME)
end
def noteable_note_item
find_element(:noteable_note_container)
end
def select_all_activities_filter
select_filter_with_text('Show all activity')
end
def select_comments_only_filter
select_filter_with_text('Show comments only')
wait_until do
has_no_element?(:system_note_content)
end
end
def select_history_only_filter
select_filter_with_text('Show history only')
wait_until do
has_element?(:discussion_filter_container) && has_no_element?(:noteable_note_container)
end
end
def has_metrics_unfurled?
has_element?(:prometheus_graph_widgets, wait: 30)
end
private
def select_filter_with_text(text)
retry_on_exception do
click_element(:title)
click_element :discussion_filter_dropdown
find_element(:filter_menu_item, text: text).click
wait_for_loading
end
end
end
end
end
......
......@@ -26,7 +26,7 @@ module QA
expect(show).not_to have_content(my_first_reply)
show.expand_replies
expect(show).to have_content(my_first_reply)
expect(show).to have_comment(my_first_reply)
expect(show).not_to have_content(one_reply)
end
end
......
......@@ -16,11 +16,11 @@ module QA
show.comment(first_version_of_comment)
expect(show).to have_content(first_version_of_comment)
expect(show).to have_comment(first_version_of_comment)
show.edit_comment(second_version_of_comment)
expect(show).to have_content(second_version_of_comment)
expect(show).to have_comment(second_version_of_comment)
expect(show).not_to have_content(first_version_of_comment)
end
end
......
......@@ -51,20 +51,22 @@ module QA
it 'comments on epic', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/525' do
comment = 'My Epic Comment'
EE::Page::Group::Epic::Show.perform do |show|
show.add_comment_to_epic(comment)
end
show.comment(comment)
expect(page).to have_content(comment)
expect(show).to have_comment(comment)
end
end
it 'closes and reopens an epic', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/524' do
EE::Page::Group::Epic::Show.perform(&:close_reopen_epic)
EE::Page::Group::Epic::Show.perform do |show|
show.close_reopen_epic
expect(page).to have_content('Closed')
expect(show).to have_system_note('closed')
EE::Page::Group::Epic::Show.perform(&:close_reopen_epic)
show.close_reopen_epic
expect(page).to have_content('Open')
expect(show).to have_system_note('opened')
end
end
end
......@@ -79,8 +81,10 @@ module QA
epic.visit!
expect(page).to have_content('added issue')
expect(page).to have_content('removed issue')
EE::Page::Group::Epic::Show.perform do |show|
expect(show).to have_system_note('added issue')
expect(show).to have_system_note('removed issue')
end
end
def create_issue_resource
......
......@@ -32,8 +32,8 @@ module QA
show.start_review
show.submit_pending_reviews
expect(show).to have_content("I'm starting a new discussion")
expect(show).to have_content("Could you please check this?")
expect(show).to have_comment("I'm starting a new discussion")
expect(show).to have_comment("Could you please check this?")
expect(show).to have_content("1 unresolved thread")
end
end
......@@ -72,7 +72,7 @@ module QA
show.click_discussions_tab
show.resolve_discussion_at_index(0)
expect(show).to have_content("Can you check this line of code?")
expect(show).to have_comment("Can you check this line of code?")
expect(show).to have_content("All threads resolved")
end
end
......
......@@ -3,10 +3,6 @@
require 'spec_helper'
RSpec.describe 'DevOps Report page', :js do
tabs_selector = '.js-devops-tabs'
tab_item_selector = '.js-devops-tab-item'
active_tab_selector = '.nav-link.active'
before do
sign_in(create(:admin))
end
......@@ -16,12 +12,6 @@ RSpec.describe 'DevOps Report page', :js do
stub_feature_flags(devops_adoption: false)
end
it 'does not show the tabbed layout' do
visit admin_dev_ops_report_path
expect(page).not_to have_selector tabs_selector
end
it 'has dismissable intro callout' do
visit admin_dev_ops_report_path
......@@ -73,92 +63,4 @@ RSpec.describe 'DevOps Report page', :js do
end
end
end
context 'with devops_adoption feature flag enabled' do
it 'shows the tabbed layout' do
visit admin_dev_ops_report_path
expect(page).to have_selector tabs_selector
end
it 'shows the correct tabs' do
visit admin_dev_ops_report_path
within tabs_selector do
expect(page.all(:css, tab_item_selector).length).to be(2)
expect(page).to have_text 'DevOps Score Adoption'
end
end
it 'defaults to the DevOps Score tab' do
visit admin_dev_ops_report_path
within tabs_selector do
expect(page).to have_selector active_tab_selector, text: 'DevOps Score'
end
end
it 'displays the Adoption tab content when selected' do
visit admin_dev_ops_report_path
click_link 'Adoption'
within tabs_selector do
expect(page).to have_selector active_tab_selector, text: 'Adoption'
end
end
context 'the devops score tab' do
it 'has dismissable intro callout' do
visit admin_dev_ops_report_path
expect(page).to have_content 'Introducing Your DevOps Report'
find('.js-close-callout').click
expect(page).not_to have_content 'Introducing Your DevOps Report'
end
context 'when usage ping is disabled' do
before do
stub_application_setting(usage_ping_enabled: false)
end
it 'shows empty state' do
visit admin_dev_ops_report_path
expect(page).to have_selector(".js-empty-state")
end
it 'hides the intro callout' do
visit admin_dev_ops_report_path
expect(page).not_to have_content 'Introducing Your DevOps Report'
end
end
context 'when there is no data to display' do
it 'shows empty state' do
stub_application_setting(usage_ping_enabled: true)
visit admin_dev_ops_report_path
expect(page).to have_content('Data is still calculating')
end
end
context 'when there is data to display' do
it 'shows numbers for each metric' do
stub_application_setting(usage_ping_enabled: true)
create(:dev_ops_report_metric)
visit admin_dev_ops_report_path
expect(page).to have_content(
'Issues created per active user 1.2 You 9.3 Lead 13.3%'
)
end
end
end
end
end
......@@ -25,6 +25,8 @@ describe('~/feature_flags/components/strategies/gitlab_user_list.vue', () => {
propsData: { ...DEFAULT_PROPS, ...props },
});
const findDropdown = () => wrapper.find(GlDropdown);
describe('with user lists', () => {
const findDropdownItem = () => wrapper.find(GlDropdownItem);
......@@ -34,7 +36,7 @@ describe('~/feature_flags/components/strategies/gitlab_user_list.vue', () => {
});
it('should show the input for userListId with the correct value', () => {
const dropdownWrapper = wrapper.find(GlDropdown);
const dropdownWrapper = findDropdown();
expect(dropdownWrapper.exists()).toBe(true);
expect(dropdownWrapper.props('text')).toBe(userList.name);
});
......@@ -87,11 +89,15 @@ describe('~/feature_flags/components/strategies/gitlab_user_list.vue', () => {
describe('without user lists', () => {
beforeEach(() => {
Api.searchFeatureFlagUserLists.mockResolvedValue({ data: [] });
wrapper = factory();
wrapper = factory({ strategy: { ...userListStrategy, userList: null } });
});
it('should display a message that there are no user lists', () => {
expect(wrapper.text()).toContain('There are no configured user lists');
});
it('should dispaly a message that no list has been selected', () => {
expect(findDropdown().text()).toContain('No user list selected');
});
});
});
......@@ -78,7 +78,7 @@ describe('NoteHeader component', () => {
expanded: true,
});
expect(findChevronIcon().classes()).toContain('fa-chevron-up');
expect(findChevronIcon().props('name')).toBe('chevron-up');
});
it('has chevron-down icon if expanded prop is false', () => {
......@@ -87,7 +87,7 @@ describe('NoteHeader component', () => {
expanded: false,
});
expect(findChevronIcon().classes()).toContain('fa-chevron-down');
expect(findChevronIcon().props('name')).toBe('chevron-down');
});
});
......
......@@ -122,6 +122,15 @@ RSpec.describe 'Auto-DevOps.gitlab-ci.yml' do
end
end
end
context 'when the platform target is EC2' do
let(:platform_value) { 'EC2' }
it 'contains the build_artifact job, not the build job' do
expect(build_names).to include('build_artifact')
expect(build_names).not_to include('build')
end
end
end
context 'when the project has no active cluster' do
......
......@@ -221,6 +221,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
gitlab: 2
},
projects_imported: {
total: 20,
gitlab_project: 2,
gitlab: 2,
github: 2,
......@@ -244,6 +245,7 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
gitlab: 1
},
projects_imported: {
total: 10,
gitlab_project: 1,
gitlab: 1,
github: 1,
......
......@@ -30,41 +30,23 @@ RSpec.describe MigrateComplianceFrameworkEnumToDatabaseFrameworkRecord, schema:
subject { described_class.new.up }
context 'when Gitlab.ee? is true' do
before do
expect(Gitlab).to receive(:ee?).and_return(true)
end
it 'updates the project settings' do
subject
it 'updates the project settings' do
subject
gdpr_framework = compliance_management_frameworks.find_by(namespace_id: root_group.id, name: 'GDPR')
expect(project_on_root_level_compliance_setting.reload.framework_id).to eq(gdpr_framework.id)
expect(project_on_sub_sub_level_compliance_setting_2.reload.framework_id).to eq(gdpr_framework.id)
gdpr_framework = compliance_management_frameworks.find_by(namespace_id: root_group.id, name: 'GDPR')
expect(project_on_root_level_compliance_setting.reload.framework_id).to eq(gdpr_framework.id)
expect(project_on_sub_sub_level_compliance_setting_2.reload.framework_id).to eq(gdpr_framework.id)
sox_framework = compliance_management_frameworks.find_by(namespace_id: root_group.id, name: 'SOX')
expect(project_on_sub_sub_level_compliance_setting_1.reload.framework_id).to eq(sox_framework.id)
sox_framework = compliance_management_frameworks.find_by(namespace_id: root_group.id, name: 'SOX')
expect(project_on_sub_sub_level_compliance_setting_1.reload.framework_id).to eq(sox_framework.id)
gdpr_framework = compliance_management_frameworks.find_by(namespace_id: namespace.id, name: 'GDPR')
expect(project_on_namespace_level_compliance_setting.reload.framework_id).to eq(gdpr_framework.id)
end
it 'adds two framework records' do
subject
expect(compliance_management_frameworks.count).to eq(3)
end
gdpr_framework = compliance_management_frameworks.find_by(namespace_id: namespace.id, name: 'GDPR')
expect(project_on_namespace_level_compliance_setting.reload.framework_id).to eq(gdpr_framework.id)
end
context 'when Gitlab.ee? is false' do
before do
expect(Gitlab).to receive(:ee?).and_return(false)
end
it 'does nothing' do
subject
it 'adds two framework records' do
subject
expect(compliance_management_frameworks.count).to eq(0)
end
expect(compliance_management_frameworks.count).to eq(3)
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment