summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/build-images.gitlab-ci.yml5
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml44
-rw-r--r--.gitlab/ci/rules.gitlab-ci.yml5
-rw-r--r--GITLAB_ELASTICSEARCH_INDEXER_VERSION2
-rw-r--r--app/assets/javascripts/analytics/shared/components/daterange.vue4
-rw-r--r--app/assets/javascripts/content_editor/extensions/paste_markdown.js14
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js2
-rw-r--r--app/assets/javascripts/cycle_analytics/components/stage_table.vue4
-rw-r--r--app/assets/javascripts/cycle_analytics/components/total_time.vue2
-rw-r--r--app/assets/javascripts/design_management/components/list/item.vue2
-rw-r--r--app/assets/javascripts/design_management/pages/index.vue12
-rw-r--r--app/assets/javascripts/locale/sprintf.js2
-rw-r--r--app/assets/javascripts/pages/projects/settings/repository/create_deploy_token/index.js4
-rw-r--r--app/assets/javascripts/repository/components/blob_content_viewer.vue28
-rw-r--r--app/assets/javascripts/repository/components/table/row.vue2
-rw-r--r--app/assets/javascripts/repository/queries/project_info.query.graphql14
-rw-r--r--app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue9
-rw-r--r--app/graphql/queries/repository/blob_info.query.graphql (renamed from app/assets/javascripts/repository/queries/blob_info.query.graphql)14
-rw-r--r--app/mailers/previews/notify_preview.rb14
-rw-r--r--app/models/ci/job_artifact.rb5
-rw-r--r--app/models/concerns/ci/partitionable.rb42
-rw-r--r--app/services/ci/job_artifacts/create_service.rb2
-rw-r--r--app/views/projects/blob/show.html.haml1
-rw-r--r--app/views/shared/milestones/_milestone.html.haml3
-rw-r--r--config/environments/development.rb2
-rw-r--r--config/environments/test.rb2
-rw-r--r--config/metrics/aggregates/code_review.yml12
-rw-r--r--config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml6
-rwxr-xr-xconfig/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml6
-rw-r--r--config/metrics/counts_28d/20220830104453_i_code_review_merge_request_widget_license_compliance_view_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220830104500_i_code_review_merge_request_widget_license_compliance_full_report_clicked_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220830104507_i_code_review_merge_request_widget_license_compliance_expand_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220830104514_i_code_review_merge_request_widget_license_compliance_expand_success_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220830104521_i_code_review_merge_request_widget_license_compliance_expand_warning_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220830104528_i_code_review_merge_request_widget_license_compliance_expand_failed_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220907202807_p_ci_templates_jobs_dependency_scanning_latest_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220907212005_p_ci_templates_security_container_scanning_latest_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220907215635_p_ci_templates_jobs_license_scanning_latest_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220912161240_p_ci_templates_implicit_jobs_dependency_scanning_latest_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220912162308_p_ci_templates_implicit_jobs_license_scanning_latest_monthly.yml25
-rw-r--r--config/metrics/counts_28d/20220912162752_p_ci_templates_implicit_security_container_scanning_latest_monthly.yml25
-rw-r--r--config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml6
-rwxr-xr-xconfig/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml3
-rw-r--r--config/metrics/counts_7d/20220830104410_i_code_review_merge_request_widget_license_compliance_view_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220830104418_i_code_review_merge_request_widget_license_compliance_full_report_clicked_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220830104424_i_code_review_merge_request_widget_license_compliance_expand_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220830104431_i_code_review_merge_request_widget_license_compliance_expand_success_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220830104438_i_code_review_merge_request_widget_license_compliance_expand_warning_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220830104446_i_code_review_merge_request_widget_license_compliance_expand_failed_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220907202801_p_ci_templates_jobs_dependency_scanning_latest_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220907211959_p_ci_templates_security_container_scanning_latest_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220907215629_p_ci_templates_jobs_license_scanning_latest_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220912161233_p_ci_templates_implicit_jobs_dependency_scanning_latest_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220912162301_p_ci_templates_implicit_jobs_license_scanning_latest_weekly.yml25
-rw-r--r--config/metrics/counts_7d/20220912162745_p_ci_templates_implicit_security_container_scanning_latest_weekly.yml25
-rw-r--r--config/metrics/counts_all/20220825115210_i_merge_request_widget_license_compliance_count_view.yml24
-rw-r--r--config/metrics/counts_all/20220825115217_i_merge_request_widget_license_compliance_count_full_report_clicked.yml24
-rw-r--r--config/metrics/counts_all/20220825115224_i_merge_request_widget_license_compliance_count_expand.yml24
-rw-r--r--config/metrics/counts_all/20220825115230_i_merge_request_widget_license_compliance_count_expand_success.yml24
-rw-r--r--config/metrics/counts_all/20220825115236_i_merge_request_widget_license_compliance_count_expand_warning.yml24
-rw-r--r--config/metrics/counts_all/20220825115242_i_merge_request_widget_license_compliance_count_expand_failed.yml24
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/api/product_analytics.md67
-rw-r--r--doc/development/contributing/index.md12
-rw-r--r--doc/development/documentation/feature_flags.md3
-rw-r--r--doc/development/documentation/versions.md5
-rw-r--r--doc/development/testing_guide/flaky_tests.md2
-rw-r--r--doc/integration/advanced_search/elasticsearch.md2
-rw-r--r--doc/user/markdown.md105
-rw-r--r--lib/gitlab/ci/config/entry/processable.rb2
-rw-r--r--lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml244
-rw-r--r--lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml48
-rw-r--r--lib/gitlab/ci/templates/Security/Container-Scanning.latest.gitlab-ci.yml68
-rw-r--r--lib/gitlab/ci/variables/helpers.rb28
-rw-r--r--lib/gitlab/ci/yaml_processor/result.rb10
-rw-r--r--lib/gitlab/usage_data_counters/known_events/ci_templates.yml24
-rw-r--r--lib/gitlab/usage_data_counters/known_events/code_review_events.yml25
-rw-r--r--lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb2
-rw-r--r--lib/gitlab_edition.rb15
-rw-r--r--locale/gitlab.pot6
-rw-r--r--rubocop/cop/gitlab/avoid_feature_get.rb7
-rw-r--r--spec/frontend/content_editor/extensions/paste_markdown_spec.js21
-rw-r--r--spec/frontend/cycle_analytics/__snapshots__/total_time_spec.js.snap12
-rw-r--r--spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap4
-rw-r--r--spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap8
-rw-r--r--spec/frontend/design_management/pages/index_spec.js2
-rw-r--r--spec/frontend/locale/sprintf_spec.js18
-rw-r--r--spec/frontend/repository/components/blob_content_viewer_spec.js49
-rw-r--r--spec/frontend/repository/mock_data.js1
-rw-r--r--spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap14
-rw-r--r--spec/frontend/work_items/components/work_item_detail_spec.js4
-rw-r--r--spec/frontend_integration/content_editor/content_editor_integration_spec.js46
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/trace/archive_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/variables/helpers_spec.rb89
-rw-r--r--spec/lib/gitlab_edition_spec.rb53
-rw-r--r--spec/mailers/previews_spec.rb44
-rw-r--r--spec/models/ci/job_artifact_spec.rb24
-rw-r--r--spec/services/ci/job_artifacts/create_service_spec.rb12
-rw-r--r--tests.yml6
102 files changed, 1767 insertions, 346 deletions
diff --git a/.gitlab/ci/build-images.gitlab-ci.yml b/.gitlab/ci/build-images.gitlab-ci.yml
index dbd956214dd..e2c707b6895 100644
--- a/.gitlab/ci/build-images.gitlab-ci.yml
+++ b/.gitlab/ci/build-images.gitlab-ci.yml
@@ -19,14 +19,19 @@ build-qa-image:
QA_IMAGE_BRANCH: ${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_REF_SLUG}
script:
- export QA_IMAGE="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_SHA}"
+ # Auto-deploy tag format uses first 12 letters of commit SHA. Tag with
+ # that reference also
+ - export QA_IMAGE_FOR_AUTO_DEPLOY="${CI_REGISTRY}/${CI_PROJECT_PATH}/gitlab-ee-qa:${CI_COMMIT_SHA:0:11}"
- echo $QA_IMAGE
- echo $QA_IMAGE_BRANCH
+ - echo $QA_IMAGE_FOR_AUTO_DEPLOY
- |
/kaniko/executor \
--context=${CI_PROJECT_DIR} \
--dockerfile=${CI_PROJECT_DIR}/qa/Dockerfile \
--destination=${QA_IMAGE} \
--destination=${QA_IMAGE_BRANCH} \
+ --destination=${QA_IMAGE_FOR_AUTO_DEPLOY} \
--build-arg=CHROME_VERSION=${CHROME_VERSION} \
--build-arg=DOCKER_VERSION=${DOCKER_VERSION} \
--build-arg=QA_BUILD_TARGET=${QA_BUILD_TARGET:-qa} \
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 967a7ddf924..0f524f03188 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -378,51 +378,19 @@ db:migrate:reset single-db:
- .single-db
- .rails:rules:single-db
-db:migrate-from-previous-major-version:
- extends: .db-job-base
- variables:
- USE_BUNDLE_INSTALL: "false"
- SETUP_DB: "false"
- PROJECT_TO_CHECKOUT: "gitlab-foss"
- TAG_TO_CHECKOUT: "v14.10.2"
- before_script:
- - !reference [.default-before_script, before_script]
- - '[[ -d "ee/" ]] || export PROJECT_TO_CHECKOUT="gitlab"'
- - '[[ -d "ee/" ]] || export TAG_TO_CHECKOUT="${TAG_TO_CHECKOUT}-ee"'
- - retry 'git fetch https://gitlab.com/gitlab-org/$PROJECT_TO_CHECKOUT.git $TAG_TO_CHECKOUT'
- - git checkout -f FETCH_HEAD
- - SETUP_DB=false USE_BUNDLE_INSTALL=true ENABLE_BOOTSNAP=false bash scripts/prepare_build.sh
- - run_timed_command "ENABLE_BOOTSNAP=false bundle exec rake db:drop db:create db:structure:load db:migrate db:seed_fu"
- - git checkout -f $CI_COMMIT_SHA
- - SETUP_DB=false USE_BUNDLE_INSTALL=true bash scripts/prepare_build.sh
- script:
- - run_timed_command "scripts/db_tasks db:migrate"
-
-db:migrate-from-previous-major-version-single-db:
- extends:
- - db:migrate-from-previous-major-version
- - .single-db
- - .rails:rules:single-db
-
-.db:check-schema-base:
+db:check-schema:
extends:
+ - .db-job-base
- .rails:rules:ee-mr-and-default-branch-only
- variables:
- TAG_TO_CHECKOUT: "v14.7.0" # this version updated grpc to 1.42.0, which supports Ruby 2 & 3
script:
+ - run_timed_command "bundle exec rake db:drop db:create"
- run_timed_command "scripts/db_tasks db:migrate"
- - scripts/schema_changed.sh
- - scripts/validate_migration_timestamps
-
-db:check-schema:
- extends:
- - db:migrate-from-previous-major-version
- - .db:check-schema-base
db:check-schema-single-db:
extends:
- - db:migrate-from-previous-major-version-single-db
- - .db:check-schema-base
+ - db:check-schema
+ - .single-db
+ - .rails:rules:single-db
db:check-migrations:
extends:
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml
index 8c51b2cb61a..a214959deab 100644
--- a/.gitlab/ci/rules.gitlab-ci.yml
+++ b/.gitlab/ci/rules.gitlab-ci.yml
@@ -643,9 +643,8 @@
changes: *ci-build-images-patterns
- <<: *if-dot-com-gitlab-org-and-security-merge-request
changes: *code-qa-patterns
- - <<: *if-dot-com-gitlab-org-default-branch
- changes: *code-qa-patterns
- - <<: *if-tag
+ - <<: *if-auto-deploy-branches
+ - <<: *if-default-branch-or-tag
- <<: *if-dot-com-gitlab-org-schedule
- <<: *if-force-ci
diff --git a/GITLAB_ELASTICSEARCH_INDEXER_VERSION b/GITLAB_ELASTICSEARCH_INDEXER_VERSION
index cb2b00e4f7a..b5021469305 100644
--- a/GITLAB_ELASTICSEARCH_INDEXER_VERSION
+++ b/GITLAB_ELASTICSEARCH_INDEXER_VERSION
@@ -1 +1 @@
-3.0.1
+3.0.2
diff --git a/app/assets/javascripts/analytics/shared/components/daterange.vue b/app/assets/javascripts/analytics/shared/components/daterange.vue
index 7df66d1b2be..5ad4464bc88 100644
--- a/app/assets/javascripts/analytics/shared/components/daterange.vue
+++ b/app/assets/javascripts/analytics/shared/components/daterange.vue
@@ -83,7 +83,7 @@ export default {
>
<gl-daterange-picker
v-model="dateRange"
- class="d-flex flex-column flex-lg-row"
+ class="gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row"
:default-start-date="startDate"
:default-end-date="endDate"
:default-min-date="minDate"
@@ -93,7 +93,7 @@ export default {
:tooltip="maxDateRangeTooltip"
theme="animate-picker"
start-picker-class="js-daterange-picker-from gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-lg-align-items-center gl-lg-mr-3 gl-mb-2 gl-lg-mb-0"
- end-picker-class="js-daterange-picker-to d-flex flex-column flex-lg-row align-items-lg-center gl-mb-2 gl-lg-mb-0"
+ end-picker-class="js-daterange-picker-to gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row gl-lg-align-items-center gl-mb-2 gl-lg-mb-0"
label-class="gl-mb-2 gl-lg-mb-0"
>
<gl-sprintf :message="n__('1 day selected', '%d days selected', numberOfDays)">
diff --git a/app/assets/javascripts/content_editor/extensions/paste_markdown.js b/app/assets/javascripts/content_editor/extensions/paste_markdown.js
index f87e4d8d1dd..848c4c12a9a 100644
--- a/app/assets/javascripts/content_editor/extensions/paste_markdown.js
+++ b/app/assets/javascripts/content_editor/extensions/paste_markdown.js
@@ -3,13 +3,7 @@ import { Plugin, PluginKey } from 'prosemirror-state';
import { __ } from '~/locale';
import { VARIANT_DANGER } from '~/flash';
import createMarkdownDeserializer from '../services/gl_api_markdown_deserializer';
-import {
- ALERT_EVENT,
- LOADING_CONTENT_EVENT,
- LOADING_SUCCESS_EVENT,
- LOADING_ERROR_EVENT,
- EXTENSION_PRIORITY_HIGHEST,
-} from '../constants';
+import { ALERT_EVENT, EXTENSION_PRIORITY_HIGHEST } from '../constants';
import CodeBlockHighlight from './code_block_highlight';
import Diagram from './diagram';
import Frontmatter from './frontmatter';
@@ -34,10 +28,8 @@ export default Extension.create({
const { renderMarkdown, eventHub } = options;
const deserializer = createMarkdownDeserializer({ render: renderMarkdown });
- eventHub.$emit(LOADING_CONTENT_EVENT);
-
deserializer
- .deserialize({ schema: editor.schema, content: markdown })
+ .deserialize({ schema: editor.schema, markdown })
.then(({ document }) => {
if (!document) {
return;
@@ -48,14 +40,12 @@ export default Extension.create({
tr.replaceWith(selection.from - 1, selection.to, document.content);
view.dispatch(tr);
- eventHub.$emit(LOADING_SUCCESS_EVENT);
})
.catch(() => {
eventHub.$emit(ALERT_EVENT, {
message: __('An error occurred while pasting text in the editor. Please try again.'),
variant: VARIANT_DANGER,
});
- eventHub.$emit(LOADING_ERROR_EVENT);
});
return true;
diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js
index 7a289df94ea..5ed7f3dc23d 100644
--- a/app/assets/javascripts/content_editor/services/create_content_editor.js
+++ b/app/assets/javascripts/content_editor/services/create_content_editor.js
@@ -127,7 +127,7 @@ export const createContentEditor = ({
MathInline,
OrderedList,
Paragraph,
- PasteMarkdown,
+ PasteMarkdown.configure({ eventHub, renderMarkdown }),
Reference,
ReferenceDefinition,
Sourcemap,
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_table.vue b/app/assets/javascripts/cycle_analytics/components/stage_table.vue
index 85a40b89b77..f1fdffd4b72 100644
--- a/app/assets/javascripts/cycle_analytics/components/stage_table.vue
+++ b/app/assets/javascripts/cycle_analytics/components/stage_table.vue
@@ -246,9 +246,7 @@ export default {
</p>
<p class="gl-m-0">
<span data-testid="vsa-stage-event-build-author-and-date">
- <gl-link class="gl-text-black-normal build-date" :href="item.url">{{
- item.date
- }}</gl-link>
+ <gl-link class="gl-text-black-normal" :href="item.url">{{ item.date }}</gl-link>
{{ s__('ByAuthor|by') }}
<gl-link
class="gl-text-black-normal issue-author-link"
diff --git a/app/assets/javascripts/cycle_analytics/components/total_time.vue b/app/assets/javascripts/cycle_analytics/components/total_time.vue
index a5a90a56974..725952c3518 100644
--- a/app/assets/javascripts/cycle_analytics/components/total_time.vue
+++ b/app/assets/javascripts/cycle_analytics/components/total_time.vue
@@ -52,7 +52,7 @@ export default {
};
</script>
<template>
- <span class="total-time">
+ <span>
<template v-if="hasData">
{{ calculatedTime.duration }} <span>{{ calculatedTime.units }}</span>
</template>
diff --git a/app/assets/javascripts/design_management/components/list/item.vue b/app/assets/javascripts/design_management/components/list/item.vue
index 3092b8554ac..1e36aa686a4 100644
--- a/app/assets/javascripts/design_management/components/list/item.vue
+++ b/app/assets/javascripts/design_management/components/list/item.vue
@@ -128,7 +128,7 @@ export default {
params: { id: filename },
query: $route.query,
}"
- class="card gl-cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
+ class="card gl-cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new gl-mb-0"
>
<div
class="card-body gl-p-0 gl-display-flex gl-align-items-center gl-justify-content-center gl-overflow-hidden gl-relative"
diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue
index 91e35ad3764..07f7a19f7d4 100644
--- a/app/assets/javascripts/design_management/pages/index.vue
+++ b/app/assets/javascripts/design_management/pages/index.vue
@@ -135,7 +135,7 @@ export default {
designDropzoneWrapperClass() {
return this.isDesignListEmpty
? 'col-12'
- : 'gl-flex-direction-column col-md-6 col-lg-3 gl-mb-3';
+ : 'gl-flex-direction-column col-md-6 col-lg-3 gl-mt-5';
},
},
mounted() {
@@ -364,15 +364,15 @@ export default {
data-testid="design-toolbar-wrapper"
>
<div
- class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full gl-flex-wrap"
+ class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-w-full gl-flex-wrap gl-gap-3"
>
- <div class="gl-display-flex gl-align-items-center gl-my-2">
+ <div class="gl-display-flex gl-align-items-center">
<span class="gl-font-weight-bold gl-mr-3">{{ s__('DesignManagement|Designs') }}</span>
<design-version-dropdown />
</div>
<div
v-show="hasDesigns"
- class="gl-display-flex gl-align-items-center gl-my-2"
+ class="gl-display-flex gl-align-items-center"
data-testid="design-selector-toolbar"
>
<gl-button
@@ -413,7 +413,7 @@ export default {
</div>
</div>
</header>
- <div class="gl-mt-6">
+ <div>
<gl-loading-icon v-if="isLoading" size="lg" />
<gl-alert v-else-if="error" variant="danger" :dismissible="false">
{{ __('An error occurred while loading designs. Please try again.') }}
@@ -449,7 +449,7 @@ export default {
<li
v-for="design in designs"
:key="design.id"
- class="col-md-6 col-lg-3 gl-mb-3 gl-bg-transparent gl-shadow-none js-design-tile"
+ class="col-md-6 col-lg-3 gl-mt-5 gl-bg-transparent gl-shadow-none js-design-tile"
>
<design-dropzone
:display-as-card="hasDesigns"
diff --git a/app/assets/javascripts/locale/sprintf.js b/app/assets/javascripts/locale/sprintf.js
index e1749331d90..c8c6b51f374 100644
--- a/app/assets/javascripts/locale/sprintf.js
+++ b/app/assets/javascripts/locale/sprintf.js
@@ -14,6 +14,8 @@ import { escape } from 'lodash';
export default (input, parameters, escapeParameters = true) => {
let output = input;
+ output = output.replace(/%+/g, '%');
+
if (parameters) {
const mappedParameters = new Map(Object.entries(parameters));
diff --git a/app/assets/javascripts/pages/projects/settings/repository/create_deploy_token/index.js b/app/assets/javascripts/pages/projects/settings/repository/create_deploy_token/index.js
index 1dc238b56b4..6a7c6028c95 100644
--- a/app/assets/javascripts/pages/projects/settings/repository/create_deploy_token/index.js
+++ b/app/assets/javascripts/pages/projects/settings/repository/create_deploy_token/index.js
@@ -1,3 +1 @@
-import initForm from '../form';
-
-initForm();
+import '../show/index';
diff --git a/app/assets/javascripts/repository/components/blob_content_viewer.vue b/app/assets/javascripts/repository/components/blob_content_viewer.vue
index 78572f11f6f..902077ba3e4 100644
--- a/app/assets/javascripts/repository/components/blob_content_viewer.vue
+++ b/app/assets/javascripts/repository/components/blob_content_viewer.vue
@@ -13,9 +13,10 @@ import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import WebIdeLink from '~/vue_shared/components/web_ide_link.vue';
import CodeIntelligence from '~/code_navigation/components/app.vue';
import LineHighlighter from '~/blob/line_highlighter';
+import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql';
import addBlameLink from '~/blob/blob_blame_link';
+import projectInfoQuery from '../queries/project_info.query.graphql';
import getRefMixin from '../mixins/get_ref';
-import blobInfoQuery from '../queries/blob_info.query.graphql';
import userInfoQuery from '../queries/user_info.query.graphql';
import applicationInfoQuery from '../queries/application_info.query.graphql';
import { DEFAULT_BLOB_INFO, TEXT_FILE_TYPE, LFS_STORAGE, LEGACY_FILE_TYPES } from '../constants';
@@ -41,6 +42,21 @@ export default {
},
},
apollo: {
+ projectInfo: {
+ query: projectInfoQuery,
+ variables() {
+ return {
+ projectPath: this.projectPath,
+ };
+ },
+ error() {
+ this.displayError();
+ },
+ update({ project }) {
+ this.pathLocks = project.pathLocks || DEFAULT_BLOB_INFO.pathLocks;
+ this.userPermissions = project.userPermissions;
+ },
+ },
gitpodEnabled: {
query: applicationInfoQuery,
error() {
@@ -121,6 +137,8 @@ export default {
gitpodEnabled: DEFAULT_BLOB_INFO.gitpodEnabled,
currentUser: DEFAULT_BLOB_INFO.currentUser,
useFallback: false,
+ pathLocks: DEFAULT_BLOB_INFO.pathLocks,
+ userPermissions: DEFAULT_BLOB_INFO.userPermissions,
};
},
computed: {
@@ -163,7 +181,7 @@ export default {
);
},
canLock() {
- const { pushCode, downloadCode } = this.project.userPermissions;
+ const { pushCode, downloadCode } = this.userPermissions;
const currentUsername = window.gon?.current_username;
if (this.pathLockedByUser && this.pathLockedByUser.username !== currentUsername) {
@@ -173,12 +191,12 @@ export default {
return pushCode && downloadCode;
},
pathLockedByUser() {
- const pathLock = this.project?.pathLocks?.nodes.find((node) => node.path === this.path);
+ const pathLock = this.pathLocks?.nodes.find((node) => node.path === this.path);
return pathLock ? pathLock.user : null;
},
showForkSuggestion() {
- const { createMergeRequestIn, forkProject } = this.project.userPermissions;
+ const { createMergeRequestIn, forkProject } = this.userPermissions;
const { canModifyBlob } = this.blobInfo;
return this.isLoggedIn && !canModifyBlob && createMergeRequestIn && forkProject;
@@ -338,7 +356,7 @@ export default {
:name="blobInfo.name"
:replace-path="blobInfo.replacePath"
:delete-path="blobInfo.webPath"
- :can-push-code="project.userPermissions.pushCode"
+ :can-push-code="userPermissions.pushCode"
:can-push-to-branch="blobInfo.canCurrentUserPushToBranch"
:empty-repo="project.repository.empty"
:project-path="projectPath"
diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue
index 49a18f40db9..c8cd64b5311 100644
--- a/app/assets/javascripts/repository/components/table/row.vue
+++ b/app/assets/javascripts/repository/components/table/row.vue
@@ -17,8 +17,8 @@ import { TREE_PAGE_SIZE, ROW_APPEAR_DELAY } from '~/repository/constants';
import FileIcon from '~/vue_shared/components/file_icon.vue';
import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql';
import getRefMixin from '../../mixins/get_ref';
-import blobInfoQuery from '../../queries/blob_info.query.graphql';
import commitQuery from '../../queries/commit.query.graphql';
export default {
diff --git a/app/assets/javascripts/repository/queries/project_info.query.graphql b/app/assets/javascripts/repository/queries/project_info.query.graphql
new file mode 100644
index 00000000000..7a380d25bb1
--- /dev/null
+++ b/app/assets/javascripts/repository/queries/project_info.query.graphql
@@ -0,0 +1,14 @@
+#import "ee_else_ce/repository/queries/path_locks.fragment.graphql"
+
+query getProjectInfo($projectPath: ID!) {
+ project(fullPath: $projectPath) {
+ id
+ userPermissions {
+ pushCode
+ downloadCode
+ createMergeRequestIn
+ forkProject
+ }
+ ...ProjectPathLocksFragment
+ }
+}
diff --git a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
index 424cab20c7e..a001b6bdf24 100644
--- a/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
+++ b/app/assets/javascripts/vue_shared/components/upload_dropzone/upload_dropzone.vue
@@ -149,7 +149,7 @@ export default {
>
<slot>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
@click="openFileUpload"
>
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index 94c37219260..c3733344131 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -97,6 +97,15 @@ export default {
error() {
this.error = this.$options.i18n.fetchError;
},
+ result() {
+ if (!this.isModal) {
+ const path = this.workItem.project?.fullPath
+ ? ` · ${this.workItem.project.fullPath}`
+ : '';
+
+ document.title = `${this.workItem.title} · ${this.workItem?.workItemType?.name}${path}`;
+ }
+ },
subscribeToMore: {
document: workItemTitleSubscription,
variables() {
diff --git a/app/assets/javascripts/repository/queries/blob_info.query.graphql b/app/graphql/queries/repository/blob_info.query.graphql
index 45a7793e559..fd463436ed4 100644
--- a/app/assets/javascripts/repository/queries/blob_info.query.graphql
+++ b/app/graphql/queries/repository/blob_info.query.graphql
@@ -1,5 +1,3 @@
-#import "ee_else_ce/repository/queries/path_locks.fragment.graphql"
-
query getBlobInfo(
$projectPath: ID!
$filePath: String!
@@ -7,17 +5,15 @@ query getBlobInfo(
$shouldFetchRawText: Boolean!
) {
project(fullPath: $projectPath) {
- userPermissions {
- pushCode
- downloadCode
- createMergeRequestIn
- forkProject
- }
- ...ProjectPathLocksFragment
+ __typename
+ id
repository {
+ __typename
empty
blobs(paths: [$filePath], ref: $ref) {
+ __typename
nodes {
+ __typename
id
webPath
name
diff --git a/app/mailers/previews/notify_preview.rb b/app/mailers/previews/notify_preview.rb
index 7dfb62dc973..15b6fec3548 100644
--- a/app/mailers/previews/notify_preview.rb
+++ b/app/mailers/previews/notify_preview.rb
@@ -65,7 +65,7 @@ class NotifyPreview < ActionMailer::Preview
end
def new_mention_in_merge_request_email
- Notify.new_mention_in_merge_request_email(user.id, issue.id, user.id).message
+ Notify.new_mention_in_merge_request_email(user.id, merge_request.id, user.id).message
end
def closed_issue_email
@@ -101,7 +101,7 @@ class NotifyPreview < ActionMailer::Preview
end
def closed_merge_request_email
- Notify.closed_merge_request_email(user.id, issue.id, user.id).message
+ Notify.closed_merge_request_email(user.id, merge_request.id, user.id).message
end
def merge_request_status_email
@@ -209,14 +209,6 @@ class NotifyPreview < ActionMailer::Preview
Notify.inactive_project_deletion_warning_email(project, user, '2022-04-22').message
end
- def user_auto_banned_instance_email
- ::Notify.user_auto_banned_email(user.id, user.id, max_project_downloads: 5, within_seconds: 600).message
- end
-
- def user_auto_banned_namespace_email
- ::Notify.user_auto_banned_email(user.id, user.id, max_project_downloads: 5, within_seconds: 600, group: group).message
- end
-
def verification_instructions_email
Notify.verification_instructions_email(user.id, token: '123456', expires_in: 60).message
end
@@ -224,7 +216,7 @@ class NotifyPreview < ActionMailer::Preview
private
def project
- @project ||= Project.find_by_full_path('gitlab-org/gitlab-test')
+ @project ||= Project.first
end
def issue
diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb
index 411ed9805f1..922806a21c3 100644
--- a/app/models/ci/job_artifact.rb
+++ b/app/models/ci/job_artifact.rb
@@ -2,6 +2,7 @@
module Ci
class JobArtifact < Ci::ApplicationRecord
+ include Ci::Partitionable
include IgnorableColumns
include AfterCommitQueue
include ObjectStorage::BackgroundMove
@@ -134,14 +135,16 @@ module Ci
mount_file_store_uploader JobArtifactUploader, skip_store_file: true
+ before_save :set_size, if: :file_changed?
after_save :store_file_in_transaction!, unless: :store_after_commit?
after_commit :store_file_after_transaction!, on: [:create, :update], if: :store_after_commit?
+ validates :job, presence: true
validates :file_format, presence: true, unless: :trace?, on: :create
validate :validate_file_format!, unless: :trace?, on: :create
- before_save :set_size, if: :file_changed?
update_project_statistics project_statistics_name: :build_artifacts_size
+ partitionable scope: :job
scope :not_expired, -> { where('expire_at IS NULL OR expire_at > ?', Time.current) }
scope :for_sha, ->(sha, project_id) { joins(job: :pipeline).where(ci_pipelines: { sha: sha, project_id: project_id }) }
diff --git a/app/models/concerns/ci/partitionable.rb b/app/models/concerns/ci/partitionable.rb
new file mode 100644
index 00000000000..08a4a6c950f
--- /dev/null
+++ b/app/models/concerns/ci/partitionable.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Ci
+ ##
+ # This module implements a way to set the `partion_id` value on a dependent
+ # resource from a parent record.
+ # Usage:
+ #
+ # class PipelineVariable < Ci::ApplicationRecord
+ # include Ci::Partitionable
+ #
+ # belongs_to :pipeline
+ # partitionable scope: :pipeline
+ #
+ module Partitionable
+ extend ActiveSupport::Concern
+ include ::Gitlab::Utils::StrongMemoize
+
+ included do
+ before_validation :set_partition_id, on: :create
+ validates :partition_id, presence: true
+
+ def set_partition_id
+ return unless partition_scope_record
+
+ self.partition_id = partition_scope_record.partition_id
+ end
+ end
+
+ class_methods do
+ private
+
+ def partitionable(scope:)
+ define_method(:partition_scope_record) do
+ strong_memoize(:partition_scope_record) do
+ scope.to_proc.call(self)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/services/ci/job_artifacts/create_service.rb b/app/services/ci/job_artifacts/create_service.rb
index af56eb221d5..3dc097a8603 100644
--- a/app/services/ci/job_artifacts/create_service.rb
+++ b/app/services/ci/job_artifacts/create_service.rb
@@ -80,7 +80,7 @@ module Ci
Gitlab::CurrentSettings.current_application_settings.default_artifacts_expire_in
artifact_attributes = {
- job_id: job.id,
+ job: job,
project: project,
expire_in: expire_in
}
diff --git a/app/views/projects/blob/show.html.haml b/app/views/projects/blob/show.html.haml
index 16ecc1cc5a0..33b2229f5d1 100644
--- a/app/views/projects/blob/show.html.haml
+++ b/app/views/projects/blob/show.html.haml
@@ -3,6 +3,7 @@
- signatures_path = namespace_project_signatures_path(namespace_id: @project.namespace.full_path, project_id: @project.path, id: @last_commit, limit: 1)
- content_for :prefetch_asset_tags do
- webpack_preload_asset_tag('monaco', prefetch: true)
+- add_page_startup_graphql_call('repository/blob_info', { projectPath: @project.full_path, ref: current_ref, filePath: @blob.path, shouldFetchRawText: @blob.rendered_as_text? && !@blob.rich_viewer })
.js-signature-container{ data: { 'signatures-path': signatures_path } }
diff --git a/app/views/shared/milestones/_milestone.html.haml b/app/views/shared/milestones/_milestone.html.haml
index 59d1537aa2b..01548325c83 100644
--- a/app/views/shared/milestones/_milestone.html.haml
+++ b/app/views/shared/milestones/_milestone.html.haml
@@ -43,7 +43,8 @@
- if milestone.merge_requests_enabled?
&middot;
= link_to pluralize(milestone.total_merge_requests_count, _('Merge request')), merge_requests_path
- .float-lg-right.light #{milestone.percent_complete}% complete
+ .float-lg-right.light
+ = format(s_('Milestone|%{percentage}%{percent} complete'), percentage: milestone.percent_complete, percent: '%')
.col-md-2
.milestone-actions.d-flex.justify-content-sm-start.justify-content-md-end
- if @project # if in milestones list on project level
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 52ac75dfa2c..5e67ed71954 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -63,7 +63,7 @@ Rails.application.configure do
config.action_mailer.raise_delivery_errors = true
# Don't make a mess when bootstrapping a development environment
config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1')
- config.action_mailer.preview_path = "#{Rails.root}{/ee,}/app/mailers/previews"
+ config.action_mailer.preview_path = GitlabEdition.path_glob('app/mailers/previews')
config.eager_load = false
diff --git a/config/environments/test.rb b/config/environments/test.rb
index f4d3d2ddfda..41413c55ba4 100644
--- a/config/environments/test.rb
+++ b/config/environments/test.rb
@@ -48,6 +48,8 @@ Rails.application.configure do
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
+ config.action_mailer.preview_path = GitlabEdition.path_glob('app/mailers/previews')
+
# Print deprecation notices to the stderr
config.active_support.deprecation = :stderr
diff --git a/config/metrics/aggregates/code_review.yml b/config/metrics/aggregates/code_review.yml
index 7cf61ea9972..e58707b20a5 100644
--- a/config/metrics/aggregates/code_review.yml
+++ b/config/metrics/aggregates/code_review.yml
@@ -118,6 +118,12 @@
- 'i_code_review_merge_request_widget_status_checks_expand_failed'
- 'i_code_review_submit_review_approve'
- 'i_code_review_submit_review_comment'
+ - 'i_code_review_merge_request_widget_license_compliance_view'
+ - 'i_code_review_merge_request_widget_license_compliance_full_report_clicked'
+ - 'i_code_review_merge_request_widget_license_compliance_expand'
+ - 'i_code_review_merge_request_widget_license_compliance_expand_success'
+ - 'i_code_review_merge_request_widget_license_compliance_expand_warning'
+ - 'i_code_review_merge_request_widget_license_compliance_expand_failed'
- name: code_review_category_monthly_active_users
operator: OR
source: redis
@@ -224,6 +230,12 @@
- 'i_code_review_merge_request_widget_status_checks_expand_failed'
- 'i_code_review_submit_review_approve'
- 'i_code_review_submit_review_comment'
+ - 'i_code_review_merge_request_widget_license_compliance_view'
+ - 'i_code_review_merge_request_widget_license_compliance_full_report_clicked'
+ - 'i_code_review_merge_request_widget_license_compliance_expand'
+ - 'i_code_review_merge_request_widget_license_compliance_expand_success'
+ - 'i_code_review_merge_request_widget_license_compliance_expand_warning'
+ - 'i_code_review_merge_request_widget_license_compliance_expand_failed'
- name: code_review_extension_category_monthly_active_users
operator: OR
source: redis
diff --git a/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml
index 33920c7f312..4d8e4409e73 100644
--- a/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184454_code_review_total_unique_counts_monthly.yml
@@ -66,6 +66,12 @@ options:
- i_code_review_merge_request_widget_test_summary_expand_warning
- i_code_review_merge_request_widget_test_summary_full_report_clicked
- i_code_review_merge_request_widget_test_summary_view
+ - i_code_review_merge_request_widget_license_compliance_expand
+ - i_code_review_merge_request_widget_license_compliance_expand_failed
+ - i_code_review_merge_request_widget_license_compliance_expand_success
+ - i_code_review_merge_request_widget_license_compliance_warning
+ - i_code_review_merge_request_widget_license_compliance_full_report_clicked
+ - i_code_review_merge_request_widget_license_compliance_view
- i_code_review_mr_diffs
- i_code_review_mr_single_file_diffs
- i_code_review_mr_with_invalid_approvers
diff --git a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
index 5224f61c5fc..2c6b21b0f6f 100755
--- a/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
+++ b/config/metrics/counts_28d/20210216184559_ci_templates_total_unique_counts_monthly.yml
@@ -51,6 +51,7 @@ options:
- p_ci_templates_security_dast_api
- p_ci_templates_security_dast_api_latest
- p_ci_templates_security_container_scanning
+ - p_ci_templates_security_container_scanning_latest
- p_ci_templates_security_dast_latest
- p_ci_templates_security_dependency_scanning
- p_ci_templates_security_api_fuzzing
@@ -94,7 +95,9 @@ options:
- p_ci_templates_jobs_code_intelligence
- p_ci_templates_jobs_code_quality
- p_ci_templates_jobs_dependency_scanning
+ - p_ci_templates_jobs_dependency_scanning_latest
- p_ci_templates_jobs_license_scanning
+ - p_ci_templates_jobs_license_scanning_latest
- p_ci_templates_jobs_deploy_ecs
- p_ci_templates_jobs_deploy_ec2
- p_ci_templates_jobs_deploy
@@ -140,7 +143,9 @@ options:
- p_ci_templates_implicit_jobs_code_intelligence
- p_ci_templates_implicit_jobs_code_quality
- p_ci_templates_implicit_jobs_dependency_scanning
+ - p_ci_templates_implicit_jobs_dependency_scanning_latest
- p_ci_templates_implicit_jobs_license_scanning
+ - p_ci_templates_implicit_jobs_license_scanning_latest
- p_ci_templates_implicit_jobs_deploy_ecs
- p_ci_templates_implicit_jobs_deploy_ec2
- p_ci_templates_implicit_auto_devops_deploy
@@ -163,6 +168,7 @@ options:
- p_ci_templates_implicit_security_dast_api
- p_ci_templates_implicit_security_dast_api_latest
- p_ci_templates_implicit_security_container_scanning
+ - p_ci_templates_implicit_security_container_scanning_latest
- p_ci_templates_implicit_security_dast_latest
- p_ci_templates_implicit_security_dependency_scanning
- p_ci_templates_implicit_security_api_fuzzing
diff --git a/config/metrics/counts_28d/20220830104453_i_code_review_merge_request_widget_license_compliance_view_monthly.yml b/config/metrics/counts_28d/20220830104453_i_code_review_merge_request_widget_license_compliance_view_monthly.yml
new file mode 100644
index 00000000000..60567037303
--- /dev/null
+++ b/config/metrics/counts_28d/20220830104453_i_code_review_merge_request_widget_license_compliance_view_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_view_monthly
+description: The count of unique users (monthly) who were able to see the License Compliance widget extension
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_view
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20220830104500_i_code_review_merge_request_widget_license_compliance_full_report_clicked_monthly.yml b/config/metrics/counts_28d/20220830104500_i_code_review_merge_request_widget_license_compliance_full_report_clicked_monthly.yml
new file mode 100644
index 00000000000..3b4c0012495
--- /dev/null
+++ b/config/metrics/counts_28d/20220830104500_i_code_review_merge_request_widget_license_compliance_full_report_clicked_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_full_report_clicked_monthly
+description: The count of unique users (monthly) who clicked the Full Report button on the License Compliance widget extension
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_full_report_clicked
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20220830104507_i_code_review_merge_request_widget_license_compliance_expand_monthly.yml b/config/metrics/counts_28d/20220830104507_i_code_review_merge_request_widget_license_compliance_expand_monthly.yml
new file mode 100644
index 00000000000..7b0ec9d0518
--- /dev/null
+++ b/config/metrics/counts_28d/20220830104507_i_code_review_merge_request_widget_license_compliance_expand_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_monthly
+description: The count of unique users (monthly) who expanded the License Compliance widget extension
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20220830104514_i_code_review_merge_request_widget_license_compliance_expand_success_monthly.yml b/config/metrics/counts_28d/20220830104514_i_code_review_merge_request_widget_license_compliance_expand_success_monthly.yml
new file mode 100644
index 00000000000..c6b7689c844
--- /dev/null
+++ b/config/metrics/counts_28d/20220830104514_i_code_review_merge_request_widget_license_compliance_expand_success_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_success_monthly
+description: The count of unique users (monthly) who expanded the License Compliance widget extension while it is in its Success state
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand_success
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20220830104521_i_code_review_merge_request_widget_license_compliance_expand_warning_monthly.yml b/config/metrics/counts_28d/20220830104521_i_code_review_merge_request_widget_license_compliance_expand_warning_monthly.yml
new file mode 100644
index 00000000000..5e164b5c3bf
--- /dev/null
+++ b/config/metrics/counts_28d/20220830104521_i_code_review_merge_request_widget_license_compliance_expand_warning_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_warning_monthly
+description: The count of unique users (monthly) who expanded the License Compliance widget extension while it is in its Warning state
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand_warning
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20220830104528_i_code_review_merge_request_widget_license_compliance_expand_failed_monthly.yml b/config/metrics/counts_28d/20220830104528_i_code_review_merge_request_widget_license_compliance_expand_failed_monthly.yml
new file mode 100644
index 00000000000..69af6c70299
--- /dev/null
+++ b/config/metrics/counts_28d/20220830104528_i_code_review_merge_request_widget_license_compliance_expand_failed_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_failed_monthly
+description: The count of unique users (monthly) who expanded the License Compliance widget extension while it is in its Failed state
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand_failed
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20220907202807_p_ci_templates_jobs_dependency_scanning_latest_monthly.yml b/config/metrics/counts_28d/20220907202807_p_ci_templates_jobs_dependency_scanning_latest_monthly.yml
new file mode 100644
index 00000000000..9cbfee008c3
--- /dev/null
+++ b/config/metrics/counts_28d/20220907202807_p_ci_templates_jobs_dependency_scanning_latest_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_dependency_scanning_latest_monthly
+description: Monthly counts for Dependency Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: dependency_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_jobs_dependency_scanning_latest
diff --git a/config/metrics/counts_28d/20220907212005_p_ci_templates_security_container_scanning_latest_monthly.yml b/config/metrics/counts_28d/20220907212005_p_ci_templates_security_container_scanning_latest_monthly.yml
new file mode 100644
index 00000000000..fbf263cd6bc
--- /dev/null
+++ b/config/metrics/counts_28d/20220907212005_p_ci_templates_security_container_scanning_latest_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_security_container_scanning_latest_monthly
+description: Monthly counts for Container Scanning CI Latest template (Security folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: container_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_security_container_scanning_latest
diff --git a/config/metrics/counts_28d/20220907215635_p_ci_templates_jobs_license_scanning_latest_monthly.yml b/config/metrics/counts_28d/20220907215635_p_ci_templates_jobs_license_scanning_latest_monthly.yml
new file mode 100644
index 00000000000..b78e5bc65fa
--- /dev/null
+++ b/config/metrics/counts_28d/20220907215635_p_ci_templates_jobs_license_scanning_latest_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_license_scanning_latest_monthly
+description: Monthly counts for License Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: license_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_jobs_license_scanning_latest
diff --git a/config/metrics/counts_28d/20220912161240_p_ci_templates_implicit_jobs_dependency_scanning_latest_monthly.yml b/config/metrics/counts_28d/20220912161240_p_ci_templates_implicit_jobs_dependency_scanning_latest_monthly.yml
new file mode 100644
index 00000000000..a3a435fca09
--- /dev/null
+++ b/config/metrics/counts_28d/20220912161240_p_ci_templates_implicit_jobs_dependency_scanning_latest_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_dependency_scanning_latest_monthly
+description: Monthly counts for implicit Dependency Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: dependency_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_implicit_jobs_dependency_scanning_latest
diff --git a/config/metrics/counts_28d/20220912162308_p_ci_templates_implicit_jobs_license_scanning_latest_monthly.yml b/config/metrics/counts_28d/20220912162308_p_ci_templates_implicit_jobs_license_scanning_latest_monthly.yml
new file mode 100644
index 00000000000..acc48ff2a44
--- /dev/null
+++ b/config/metrics/counts_28d/20220912162308_p_ci_templates_implicit_jobs_license_scanning_latest_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_license_scanning_latest_monthly
+description: Monthly counts for implicit License Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: license_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_implicit_jobs_license_scanning_latest
diff --git a/config/metrics/counts_28d/20220912162752_p_ci_templates_implicit_security_container_scanning_latest_monthly.yml b/config/metrics/counts_28d/20220912162752_p_ci_templates_implicit_security_container_scanning_latest_monthly.yml
new file mode 100644
index 00000000000..2aebbc3a9eb
--- /dev/null
+++ b/config/metrics/counts_28d/20220912162752_p_ci_templates_implicit_security_container_scanning_latest_monthly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_container_scanning_latest_monthly
+description: Monthly counts for implicit Container Scanning CI Latest template (Security folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: container_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 28d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_implicit_security_container_scanning_latest
diff --git a/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml
index 1fe239e7d6f..60619deb786 100644
--- a/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184452_code_review_total_unique_counts_weekly.yml
@@ -66,6 +66,12 @@ options:
- i_code_review_merge_request_widget_test_summary_expand_warning
- i_code_review_merge_request_widget_test_summary_full_report_clicked
- i_code_review_merge_request_widget_test_summary_view
+ - i_code_review_merge_request_widget_license_compliance_expand
+ - i_code_review_merge_request_widget_license_compliance_expand_failed
+ - i_code_review_merge_request_widget_license_compliance_expand_success
+ - i_code_review_merge_request_widget_license_compliance_warning
+ - i_code_review_merge_request_widget_license_compliance_full_report_clicked
+ - i_code_review_merge_request_widget_license_compliance_view
- i_code_review_mr_diffs
- i_code_review_mr_single_file_diffs
- i_code_review_mr_with_invalid_approvers
diff --git a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
index faaf5be63a0..16186a412b8 100755
--- a/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
+++ b/config/metrics/counts_7d/20210216184557_ci_templates_total_unique_counts_weekly.yml
@@ -51,6 +51,7 @@ options:
- p_ci_templates_security_dast_api
- p_ci_templates_security_dast_api_latest
- p_ci_templates_security_container_scanning
+ - p_ci_templates_security_container_scanning_latest
- p_ci_templates_security_dast_latest
- p_ci_templates_security_dependency_scanning
- p_ci_templates_security_api_fuzzing
@@ -94,7 +95,9 @@ options:
- p_ci_templates_jobs_code_intelligence
- p_ci_templates_jobs_code_quality
- p_ci_templates_jobs_dependency_scanning
+ - p_ci_templates_jobs_dependency_scanning_latest
- p_ci_templates_jobs_license_scanning
+ - p_ci_templates_jobs_license_scanning_latest
- p_ci_templates_jobs_deploy_ecs
- p_ci_templates_jobs_deploy_ec2
- p_ci_templates_jobs_deploy
diff --git a/config/metrics/counts_7d/20220830104410_i_code_review_merge_request_widget_license_compliance_view_weekly.yml b/config/metrics/counts_7d/20220830104410_i_code_review_merge_request_widget_license_compliance_view_weekly.yml
new file mode 100644
index 00000000000..6e9415bdc42
--- /dev/null
+++ b/config/metrics/counts_7d/20220830104410_i_code_review_merge_request_widget_license_compliance_view_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_view_weekly
+description: The count of unique users (weekly) who were able to see the License Compliance widget extension
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_view
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220830104418_i_code_review_merge_request_widget_license_compliance_full_report_clicked_weekly.yml b/config/metrics/counts_7d/20220830104418_i_code_review_merge_request_widget_license_compliance_full_report_clicked_weekly.yml
new file mode 100644
index 00000000000..c3a8d7bfdfb
--- /dev/null
+++ b/config/metrics/counts_7d/20220830104418_i_code_review_merge_request_widget_license_compliance_full_report_clicked_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_full_report_clicked_weekly
+description: The count of unique users (weekly) who clicked the Full Report button on the License Compliance widget extension
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_full_report_clicked
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220830104424_i_code_review_merge_request_widget_license_compliance_expand_weekly.yml b/config/metrics/counts_7d/20220830104424_i_code_review_merge_request_widget_license_compliance_expand_weekly.yml
new file mode 100644
index 00000000000..69083c5ca2c
--- /dev/null
+++ b/config/metrics/counts_7d/20220830104424_i_code_review_merge_request_widget_license_compliance_expand_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_weekly
+description: The count of unique users (weekly) who expanded the License Compliance widget extension
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220830104431_i_code_review_merge_request_widget_license_compliance_expand_success_weekly.yml b/config/metrics/counts_7d/20220830104431_i_code_review_merge_request_widget_license_compliance_expand_success_weekly.yml
new file mode 100644
index 00000000000..d145ae31f38
--- /dev/null
+++ b/config/metrics/counts_7d/20220830104431_i_code_review_merge_request_widget_license_compliance_expand_success_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_success_weekly
+description: The count of unique users (weekly) who expanded the License Compliance widget extension while it is in its Success state
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand_success
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220830104438_i_code_review_merge_request_widget_license_compliance_expand_warning_weekly.yml b/config/metrics/counts_7d/20220830104438_i_code_review_merge_request_widget_license_compliance_expand_warning_weekly.yml
new file mode 100644
index 00000000000..58c3d89497f
--- /dev/null
+++ b/config/metrics/counts_7d/20220830104438_i_code_review_merge_request_widget_license_compliance_expand_warning_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_warning_weekly
+description: The count of unique users (weekly) who expanded the License Compliance widget extension while it is in its Warning state
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand_warning
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220830104446_i_code_review_merge_request_widget_license_compliance_expand_failed_weekly.yml b/config/metrics/counts_7d/20220830104446_i_code_review_merge_request_widget_license_compliance_expand_failed_weekly.yml
new file mode 100644
index 00000000000..d8d9637f920
--- /dev/null
+++ b/config/metrics/counts_7d/20220830104446_i_code_review_merge_request_widget_license_compliance_expand_failed_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.code_review.i_code_review_merge_request_widget_license_compliance_expand_failed_weekly
+description: The count of unique users (weekly) who expanded the License Compliance widget extension while it is in its Failed state
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_expand_failed
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_7d/20220907202801_p_ci_templates_jobs_dependency_scanning_latest_weekly.yml b/config/metrics/counts_7d/20220907202801_p_ci_templates_jobs_dependency_scanning_latest_weekly.yml
new file mode 100644
index 00000000000..c2a9f72ec8b
--- /dev/null
+++ b/config/metrics/counts_7d/20220907202801_p_ci_templates_jobs_dependency_scanning_latest_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_dependency_scanning_latest_weekly
+description: Weekly counts for Dependency Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: dependency_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_jobs_dependency_scanning_latest
diff --git a/config/metrics/counts_7d/20220907211959_p_ci_templates_security_container_scanning_latest_weekly.yml b/config/metrics/counts_7d/20220907211959_p_ci_templates_security_container_scanning_latest_weekly.yml
new file mode 100644
index 00000000000..8e7c6e8cbaf
--- /dev/null
+++ b/config/metrics/counts_7d/20220907211959_p_ci_templates_security_container_scanning_latest_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_security_container_scanning_latest_weekly
+description: Weekly counts for Container Scanning CI Latest template (Security folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: container_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_security_container_scanning_latest
diff --git a/config/metrics/counts_7d/20220907215629_p_ci_templates_jobs_license_scanning_latest_weekly.yml b/config/metrics/counts_7d/20220907215629_p_ci_templates_jobs_license_scanning_latest_weekly.yml
new file mode 100644
index 00000000000..f3cb628da5a
--- /dev/null
+++ b/config/metrics/counts_7d/20220907215629_p_ci_templates_jobs_license_scanning_latest_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_jobs_license_scanning_latest_weekly
+description: Weekly counts for License Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: license_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_jobs_license_scanning_latest
diff --git a/config/metrics/counts_7d/20220912161233_p_ci_templates_implicit_jobs_dependency_scanning_latest_weekly.yml b/config/metrics/counts_7d/20220912161233_p_ci_templates_implicit_jobs_dependency_scanning_latest_weekly.yml
new file mode 100644
index 00000000000..243d24bcf50
--- /dev/null
+++ b/config/metrics/counts_7d/20220912161233_p_ci_templates_implicit_jobs_dependency_scanning_latest_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_dependency_scanning_latest_weekly
+description: Weekly counts for implicit Dependency Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: dependency_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_implicit_jobs_dependency_scanning_latest
diff --git a/config/metrics/counts_7d/20220912162301_p_ci_templates_implicit_jobs_license_scanning_latest_weekly.yml b/config/metrics/counts_7d/20220912162301_p_ci_templates_implicit_jobs_license_scanning_latest_weekly.yml
new file mode 100644
index 00000000000..8fdd6c15c1d
--- /dev/null
+++ b/config/metrics/counts_7d/20220912162301_p_ci_templates_implicit_jobs_license_scanning_latest_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_jobs_license_scanning_latest_weekly
+description: Weekly counts for implicit License Scanning CI Latest template (Jobs folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: license_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_implicit_jobs_license_scanning_latest
diff --git a/config/metrics/counts_7d/20220912162745_p_ci_templates_implicit_security_container_scanning_latest_weekly.yml b/config/metrics/counts_7d/20220912162745_p_ci_templates_implicit_security_container_scanning_latest_weekly.yml
new file mode 100644
index 00000000000..c3818fb819c
--- /dev/null
+++ b/config/metrics/counts_7d/20220912162745_p_ci_templates_implicit_security_container_scanning_latest_weekly.yml
@@ -0,0 +1,25 @@
+---
+key_path: redis_hll_counters.ci_templates.p_ci_templates_implicit_security_container_scanning_latest_weekly
+description: Weekly counts for implicit Container Scanning CI Latest template (Security folder)
+product_section: sec
+product_stage: secure
+product_group: composition_analysis
+product_category: container_scanning
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/97323'
+time_frame: 7d
+data_source: redis_hll
+data_category: optional
+instrumentation_class: RedisHLLMetric
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
+options:
+ events:
+ - p_ci_templates_implicit_security_container_scanning_latest
diff --git a/config/metrics/counts_all/20220825115210_i_merge_request_widget_license_compliance_count_view.yml b/config/metrics/counts_all/20220825115210_i_merge_request_widget_license_compliance_count_view.yml
new file mode 100644
index 00000000000..3542f4fd8ac
--- /dev/null
+++ b/config/metrics/counts_all/20220825115210_i_merge_request_widget_license_compliance_count_view.yml
@@ -0,0 +1,24 @@
+---
+key_path: counts.i_code_review_merge_request_widget_license_compliance_count_view
+description: Total number of times the License Compliance widget extension was viewed (rendered to the screen)
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: all
+data_source: redis
+data_category: optional
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_count_view
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220825115217_i_merge_request_widget_license_compliance_count_full_report_clicked.yml b/config/metrics/counts_all/20220825115217_i_merge_request_widget_license_compliance_count_full_report_clicked.yml
new file mode 100644
index 00000000000..580d0d4dff3
--- /dev/null
+++ b/config/metrics/counts_all/20220825115217_i_merge_request_widget_license_compliance_count_full_report_clicked.yml
@@ -0,0 +1,24 @@
+---
+key_path: counts.i_code_review_merge_request_widget_license_compliance_count_full_report_clicked
+description: Total number of times the License Compliance widget extension Full Report button was clicked
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: all
+data_source: redis
+data_category: optional
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_count_full_report_clicked
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220825115224_i_merge_request_widget_license_compliance_count_expand.yml b/config/metrics/counts_all/20220825115224_i_merge_request_widget_license_compliance_count_expand.yml
new file mode 100644
index 00000000000..1829e1c87c0
--- /dev/null
+++ b/config/metrics/counts_all/20220825115224_i_merge_request_widget_license_compliance_count_expand.yml
@@ -0,0 +1,24 @@
+---
+key_path: counts.i_code_review_merge_request_widget_license_compliance_count_expand
+description: Total number of times the License Compliance widget extension was expanded (in any state)
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: all
+data_source: redis
+data_category: optional
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_count_expand
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220825115230_i_merge_request_widget_license_compliance_count_expand_success.yml b/config/metrics/counts_all/20220825115230_i_merge_request_widget_license_compliance_count_expand_success.yml
new file mode 100644
index 00000000000..4a8f35a7c5b
--- /dev/null
+++ b/config/metrics/counts_all/20220825115230_i_merge_request_widget_license_compliance_count_expand_success.yml
@@ -0,0 +1,24 @@
+---
+key_path: counts.i_code_review_merge_request_widget_license_compliance_count_expand_success
+description: Total number of times the License Compliance widget extension was expanded (while in its Success state)
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: all
+data_source: redis
+data_category: optional
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_count_expand_success
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220825115236_i_merge_request_widget_license_compliance_count_expand_warning.yml b/config/metrics/counts_all/20220825115236_i_merge_request_widget_license_compliance_count_expand_warning.yml
new file mode 100644
index 00000000000..1ebc20fca26
--- /dev/null
+++ b/config/metrics/counts_all/20220825115236_i_merge_request_widget_license_compliance_count_expand_warning.yml
@@ -0,0 +1,24 @@
+---
+key_path: counts.i_code_review_merge_request_widget_license_compliance_count_expand_warning
+description: Total number of times the License Compliance widget extension was expanded (while in its Warning state)
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: all
+data_source: redis
+data_category: optional
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_count_expand_warning
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20220825115242_i_merge_request_widget_license_compliance_count_expand_failed.yml b/config/metrics/counts_all/20220825115242_i_merge_request_widget_license_compliance_count_expand_failed.yml
new file mode 100644
index 00000000000..7fe8263a53e
--- /dev/null
+++ b/config/metrics/counts_all/20220825115242_i_merge_request_widget_license_compliance_count_expand_failed.yml
@@ -0,0 +1,24 @@
+---
+key_path: counts.i_code_review_merge_request_widget_license_compliance_count_expand_failed
+description: Total number of times the License Compliance widget extension was expanded (while in its Failed state)
+product_section: dev
+product_stage: create
+product_group: code_review
+product_category: code_review
+value_type: number
+status: active
+milestone: "15.4"
+introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96538"
+time_frame: all
+data_source: redis
+data_category: optional
+options:
+ events:
+ - i_code_review_merge_request_widget_license_compliance_count_expand_failed
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 742f09124fd..a6cc582e12d 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -9909,6 +9909,7 @@ Represents an epic on an issue board.
| <a id="boardepiccolor"></a>`color` | [`String`](#string) | Color of the epic. Returns `null` if `epic_color_highlight` feature flag is disabled. |
| <a id="boardepicconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. |
| <a id="boardepiccreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of when the epic was created. |
+| <a id="boardepicdefaultprojectforissuecreation"></a>`defaultProjectForIssueCreation` | [`Project`](#project) | Default Project for issue creation. Based on the project the user created the last issue in. |
| <a id="boardepicdescendantcounts"></a>`descendantCounts` | [`EpicDescendantCount`](#epicdescendantcount) | Number of open and closed descendant epics and issues. |
| <a id="boardepicdescendantweightsum"></a>`descendantWeightSum` | [`EpicDescendantWeights`](#epicdescendantweights) | Total weight of open and closed issues in the epic and its descendants. |
| <a id="boardepicdescription"></a>`description` | [`String`](#string) | Description of the epic. |
@@ -11734,6 +11735,7 @@ Represents an epic.
| <a id="epiccolor"></a>`color` | [`String`](#string) | Color of the epic. Returns `null` if `epic_color_highlight` feature flag is disabled. |
| <a id="epicconfidential"></a>`confidential` | [`Boolean`](#boolean) | Indicates if the epic is confidential. |
| <a id="epiccreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of when the epic was created. |
+| <a id="epicdefaultprojectforissuecreation"></a>`defaultProjectForIssueCreation` | [`Project`](#project) | Default Project for issue creation. Based on the project the user created the last issue in. |
| <a id="epicdescendantcounts"></a>`descendantCounts` | [`EpicDescendantCount`](#epicdescendantcount) | Number of open and closed descendant epics and issues. |
| <a id="epicdescendantweightsum"></a>`descendantWeightSum` | [`EpicDescendantWeights`](#epicdescendantweights) | Total weight of open and closed issues in the epic and its descendants. |
| <a id="epicdescription"></a>`description` | [`String`](#string) | Description of the epic. |
diff --git a/doc/api/product_analytics.md b/doc/api/product_analytics.md
new file mode 100644
index 00000000000..c3114baff8a
--- /dev/null
+++ b/doc/api/product_analytics.md
@@ -0,0 +1,67 @@
+---
+stage: Analyze
+group: Product Analytics
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Product analytics API
+
+> Introduced in GitLab 15.4 [with a flag](../administration/feature_flags.md) named `cube_api_proxy`. Disabled by default.
+
+FLAG:
+On self-managed GitLab, by default this feature is not available. To make it available per project or for your entire instance, ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `cube_api_proxy`.
+On GitLab.com, this feature is not available.
+This feature is not ready for production use.
+
+NOTE:
+Make sure to define the `cube_api_base_url` and `cube_api_key` application settings first using [the API](settings.md).
+
+## Send request to Cube
+
+Generate an access token that can be used to query the Cube API. For example:
+
+```plaintext
+POST /projects/:id/product_analytics/request
+```
+
+| Attribute | Type | Required | Description |
+| --------- |------------------| -------- |---------------------------------------------------------------|
+| `id` | integer | yes | The ID of a project that the current user has read access to. |
+
+### Request body
+
+The body of the request should be a valid Cube query.
+
+```json
+{
+ "query": {
+ "measures": [
+ "Jitsu.count"
+ ],
+ "timeDimensions": [
+ {
+ "dimension": "Jitsu.utcTime",
+ "dateRange": "This week"
+ }
+ ],
+ "order": [
+ [
+ "Jitsu.count",
+ "desc"
+ ],
+ [
+ "Jitsu.docPath",
+ "desc"
+ ],
+ [
+ "Jitsu.utcTime",
+ "asc"
+ ]
+ ],
+ "dimensions": [
+ "Jitsu.docPath"
+ ],
+ "limit": 23
+ }
+}
+```
diff --git a/doc/development/contributing/index.md b/doc/development/contributing/index.md
index 6999ffe810e..2ff51e765a3 100644
--- a/doc/development/contributing/index.md
+++ b/doc/development/contributing/index.md
@@ -99,10 +99,14 @@ If you would like to contribute to GitLab:
could speed them up.
- Consult the [Contribution Flow](#contribution-flow) section to learn the process.
-If you have any questions or need help visit [Getting Help](https://about.gitlab.com/get-help/) to
-learn how to communicate with GitLab. We have a [Gitter channel for contributors](https://gitter.im/gitlab/contributors),
-however we favor
-[asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real time communication.
+### Communication channels
+
+If you have any questions or need help, visit [Getting Help](https://about.gitlab.com/get-help/) to learn how to
+communicate with the GitLab community. GitLab prefers [asynchronous communication](https://about.gitlab.com/handbook/communication/#internal-communication) over real-time communication.
+
+We do encourage you to connect and hang out with us. GitLab has a Gitter room dedicated for [contributors](https://gitter.im/gitlab/contributors), which is bridged with our
+internal Slack. We actively monitor this channel. There is also a community-run [Discord server](https://discord.gg/S4cwz9sR8u) where you can
+find other contributors in the `#contributors` channel.
Thanks for your contribution!
diff --git a/doc/development/documentation/feature_flags.md b/doc/development/documentation/feature_flags.md
index 89e54183e50..87d2930dcb5 100644
--- a/doc/development/documentation/feature_flags.md
+++ b/doc/development/documentation/feature_flags.md
@@ -24,7 +24,8 @@ When you document feature flags, you must:
## Add version history text
-When the state of a flag changes (for example, disabled by default to enabled by default), add the change to the version history.
+When the state of a flag changes (for example, disabled by default to enabled by default), add the change to the
+[version history](versions.md#add-a-version-history-item).
Possible version history entries are:
diff --git a/doc/development/documentation/versions.md b/doc/development/documentation/versions.md
index acc0e870d24..85733603cfe 100644
--- a/doc/development/documentation/versions.md
+++ b/doc/development/documentation/versions.md
@@ -69,6 +69,11 @@ If a feature is moved to another subscription tier, use `moved`:
> - [Moved](<link-to-issue>) from GitLab Premium to GitLab Free in 12.0.
```
+#### Features introduced behind feature flags
+
+When features are introduced behind feature flags, you must add details about the feature flag to the documentation.
+For more information, see [Document features deployed behind feature flags](feature_flags.md).
+
### Inline version text
If you're adding content to an existing topic, you can add version information
diff --git a/doc/development/testing_guide/flaky_tests.md b/doc/development/testing_guide/flaky_tests.md
index 3c8df7d3416..7409f15969d 100644
--- a/doc/development/testing_guide/flaky_tests.md
+++ b/doc/development/testing_guide/flaky_tests.md
@@ -123,7 +123,7 @@ reproduction.
### Hanging specs
-If a spec hangs, it might be caused by a [bug in Rails](https://github.com/rails/rails/issues/34310):
+If a spec hangs, it might be caused by a [bug in Rails](https://github.com/rails/rails/issues/45994):
- <https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81112>
- <https://gitlab.com/gitlab-org/gitlab/-/issues/337039>
diff --git a/doc/integration/advanced_search/elasticsearch.md b/doc/integration/advanced_search/elasticsearch.md
index bab7deb9fec..93118cc7eb2 100644
--- a/doc/integration/advanced_search/elasticsearch.md
+++ b/doc/integration/advanced_search/elasticsearch.md
@@ -166,7 +166,7 @@ may need to set the `production -> elasticsearch -> indexer_path` setting in you
### View indexing errors
Errors from the [GitLab Elasticsearch Indexer](https://gitlab.com/gitlab-org/gitlab-elasticsearch-indexer) are reported in
-the [`sidekiq.log`](../../administration/logs/index.md#sidekiqlog) file with a `json.exception.class` of `Gitlab::Elastic::Indexer::Error`.
+the [`elasticsearch.log`](../../administration/logs/index.md#elasticsearchlog) file and the [`sidekiq.log`](../../administration/logs/index.md#sidekiqlog) file with a `json.exception.class` of `Gitlab::Elastic::Indexer::Error`.
These errors may occur when indexing Git repository data.
## Enable Advanced Search
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 03873394aa2..d61190fbd31 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -1620,6 +1620,15 @@ To render tables with JSON code blocks, use the following syntax:
```
````
+Watch the following video walkthrough of this feature:
+
+<div class="video-fallback">
+ See the video: <a href="https://www.youtube.com/watch?v=12yWKw1AdKY">Demo: JSON Tables in Markdown</a>.
+</div>
+<figure class="video-container">
+ <iframe src="https://www.youtube.com/embed/12yWKw1AdKY" frameborder="0" allowfullscreen="true"> </iframe>
+</figure>
+
The `items` attribute is a list of objects representing the data points.
````markdown
@@ -1632,14 +1641,6 @@ The `items` attribute is a list of objects representing the data points.
```
````
-```json:table
-{
- "items" : [
- {"a": "11", "b": "22", "c": "33"}
- ]
-}
-```
-
To specify the table labels, use the `fields` attribute.
````markdown
@@ -1653,15 +1654,6 @@ To specify the table labels, use the `fields` attribute.
```
````
-```json:table
-{
- "fields" : ["a", "b", "c"],
- "items" : [
- {"a": "11", "b": "22", "c": "33"}
- ]
-}
-```
-
Not all elements of `items` must have corresponding values in `fields`.
````markdown
@@ -1676,16 +1668,6 @@ Not all elements of `items` must have corresponding values in `fields`.
```
````
-```json:table
-{
- "fields" : ["a", "b", "c"],
- "items" : [
- {"a": "11", "b": "22", "c": "33"},
- {"a": "211", "c": "233"}
- ]
-}
-```
-
When `fields` is not explicitly specified, the labels are picked from the first element of `items`.
````markdown
@@ -1699,15 +1681,6 @@ When `fields` is not explicitly specified, the labels are picked from the first
```
````
-```json:table
-{
- "items" : [
- {"a": "11", "b": "22", "c": "33"},
- {"a": "211", "c": "233"}
- ]
-}
-```
-
You can specify custom labels for `fields`.
````markdown
@@ -1726,20 +1699,6 @@ You can specify custom labels for `fields`.
```
````
-```json:table
-{
- "fields" : [
- {"key": "a", "label": "AA"},
- {"key": "b", "label": "BB"},
- {"key": "c", "label": "CC"}
- ],
- "items" : [
- {"a": "11", "b": "22", "c": "33"},
- {"a": "211", "b": "222", "c": "233"}
- ]
-}
-```
-
You can enable sorting for individual elements of `fields`.
````markdown
@@ -1758,20 +1717,6 @@ You can enable sorting for individual elements of `fields`.
```
````
-```json:table
-{
- "fields" : [
- {"key": "a", "label": "AA", "sortable": true},
- {"key": "b", "label": "BB"},
- {"key": "c", "label": "CC"}
- ],
- "items" : [
- {"a": "11", "b": "22", "c": "33"},
- {"a": "211", "b": "222", "c": "233"}
- ]
-}
-```
-
You can use the `filter` attribute to render a table with content filtered dynamically by user input.
````markdown
@@ -1791,21 +1736,6 @@ You can use the `filter` attribute to render a table with content filtered dynam
```
````
-```json:table
-{
- "fields" : [
- {"key": "a", "label": "AA"},
- {"key": "b", "label": "BB"},
- {"key": "c", "label": "CC"}
- ],
- "items" : [
- {"a": "11", "b": "22", "c": "33"},
- {"a": "211", "b": "222", "c": "233"}
- ],
- "filter" : true
-}
-```
-
By default, every JSON table has the caption `Generated with JSON data`.
You can override this caption by specifying the `caption` attribute.
@@ -1820,15 +1750,6 @@ You can override this caption by specifying the `caption` attribute.
```
````
-```json:table
-{
- "items" : [
- {"a": "11", "b": "22", "c": "33"}
- ],
- "caption" : "Custom caption"
-}
-```
-
If JSON is invalid, an error occurs.
````markdown
@@ -1841,14 +1762,6 @@ If JSON is invalid, an error occurs.
```
````
-```json:table
-{
- "items" : [
- {"a": "11", "b": "22", "c": "33"}
- ],
-}
-```
-
## References
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
diff --git a/lib/gitlab/ci/config/entry/processable.rb b/lib/gitlab/ci/config/entry/processable.rb
index 6077d70a080..2d2032b1d8c 100644
--- a/lib/gitlab/ci/config/entry/processable.rb
+++ b/lib/gitlab/ci/config/entry/processable.rb
@@ -120,7 +120,7 @@ module Gitlab
stage: stage_value,
extends: extends,
rules: rules_value,
- job_variables: variables_value.to_h,
+ job_variables: variables_entry.value_with_data,
root_variables_inheritance: root_variables_inheritance,
only: only_value,
except: except_value,
diff --git a/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..70f85382967
--- /dev/null
+++ b/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.latest.gitlab-ci.yml
@@ -0,0 +1,244 @@
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Dependency-Scanning.gitlab-ci.yml
+
+# Read more about this feature here: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/
+#
+# Configure dependency scanning with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html).
+# List of available variables: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/index.html#available-variables
+
+variables:
+ # Setting this variable will affect all Security templates
+ # (SAST, Dependency Scanning, ...)
+ SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
+ DS_EXCLUDED_ANALYZERS: ""
+ DS_EXCLUDED_PATHS: "spec, test, tests, tmp"
+ DS_MAJOR_VERSION: 3
+
+dependency_scanning:
+ stage: test
+ script:
+ - echo "$CI_JOB_NAME is used for configuration only, and its script should not be executed"
+ - exit 1
+ artifacts:
+ reports:
+ dependency_scanning: gl-dependency-scanning-report.json
+ dependencies: []
+ rules:
+ - when: never
+
+.ds-analyzer:
+ extends: dependency_scanning
+ allow_failure: true
+ variables:
+ # DS_ANALYZER_IMAGE is an undocumented variable used internally to allow QA to
+ # override the analyzer image with a custom value. This may be subject to change or
+ # breakage across GitLab releases.
+ DS_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/$DS_ANALYZER_NAME:$DS_MAJOR_VERSION"
+ # DS_ANALYZER_NAME is an undocumented variable used in job definitions
+ # to inject the analyzer name in the image name.
+ DS_ANALYZER_NAME: ""
+ image:
+ name: "$DS_ANALYZER_IMAGE$DS_IMAGE_SUFFIX"
+ # `rules` must be overridden explicitly by each child job
+ # see https://gitlab.com/gitlab-org/gitlab/-/issues/218444
+ script:
+ - /analyzer run
+
+.cyclonedx-reports:
+ artifacts:
+ paths:
+ - "**/gl-sbom-*.cdx.json"
+
+.gemnasium-shared-rule:
+ exists:
+ - '{Gemfile.lock,*/Gemfile.lock,*/*/Gemfile.lock}'
+ - '{composer.lock,*/composer.lock,*/*/composer.lock}'
+ - '{gems.locked,*/gems.locked,*/*/gems.locked}'
+ - '{go.sum,*/go.sum,*/*/go.sum}'
+ - '{npm-shrinkwrap.json,*/npm-shrinkwrap.json,*/*/npm-shrinkwrap.json}'
+ - '{package-lock.json,*/package-lock.json,*/*/package-lock.json}'
+ - '{yarn.lock,*/yarn.lock,*/*/yarn.lock}'
+ - '{packages.lock.json,*/packages.lock.json,*/*/packages.lock.json}'
+ - '{conan.lock,*/conan.lock,*/*/conan.lock}'
+
+gemnasium-dependency_scanning:
+ extends:
+ - .ds-analyzer
+ - .cyclonedx-reports
+ variables:
+ DS_ANALYZER_NAME: "gemnasium"
+ GEMNASIUM_LIBRARY_SCAN_ENABLED: "true"
+ rules:
+ - if: $DEPENDENCY_SCANNING_DISABLED
+ when: never
+ - if: $DS_EXCLUDED_ANALYZERS =~ /gemnasium([^-]|$)/
+ when: never
+
+ # Add the job to merge request pipelines if there's an open merge request.
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ exists: !reference [.gemnasium-shared-rule, exists]
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ DS_REMEDIATE: "false"
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ exists: !reference [.gemnasium-shared-rule, exists]
+
+ # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ - if: $CI_OPEN_MERGE_REQUESTS
+ when: never
+
+ # Add the job to branch pipelines.
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ exists: !reference [.gemnasium-shared-rule, exists]
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ DS_REMEDIATE: "false"
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ exists: !reference [.gemnasium-shared-rule, exists]
+
+.gemnasium-maven-shared-rule:
+ exists:
+ - '{build.gradle,*/build.gradle,*/*/build.gradle}'
+ - '{build.gradle.kts,*/build.gradle.kts,*/*/build.gradle.kts}'
+ - '{build.sbt,*/build.sbt,*/*/build.sbt}'
+ - '{pom.xml,*/pom.xml,*/*/pom.xml}'
+
+gemnasium-maven-dependency_scanning:
+ extends:
+ - .ds-analyzer
+ - .cyclonedx-reports
+ variables:
+ DS_ANALYZER_NAME: "gemnasium-maven"
+ rules:
+ - if: $DEPENDENCY_SCANNING_DISABLED
+ when: never
+ - if: $DS_EXCLUDED_ANALYZERS =~ /gemnasium-maven/
+ when: never
+
+ # Add the job to merge request pipelines if there's an open merge request.
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ exists: !reference [.gemnasium-maven-shared-rule, exists]
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ DS_REMEDIATE: "false"
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ exists: !reference [.gemnasium-maven-shared-rule, exists]
+
+ # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ - if: $CI_OPEN_MERGE_REQUESTS
+ when: never
+
+ # Add the job to branch pipelines.
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ exists: !reference [.gemnasium-maven-shared-rule, exists]
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ exists: !reference [.gemnasium-maven-shared-rule, exists]
+
+.gemnasium-python-shared-rule:
+ exists:
+ - '{requirements.txt,*/requirements.txt,*/*/requirements.txt}'
+ - '{requirements.pip,*/requirements.pip,*/*/requirements.pip}'
+ - '{Pipfile,*/Pipfile,*/*/Pipfile}'
+ - '{requires.txt,*/requires.txt,*/*/requires.txt}'
+ - '{setup.py,*/setup.py,*/*/setup.py}'
+ - '{poetry.lock,*/poetry.lock,*/*/poetry.lock}'
+
+gemnasium-python-dependency_scanning:
+ extends:
+ - .ds-analyzer
+ - .cyclonedx-reports
+ variables:
+ DS_ANALYZER_NAME: "gemnasium-python"
+ rules:
+ - if: $DEPENDENCY_SCANNING_DISABLED
+ when: never
+ - if: $DS_EXCLUDED_ANALYZERS =~ /gemnasium-python/
+ when: never
+
+ # Add the job to merge request pipelines if there's an open merge request.
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ exists: !reference [.gemnasium-python-shared-rule, exists]
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ exists: !reference [.gemnasium-python-shared-rule, exists]
+ # Support passing of $PIP_REQUIREMENTS_FILE
+ # See https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuring-specific-analyzers-used-by-dependency-scanning
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $PIP_REQUIREMENTS_FILE &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $PIP_REQUIREMENTS_FILE
+
+ # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ - if: $CI_OPEN_MERGE_REQUESTS
+ when: never
+
+ # Add the job to branch pipelines.
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ exists: !reference [.gemnasium-python-shared-rule, exists]
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/
+ exists: !reference [.gemnasium-python-shared-rule, exists]
+ # Support passing of $PIP_REQUIREMENTS_FILE
+ # See https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#configuring-specific-analyzers-used-by-dependency-scanning
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $PIP_REQUIREMENTS_FILE &&
+ $CI_GITLAB_FIPS_MODE == "true"
+ variables:
+ DS_IMAGE_SUFFIX: "-fips"
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\bdependency_scanning\b/ &&
+ $PIP_REQUIREMENTS_FILE
+
+bundler-audit-dependency_scanning:
+ extends: .ds-analyzer
+ variables:
+ DS_ANALYZER_NAME: "bundler-audit"
+ DS_MAJOR_VERSION: 2
+ script:
+ - echo "This job was deprecated in GitLab 14.8 and removed in GitLab 15.0"
+ - echo "For more information see https://gitlab.com/gitlab-org/gitlab/-/issues/347491"
+ - exit 1
+ rules:
+ - when: never
+
+retire-js-dependency_scanning:
+ extends: .ds-analyzer
+ variables:
+ DS_ANALYZER_NAME: "retire.js"
+ DS_MAJOR_VERSION: 2
+ script:
+ - echo "This job was deprecated in GitLab 14.8 and removed in GitLab 15.0"
+ - echo "For more information see https://gitlab.com/gitlab-org/gitlab/-/issues/289830"
+ - exit 1
+ rules:
+ - when: never
diff --git a/lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..e47f669c2e2
--- /dev/null
+++ b/lib/gitlab/ci/templates/Jobs/License-Scanning.latest.gitlab-ci.yml
@@ -0,0 +1,48 @@
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/License-Scanning.gitlab-ci.yml
+
+# Read more about this feature here: https://docs.gitlab.com/ee/user/compliance/license_compliance/index.html
+#
+# Configure license scanning with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html).
+# List of available variables: https://docs.gitlab.com/ee/user/compliance/license_compliance/#available-variables
+
+variables:
+ # Setting this variable will affect all Security templates
+ # (SAST, Dependency Scanning, ...)
+ SECURE_ANALYZERS_PREFIX: "$CI_TEMPLATE_REGISTRY_HOST/security-products"
+
+ LICENSE_MANAGEMENT_SETUP_CMD: '' # If needed, specify a command to setup your environment with a custom package manager.
+ LICENSE_MANAGEMENT_VERSION: 4
+
+license_scanning:
+ stage: test
+ image:
+ name: "$SECURE_ANALYZERS_PREFIX/license-finder:$LICENSE_MANAGEMENT_VERSION"
+ entrypoint: [""]
+ variables:
+ LM_REPORT_VERSION: '2.1'
+ SETUP_CMD: $LICENSE_MANAGEMENT_SETUP_CMD
+ allow_failure: true
+ script:
+ - /run.sh analyze .
+ artifacts:
+ reports:
+ license_scanning: gl-license-scanning-report.json
+ dependencies: []
+ rules:
+ - if: $LICENSE_MANAGEMENT_DISABLED
+ when: never
+
+ # Add the job to merge request pipelines if there's an open merge request.
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $GITLAB_FEATURES =~ /\blicense_scanning\b/
+
+ # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ - if: $CI_OPEN_MERGE_REQUESTS
+ when: never
+
+ # Add the job to branch pipelines.
+ - if: $CI_COMMIT_BRANCH &&
+ $GITLAB_FEATURES =~ /\blicense_scanning\b/
diff --git a/lib/gitlab/ci/templates/Security/Container-Scanning.latest.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/Container-Scanning.latest.gitlab-ci.yml
new file mode 100644
index 00000000000..f7b1d12b3b3
--- /dev/null
+++ b/lib/gitlab/ci/templates/Security/Container-Scanning.latest.gitlab-ci.yml
@@ -0,0 +1,68 @@
+# To contribute improvements to CI/CD templates, please follow the Development guide at:
+# https://docs.gitlab.com/ee/development/cicd/templates.html
+# This specific template is located at:
+# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml
+
+# Use this template to enable container scanning in your project.
+# You should add this template to an existing `.gitlab-ci.yml` file by using the `include:`
+# keyword.
+# The template should work without modifications but you can customize the template settings if
+# needed: https://docs.gitlab.com/ee/user/application_security/container_scanning/#customizing-the-container-scanning-settings
+#
+# Requirements:
+# - A `test` stage to be present in the pipeline.
+# - You must define the image to be scanned in the CS_IMAGE variable. If CS_IMAGE is the
+# same as $CI_APPLICATION_REPOSITORY:$CI_APPLICATION_TAG, you can skip this.
+# - Container registry credentials defined by `CS_REGISTRY_USER` and `CS_REGISTRY_PASSWORD` variables if the
+# image to be scanned is in a private registry.
+# - For auto-remediation, a readable Dockerfile in the root of the project or as defined by the
+# CS_DOCKERFILE_PATH variable.
+#
+# Configure container scanning with CI/CD variables (https://docs.gitlab.com/ee/ci/variables/index.html).
+# List of available variables: https://docs.gitlab.com/ee/user/application_security/container_scanning/#available-variables
+
+variables:
+ CS_ANALYZER_IMAGE: "$CI_TEMPLATE_REGISTRY_HOST/security-products/container-scanning:5"
+
+container_scanning:
+ image: "$CS_ANALYZER_IMAGE$CS_IMAGE_SUFFIX"
+ stage: test
+ variables:
+ # To provide a `vulnerability-allowlist.yml` file, override the GIT_STRATEGY variable in your
+ # `.gitlab-ci.yml` file and set it to `fetch`.
+ # For details, see the following links:
+ # https://docs.gitlab.com/ee/user/application_security/container_scanning/index.html#overriding-the-container-scanning-template
+ # https://docs.gitlab.com/ee/user/application_security/container_scanning/#vulnerability-allowlisting
+ GIT_STRATEGY: none
+ allow_failure: true
+ artifacts:
+ reports:
+ container_scanning: gl-container-scanning-report.json
+ dependency_scanning: gl-dependency-scanning-report.json
+ paths: [gl-container-scanning-report.json, gl-dependency-scanning-report.json]
+ dependencies: []
+ script:
+ - gtcs scan
+ rules:
+ - if: $CONTAINER_SCANNING_DISABLED
+ when: never
+
+ # Add the job to merge request pipelines if there's an open merge request.
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event" &&
+ $CI_GITLAB_FIPS_MODE == "true" &&
+ $CS_ANALYZER_IMAGE !~ /-(fips|ubi)\z/
+ variables:
+ CS_IMAGE_SUFFIX: -fips
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+
+ # Don't add it to a *branch* pipeline if it's already in a merge request pipeline.
+ - if: $CI_OPEN_MERGE_REQUESTS
+ when: never
+
+ # Add the job to branch pipelines.
+ - if: $CI_COMMIT_BRANCH &&
+ $CI_GITLAB_FIPS_MODE == "true" &&
+ $CS_ANALYZER_IMAGE !~ /-(fips|ubi)\z/
+ variables:
+ CS_IMAGE_SUFFIX: -fips
+ - if: $CI_COMMIT_BRANCH
diff --git a/lib/gitlab/ci/variables/helpers.rb b/lib/gitlab/ci/variables/helpers.rb
index a77ca71b9cf..16e3afd8620 100644
--- a/lib/gitlab/ci/variables/helpers.rb
+++ b/lib/gitlab/ci/variables/helpers.rb
@@ -6,24 +6,24 @@ module Gitlab
module Helpers
class << self
def merge_variables(current_vars, new_vars)
- current_vars = transform_from_yaml_variables(current_vars)
- new_vars = transform_from_yaml_variables(new_vars)
+ return current_vars if new_vars.blank?
- transform_to_yaml_variables(
- current_vars.merge(new_vars)
- )
- end
+ current_vars = transform_to_array(current_vars) if current_vars.is_a?(Hash)
+ new_vars = transform_to_array(new_vars) if new_vars.is_a?(Hash)
- def transform_to_yaml_variables(vars)
- vars.to_h.map do |key, value|
- { key: key.to_s, value: value }
- end
+ (new_vars + current_vars).uniq { |var| var[:key] }
end
- def transform_from_yaml_variables(vars)
- return vars.stringify_keys.transform_values(&:to_s) if vars.is_a?(Hash)
+ def transform_to_array(vars)
+ return [] if vars.blank?
- vars.to_a.to_h { |var| [var[:key].to_s, var[:value]] }
+ vars.map do |key, data|
+ if data.is_a?(Hash)
+ { key: key.to_s, **data.except(:key) }
+ else
+ { key: key.to_s, value: data }
+ end
+ end
end
def inherit_yaml_variables(from:, to:, inheritance:)
@@ -35,7 +35,7 @@ module Gitlab
def apply_inheritance(variables, inheritance)
case inheritance
when true then variables
- when false then {}
+ when false then []
when Array then variables.select { |var| inheritance.include?(var[:key]) }
end
end
diff --git a/lib/gitlab/ci/yaml_processor/result.rb b/lib/gitlab/ci/yaml_processor/result.rb
index 4bd1ac3b67f..f203f88442d 100644
--- a/lib/gitlab/ci/yaml_processor/result.rb
+++ b/lib/gitlab/ci/yaml_processor/result.rb
@@ -43,7 +43,7 @@ module Gitlab
end
def root_variables
- @root_variables ||= transform_to_yaml_variables(variables)
+ @root_variables ||= transform_to_array(variables)
end
def jobs
@@ -70,7 +70,7 @@ module Gitlab
environment: job[:environment_name],
coverage_regex: job[:coverage],
# yaml_variables is calculated with using job_variables in Seed::Build
- job_variables: transform_to_yaml_variables(job[:job_variables]),
+ job_variables: transform_to_array(job[:job_variables]),
root_variables_inheritance: job[:root_variables_inheritance],
needs_attributes: job.dig(:needs, :job),
interruptible: job[:interruptible],
@@ -114,7 +114,7 @@ module Gitlab
Gitlab::Ci::Variables::Helpers.inherit_yaml_variables(
from: root_variables,
- to: transform_to_yaml_variables(job[:job_variables]),
+ to: job[:job_variables],
inheritance: job.fetch(:root_variables_inheritance, true)
)
end
@@ -137,8 +137,8 @@ module Gitlab
job[:release]
end
- def transform_to_yaml_variables(variables)
- ::Gitlab::Ci::Variables::Helpers.transform_to_yaml_variables(variables)
+ def transform_to_array(variables)
+ ::Gitlab::Ci::Variables::Helpers.transform_to_array(variables)
end
end
end
diff --git a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
index c4074f70d91..10e36a75a3a 100644
--- a/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
+++ b/lib/gitlab/usage_data_counters/known_events/ci_templates.yml
@@ -139,6 +139,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
+- name: p_ci_templates_security_container_scanning_latest
+ category: ci_templates
+ redis_slot: ci_templates
+ aggregation: weekly
- name: p_ci_templates_security_api_fuzzing
category: ci_templates
redis_slot: ci_templates
@@ -323,6 +327,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
+- name: p_ci_templates_jobs_license_scanning_latest
+ category: ci_templates
+ redis_slot: ci_templates
+ aggregation: weekly
- name: p_ci_templates_jobs_deploy
category: ci_templates
redis_slot: ci_templates
@@ -335,6 +343,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
+- name: p_ci_templates_jobs_dependency_scanning_latest
+ category: ci_templates
+ redis_slot: ci_templates
+ aggregation: weekly
- name: p_ci_templates_jobs_test
category: ci_templates
redis_slot: ci_templates
@@ -527,6 +539,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
+- name: p_ci_templates_implicit_jobs_license_scanning_latest
+ category: ci_templates
+ redis_slot: ci_templates
+ aggregation: weekly
- name: p_ci_templates_implicit_jobs_deploy
category: ci_templates
redis_slot: ci_templates
@@ -539,6 +555,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
+- name: p_ci_templates_implicit_jobs_dependency_scanning_latest
+ category: ci_templates
+ redis_slot: ci_templates
+ aggregation: weekly
- name: p_ci_templates_implicit_jobs_test
category: ci_templates
redis_slot: ci_templates
@@ -639,6 +659,10 @@
category: ci_templates
redis_slot: ci_templates
aggregation: weekly
+- name: p_ci_templates_implicit_security_container_scanning_latest
+ category: ci_templates
+ redis_slot: ci_templates
+ aggregation: weekly
- name: p_ci_templates_implicit_security_api_fuzzing
category: ci_templates
redis_slot: ci_templates
diff --git a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
index d8204e81221..f854fcb1771 100644
--- a/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
+++ b/lib/gitlab/usage_data_counters/known_events/code_review_events.yml
@@ -404,3 +404,28 @@
redis_slot: code_review
category: code_review
aggregation: weekly
+## License Compliance
+- name: i_code_review_merge_request_widget_license_compliance_view
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+- name: i_code_review_merge_request_widget_license_compliance_full_report_clicked
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+- name: i_code_review_merge_request_widget_license_compliance_expand
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+- name: i_code_review_merge_request_widget_license_compliance_expand_success
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+- name: i_code_review_merge_request_widget_license_compliance_expand_warning
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
+- name: i_code_review_merge_request_widget_license_compliance_expand_failed
+ redis_slot: code_review
+ category: code_review
+ aggregation: weekly
diff --git a/lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb b/lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb
index dafc36ab7ce..f88bbc41c70 100644
--- a/lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb
+++ b/lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb
@@ -5,7 +5,7 @@ module Gitlab
class MergeRequestWidgetExtensionCounter < BaseCounter
KNOWN_EVENTS = %w[view full_report_clicked expand expand_success expand_warning expand_failed].freeze
PREFIX = 'i_code_review_merge_request_widget'
- WIDGETS = %w[accessibility code_quality status_checks terraform test_summary metrics].freeze
+ WIDGETS = %w[accessibility code_quality license_compliance status_checks terraform test_summary metrics].freeze
class << self
private
diff --git a/lib/gitlab_edition.rb b/lib/gitlab_edition.rb
index 02006148a34..5e3ed35ace4 100644
--- a/lib/gitlab_edition.rb
+++ b/lib/gitlab_edition.rb
@@ -7,6 +7,21 @@ module GitlabEdition
Pathname.new(File.expand_path('..', __dir__))
end
+ def self.path_glob(path)
+ "#{root}/#{extension_path_prefixes}#{path}"
+ end
+
+ def self.extension_path_prefixes
+ path_prefixes = extensions
+ return '' if path_prefixes.empty?
+
+ path_prefixes.map! { "#{_1}/" }
+ path_prefixes.unshift ''
+
+ # For example `{,ee/,jh/}`
+ "{#{path_prefixes.join(',')}}"
+ end
+
def self.extensions
if jh?
%w[ee jh]
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 914bc7fdf89..bea2ef2c9c4 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -25681,6 +25681,9 @@ msgstr ""
msgid "Milestones|Use milestones to track issues and merge requests over a fixed period of time"
msgstr ""
+msgid "Milestone|%{percentage}%{percent} complete"
+msgstr ""
+
msgid "Min Value"
msgstr ""
@@ -34614,9 +34617,6 @@ msgstr ""
msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} actions for the %{scopes} %{branches}"
msgstr ""
-msgid "ScanExecutionPolicy|%{ifLabelStart}if%{ifLabelEnd} %{rules} for the %{branches} branch(es)"
-msgstr ""
-
msgid "ScanExecutionPolicy|%{period} %{days} at %{time}"
msgstr ""
diff --git a/rubocop/cop/gitlab/avoid_feature_get.rb b/rubocop/cop/gitlab/avoid_feature_get.rb
index abde1383fca..7664f66521a 100644
--- a/rubocop/cop/gitlab/avoid_feature_get.rb
+++ b/rubocop/cop/gitlab/avoid_feature_get.rb
@@ -9,11 +9,16 @@ module RuboCop
#
# # bad
#
- # Feature.get(:x)
+ # Feature.get(:x).enable
+ # Feature.get(:x).enable_percentage_of_time(100)
+ # Feature.get(:x).remove
#
# # good
#
# stub_feature_flags(x: true)
+ # Feature.enable(:x)
+ # Feature.enable_percentage_of_time(:x, 100)
+ # Feature.remove(:x)
#
class AvoidFeatureGet < RuboCop::Cop::Cop
MSG = 'Use `stub_feature_flags` method instead of `Feature.get`. ' \
diff --git a/spec/frontend/content_editor/extensions/paste_markdown_spec.js b/spec/frontend/content_editor/extensions/paste_markdown_spec.js
index 53efda6aee2..30e798e8817 100644
--- a/spec/frontend/content_editor/extensions/paste_markdown_spec.js
+++ b/spec/frontend/content_editor/extensions/paste_markdown_spec.js
@@ -5,12 +5,7 @@ import Frontmatter from '~/content_editor/extensions/frontmatter';
import Bold from '~/content_editor/extensions/bold';
import { VARIANT_DANGER } from '~/flash';
import eventHubFactory from '~/helpers/event_hub_factory';
-import {
- ALERT_EVENT,
- LOADING_CONTENT_EVENT,
- LOADING_SUCCESS_EVENT,
- LOADING_ERROR_EVENT,
-} from '~/content_editor/constants';
+import { ALERT_EVENT } from '~/content_editor/constants';
import waitForPromises from 'helpers/wait_for_promises';
import { createTestEditor, createDocBuilder, waitUntilNextDocTransaction } from '../test_utils';
@@ -115,13 +110,6 @@ describe('content_editor/extensions/paste_markdown', () => {
expect(tiptapEditor.state.doc.toJSON()).toEqual(expectedDoc.toJSON());
});
-
- it(`triggers ${LOADING_SUCCESS_EVENT}`, async () => {
- await triggerPasteEventHandlerAndWaitForTransaction(buildClipboardEvent());
-
- expect(eventHub.$emit).toHaveBeenCalledWith(LOADING_CONTENT_EVENT);
- expect(eventHub.$emit).toHaveBeenCalledWith(LOADING_SUCCESS_EVENT);
- });
});
describe('when rendering markdown fails', () => {
@@ -129,13 +117,6 @@ describe('content_editor/extensions/paste_markdown', () => {
renderMarkdown.mockRejectedValueOnce();
});
- it(`triggers ${LOADING_ERROR_EVENT} event`, async () => {
- await triggerPasteEventHandler(buildClipboardEvent());
- await waitForPromises();
-
- expect(eventHub.$emit).toHaveBeenCalledWith(LOADING_ERROR_EVENT);
- });
-
it(`triggers ${ALERT_EVENT} event`, async () => {
await triggerPasteEventHandler(buildClipboardEvent());
await waitForPromises();
diff --git a/spec/frontend/cycle_analytics/__snapshots__/total_time_spec.js.snap b/spec/frontend/cycle_analytics/__snapshots__/total_time_spec.js.snap
index 7f211c1028e..92927ef16ec 100644
--- a/spec/frontend/cycle_analytics/__snapshots__/total_time_spec.js.snap
+++ b/spec/frontend/cycle_analytics/__snapshots__/total_time_spec.js.snap
@@ -1,28 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`TotalTime with a blank object should render -- 1`] = `"<span class=\\"total-time\\"> -- </span>"`;
+exports[`TotalTime with a blank object should render -- 1`] = `"<span> -- </span>"`;
exports[`TotalTime with a valid time object with {"days": 3, "mins": 47, "seconds": 3} 1`] = `
-"<span class=\\"total-time\\">
+"<span>
3 <span>days</span></span>"
`;
exports[`TotalTime with a valid time object with {"hours": 7, "mins": 20, "seconds": 10} 1`] = `
-"<span class=\\"total-time\\">
+"<span>
7 <span>hrs</span></span>"
`;
exports[`TotalTime with a valid time object with {"hours": 23, "mins": 10} 1`] = `
-"<span class=\\"total-time\\">
+"<span>
23 <span>hrs</span></span>"
`;
exports[`TotalTime with a valid time object with {"mins": 47, "seconds": 3} 1`] = `
-"<span class=\\"total-time\\">
+"<span>
47 <span>mins</span></span>"
`;
exports[`TotalTime with a valid time object with {"seconds": 35} 1`] = `
-"<span class=\\"total-time\\">
+"<span>
35 <span>s</span></span>"
`;
diff --git a/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap b/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
index 8fe3e92360a..096d776a7d2 100644
--- a/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
+++ b/spec/frontend/design_management/components/list/__snapshots__/item_spec.js.snap
@@ -11,7 +11,7 @@ exports[`Design management list item component when item appears in view after i
exports[`Design management list item component with notes renders item with multiple comments 1`] = `
<router-link-stub
ariacurrentvalue="page"
- class="card gl-cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
+ class="card gl-cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new gl-mb-0"
event="click"
tag="a"
to="[object Object]"
@@ -88,7 +88,7 @@ exports[`Design management list item component with notes renders item with mult
exports[`Design management list item component with notes renders item with single comment 1`] = `
<router-link-stub
ariacurrentvalue="page"
- class="card gl-cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new"
+ class="card gl-cursor-pointer text-plain js-design-list-item design-list-item design-list-item-new gl-mb-0"
event="click"
tag="a"
to="[object Object]"
diff --git a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
index 9997f02cd01..8cfe11c9040 100644
--- a/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
+++ b/spec/frontend/design_management/pages/__snapshots__/index_spec.js.snap
@@ -9,9 +9,7 @@ exports[`Design management index page designs renders error 1`] = `
<!---->
- <div
- class="gl-mt-6"
- >
+ <div>
<gl-alert-stub
dismisslabel="Dismiss"
primarybuttonlink=""
@@ -43,9 +41,7 @@ exports[`Design management index page designs renders loading icon 1`] = `
<!---->
- <div
- class="gl-mt-6"
- >
+ <div>
<gl-loading-icon-stub
color="dark"
label="Loading"
diff --git a/spec/frontend/design_management/pages/index_spec.js b/spec/frontend/design_management/pages/index_spec.js
index f90feaadfb0..1033b509419 100644
--- a/spec/frontend/design_management/pages/index_spec.js
+++ b/spec/frontend/design_management/pages/index_spec.js
@@ -254,7 +254,7 @@ describe('Design management index page', () => {
'gl-flex-direction-column',
'col-md-6',
'col-lg-3',
- 'gl-mb-3',
+ 'gl-mt-5',
]);
});
});
diff --git a/spec/frontend/locale/sprintf_spec.js b/spec/frontend/locale/sprintf_spec.js
index 52e903b819f..e0d0e117ea4 100644
--- a/spec/frontend/locale/sprintf_spec.js
+++ b/spec/frontend/locale/sprintf_spec.js
@@ -63,12 +63,26 @@ describe('locale', () => {
it('does not escape parameters for escapeParameters = false', () => {
const input = 'contains %{safeContent}';
const parameters = {
- safeContent: '<strong>bold attempt</strong>',
+ safeContent: '15',
};
const output = sprintf(input, parameters, false);
- expect(output).toBe('contains <strong>bold attempt</strong>');
+ expect(output).toBe('contains 15');
+ });
+
+ describe('replaces duplicated % in input', () => {
+ it('removes duplicated percentage signs', () => {
+ const input = 'contains duplicated %{safeContent}%%';
+
+ const parameters = {
+ safeContent: '15',
+ };
+
+ const output = sprintf(input, parameters, false);
+
+ expect(output).toBe('contains duplicated 15%');
+ });
});
});
});
diff --git a/spec/frontend/repository/components/blob_content_viewer_spec.js b/spec/frontend/repository/components/blob_content_viewer_spec.js
index 0f7cf4e61b2..6ece72c41bb 100644
--- a/spec/frontend/repository/components/blob_content_viewer_spec.js
+++ b/spec/frontend/repository/components/blob_content_viewer_spec.js
@@ -17,7 +17,8 @@ import { loadViewer } from '~/repository/components/blob_viewers';
import DownloadViewer from '~/repository/components/blob_viewers/download_viewer.vue';
import EmptyViewer from '~/repository/components/blob_viewers/empty_viewer.vue';
import SourceViewer from '~/vue_shared/components/source_viewer/source_viewer.vue';
-import blobInfoQuery from '~/repository/queries/blob_info.query.graphql';
+import blobInfoQuery from 'shared_queries/repository/blob_info.query.graphql';
+import projectInfoQuery from '~/repository/queries/project_info.query.graphql';
import userInfoQuery from '~/repository/queries/user_info.query.graphql';
import applicationInfoQuery from '~/repository/queries/application_info.query.graphql';
import CodeIntelligence from '~/code_navigation/components/app.vue';
@@ -45,8 +46,9 @@ jest.mock('~/lib/utils/common_utils');
jest.mock('~/blob/line_highlighter');
let wrapper;
-let mockResolver;
+let blobInfoMockResolver;
let userInfoMockResolver;
+let projectInfoMockResolver;
let applicationInfoMockResolver;
const mockAxios = new MockAdapter(axios);
@@ -74,22 +76,40 @@ const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute
highlightJs = true,
} = mockData;
- const project = {
+ const blobInfo = {
...projectMock,
+ repository: {
+ empty,
+ blobs: { nodes: [blob] },
+ },
+ };
+
+ const projectInfo = {
+ __typename: 'Project',
+ id: '123',
userPermissions: {
pushCode,
forkProject,
downloadCode,
createMergeRequestIn,
},
- repository: {
- empty,
- blobs: { nodes: [blob] },
+ pathLocks: {
+ nodes: [
+ {
+ id: 'test',
+ path: 'locked_file.js',
+ user: { id: '123', username: 'root' },
+ },
+ ],
},
};
- mockResolver = jest.fn().mockResolvedValue({
- data: { isBinary, project },
+ projectInfoMockResolver = jest.fn().mockResolvedValue({
+ data: { project: projectInfo },
+ });
+
+ blobInfoMockResolver = jest.fn().mockResolvedValue({
+ data: { isBinary, project: blobInfo },
});
userInfoMockResolver = jest.fn().mockResolvedValue({
@@ -101,8 +121,9 @@ const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute
});
const fakeApollo = createMockApollo([
- [blobInfoQuery, mockResolver],
+ [blobInfoQuery, blobInfoMockResolver],
[userInfoQuery, userInfoMockResolver],
+ [projectInfoQuery, projectInfoMockResolver],
[applicationInfoQuery, applicationInfoMockResolver],
]);
@@ -129,7 +150,7 @@ const createComponent = async (mockData = {}, mountFn = shallowMount, mockRoute
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ project, isBinary });
+ wrapper.setData({ project: blobInfo, isBinary });
await waitForPromises();
};
@@ -504,14 +525,16 @@ describe('Blob content viewer component', () => {
async ({ highlightJs, shouldFetchRawText }) => {
await createComponent({ highlightJs });
- expect(mockResolver).toHaveBeenCalledWith(expect.objectContaining({ shouldFetchRawText }));
+ expect(blobInfoMockResolver).toHaveBeenCalledWith(
+ expect.objectContaining({ shouldFetchRawText }),
+ );
},
);
it('is called with originalBranch value if the prop has a value', async () => {
await createComponent({ inject: { originalBranch: 'some-branch' } });
- expect(mockResolver).toHaveBeenCalledWith(
+ expect(blobInfoMockResolver).toHaveBeenCalledWith(
expect.objectContaining({
ref: 'some-branch',
}),
@@ -521,7 +544,7 @@ describe('Blob content viewer component', () => {
it('is called with ref value if the originalBranch prop has no value', async () => {
await createComponent();
- expect(mockResolver).toHaveBeenCalledWith(
+ expect(blobInfoMockResolver).toHaveBeenCalledWith(
expect.objectContaining({
ref: 'default-ref',
}),
diff --git a/spec/frontend/repository/mock_data.js b/spec/frontend/repository/mock_data.js
index 4db295fe0b7..cda47a5b0a5 100644
--- a/spec/frontend/repository/mock_data.js
+++ b/spec/frontend/repository/mock_data.js
@@ -1,4 +1,5 @@
export const simpleViewerMock = {
+ __typename: 'RepositoryBlob',
id: '1',
name: 'some_file.js',
size: 123,
diff --git a/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap b/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
index 1798ca5ccde..f9d615d4f68 100644
--- a/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
+++ b/spec/frontend/vue_shared/components/upload_dropzone/__snapshots__/upload_dropzone_spec.js.snap
@@ -5,7 +5,7 @@ exports[`Upload dropzone component correctly overrides description and drop mess
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
@@ -86,7 +86,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
@@ -171,7 +171,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
@@ -256,7 +256,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
@@ -342,7 +342,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
@@ -428,7 +428,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
@@ -514,7 +514,7 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
class="gl-w-full gl-relative"
>
<button
- class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4"
+ class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-4 gl-mb-0"
type="button"
>
<div
diff --git a/spec/frontend/work_items/components/work_item_detail_spec.js b/spec/frontend/work_items/components/work_item_detail_spec.js
index 49f7957440d..351a363590c 100644
--- a/spec/frontend/work_items/components/work_item_detail_spec.js
+++ b/spec/frontend/work_items/components/work_item_detail_spec.js
@@ -142,6 +142,10 @@ describe('WorkItemDetail component', () => {
expect(findWorkItemState().exists()).toBe(true);
expect(findWorkItemTitle().exists()).toBe(true);
});
+
+ it('updates the document title', () => {
+ expect(document.title).toEqual('Updated title · Task · test-project-path');
+ });
});
describe('close button', () => {
diff --git a/spec/frontend_integration/content_editor/content_editor_integration_spec.js b/spec/frontend_integration/content_editor/content_editor_integration_spec.js
index 7781a463fd6..c0c6b5e5dc8 100644
--- a/spec/frontend_integration/content_editor/content_editor_integration_spec.js
+++ b/spec/frontend_integration/content_editor/content_editor_integration_spec.js
@@ -27,6 +27,10 @@ describe('content_editor', () => {
await nextTick();
};
+ const mockRenderMarkdownResponse = (response) => {
+ renderMarkdown.mockImplementation((markdown) => (markdown ? response : null));
+ };
+
beforeEach(() => {
renderMarkdown = jest.fn();
});
@@ -34,7 +38,7 @@ describe('content_editor', () => {
describe('when loading initial content', () => {
describe('when the initial content is empty', () => {
it('still hides the loading indicator', async () => {
- renderMarkdown.mockResolvedValue('');
+ mockRenderMarkdownResponse('');
buildWrapper();
@@ -47,9 +51,11 @@ describe('content_editor', () => {
describe('when the initial content is not empty', () => {
const initialContent = '<p><strong>bold text</strong></p>';
beforeEach(async () => {
- renderMarkdown.mockResolvedValue(initialContent);
+ mockRenderMarkdownResponse(initialContent);
- buildWrapper();
+ buildWrapper({
+ markdown: '**bold text**',
+ });
await waitUntilContentIsLoaded();
});
@@ -129,4 +135,38 @@ This reference tag is a mix of letters and numbers [^footnote].
expect(wrapper.findByTestId('table-of-contents').text()).toContain('Heading 1');
expect(wrapper.findByTestId('table-of-contents').text()).toContain('Heading 2');
});
+
+ describe('when pasting content', () => {
+ const buildClipboardData = (data = {}) => ({
+ clipboardData: {
+ getData(mimeType) {
+ return data[mimeType];
+ },
+ types: Object.keys(data),
+ },
+ });
+
+ describe('when the clipboard does not contain text/html data', () => {
+ it('processes the clipboard content as markdown', async () => {
+ const processedMarkdown = '<strong>bold text</strong>';
+
+ buildWrapper();
+
+ await waitUntilContentIsLoaded();
+
+ mockRenderMarkdownResponse(processedMarkdown);
+
+ wrapper.find('[contenteditable]').trigger(
+ 'paste',
+ buildClipboardData({
+ 'text/plain': '**bold text**',
+ }),
+ );
+
+ await waitUntilContentIsLoaded();
+
+ expect(wrapper.find('[contenteditable]').html()).toContain(processedMarkdown);
+ });
+ });
+ });
});
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index 19a4c82dcc1..3d19987a0be 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -155,7 +155,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: "postgres:9.1" }, { name: "mysql:5.5" }],
cache: [{ key: "k", untracked: true, paths: ["public/"], policy: "pull-push", when: 'on_success' }],
only: { refs: %w(branches tags) },
- job_variables: { 'VAR' => 'job' },
+ job_variables: { 'VAR' => { value: 'job' } },
root_variables_inheritance: true,
after_script: [],
ignore: false,
@@ -215,7 +215,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
services: [{ name: 'postgres:9.1' }, { name: 'mysql:5.5' }],
stage: 'test',
cache: [{ key: 'k', untracked: true, paths: ['public/'], policy: 'pull-push', when: 'on_success' }],
- job_variables: { 'VAR' => 'job' },
+ job_variables: { 'VAR' => { value: 'job' } },
root_variables_inheritance: true,
ignore: false,
after_script: ['make clean'],
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index b6cb07bf119..75f6a773c2d 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -104,8 +104,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
it do
is_expected.to include(yaml_variables: [{ key: 'VAR1', value: 'new var 1' },
- { key: 'VAR2', value: 'var 2' },
- { key: 'VAR3', value: 'var 3' }])
+ { key: 'VAR3', value: 'var 3' },
+ { key: 'VAR2', value: 'var 2' }])
end
end
diff --git a/spec/lib/gitlab/ci/trace/archive_spec.rb b/spec/lib/gitlab/ci/trace/archive_spec.rb
index 3ae0e5d1f0e..f91cb03883a 100644
--- a/spec/lib/gitlab/ci/trace/archive_spec.rb
+++ b/spec/lib/gitlab/ci/trace/archive_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Trace::Archive do
context 'with transactional fixtures' do
- let_it_be(:job) { create(:ci_build, :success, :trace_live) }
+ let_it_be_with_reload(:job) { create(:ci_build, :success, :trace_live) }
let_it_be_with_reload(:trace_metadata) { create(:ci_build_trace_metadata, build: job) }
let_it_be(:src_checksum) do
job.trace.read { |stream| Digest::MD5.hexdigest(stream.raw) }
diff --git a/spec/lib/gitlab/ci/variables/helpers_spec.rb b/spec/lib/gitlab/ci/variables/helpers_spec.rb
index ece456ee2d3..fb1e66bd605 100644
--- a/spec/lib/gitlab/ci/variables/helpers_spec.rb
+++ b/spec/lib/gitlab/ci/variables/helpers_spec.rb
@@ -22,14 +22,14 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
subject { described_class.merge_variables(current_variables, new_variables) }
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
context 'when new variables is a hash' do
let(:new_variables) do
{ 'key2' => 'value22', 'key3' => 'value3' }
end
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
end
context 'when new variables is a hash with symbol keys' do
@@ -37,7 +37,7 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
{ key2: 'value22', key3: 'value3' }
end
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
end
context 'when new variables is nil' do
@@ -47,69 +47,58 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
{ key: 'key2', value: 'value2' }]
end
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
end
end
- describe '.transform_to_yaml_variables' do
- let(:variables) do
- { 'key1' => 'value1', 'key2' => 'value2' }
- end
+ describe '.transform_to_array' do
+ subject { described_class.transform_to_array(variables) }
- let(:result) do
- [{ key: 'key1', value: 'value1' },
- { key: 'key2', value: 'value2' }]
- end
-
- subject { described_class.transform_to_yaml_variables(variables) }
-
- it { is_expected.to eq(result) }
-
- context 'when variables is nil' do
- let(:variables) {}
-
- it { is_expected.to eq([]) }
- end
- end
+ context 'when values are strings' do
+ let(:variables) do
+ { 'key1' => 'value1', 'key2' => 'value2' }
+ end
- describe '.transform_from_yaml_variables' do
- let(:variables) do
- [{ key: 'key1', value: 'value1' },
- { key: 'key2', value: 'value2' }]
- end
+ let(:result) do
+ [{ key: 'key1', value: 'value1' },
+ { key: 'key2', value: 'value2' }]
+ end
- let(:result) do
- { 'key1' => 'value1', 'key2' => 'value2' }
+ it { is_expected.to match_array(result) }
end
- subject { described_class.transform_from_yaml_variables(variables) }
-
- it { is_expected.to eq(result) }
-
context 'when variables is nil' do
let(:variables) {}
- it { is_expected.to eq({}) }
+ it { is_expected.to match_array([]) }
end
- context 'when variables is a hash' do
+ context 'when values are hashes' do
let(:variables) do
- { key1: 'value1', 'key2' => 'value2' }
+ { 'key1' => { value: 'value1', description: 'var 1' }, 'key2' => { value: 'value2' } }
end
- it { is_expected.to eq(result) }
- end
-
- context 'when variables contain integers and symbols' do
- let(:variables) do
- { key1: 1, key2: :value2 }
+ let(:result) do
+ [{ key: 'key1', value: 'value1', description: 'var 1' },
+ { key: 'key2', value: 'value2' }]
end
- let(:result1) do
- { 'key1' => '1', 'key2' => 'value2' }
- end
+ it { is_expected.to match_array(result) }
+
+ context 'when a value data has `key` as a key' do
+ let(:variables) do
+ { 'key1' => { value: 'value1', key: 'new_key1' }, 'key2' => { value: 'value2' } }
+ end
- it { is_expected.to eq(result1) }
+ let(:result) do
+ [{ key: 'key1', value: 'value1' },
+ { key: 'key2', value: 'value2' }]
+ end
+
+ it 'ignores the key set with "key"' do
+ is_expected.to match_array(result)
+ end
+ end
end
end
@@ -134,7 +123,7 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
subject { described_class.inherit_yaml_variables(from: from, to: to, inheritance: inheritance) }
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
context 'when inheritance is false' do
let(:inheritance) { false }
@@ -144,7 +133,7 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
{ key: 'key3', value: 'value3' }]
end
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
end
context 'when inheritance is array' do
@@ -155,7 +144,7 @@ RSpec.describe Gitlab::Ci::Variables::Helpers do
{ key: 'key3', value: 'value3' }]
end
- it { is_expected.to eq(result) }
+ it { is_expected.to match_array(result) }
end
end
end
diff --git a/spec/lib/gitlab_edition_spec.rb b/spec/lib/gitlab_edition_spec.rb
index 0ee63279984..46be1471896 100644
--- a/spec/lib/gitlab_edition_spec.rb
+++ b/spec/lib/gitlab_edition_spec.rb
@@ -1,6 +1,7 @@
# frozen_string_literal: true
require 'fast_spec_helper'
+require 'rspec-parameterized'
RSpec.describe GitlabEdition do
def remove_instance_variable(ivar)
@@ -27,7 +28,57 @@ RSpec.describe GitlabEdition do
end
end
- describe 'extensions' do
+ describe '.path_glob' do
+ using RSpec::Parameterized::TableSyntax
+
+ let(:root) { described_class.root.to_s }
+
+ subject { described_class.path_glob(path) }
+
+ before do
+ allow(described_class).to receive(:jh?).and_return(jh)
+ allow(described_class).to receive(:ee?).and_return(ee)
+ end
+
+ where(:ee, :jh, :path, :expected) do
+ false | false | nil | ''
+ true | false | nil | '{,ee/}'
+ true | true | nil | '{,ee/,jh/}'
+ false | true | nil | '{,ee/,jh/}'
+ false | false | 'app/models' | 'app/models'
+ true | false | 'app/models' | '{,ee/}app/models'
+ true | true | 'app/models' | '{,ee/,jh/}app/models'
+ false | true | 'app/models' | '{,ee/,jh/}app/models'
+ end
+
+ with_them do
+ it { is_expected.to eq("#{root}/#{expected}") }
+ end
+ end
+
+ describe '.extension_path_prefixes' do
+ using RSpec::Parameterized::TableSyntax
+
+ subject { described_class.extension_path_prefixes }
+
+ before do
+ allow(described_class).to receive(:jh?).and_return(jh)
+ allow(described_class).to receive(:ee?).and_return(ee)
+ end
+
+ where(:ee, :jh, :expected) do
+ false | false | ''
+ true | false | '{,ee/}'
+ true | true | '{,ee/,jh/}'
+ false | true | '{,ee/,jh/}'
+ end
+
+ with_them do
+ it { is_expected.to eq(expected) }
+ end
+ end
+
+ describe '.extensions' do
context 'when .jh? is true' do
before do
allow(described_class).to receive(:jh?).and_return(true)
diff --git a/spec/mailers/previews_spec.rb b/spec/mailers/previews_spec.rb
new file mode 100644
index 00000000000..14bd56e5d40
--- /dev/null
+++ b/spec/mailers/previews_spec.rb
@@ -0,0 +1,44 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe 'Mailer previews' do
+ # Setup needed for email previews
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, :import_failed, group: group, import_last_error: 'some error') }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:merge_request) { create(:merge_request, source_project: project) }
+ let_it_be(:milestone) { create(:milestone, project: project) }
+ let_it_be(:issue) { create(:issue, project: project, milestone: milestone) }
+ let_it_be(:remote_mirror) { create(:remote_mirror, project: project) }
+ let_it_be(:member) { create(:project_member, :maintainer, project: project, created_by: user) }
+
+ Gitlab.ee do
+ let_it_be(:epic) { create(:epic, group: group) }
+ end
+
+ let(:expected_kind) { [Mail::Message, ActionMailer::MessageDelivery] }
+
+ let(:pending_failures) do
+ {
+ 'NotifyPreview#note_merge_request_email_for_diff_discussion' =>
+ 'https://gitlab.com/gitlab-org/gitlab/-/issues/372885'
+ }
+ end
+
+ subject { preview.call(email) }
+
+ where(:preview, :email) do
+ ActionMailer::Preview.all.flat_map { |preview| preview.emails.map { |email| [preview, email] } }
+ end
+
+ with_them do
+ it do
+ issue_link = pending_failures["#{preview.name}##{email}"]
+ pending "See #{issue_link}" if issue_link
+
+ is_expected.to be_kind_of(Mail::Message).or(be_kind_of(ActionMailer::MessageDelivery))
+ end
+ end
+end
diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb
index f31edb747bd..1962d232f3d 100644
--- a/spec/models/ci/job_artifact_spec.rb
+++ b/spec/models/ci/job_artifact_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe Ci::JobArtifact do
describe "Associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:job) }
+ it { is_expected.to validate_presence_of(:job) }
+ it { is_expected.to validate_presence_of(:partition_id) }
end
it { is_expected.to respond_to(:file) }
@@ -758,4 +760,26 @@ RSpec.describe Ci::JobArtifact do
let!(:model) { create(:ci_job_artifact, project: parent) }
end
end
+
+ context 'with partition_id' do
+ let(:job) { build(:ci_build, partition_id: 123) }
+ let(:artifact) { build(:ci_job_artifact, job: job, partition_id: nil) }
+
+ it 'copies the partition_id from job' do
+ expect { artifact.valid? }.to change(artifact, :partition_id).from(nil).to(123)
+ end
+
+ context 'when the job is missing' do
+ let(:artifact) do
+ build(:ci_job_artifact,
+ project: build_stubbed(:project),
+ job: nil,
+ partition_id: nil)
+ end
+
+ it 'does not change the partition_id value' do
+ expect { artifact.valid? }.not_to change(artifact, :partition_id)
+ end
+ end
+ end
end
diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb
index 6809b694b22..a2259f9813b 100644
--- a/spec/services/ci/job_artifacts/create_service_spec.rb
+++ b/spec/services/ci/job_artifacts/create_service_spec.rb
@@ -181,6 +181,18 @@ RSpec.describe Ci::JobArtifacts::CreateService do
end
end
+ context 'with job partitioning' do
+ let(:job) { create(:ci_build, project: project, partition_id: 123) }
+
+ it 'sets partition_id on artifacts' do
+ expect { subject }.to change { Ci::JobArtifact.count }
+
+ artifacts_partitions = job.job_artifacts.map(&:partition_id).uniq
+
+ expect(artifacts_partitions).to eq([123])
+ end
+ end
+
shared_examples 'rescues object storage error' do |klass, message, expected_message|
it "handles #{klass}" do
allow_next_instance_of(JobArtifactUploader) do |uploader|
diff --git a/tests.yml b/tests.yml
index d38b05af991..c530ec30416 100644
--- a/tests.yml
+++ b/tests.yml
@@ -69,3 +69,9 @@ mapping:
- source: lib/gitlab/usage_data_counters/known_events/.+\.yml
test: spec/lib/gitlab/usage_data_spec.rb
+ # Mailer previews
+ - source: (ee/)?app/mailers/previews/.+\.rb
+ test: spec/mailers/previews_spec.rb
+ - source: ee/app/mailers/ee/preview/.+\.rb
+ test: spec/mailers/previews_spec.rb
+