Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-06-17 00:16:40 +00:00
parent a2dbe2a8d8
commit 35c9eaced5
24 changed files with 472 additions and 337 deletions

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 304 182" style="enable-background:new 0 0 304 182;" xml:space="preserve">
<style type="text/css">
.st0{fill:#252F3E;}
.st1{fill-rule:evenodd;clip-rule:evenodd;fill:#FF9900;}
</style>
<g>
<path class="st0" d="M86.4,66.4c0,3.7,0.4,6.7,1.1,8.9c0.8,2.2,1.8,4.6,3.2,7.2c0.5,0.8,0.7,1.6,0.7,2.3c0,1-0.6,2-1.9,3l-6.3,4.2
c-0.9,0.6-1.8,0.9-2.6,0.9c-1,0-2-0.5-3-1.4C76.2,90,75,88.4,74,86.8c-1-1.7-2-3.6-3.1-5.9c-7.8,9.2-17.6,13.8-29.4,13.8
c-8.4,0-15.1-2.4-20-7.2c-4.9-4.8-7.4-11.2-7.4-19.2c0-8.5,3-15.4,9.1-20.6c6.1-5.2,14.2-7.8,24.5-7.8c3.4,0,6.9,0.3,10.6,0.8
c3.7,0.5,7.5,1.3,11.5,2.2v-7.3c0-7.6-1.6-12.9-4.7-16c-3.2-3.1-8.6-4.6-16.3-4.6c-3.5,0-7.1,0.4-10.8,1.3c-3.7,0.9-7.3,2-10.8,3.4
c-1.6,0.7-2.8,1.1-3.5,1.3c-0.7,0.2-1.2,0.3-1.6,0.3c-1.4,0-2.1-1-2.1-3.1v-4.9c0-1.6,0.2-2.8,0.7-3.5c0.5-0.7,1.4-1.4,2.8-2.1
c3.5-1.8,7.7-3.3,12.6-4.5c4.9-1.3,10.1-1.9,15.6-1.9c11.9,0,20.6,2.7,26.2,8.1c5.5,5.4,8.3,13.6,8.3,24.6V66.4z M45.8,81.6
c3.3,0,6.7-0.6,10.3-1.8c3.6-1.2,6.8-3.4,9.5-6.4c1.6-1.9,2.8-4,3.4-6.4c0.6-2.4,1-5.3,1-8.7v-4.2c-2.9-0.7-6-1.3-9.2-1.7
c-3.2-0.4-6.3-0.6-9.4-0.6c-6.7,0-11.6,1.3-14.9,4c-3.3,2.7-4.9,6.5-4.9,11.5c0,4.7,1.2,8.2,3.7,10.6
C37.7,80.4,41.2,81.6,45.8,81.6z M126.1,92.4c-1.8,0-3-0.3-3.8-1c-0.8-0.6-1.5-2-2.1-3.9L96.7,10.2c-0.6-2-0.9-3.3-0.9-4
c0-1.6,0.8-2.5,2.4-2.5h9.8c1.9,0,3.2,0.3,3.9,1c0.8,0.6,1.4,2,2,3.9l16.8,66.2l15.6-66.2c0.5-2,1.1-3.3,1.9-3.9c0.8-0.6,2.2-1,4-1
h8c1.9,0,3.2,0.3,4,1c0.8,0.6,1.5,2,1.9,3.9l15.8,67l17.3-67c0.6-2,1.3-3.3,2-3.9c0.8-0.6,2.1-1,3.9-1h9.3c1.6,0,2.5,0.8,2.5,2.5
c0,0.5-0.1,1-0.2,1.6c-0.1,0.6-0.3,1.4-0.7,2.5l-24.1,77.3c-0.6,2-1.3,3.3-2.1,3.9c-0.8,0.6-2.1,1-3.8,1h-8.6c-1.9,0-3.2-0.3-4-1
c-0.8-0.7-1.5-2-1.9-4L156,23l-15.4,64.4c-0.5,2-1.1,3.3-1.9,4c-0.8,0.7-2.2,1-4,1H126.1z M254.6,95.1c-5.2,0-10.4-0.6-15.4-1.8
c-5-1.2-8.9-2.5-11.5-4c-1.6-0.9-2.7-1.9-3.1-2.8c-0.4-0.9-0.6-1.9-0.6-2.8v-5.1c0-2.1,0.8-3.1,2.3-3.1c0.6,0,1.2,0.1,1.8,0.3
c0.6,0.2,1.5,0.6,2.5,1c3.4,1.5,7.1,2.7,11,3.5c4,0.8,7.9,1.2,11.9,1.2c6.3,0,11.2-1.1,14.6-3.3c3.4-2.2,5.2-5.4,5.2-9.5
c0-2.8-0.9-5.1-2.7-7c-1.8-1.9-5.2-3.6-10.1-5.2L246,52c-7.3-2.3-12.7-5.7-16-10.2c-3.3-4.4-5-9.3-5-14.5c0-4.2,0.9-7.9,2.7-11.1
c1.8-3.2,4.2-6,7.2-8.2c3-2.3,6.4-4,10.4-5.2c4-1.2,8.2-1.7,12.6-1.7c2.2,0,4.5,0.1,6.7,0.4c2.3,0.3,4.4,0.7,6.5,1.1
c2,0.5,3.9,1,5.7,1.6c1.8,0.6,3.2,1.2,4.2,1.8c1.4,0.8,2.4,1.6,3,2.5c0.6,0.8,0.9,1.9,0.9,3.3v4.7c0,2.1-0.8,3.2-2.3,3.2
c-0.8,0-2.1-0.4-3.8-1.2c-5.7-2.6-12.1-3.9-19.2-3.9c-5.7,0-10.2,0.9-13.3,2.8c-3.1,1.9-4.7,4.8-4.7,8.9c0,2.8,1,5.2,3,7.1
c2,1.9,5.7,3.8,11,5.5l14.2,4.5c7.2,2.3,12.4,5.5,15.5,9.6c3.1,4.1,4.6,8.8,4.6,14c0,4.3-0.9,8.2-2.6,11.6
c-1.8,3.4-4.2,6.4-7.3,8.8c-3.1,2.5-6.8,4.3-11.1,5.6C264.4,94.4,259.7,95.1,254.6,95.1z"/>
<g>
<path class="st1" d="M273.5,143.7c-32.9,24.3-80.7,37.2-121.8,37.2c-57.6,0-109.5-21.3-148.7-56.7c-3.1-2.8-0.3-6.6,3.4-4.4
c42.4,24.6,94.7,39.5,148.8,39.5c36.5,0,76.6-7.6,113.5-23.2C274.2,133.6,278.9,139.7,273.5,143.7z"/>
<path class="st1" d="M287.2,128.1c-4.2-5.4-27.8-2.6-38.5-1.3c-3.2,0.4-3.7-2.4-0.8-4.5c18.8-13.2,49.7-9.4,53.3-5
c3.6,4.5-1,35.4-18.6,50.2c-2.7,2.3-5.3,1.1-4.1-1.9C282.5,155.7,291.4,133.4,287.2,128.1z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,19 +1,29 @@
<script>
import {
GlAlert,
GlButton,
GlCollapse,
GlDeprecatedButton,
GlModal,
GlFormSelect,
GlFormCheckbox,
GlFormGroup,
GlFormInput,
GlFormSelect,
GlFormTextarea,
GlFormCheckbox,
GlLink,
GlIcon,
GlLink,
GlModal,
GlSprintf,
} from '@gitlab/ui';
import Cookies from 'js-cookie';
import { mapActions, mapState } from 'vuex';
import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { ADD_CI_VARIABLE_MODAL_ID } from '../constants';
import {
AWS_TOKEN_CONSTANTS,
ADD_CI_VARIABLE_MODAL_ID,
AWS_TIP_DISMISSED_COOKIE_NAME,
AWS_TIP_MESSAGE,
} from '../constants';
import { awsTokens, awsTokenList } from './ci_variable_autocomplete_tokens';
import CiKeyField from './ci_key_field.vue';
import CiEnvironmentsDropdown from './ci_environments_dropdown.vue';
@ -23,19 +33,29 @@ export default {
components: {
CiEnvironmentsDropdown,
CiKeyField,
GlAlert,
GlButton,
GlCollapse,
GlDeprecatedButton,
GlModal,
GlFormSelect,
GlFormCheckbox,
GlFormGroup,
GlFormInput,
GlFormSelect,
GlFormTextarea,
GlFormCheckbox,
GlLink,
GlIcon,
GlLink,
GlModal,
GlSprintf,
},
mixins: [glFeatureFlagsMixin()],
tokens: awsTokens,
tokenList: awsTokenList,
awsTipMessage: AWS_TIP_MESSAGE,
data() {
return {
isTipDismissed: Cookies.get(AWS_TIP_DISMISSED_COOKIE_NAME) === 'true',
};
},
computed: {
...mapState([
'projectId',
@ -47,7 +67,16 @@ export default {
'maskableRegex',
'selectedEnvironment',
'isProtectedByDefault',
'awsLogoSvgPath',
'awsTipDeployLink',
'awsTipCommandsLink',
'awsTipLearnLink',
'protectedEnvironmentVariablesLink',
'maskedEnvironmentVariablesLink',
]),
isTipVisible() {
return !this.isTipDismissed && AWS_TOKEN_CONSTANTS.includes(this.variableData.key);
},
canSubmit() {
return (
this.variableValidationState &&
@ -126,6 +155,10 @@ export default {
'setSelectedEnvironment',
'setVariableProtected',
]),
dismissTip() {
Cookies.set(AWS_TIP_DISMISSED_COOKIE_NAME, 'true', { expires: 90 });
this.isTipDismissed = true;
},
deleteVarAndClose() {
this.deleteVariable(this.variableBeingEdited);
this.hideModal();
@ -232,7 +265,7 @@ export default {
<gl-form-group :label="__('Flags')" label-for="ci-variable-flags">
<gl-form-checkbox v-model="variableData.protected" class="mb-0">
{{ __('Protect variable') }}
<gl-link href="/help/ci/variables/README#protected-environment-variables">
<gl-link target="_blank" :href="protectedEnvironmentVariablesLink">
<gl-icon name="question" :size="12" />
</gl-link>
<p class="gl-mt-2 text-secondary">
@ -246,7 +279,7 @@ export default {
data-qa-selector="ci_variable_masked_checkbox"
>
{{ __('Mask variable') }}
<gl-link href="/help/ci/variables/README#masked-variables">
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">
<gl-icon name="question" :size="12" />
</gl-link>
<p class="gl-mt-2 gl-mb-0 text-secondary">
@ -258,13 +291,52 @@ export default {
>
{{ __('Requires values to meet regular expression requirements.') }}</span
>
<gl-link href="/help/ci/variables/README#masked-variables">{{
<gl-link target="_blank" :href="maskedEnvironmentVariablesLink">{{
__('More information')
}}</gl-link>
</p>
</gl-form-checkbox>
</gl-form-group>
</form>
<gl-collapse :visible="isTipVisible">
<gl-alert
:title="__('Deploying to AWS is easy with GitLab')"
variant="tip"
data-testid="aws-guidance-tip"
@dismiss="dismissTip"
>
<div class="gl-display-flex gl-flex-direction-row">
<div>
<p>
<gl-sprintf :message="$options.awsTipMessage">
<template #deployLink="{ content }">
<gl-link :href="awsTipDeployLink" target="_blank">{{ content }}</gl-link>
</template>
<template #commandsLink="{ content }">
<gl-link :href="awsTipCommandsLink" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<p>
<gl-button
:href="awsTipLearnLink"
target="_blank"
category="secondary"
variant="info"
class="gl-overflow-wrap-break"
>{{ __('Learn more about deploying to AWS') }}</gl-button
>
</p>
</div>
<img
class="gl-mt-3"
:alt="__('Amazon Web Services Logo')"
:src="awsLogoSvgPath"
height="32"
/>
</div>
</gl-alert>
</gl-collapse>
<template #modal-footer>
<gl-deprecated-button @click="hideModal">{{ __('Cancel') }}</gl-deprecated-button>
<gl-deprecated-button

View File

@ -15,7 +15,13 @@ export const types = {
allEnvironmentsType: '*',
};
export const AWS_TIP_DISMISSED_COOKIE_NAME = 'ci_variable_list_constants_aws_tip_dismissed';
export const AWS_TIP_MESSAGE = __(
'%{deployLinkStart}Use a template to deploy to ECS%{deployLinkEnd}, or use a docker image to %{commandsLinkStart}run AWS commands in GitLab CI/CD%{commandsLinkEnd}.',
);
// AWS TOKEN CONSTANTS
export const AWS_ACCESS_KEY_ID = 'AWS_ACCESS_KEY_ID';
export const AWS_DEFAULT_REGION = 'AWS_DEFAULT_REGION';
export const AWS_SECRET_ACCESS_KEY = 'AWS_SECRET_ACCESS_KEY';
export const AWS_TOKEN_CONSTANTS = [AWS_ACCESS_KEY_ID, AWS_DEFAULT_REGION, AWS_SECRET_ACCESS_KEY];

View File

@ -5,7 +5,19 @@ import { parseBoolean } from '~/lib/utils/common_utils';
export default (containerId = 'js-ci-project-variables') => {
const containerEl = document.getElementById(containerId);
const { endpoint, projectId, group, maskableRegex, protectedByDefault } = containerEl.dataset;
const {
endpoint,
projectId,
group,
maskableRegex,
protectedByDefault,
awsLogoSvgPath,
awsTipDeployLink,
awsTipCommandsLink,
awsTipLearnLink,
protectedEnvironmentVariablesLink,
maskedEnvironmentVariablesLink,
} = containerEl.dataset;
const isGroup = parseBoolean(group);
const isProtectedByDefault = parseBoolean(protectedByDefault);
@ -15,6 +27,12 @@ export default (containerId = 'js-ci-project-variables') => {
isGroup,
maskableRegex,
isProtectedByDefault,
awsLogoSvgPath,
awsTipDeployLink,
awsTipCommandsLink,
awsTipLearnLink,
protectedEnvironmentVariablesLink,
maskedEnvironmentVariablesLink,
});
return new Vue({

View File

@ -8,7 +8,18 @@
- if Feature.enabled?(:new_variables_ui, @project || @group, default_enabled: true)
- is_group = !@group.nil?
#js-ci-project-variables{ data: { endpoint: save_endpoint, project_id: @project&.id || '', group: is_group.to_s, maskable_regex: ci_variable_maskable_regex, protected_by_default: ci_variable_protected_by_default?.to_s} }
#js-ci-project-variables{ data: { endpoint: save_endpoint,
project_id: @project&.id || '',
group: is_group.to_s,
maskable_regex: ci_variable_maskable_regex,
protected_by_default: ci_variable_protected_by_default?.to_s,
aws_logo_svg_path: image_path('aws_logo.svg'),
aws_tip_deploy_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'deploy-your-application-to-the-aws-elastic-container-service-ecs'),
aws_tip_commands_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'run-aws-commands-from-gitlab-cicd'),
aws_tip_learn_link: help_page_path('ci/cloud_deployment/index.md', anchor: 'aws'),
protected_environment_variables_link: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable'),
masked_environment_variables_link: help_page_path('ci/variables/README', anchor: 'mask-a-custom-variable'),
} }
- else
.row

View File

@ -5,6 +5,7 @@ module AuthorizedProjectUpdate
feature_category :authentication_and_authorization
urgency :low
queue_namespace :authorized_project_update
deduplicate :until_executing, including_scheduled: true
idempotent!
end

View File

@ -119,6 +119,20 @@ module WorkerAttributes
Array(worker_attributes[:tags])
end
def deduplicate(strategy, options = {})
worker_attributes[:deduplication_strategy] = strategy
worker_attributes[:deduplication_options] = options
end
def get_deduplicate_strategy
worker_attributes[:deduplication_strategy] ||
Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DEFAULT_STRATEGY
end
def get_deduplication_options
worker_attributes[:deduplication_options] || {}
end
protected
# Returns a worker attribute declared on this class or its parent class.

View File

@ -1,5 +0,0 @@
---
title: Add :section to approval_merge_request_rule unique index
merge_request: 33121
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Adds AWS guidance to CI/CD > Add Variable modal
merge_request: 34009
author:
type: added

View File

@ -1,112 +0,0 @@
# frozen_string_literal: true
class UpdateIndexApprovalRuleNameForCodeOwnersRuleType < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
LEGACY_INDEX_NAME_RULE_TYPE = "index_approval_rule_name_for_code_owners_rule_type"
LEGACY_INDEX_NAME_CODE_OWNERS = "approval_rule_name_index_for_code_owners"
SECTIONAL_INDEX_NAME = "index_approval_rule_name_for_sectional_code_owners_rule_type"
CODE_OWNER_RULE_TYPE = 2
def up
unless index_exists_by_name?(:approval_merge_request_rules, SECTIONAL_INDEX_NAME)
# Ensure only 1 code_owner rule with the same name and section per merge_request
#
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :name, :section],
unique: true,
where: "rule_type = #{CODE_OWNER_RULE_TYPE}",
name: SECTIONAL_INDEX_NAME
)
end
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_RULE_TYPE
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_CODE_OWNERS
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :name],
unique: true,
where: "rule_type = #{CODE_OWNER_RULE_TYPE} AND section IS NULL",
name: LEGACY_INDEX_NAME_RULE_TYPE
)
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :code_owner, :name],
unique: true,
where: "code_owner = true AND section IS NULL",
name: LEGACY_INDEX_NAME_CODE_OWNERS
)
end
def down
# In a rollback situation, we can't guarantee that there will not be
# records that were allowed under the more specific SECTIONAL_INDEX_NAME
# index but would cause uniqueness violations under both the
# LEGACY_INDEX_NAME_RULE_TYPE and LEGACY_INDEX_NAME_CODE_OWNERS indices.
# Therefore, we need to first find all the MergeRequests with
# ApprovalMergeRequestRules that would violate these "new" indices and
# delete those approval rules, then create the new index, then finally
# recreate the approval rules for those merge requests.
#
# First, find all MergeRequests with ApprovalMergeRequestRules that will
# violate the new index.
#
merge_request_ids = ApprovalMergeRequestRule
.select(:merge_request_id)
.where(rule_type: CODE_OWNER_RULE_TYPE)
.group(:merge_request_id, :rule_type, :name)
.includes(:merge_request)
.having("count(*) > 1")
.collect(&:merge_request_id)
# Delete ALL their code_owner approval rules
#
merge_request_ids.each_slice(10) do |ids|
ApprovalMergeRequestRule.where(merge_request_id: ids).code_owner.delete_all
end
# Remove legacy partial indices that only apply to `section IS NULL` records
#
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_RULE_TYPE
remove_concurrent_index_by_name :approval_merge_request_rules, LEGACY_INDEX_NAME_CODE_OWNERS
# Reconstruct original "legacy" indices
#
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :name],
unique: true,
where: "rule_type = #{CODE_OWNER_RULE_TYPE}",
name: LEGACY_INDEX_NAME_RULE_TYPE
)
add_concurrent_index(
:approval_merge_request_rules,
[:merge_request_id, :code_owner, :name],
unique: true,
where: "code_owner = true",
name: LEGACY_INDEX_NAME_CODE_OWNERS
)
# MergeRequest::SyncCodeOwnerApprovalRules recreates the code_owner rules
# from scratch, adding them to the index. Duplicates will be rejected.
#
merge_request_ids.each_slice(10) do |ids|
MergeRequest.where(id: ids).each do |merge_request|
MergeRequests::SyncCodeOwnerApprovalRules.new(merge_request).execute
end
end
remove_concurrent_index_by_name :approval_merge_request_rules, SECTIONAL_INDEX_NAME
end
end

View File

@ -9156,7 +9156,7 @@ CREATE UNIQUE INDEX any_approver_merge_request_rule_type_unique_index ON public.
CREATE UNIQUE INDEX any_approver_project_rule_type_unique_index ON public.approval_project_rules USING btree (project_id) WHERE (rule_type = 3);
CREATE UNIQUE INDEX approval_rule_name_index_for_code_owners ON public.approval_merge_request_rules USING btree (merge_request_id, code_owner, name) WHERE ((code_owner = true) AND (section IS NULL));
CREATE UNIQUE INDEX approval_rule_name_index_for_code_owners ON public.approval_merge_request_rules USING btree (merge_request_id, code_owner, name) WHERE (code_owner = true);
CREATE INDEX ci_builds_gitlab_monitor_metrics ON public.ci_builds USING btree (status, created_at, project_id) WHERE ((type)::text = 'Ci::Build'::text);
@ -9334,9 +9334,7 @@ CREATE UNIQUE INDEX index_approval_project_rules_users_1 ON public.approval_proj
CREATE INDEX index_approval_project_rules_users_2 ON public.approval_project_rules_users USING btree (user_id);
CREATE UNIQUE INDEX index_approval_rule_name_for_code_owners_rule_type ON public.approval_merge_request_rules USING btree (merge_request_id, name) WHERE ((rule_type = 2) AND (section IS NULL));
CREATE UNIQUE INDEX index_approval_rule_name_for_sectional_code_owners_rule_type ON public.approval_merge_request_rules USING btree (merge_request_id, name, section) WHERE (rule_type = 2);
CREATE UNIQUE INDEX index_approval_rule_name_for_code_owners_rule_type ON public.approval_merge_request_rules USING btree (merge_request_id, name) WHERE (rule_type = 2);
CREATE INDEX index_approval_rules_code_owners_rule_type ON public.approval_merge_request_rules USING btree (merge_request_id) WHERE (rule_type = 2);
@ -13963,7 +13961,6 @@ COPY "schema_migrations" (version) FROM STDIN;
20200526153844
20200526164946
20200526164947
20200526231421
20200527092027
20200527094322
20200527095401

View File

@ -42,7 +42,7 @@ are very appreciative of the work done by translators and proofreaders!
- Estonian
- Proofreaders needed.
- Filipino
- Proofreaders needed.
- Andrei Jiroh Halili - [GitLab](https://gitlab.com/AJHalili2006DevPH), [Crowdin](https://crowdin.com/profile/AndreiJirohHaliliDev2006)
- French
- Davy Defaud - [GitLab](https://gitlab.com/DevDef), [CrowdIn](https://crowdin.com/profile/DevDef)
- Galician

View File

@ -322,7 +322,11 @@ Examples of query optimization work:
When adding, changing, or updating metrics, please update the [Usage Statistics definition table](#usage-statistics-definitions).
### 5. Ask for a Telemetry Review
### 5. Add new metric to Versions Application
Check if new metrics need to be added to the Versions Application. See `usage_data` [schema](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/db/schema.rb#L147) and usage data [parameters accepted](https://gitlab.com/gitlab-services/version-gitlab-com/-/blob/master/app/services/usage_ping.rb). Any metrics added under the `counts` key are saved in the `counts` column.
### 6. Ask for a Telemetry Review
On GitLab.com, we have DangerBot setup to monitor Telemetry related files and DangerBot will recommend a Telemetry review. Mention `@gitlab-org/growth/telemetry/engineers` in your MR for a review.

View File

@ -471,9 +471,6 @@ DAST can be [configured](#customizing-the-dast-settings) using environment varia
| `DAST_INCLUDE_ALPHA_VULNERABILITIES` | no | Include alpha passive and active scan rules. Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
| `DAST_USE_AJAX_SPIDER` | no | Use the AJAX spider in addition to the traditional spider, useful for crawling sites that require JavaScript. Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
| `DAST_ZAP_CLI_OPTIONS` | no | ZAP server command-line options. For example, `-Xmx3072m` would set the Java maximum memory allocation pool size. |
| `DAST_ZAP_GENERATE_CONFIG` | no | The file name of the generated sample ZAP configuration file for use with `DAST_ZAP_CONFIG_FILE`. |
| `DAST_ZAP_CONFIG_FILE` | no | Name of configuration file used to determine thresholds of vulnerability rules. |
| `DAST_ZAP_CONFIG_URL` | no | URL of configuration file used to determine thresholds of vulnerability rules. |
| `DAST_ZAP_LOG_CONFIGURATION` | no | Set to a semicolon-separated list of additional log4j properties for the ZAP Server. For example, `log4j.logger.org.parosproxy.paros.network.HttpSender=DEBUG` |
### DAST command-line options

View File

@ -38,12 +38,14 @@ immediately identify which alerts you should prioritize investigating:
Alerts contain one of the following icons:
- **Critical**: **{severity-critical}** and hexadecimal color `#8b2615`
- **High**: **{severity-high}** and hexadecimal color `#c0341d`
- **Medium**: **{severity-medium}** and hexadecimal color `#fca429`
- **Low**: **{severity-low}** and hexadecimal color `#fdbc60`
- **Info**: **{severity-info}** and hexadecimal color `#418cd8`
- **Unknown**: **{severity-unknown}** and hexadecimal color `#bababa`
| Severity | Icon | Color (hexadecimal) |
|---|---|---|
| Critical | **{severity-critical}** | `#8b2615` |
| High | **{severity-high}** | `#c0341d` |
| Medium | **{severity-medium}** | `#fca429` |
| Low | **{severity-low}** | `#fdbc60` |
| Info | **{severity-info}** | `#418cd8` |
| Unknown | **{severity-unknown}** | `#bababa` |
## Alert Management list

View File

@ -5,9 +5,6 @@ module Gitlab
module DuplicateJobs
class Client
def call(worker_class, job, queue, _redis_pool, &block)
# We don't try to deduplicate jobs that are scheduled in the future
return yield if job['at']
DuplicateJob.new(job, queue).schedule(&block)
end
end

View File

@ -18,13 +18,13 @@ module Gitlab
# When new jobs can be scheduled again, the strategy calls `#delete`.
class DuplicateJob
DUPLICATE_KEY_TTL = 6.hours
DEFAULT_STRATEGY = :until_executing
attr_reader :existing_jid
def initialize(job, queue_name, strategy: :until_executing)
def initialize(job, queue_name)
@job = job
@queue_name = queue_name
@strategy = strategy
end
# This will continue the middleware chain if the job should be scheduled
@ -41,12 +41,12 @@ module Gitlab
end
# This method will return the jid that was set in redis
def check!
def check!(expiry = DUPLICATE_KEY_TTL)
read_jid = nil
Sidekiq.redis do |redis|
redis.multi do |multi|
redis.set(idempotency_key, jid, ex: DUPLICATE_KEY_TTL, nx: true)
redis.set(idempotency_key, jid, ex: expiry, nx: true)
read_jid = redis.get(idempotency_key)
end
end
@ -60,6 +60,10 @@ module Gitlab
end
end
def scheduled?
scheduled_at.present?
end
def duplicate?
raise "Call `#check!` first to check for existing duplicates" unless existing_jid
@ -67,14 +71,36 @@ module Gitlab
end
def droppable?
idempotent? && duplicate? && ::Feature.disabled?("disable_#{queue_name}_deduplication")
idempotent? && ::Feature.disabled?("disable_#{queue_name}_deduplication")
end
def scheduled_at
job['at']
end
def options
return {} unless worker_klass
return {} unless worker_klass.respond_to?(:get_deduplication_options)
worker_klass.get_deduplication_options
end
private
attr_reader :queue_name, :strategy, :job
attr_reader :queue_name, :job
attr_writer :existing_jid
def worker_klass
@worker_klass ||= worker_class_name.to_s.safe_constantize
end
def strategy
return DEFAULT_STRATEGY unless worker_klass
return DEFAULT_STRATEGY unless worker_klass.respond_to?(:idempotent?)
worker_klass.get_deduplicate_strategy
end
def worker_class_name
job['class']
end
@ -104,11 +130,10 @@ module Gitlab
end
def idempotent?
worker_class = worker_class_name.to_s.safe_constantize
return false unless worker_class
return false unless worker_class.respond_to?(:idempotent?)
return false unless worker_klass
return false unless worker_klass.respond_to?(:idempotent?)
worker_class.idempotent?
worker_klass.idempotent?
end
end
end

View File

@ -13,13 +13,13 @@ module Gitlab
end
def schedule(job)
if duplicate_job.check! && duplicate_job.duplicate?
if deduplicatable_job? && check! && duplicate_job.duplicate?
job['duplicate-of'] = duplicate_job.existing_jid
end
if duplicate_job.droppable?
Gitlab::SidekiqLogging::DeduplicationLogger.instance.log(job, "dropped until executing")
return false
if duplicate_job.droppable?
Gitlab::SidekiqLogging::DeduplicationLogger.instance.log(job, "dropped until executing")
return false
end
end
yield
@ -34,6 +34,22 @@ module Gitlab
private
attr_reader :duplicate_job
def deduplicatable_job?
!duplicate_job.scheduled? || duplicate_job.options[:including_scheduled]
end
def check!
duplicate_job.check!(expiry)
end
def expiry
return DuplicateJob::DUPLICATE_KEY_TTL unless duplicate_job.scheduled?
time_diff = duplicate_job.scheduled_at.to_i - Time.now.to_i
time_diff > 0 ? time_diff : DuplicateJob::DUPLICATE_KEY_TTL
end
end
end
end

View File

@ -329,6 +329,9 @@ msgstr ""
msgid "%{days} days until tags are automatically removed"
msgstr ""
msgid "%{deployLinkStart}Use a template to deploy to ECS%{deployLinkEnd}, or use a docker image to %{commandsLinkStart}run AWS commands in GitLab CI/CD%{commandsLinkEnd}."
msgstr ""
msgid "%{description}- Sentry event: %{errorUrl}- First seen: %{firstSeen}- Last seen: %{lastSeen} %{countLabel}: %{count}%{userCountLabel}: %{userCount}"
msgstr ""
@ -2176,6 +2179,9 @@ msgstr ""
msgid "Amazon Web Services"
msgstr ""
msgid "Amazon Web Services Logo"
msgstr ""
msgid "Amazon authentication is not %{link_start}correctly configured%{link_end}. Ask your GitLab administrator if you want to use this service."
msgstr ""
@ -7572,6 +7578,9 @@ msgstr ""
msgid "Deploying to"
msgstr ""
msgid "Deploying to AWS is easy with GitLab"
msgstr ""
msgid "Deployment Frequency"
msgstr ""
@ -13039,6 +13048,9 @@ msgstr ""
msgid "Learn more about custom project templates"
msgstr ""
msgid "Learn more about deploying to AWS"
msgstr ""
msgid "Learn more about deploying to a cluster"
msgstr ""

View File

@ -105,6 +105,46 @@ describe('Ci variable modal', () => {
});
});
describe('Adding a new non-AWS variable', () => {
beforeEach(() => {
const [variable] = mockData.mockVariables;
const invalidKeyVariable = {
...variable,
key: 'key',
value: 'value',
secret_value: 'secret_value',
};
createComponent(mount);
store.state.variable = invalidKeyVariable;
});
it('does not show AWS guidance tip', () => {
const tip = wrapper.find(`div[data-testid='aws-guidance-tip']`);
expect(tip.exists()).toBe(true);
expect(tip.isVisible()).toBe(false);
});
});
describe('Adding a new AWS variable', () => {
beforeEach(() => {
const [variable] = mockData.mockVariables;
const invalidKeyVariable = {
...variable,
key: AWS_ACCESS_KEY_ID,
value: 'AKIAIOSFODNN7EXAMPLEjdhy',
secret_value: 'AKIAIOSFODNN7EXAMPLEjdhy',
};
createComponent(mount);
store.state.variable = invalidKeyVariable;
});
it('shows AWS guidance tip', () => {
const tip = wrapper.find(`[data-testid='aws-guidance-tip']`);
expect(tip.exists()).toBe(true);
expect(tip.isVisible()).toBe(true);
});
});
describe('Editing a variable', () => {
beforeEach(() => {
const [variable] = mockData.mockVariables;

View File

@ -31,14 +31,51 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::Client, :clean_gitlab_redis_q
expect(job3['duplicate-of']).to eq(job1['jid'])
end
it "does not mark a job that's scheduled in the future as a duplicate" do
TestDeduplicationWorker.perform_async('args1')
TestDeduplicationWorker.perform_at(1.day.from_now, 'args1')
TestDeduplicationWorker.perform_in(3.hours, 'args1')
context 'without scheduled deduplication' do
it "does not mark a job that's scheduled in the future as a duplicate" do
TestDeduplicationWorker.perform_async('args1')
TestDeduplicationWorker.perform_at(1.day.from_now, 'args1')
TestDeduplicationWorker.perform_in(3.hours, 'args1')
duplicates = TestDeduplicationWorker.jobs.map { |job| job['duplicate-of'] }
duplicates = TestDeduplicationWorker.jobs.map { |job| job['duplicate-of'] }
expect(duplicates).to all(be_nil)
expect(duplicates).to all(be_nil)
end
end
context 'with scheduled deduplication' do
let(:scheduled_worker_class) do
Class.new do
def self.name
'TestDeduplicationWorker'
end
include ApplicationWorker
deduplicate :until_executing, including_scheduled: true
def perform(*args)
end
end
end
before do
stub_const('TestDeduplicationWorker', scheduled_worker_class)
end
it 'adds a correct duplicate tag to the jobs', :aggregate_failures do
TestDeduplicationWorker.perform_async('args1')
TestDeduplicationWorker.perform_at(1.day.from_now, 'args1')
TestDeduplicationWorker.perform_in(3.hours, 'args1')
TestDeduplicationWorker.perform_in(3.hours, 'args2')
job1, job2, job3, job4 = TestDeduplicationWorker.jobs
expect(job1['duplicate-of']).to be_nil
expect(job2['duplicate-of']).to eq(job1['jid'])
expect(job3['duplicate-of']).to eq(job1['jid'])
expect(job4['duplicate-of']).to be_nil
end
end
end
end

View File

@ -93,6 +93,25 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gitlab_r
end
end
describe '#scheduled?' do
it 'returns false for non-scheduled jobs' do
expect(duplicate_job.scheduled?).to be(false)
end
context 'scheduled jobs' do
let(:job) do
{ 'class' => 'AuthorizedProjectsWorker',
'args' => [1],
'jid' => '123',
'at' => 42 }
end
it 'returns true' do
expect(duplicate_job.scheduled?).to be(true)
end
end
end
describe '#duplicate?' do
it "raises an error if the check wasn't performed" do
expect { duplicate_job.duplicate? }.to raise_error /Call `#check!` first/
@ -112,28 +131,23 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gitlab_r
end
end
describe 'droppable?' do
where(:idempotent, :duplicate, :prevent_deduplication) do
# [true, false].repeated_permutation(3)
[[true, true, true],
[true, true, false],
[true, false, true],
[true, false, false],
[false, true, true],
[false, true, false],
[false, false, true],
[false, false, false]]
describe '#droppable?' do
where(:idempotent, :prevent_deduplication) do
# [true, false].repeated_permutation(2)
[[true, true],
[true, false],
[false, true],
[false, false]]
end
with_them do
before do
allow(AuthorizedProjectsWorker).to receive(:idempotent?).and_return(idempotent)
allow(duplicate_job).to receive(:duplicate?).and_return(duplicate)
stub_feature_flags("disable_#{queue}_deduplication" => prevent_deduplication)
end
it 'is droppable when all conditions are met' do
if idempotent && duplicate && !prevent_deduplication
if idempotent && !prevent_deduplication
expect(duplicate_job).to be_droppable
else
expect(duplicate_job).not_to be_droppable
@ -142,6 +156,31 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob, :clean_gitlab_r
end
end
describe '#scheduled_at' do
let(:scheduled_at) { 42 }
let(:job) do
{ 'class' => 'AuthorizedProjectsWorker',
'args' => [1],
'jid' => '123',
'at' => scheduled_at }
end
it 'returns when the job is scheduled at' do
expect(duplicate_job.scheduled_at).to eq(scheduled_at)
end
end
describe '#options' do
let(:worker_options) { { foo: true } }
it 'returns worker options' do
allow(AuthorizedProjectsWorker).to(
receive(:get_deduplication_options).and_return(worker_options))
expect(duplicate_job.options).to eq(worker_options)
end
end
def set_idempotency_key(key, value = '1')
Sidekiq.redis { |r| r.set(key, value) }
end

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'timecop'
describe Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies::UntilExecuting do
let(:fake_duplicate_job) do
@ -15,28 +16,90 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies::UntilExecuting do
end
it 'checks for duplicates before yielding' do
expect(fake_duplicate_job).to receive(:check!).ordered.and_return('a jid')
expect(fake_duplicate_job).to receive(:scheduled?).twice.ordered.and_return(false)
expect(fake_duplicate_job).to(
receive(:check!)
.with(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DUPLICATE_KEY_TTL)
.ordered
.and_return('a jid'))
expect(fake_duplicate_job).to receive(:duplicate?).ordered.and_return(false)
expect(fake_duplicate_job).to receive(:droppable?).ordered.and_return(false)
expect { |b| strategy.schedule({}, &b) }.to yield_control
end
it 'adds the jid of the existing job to the job hash' do
allow(fake_duplicate_job).to receive(:check!).and_return('the jid')
allow(fake_duplicate_job).to receive(:droppable?).and_return(true)
job_hash = {}
it 'checks worker options for scheduled jobs' do
expect(fake_duplicate_job).to receive(:scheduled?).ordered.and_return(true)
expect(fake_duplicate_job).to receive(:options).ordered.and_return({})
expect(fake_duplicate_job).not_to receive(:check!)
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
expect(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
expect { |b| strategy.schedule({}, &b) }.to yield_control
end
strategy.schedule(job_hash) {}
context 'job marking' do
it 'adds the jid of the existing job to the job hash' do
allow(fake_duplicate_job).to receive(:scheduled?).and_return(false)
allow(fake_duplicate_job).to receive(:check!).and_return('the jid')
allow(fake_duplicate_job).to receive(:droppable?).and_return(true)
job_hash = {}
expect(job_hash).to include('duplicate-of' => 'the jid')
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
expect(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
strategy.schedule(job_hash) {}
expect(job_hash).to include('duplicate-of' => 'the jid')
end
context 'scheduled jobs' do
let(:time_diff) { 1.minute }
context 'scheduled in the past' do
it 'adds the jid of the existing job to the job hash' do
allow(fake_duplicate_job).to receive(:scheduled?).twice.and_return(true)
allow(fake_duplicate_job).to receive(:scheduled_at).and_return(Time.now - time_diff)
allow(fake_duplicate_job).to receive(:options).and_return({ including_scheduled: true })
allow(fake_duplicate_job).to(
receive(:check!)
.with(Gitlab::SidekiqMiddleware::DuplicateJobs::DuplicateJob::DUPLICATE_KEY_TTL)
.and_return('the jid'))
allow(fake_duplicate_job).to receive(:droppable?).and_return(true)
job_hash = {}
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
expect(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
strategy.schedule(job_hash) {}
expect(job_hash).to include('duplicate-of' => 'the jid')
end
end
context 'scheduled in the future' do
it 'adds the jid of the existing job to the job hash' do
Timecop.freeze do
allow(fake_duplicate_job).to receive(:scheduled?).twice.and_return(true)
allow(fake_duplicate_job).to receive(:scheduled_at).and_return(Time.now + time_diff)
allow(fake_duplicate_job).to receive(:options).and_return({ including_scheduled: true })
allow(fake_duplicate_job).to(
receive(:check!).with(time_diff.to_i).and_return('the jid'))
allow(fake_duplicate_job).to receive(:droppable?).and_return(true)
job_hash = {}
expect(fake_duplicate_job).to receive(:duplicate?).and_return(true)
expect(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
strategy.schedule(job_hash) {}
expect(job_hash).to include('duplicate-of' => 'the jid')
end
end
end
end
end
context "when the job is droppable" do
before do
allow(fake_duplicate_job).to receive(:scheduled?).and_return(false)
allow(fake_duplicate_job).to receive(:check!).and_return('the jid')
allow(fake_duplicate_job).to receive(:duplicate?).and_return(true)
allow(fake_duplicate_job).to receive(:existing_jid).and_return('the jid')
@ -52,7 +115,7 @@ describe Gitlab::SidekiqMiddleware::DuplicateJobs::Strategies::UntilExecuting do
expect(schedule_result).to be(false)
end
it 'logs that the job wass dropped' do
it 'logs that the job was dropped' do
fake_logger = instance_double(Gitlab::SidekiqLogging::DeduplicationLogger)
expect(Gitlab::SidekiqLogging::DeduplicationLogger).to receive(:instance).and_return(fake_logger)

View File

@ -1,142 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20200526231421_update_index_approval_rule_name_for_code_owners_rule_type.rb')
describe UpdateIndexApprovalRuleNameForCodeOwnersRuleType do
let(:migration) { described_class.new }
let(:approval_rules) { table(:approval_merge_request_rules) }
let(:namespace) { table(:namespaces).create!(name: 'gitlab', path: 'gitlab') }
let(:project) do
table(:projects).create!(
namespace_id: namespace.id,
name: 'gitlab',
path: 'gitlab'
)
end
let(:merge_request) do
table(:merge_requests).create!(
target_project_id: project.id,
source_project_id: project.id,
target_branch: 'feature',
source_branch: 'master'
)
end
let(:index_names) do
ActiveRecord::Base.connection
.indexes(:approval_merge_request_rules)
.collect(&:name)
end
def create_sectional_approval_rules
approval_rules.create!(
merge_request_id: merge_request.id,
name: "*.rb",
code_owner: true,
rule_type: 2,
section: "First Section"
)
approval_rules.create!(
merge_request_id: merge_request.id,
name: "*.rb",
code_owner: true,
rule_type: 2,
section: "Second Section"
)
end
def create_two_matching_nil_section_approval_rules
2.times do
approval_rules.create!(
merge_request_id: merge_request.id,
name: "nil_section",
code_owner: true,
rule_type: 2
)
end
end
before do
approval_rules.delete_all
end
describe "#up" do
it "creates the new index and removes the 'legacy' indices" do
# Confirm that existing legacy indices prevent duplicate entries
#
expect { create_sectional_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
expect { create_two_matching_nil_section_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
approval_rules.delete_all
disable_migrations_output { migrate! }
# After running the migration, expect `section == nil` rules to still
# be blocked by the legacy indices, but sectional rules are allowed.
#
expect { create_sectional_approval_rules }
.to change { approval_rules.count }.by(2)
expect { create_two_matching_nil_section_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
# Attempt to rerun the creation of sectional rules, and see that sectional
# rules are unique by section
#
expect { create_sectional_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
expect(index_names).to include(
described_class::SECTIONAL_INDEX_NAME,
described_class::LEGACY_INDEX_NAME_RULE_TYPE,
described_class::LEGACY_INDEX_NAME_CODE_OWNERS
)
end
end
describe "#down" do
it "recreates 'legacy' indices and removes duplicate code owner approval rules" do
disable_migrations_output { migrate! }
expect { create_sectional_approval_rules }
.to change { approval_rules.count }.by(2)
expect { create_two_matching_nil_section_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
# Run the down migration. This will remove the 2 approval rules we create
# above, and call MergeRequests::SyncCodeOwnerApprovalRules to recreate
# new ones.
#
expect(MergeRequests::SyncCodeOwnerApprovalRules)
.to receive(:new).with(MergeRequest.find(merge_request.id)).once.and_call_original
# We expect approval_rules.count to be changed by -2 as we're deleting the
# 3 rules created above, and MergeRequests::SyncCodeOwnerApprovalRules
# will not be able to create new one with an empty (or missing)
# CODEOWNERS file.
#
expect { disable_migrations_output { migration.down } }
.to change { approval_rules.count }.by(-3)
# Test that the index does not allow us to create the same rules as the
# previous sectional index.
#
expect { create_sectional_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
expect { create_two_matching_nil_section_approval_rules }
.to raise_exception(ActiveRecord::RecordNotUnique)
expect(index_names).not_to include(described_class::SECTIONAL_INDEX_NAME)
expect(index_names).to include(
described_class::LEGACY_INDEX_NAME_RULE_TYPE,
described_class::LEGACY_INDEX_NAME_CODE_OWNERS
)
end
end
end