summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-05-05 18:08:40 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2022-05-05 18:08:40 +0000
commit0b789f95a35aa3e4b99ce12fc98bd3cce6555602 (patch)
tree886c728abbd90836e6846fcf4bb789be243c5253
parentdad16033c2b7cfd54ffe20ca5cc1d844e9e41be6 (diff)
downloadgitlab-ce-0b789f95a35aa3e4b99ce12fc98bd3cce6555602.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITALY_SERVER_VERSION2
-rw-r--r--app/assets/javascripts/admin/background_migrations/components/database_listbox.vue51
-rw-r--r--app/assets/javascripts/admin/background_migrations/index.js38
-rw-r--r--app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue2
-rw-r--r--app/assets/javascripts/content_editor/components/wrappers/code_block.vue (renamed from app/assets/javascripts/content_editor/components/wrappers/frontmatter.vue)14
-rw-r--r--app/assets/javascripts/content_editor/extensions/code_block_highlight.js17
-rw-r--r--app/assets/javascripts/content_editor/extensions/diagram.js3
-rw-r--r--app/assets/javascripts/content_editor/extensions/frontmatter.js15
-rw-r--r--app/assets/javascripts/content_editor/services/code_block_language_loader.js24
-rw-r--r--app/assets/javascripts/content_editor/services/content_editor.js11
-rw-r--r--app/assets/javascripts/content_editor/services/create_content_editor.js4
-rw-r--r--app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js7
-rw-r--r--app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js6
-rw-r--r--app/assets/javascripts/editor/schema/ci.json17
-rw-r--r--app/assets/javascripts/pages/admin/background_migrations/index.js3
-rw-r--r--app/controllers/admin/application_settings_controller.rb14
-rw-r--r--app/controllers/admin/background_migrations_controller.rb4
-rw-r--r--app/graphql/types/container_repository_type.rb1
-rw-r--r--app/models/raw_usage_data.rb7
-rw-r--r--app/views/admin/background_migrations/_migration.html.haml6
-rw-r--r--app/views/admin/background_migrations/index.html.haml20
-rw-r--r--doc/api/graphql/reference/index.md2
-rw-r--r--doc/ci/yaml/artifacts_reports.md23
-rw-r--r--doc/development/code_review.md2
-rw-r--r--doc/development/dangerbot.md2
-rw-r--r--doc/development/documentation/styleguide/word_list.md2
-rw-r--r--doc/development/fe_guide/design_anti_patterns.md2
-rw-r--r--doc/development/fips_compliance.md14
-rw-r--r--doc/development/pipelines.md2
-rw-r--r--doc/development/ruby_upgrade.md2
-rw-r--r--doc/development/service_ping/implement.md2
-rw-r--r--doc/topics/git/troubleshooting_git.md2
-rw-r--r--doc/user/project/merge_requests/test_coverage_visualization.md2
-rw-r--r--lib/gitlab/ci/config/entry/reports.rb5
-rw-r--r--lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml4
-rw-r--r--lib/gitlab/usage/service_ping_report.rb4
-rw-r--r--locale/gitlab.pot39
-rw-r--r--qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb3
-rw-r--r--spec/controllers/admin/application_settings_controller_spec.rb53
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb90
-rw-r--r--spec/features/admin/admin_settings_spec.rb5
-rw-r--r--spec/fixtures/api/schemas/graphql/container_repository.json5
-rw-r--r--spec/frontend/admin/background_migrations/components/database_listbox_spec.js57
-rw-r--r--spec/frontend/admin/background_migrations/mock_data.js6
-rw-r--r--spec/frontend/content_editor/components/bubble_menus/code_block_spec.js4
-rw-r--r--spec/frontend/content_editor/components/wrappers/code_block_spec.js (renamed from spec/frontend/content_editor/components/wrappers/frontmatter_spec.js)33
-rw-r--r--spec/frontend/content_editor/extensions/code_block_highlight_spec.js13
-rw-r--r--spec/frontend/content_editor/extensions/diagram_spec.js16
-rw-r--r--spec/frontend/content_editor/extensions/frontmatter_spec.js12
-rw-r--r--spec/frontend/content_editor/services/code_block_language_loader_spec.js18
-rw-r--r--spec/frontend/content_editor/services/content_editor_spec.js9
-rw-r--r--spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js4
-rw-r--r--spec/frontend/content_editor/services/remark_markdown_deserializer_spec.js8
-rw-r--r--spec/frontend/editor/schema/ci/json_tests/positive_tests/gitlab-ci.json10
-rw-r--r--spec/graphql/types/container_repository_details_type_spec.rb2
-rw-r--r--spec/graphql/types/container_repository_type_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/reports_spec.rb13
-rw-r--r--spec/models/raw_usage_data_spec.rb25
58 files changed, 587 insertions, 176 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION
index ae9fa84a927..292efacb872 100644
--- a/GITALY_SERVER_VERSION
+++ b/GITALY_SERVER_VERSION
@@ -1 +1 @@
-1f98d5a94c880e3e556ae3ace095f83e44f002fb
+86aa7ee82a5dd241fd7d4b33435da0a7ecad12b0
diff --git a/app/assets/javascripts/admin/background_migrations/components/database_listbox.vue b/app/assets/javascripts/admin/background_migrations/components/database_listbox.vue
new file mode 100644
index 00000000000..7f6e5dc4f35
--- /dev/null
+++ b/app/assets/javascripts/admin/background_migrations/components/database_listbox.vue
@@ -0,0 +1,51 @@
+<script>
+import { GlListbox } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { setUrlParams, visitUrl } from '~/lib/utils/url_utility';
+
+export default {
+ name: 'BackgroundMigrationsDatabaseListbox',
+ i18n: {
+ database: s__('BackgroundMigrations|Database'),
+ },
+ components: {
+ GlListbox,
+ },
+ props: {
+ databases: {
+ type: Array,
+ required: true,
+ },
+ selectedDatabase: {
+ type: String,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ selected: this.selectedDatabase,
+ };
+ },
+ methods: {
+ selectDatabase(database) {
+ visitUrl(setUrlParams({ database }));
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex gl-align-items-center" data-testid="database-listbox">
+ <label id="label" class="gl-font-weight-bold gl-mr-4 gl-mb-0">{{
+ $options.i18n.database
+ }}</label>
+ <gl-listbox
+ v-model="selected"
+ :items="databases"
+ right
+ :toggle-text="selectedDatabase"
+ aria-labelledby="label"
+ @select="selectDatabase"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/admin/background_migrations/index.js b/app/assets/javascripts/admin/background_migrations/index.js
new file mode 100644
index 00000000000..4ddd8f17c9a
--- /dev/null
+++ b/app/assets/javascripts/admin/background_migrations/index.js
@@ -0,0 +1,38 @@
+import Vue from 'vue';
+import * as Sentry from '@sentry/browser';
+import Translate from '~/vue_shared/translate';
+import BackgroundMigrationsDatabaseListbox from './components/database_listbox.vue';
+
+Vue.use(Translate);
+
+export const initBackgroundMigrationsApp = () => {
+ const el = document.getElementById('js-database-listbox');
+
+ if (!el) {
+ return false;
+ }
+
+ const { selectedDatabase } = el.dataset;
+ let { databases } = el.dataset;
+
+ try {
+ databases = JSON.parse(databases).map((database) => ({
+ value: database,
+ text: database,
+ }));
+ } catch (e) {
+ Sentry.captureException(e);
+ }
+
+ return new Vue({
+ el,
+ render(createElement) {
+ return createElement(BackgroundMigrationsDatabaseListbox, {
+ props: {
+ databases,
+ selectedDatabase,
+ },
+ });
+ },
+ });
+};
diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue b/app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue
index 210f259b20f..518ddd7a09c 100644
--- a/app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue
+++ b/app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue
@@ -72,7 +72,7 @@ export default {
async applySelectedLanguage(language) {
this.selectedLanguage = language;
- await codeBlockLanguageLoader.loadLanguages([language.syntax]);
+ await codeBlockLanguageLoader.loadLanguage(language.syntax);
this.tiptapEditor.commands.setCodeBlock({ language: this.selectedLanguage.syntax });
},
diff --git a/app/assets/javascripts/content_editor/components/wrappers/frontmatter.vue b/app/assets/javascripts/content_editor/components/wrappers/code_block.vue
index e8829d00986..1390b9b2daf 100644
--- a/app/assets/javascripts/content_editor/components/wrappers/frontmatter.vue
+++ b/app/assets/javascripts/content_editor/components/wrappers/code_block.vue
@@ -1,9 +1,10 @@
<script>
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2';
import { __ } from '~/locale';
+import codeBlockLanguageLoader from '../../services/code_block_language_loader';
export default {
- name: 'FrontMatter',
+ name: 'CodeBlock',
components: {
NodeViewWrapper,
NodeViewContent,
@@ -13,6 +14,16 @@ export default {
type: Object,
required: true,
},
+ updateAttributes: {
+ type: Function,
+ required: true,
+ },
+ },
+ async mounted() {
+ const lang = codeBlockLanguageLoader.findLanguageBySyntax(this.node.attrs.language);
+ await codeBlockLanguageLoader.loadLanguage(lang.syntax);
+
+ this.updateAttributes({ language: this.node.attrs.language });
},
i18n: {
frontmatter: __('frontmatter'),
@@ -22,6 +33,7 @@ export default {
<template>
<node-view-wrapper class="content-editor-code-block gl-relative code highlight" as="pre">
<span
+ v-if="node.attrs.isFrontmatter"
data-testid="frontmatter-label"
class="gl-absolute gl-top-0 gl-right-3"
contenteditable="false"
diff --git a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js
index 61f379fc0a2..cc4ba84a29d 100644
--- a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js
+++ b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js
@@ -1,6 +1,8 @@
import { CodeBlockLowlight } from '@tiptap/extension-code-block-lowlight';
import { textblockTypeInputRule } from '@tiptap/core';
-import codeBlockLanguageLoader from '../services/code_block_language_loader';
+import { VueNodeViewRenderer } from '@tiptap/vue-2';
+import languageLoader from '../services/code_block_language_loader';
+import CodeBlockWrapper from '../components/wrappers/code_block.vue';
const extractLanguage = (element) => element.getAttribute('lang');
export const backtickInputRegex = /^```([a-z]+)?[\s\n]$/;
@@ -9,14 +11,6 @@ export const tildeInputRegex = /^~~~([a-z]+)?[\s\n]$/;
export default CodeBlockLowlight.extend({
isolating: true,
exitOnArrowDown: false,
-
- addOptions() {
- return {
- ...this.parent?.(),
- languageLoader: codeBlockLanguageLoader,
- };
- },
-
addAttributes() {
return {
language: {
@@ -30,7 +24,6 @@ export default CodeBlockLowlight.extend({
};
},
addInputRules() {
- const { languageLoader } = this.options;
const getAttributes = (match) => languageLoader?.loadLanguageFromInputRule(match) || {};
return [
@@ -65,4 +58,8 @@ export default CodeBlockLowlight.extend({
['code', {}, 0],
];
},
+
+ addNodeView() {
+ return new VueNodeViewRenderer(CodeBlockWrapper);
+ },
});
diff --git a/app/assets/javascripts/content_editor/extensions/diagram.js b/app/assets/javascripts/content_editor/extensions/diagram.js
index d192b815092..f9dfeb92e9a 100644
--- a/app/assets/javascripts/content_editor/extensions/diagram.js
+++ b/app/assets/javascripts/content_editor/extensions/diagram.js
@@ -14,6 +14,9 @@ export default CodeBlockHighlight.extend({
return element.dataset.diagram;
},
},
+ isDiagram: {
+ default: true,
+ },
};
},
diff --git a/app/assets/javascripts/content_editor/extensions/frontmatter.js b/app/assets/javascripts/content_editor/extensions/frontmatter.js
index 9842027e192..2ec22158106 100644
--- a/app/assets/javascripts/content_editor/extensions/frontmatter.js
+++ b/app/assets/javascripts/content_editor/extensions/frontmatter.js
@@ -1,10 +1,18 @@
-import { VueNodeViewRenderer } from '@tiptap/vue-2';
import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants';
-import FrontmatterWrapper from '../components/wrappers/frontmatter.vue';
import CodeBlockHighlight from './code_block_highlight';
export default CodeBlockHighlight.extend({
name: 'frontmatter',
+
+ addAttributes() {
+ return {
+ ...this.parent?.(),
+ isFrontmatter: {
+ default: true,
+ },
+ };
+ },
+
parseHTML() {
return [
{
@@ -24,9 +32,6 @@ export default CodeBlockHighlight.extend({
},
};
},
- addNodeView() {
- return new VueNodeViewRenderer(FrontmatterWrapper);
- },
addInputRules() {
return [];
diff --git a/app/assets/javascripts/content_editor/services/code_block_language_loader.js b/app/assets/javascripts/content_editor/services/code_block_language_loader.js
index 0d5a8c91907..1afaf4bfef6 100644
--- a/app/assets/javascripts/content_editor/services/code_block_language_loader.js
+++ b/app/assets/javascripts/content_editor/services/code_block_language_loader.js
@@ -40,25 +40,21 @@ const codeBlockLanguageLoader = {
loadLanguageFromInputRule(match) {
const { syntax } = this.findLanguageBySyntax(match[1]);
- this.loadLanguages([syntax]);
+ this.loadLanguage(syntax);
return { language: syntax };
},
- loadLanguages(languageList = []) {
- const loaders = languageList
- .filter(
- (languageName) => !this.isLanguageLoaded(languageName) && languageName in languageLoader,
- )
- .map((languageName) => {
- return languageLoader[languageName]()
- .then(({ default: language }) => {
- this.lowlight.registerLanguage(languageName, language);
- })
- .catch(() => false);
- });
+ async loadLanguage(languageName) {
+ if (this.isLanguageLoaded(languageName)) return false;
- return Promise.all(loaders);
+ try {
+ const { default: language } = await languageLoader[languageName]();
+ this.lowlight.registerLanguage(languageName, language);
+ return true;
+ } catch {
+ return false;
+ }
},
};
diff --git a/app/assets/javascripts/content_editor/services/content_editor.js b/app/assets/javascripts/content_editor/services/content_editor.js
index b993851a92f..5078668c620 100644
--- a/app/assets/javascripts/content_editor/services/content_editor.js
+++ b/app/assets/javascripts/content_editor/services/content_editor.js
@@ -3,12 +3,11 @@ import { LOADING_CONTENT_EVENT, LOADING_SUCCESS_EVENT, LOADING_ERROR_EVENT } fro
/* eslint-disable no-underscore-dangle */
export class ContentEditor {
- constructor({ tiptapEditor, serializer, deserializer, assetResolver, eventHub, languageLoader }) {
+ constructor({ tiptapEditor, serializer, deserializer, assetResolver, eventHub }) {
this._tiptapEditor = tiptapEditor;
this._serializer = serializer;
this._deserializer = deserializer;
this._eventHub = eventHub;
- this._languageLoader = languageLoader;
this._assetResolver = assetResolver;
}
@@ -49,7 +48,7 @@ export class ContentEditor {
}
async setSerializedContent(serializedContent) {
- const { _tiptapEditor: editor, _eventHub: eventHub, _languageLoader: languageLoader } = this;
+ const { _tiptapEditor: editor, _eventHub: eventHub } = this;
const { doc, tr } = editor.state;
const selection = TextSelection.create(doc, 0, doc.content.size);
@@ -58,12 +57,8 @@ export class ContentEditor {
const result = await this.deserialize(serializedContent);
if (Object.keys(result).length !== 0) {
- const { document, languages } = result;
-
- await languageLoader.loadLanguages(languages);
-
tr.setSelection(selection)
- .replaceSelectionWith(document, false)
+ .replaceSelectionWith(result.document, false)
.setMeta('preventUpdate', true);
editor.view.dispatch(tr);
}
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 adb1398b2c4..db76073510e 100644
--- a/app/assets/javascripts/content_editor/services/create_content_editor.js
+++ b/app/assets/javascripts/content_editor/services/create_content_editor.js
@@ -62,7 +62,6 @@ import createGlApiMarkdownDeserializer from './gl_api_markdown_deserializer';
import createRemarkMarkdownDeserializer from './remark_markdown_deserializer';
import createAssetResolver from './asset_resolver';
import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts';
-import languageLoader from './code_block_language_loader';
const createTiptapEditor = ({ extensions = [], ...options } = {}) =>
new Editor({
@@ -96,7 +95,7 @@ export const createContentEditor = ({
BulletList,
Code,
ColorChip,
- CodeBlockHighlight.configure({ lowlight, languageLoader }),
+ CodeBlockHighlight.configure({ lowlight }),
DescriptionItem,
DescriptionList,
Details,
@@ -160,7 +159,6 @@ export const createContentEditor = ({
serializer,
eventHub,
deserializer,
- languageLoader,
assetResolver,
});
};
diff --git a/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js b/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js
index 3742d14bfd1..dcd56e55268 100644
--- a/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js
+++ b/app/assets/javascripts/content_editor/services/gl_api_markdown_deserializer.js
@@ -18,7 +18,6 @@ export default ({ render }) => {
return {
deserialize: async ({ schema, content }) => {
const html = await render(content);
- const languages = [];
if (!html) return {};
@@ -28,11 +27,7 @@ export default ({ render }) => {
// append original source as a comment that nodes can access
body.append(document.createComment(content));
- body.querySelectorAll('pre').forEach((preElement) => {
- languages.push(preElement.getAttribute('lang'));
- });
-
- return { document: ProseMirrorDOMParser.fromSchema(schema).parse(body), languages };
+ return { document: ProseMirrorDOMParser.fromSchema(schema).parse(body) };
},
};
};
diff --git a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
index ef0a6ce0fac..770de1df0d0 100644
--- a/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
+++ b/app/assets/javascripts/content_editor/services/remark_markdown_deserializer.js
@@ -35,10 +35,10 @@ const factorySpecs = {
pre: {
block: 'codeBlock',
skipChildren: true,
- getContent: ({ hastNodeText }) => hastNodeText,
+ getContent: ({ hastNodeText }) => hastNodeText.replace(/\n$/, ''),
getAttrs: (hastNode) => {
const languageClass = hastNode.children[0]?.properties.className?.[0];
- const language = isString(languageClass) ? languageClass.replace('language-', '') : '';
+ const language = isString(languageClass) ? languageClass.replace('language-', '') : null;
return { language };
},
@@ -81,7 +81,7 @@ export default () => {
}),
});
- return { document, languages: [] };
+ return { document };
},
};
};
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json
index eaf31a2b396..1352211b927 100644
--- a/app/assets/javascripts/editor/schema/ci.json
+++ b/app/assets/javascripts/editor/schema/ci.json
@@ -170,23 +170,6 @@
}
]
},
- "cobertura": {
- "description": "Path for file(s) that should be parsed as Cobertura XML coverage report",
- "oneOf": [
- {
- "type": "string",
- "description": "Path to a single XML file"
- },
- {
- "type": "array",
- "description": "A list of paths to XML files that will automatically be merged into one report",
- "items": {
- "type": "string"
- },
- "minItems": 1
- }
- ]
- },
"coverage_report": {
"type": "object",
"description": "Used to collect coverage reports from the job.",
diff --git a/app/assets/javascripts/pages/admin/background_migrations/index.js b/app/assets/javascripts/pages/admin/background_migrations/index.js
new file mode 100644
index 00000000000..4c59613140b
--- /dev/null
+++ b/app/assets/javascripts/pages/admin/background_migrations/index.js
@@ -0,0 +1,3 @@
+import { initBackgroundMigrationsApp } from '~/admin/background_migrations';
+
+initBackgroundMigrationsApp();
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index dff6a44f9a3..8f13783da66 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -54,7 +54,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
end
def service_usage_data
- @service_ping_data_present = Rails.cache.exist?('usage_data')
+ @service_ping_data_present = prerecorded_service_ping_data.present?
end
def update
@@ -64,7 +64,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def usage_data
respond_to do |format|
format.html do
- usage_data_json = Gitlab::Json.pretty_generate(Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true))
+ usage_data_json = Gitlab::Json.pretty_generate(service_ping_data)
render html: Gitlab::Highlight.highlight('payload.json', usage_data_json, language: 'json')
end
@@ -72,7 +72,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
format.json do
Gitlab::UsageDataCounters::ServiceUsageDataCounter.count(:download_payload_click)
- render json: Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true).to_json
+ render json: service_ping_data.to_json
end
end
end
@@ -307,6 +307,14 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def valid_setting_panels
VALID_SETTING_PANELS
end
+
+ def service_ping_data
+ prerecorded_service_ping_data || Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
+ end
+
+ def prerecorded_service_ping_data
+ Rails.cache.fetch(Gitlab::Usage::ServicePingReport::CACHE_KEY) || ::RawUsageData.for_current_reporting_cycle.first&.payload
+ end
end
Admin::ApplicationSettingsController.prepend_mod_with('Admin::ApplicationSettingsController')
diff --git a/app/controllers/admin/background_migrations_controller.rb b/app/controllers/admin/background_migrations_controller.rb
index 16e53c8bd0c..fc1ac163449 100644
--- a/app/controllers/admin/background_migrations_controller.rb
+++ b/app/controllers/admin/background_migrations_controller.rb
@@ -53,9 +53,9 @@ class Admin::BackgroundMigrationsController < Admin::ApplicationController
end
def base_model
- database = params[:database] || Gitlab::Database::MAIN_DATABASE_NAME
+ @selected_database = params[:database] || Gitlab::Database::MAIN_DATABASE_NAME
- Gitlab::Database.database_base_models[database]
+ Gitlab::Database.database_base_models[@selected_database]
end
def batched_migration_class
diff --git a/app/graphql/types/container_repository_type.rb b/app/graphql/types/container_repository_type.rb
index dddf9a3ee97..cb818ac5e92 100644
--- a/app/graphql/types/container_repository_type.rb
+++ b/app/graphql/types/container_repository_type.rb
@@ -21,6 +21,7 @@ module Types
field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.'
field :tags_count, GraphQL::Types::Int, null: false, description: 'Number of tags associated with this image.'
field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.'
+ field :last_cleanup_deleted_tags_count, GraphQL::Types::Int, null: true, description: 'Number of deleted tags from the last cleanup.'
def can_delete
Ability.allowed?(current_user, :update_container_image, object)
diff --git a/app/models/raw_usage_data.rb b/app/models/raw_usage_data.rb
index 6fe3b26b58b..a6844eb8616 100644
--- a/app/models/raw_usage_data.rb
+++ b/app/models/raw_usage_data.rb
@@ -1,9 +1,16 @@
# frozen_string_literal: true
class RawUsageData < ApplicationRecord
+ REPORTING_CADENCE = 7.days.freeze
+
validates :payload, presence: true
validates :recorded_at, presence: true, uniqueness: true
+ scope :for_current_reporting_cycle, -> do
+ where('created_at >= ?', REPORTING_CADENCE.ago.beginning_of_day)
+ .order(created_at: :desc)
+ end
+
def update_version_metadata!(usage_data_id:)
self.update_columns(sent_at: Time.current, version_usage_data_id_value: usage_data_id)
end
diff --git a/app/views/admin/background_migrations/_migration.html.haml b/app/views/admin/background_migrations/_migration.html.haml
index 2419af2e746..33fcfbd6790 100644
--- a/app/views/admin/background_migrations/_migration.html.haml
+++ b/app/views/admin/background_migrations/_migration.html.haml
@@ -12,14 +12,14 @@
= gl_badge_tag migration.status_name.to_s.humanize, { size: :sm, variant: batched_migration_status_badge_variant(migration) }
%td{ role: 'cell', data: { label: _('Action') } }
- if migration.active?
- = button_to pause_admin_background_migration_path(migration),
+ = button_to pause_admin_background_migration_path(migration, database: params[:database]),
class: 'gl-button btn btn-icon has-tooltip', title: _('Pause'), 'aria-label' => _('Pause') do
= sprite_icon('pause', css_class: 'gl-button-icon gl-icon')
- elsif migration.paused?
- = button_to resume_admin_background_migration_path(migration),
+ = button_to resume_admin_background_migration_path(migration, database: params[:database]),
class: 'gl-button btn btn-icon has-tooltip', title: _('Resume'), 'aria-label' => _('Resume') do
= sprite_icon('play', css_class: 'gl-button-icon gl-icon')
- elsif migration.failed?
- = button_to retry_admin_background_migration_path(migration),
+ = button_to retry_admin_background_migration_path(migration, database: params[:database]),
class: 'gl-button btn btn-icon has-tooltip', title: _('Retry'), 'aria-label' => _('Retry') do
= sprite_icon('retry', css_class: 'gl-button-icon gl-icon')
diff --git a/app/views/admin/background_migrations/index.html.haml b/app/views/admin/background_migrations/index.html.haml
index 089bcfbf51e..b2b66a94970 100644
--- a/app/views/admin/background_migrations/index.html.haml
+++ b/app/views/admin/background_migrations/index.html.haml
@@ -1,13 +1,25 @@
-- page_title _('Background Migrations')
+- page_title s_('BackgroundMigrations|Background Migrations')
+
+.gl-display-flex.gl-sm-flex-direction-column.gl-sm-align-items-flex-end.gl-pb-5.gl-border-b-1.gl-border-b-solid.gl-border-b-gray-100
+ .gl-flex-grow-1.gl-mr-7
+ %h3= s_('BackgroundMigrations|Background Migrations')
+ %p.light.gl-mb-0
+ - learnmore_link = help_page_path('development/database/batched_background_migrations')
+ - learnmore_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: learnmore_link }
+ = html_escape(s_('BackgroundMigrations|Background migrations are used to perform data migrations whenever a migration exceeds the time limits in our guidelines. %{linkStart}Learn more%{linkEnd}')) % { linkStart: learnmore_link_start, linkEnd: '</a>'.html_safe }
+
+ - if @databases.size > 1
+ .gl-display-flex.gl-align-items-center.gl-flex-grow-0.gl-flex-basis-0.gl-sm-mt-0.gl-mt-5
+ #js-database-listbox{ data: { databases: @databases, selected_database: @selected_database } }
= gl_tabs_nav do
- = gl_tab_link_to admin_background_migrations_path, item_active: @current_tab == 'queued' do
+ = gl_tab_link_to admin_background_migrations_path({ tab: nil, database: params[:database] }), item_active: @current_tab == 'queued' do
= _('Queued')
= gl_tab_counter_badge limited_counter_with_delimiter(@relations_by_tab['queued'])
- = gl_tab_link_to admin_background_migrations_path(tab: 'failed'), item_active: @current_tab == 'failed' do
+ = gl_tab_link_to admin_background_migrations_path({ tab: 'failed', database: params[:database] }), item_active: @current_tab == 'failed' do
= _('Failed')
= gl_tab_counter_badge limited_counter_with_delimiter(@relations_by_tab['failed'])
- = gl_tab_link_to admin_background_migrations_path(tab: 'finished'), item_active: @current_tab == 'finished' do
+ = gl_tab_link_to admin_background_migrations_path({ tab: 'finished', database: params[:database] }), item_active: @current_tab == 'finished' do
= _('Finished')
= gl_tab_counter_badge limited_counter_with_delimiter(@relations_by_tab['finished'])
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 10b32c3f03f..eb06030ddb1 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -9833,6 +9833,7 @@ A container repository.
| <a id="containerrepositoryexpirationpolicycleanupstatus"></a>`expirationPolicyCleanupStatus` | [`ContainerRepositoryCleanupStatus`](#containerrepositorycleanupstatus) | Tags cleanup status for the container repository. |
| <a id="containerrepositoryexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
| <a id="containerrepositoryid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
+| <a id="containerrepositorylastcleanupdeletedtagscount"></a>`lastCleanupDeletedTagsCount` | [`Int`](#int) | Number of deleted tags from the last cleanup. |
| <a id="containerrepositorylocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
| <a id="containerrepositorymigrationstate"></a>`migrationState` | [`String!`](#string) | Migration state of the container repository. |
| <a id="containerrepositoryname"></a>`name` | [`String!`](#string) | Name of the container repository. |
@@ -9855,6 +9856,7 @@ Details of a container repository.
| <a id="containerrepositorydetailsexpirationpolicycleanupstatus"></a>`expirationPolicyCleanupStatus` | [`ContainerRepositoryCleanupStatus`](#containerrepositorycleanupstatus) | Tags cleanup status for the container repository. |
| <a id="containerrepositorydetailsexpirationpolicystartedat"></a>`expirationPolicyStartedAt` | [`Time`](#time) | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
| <a id="containerrepositorydetailsid"></a>`id` | [`ID!`](#id) | ID of the container repository. |
+| <a id="containerrepositorydetailslastcleanupdeletedtagscount"></a>`lastCleanupDeletedTagsCount` | [`Int`](#int) | Number of deleted tags from the last cleanup. |
| <a id="containerrepositorydetailslocation"></a>`location` | [`String!`](#string) | URL of the container repository. |
| <a id="containerrepositorydetailsmigrationstate"></a>`migrationState` | [`String!`](#string) | Migration state of the container repository. |
| <a id="containerrepositorydetailsname"></a>`name` | [`String!`](#string) | Name of the container repository. |
diff --git a/doc/ci/yaml/artifacts_reports.md b/doc/ci/yaml/artifacts_reports.md
index 874c3c2b196..486e37407ad 100644
--- a/doc/ci/yaml/artifacts_reports.md
+++ b/doc/ci/yaml/artifacts_reports.md
@@ -80,34 +80,17 @@ GitLab can display the results of one or more reports in:
- The [security dashboard](../../user/application_security/security_dashboard/index.md).
- The [Project Vulnerability report](../../user/application_security/vulnerability_report/index.md).
-## `artifacts:reports:cobertura` (DEPRECATED)
+## `artifacts:reports:coverage_report`
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3708) in GitLab 12.9.
-> - [Deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78132) in GitLab 14.9.
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344533) in GitLab 14.10.
-WARNING:
-This feature is in its end-of-life process. It is [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78132)
-in GitLab 14.9 and planned for removal in GitLab 15.0. The alternative `artifacts:reports:coverage_report`
-is available GitLab 14.10.
+Use `coverage_report` to collect coverage report in Cobertura format.
The `cobertura` report collects [Cobertura coverage XML files](../../user/project/merge_requests/test_coverage_visualization.md).
-The collected Cobertura coverage reports upload to GitLab as an artifact.
-
-GitLab can display the results of one or more reports in the merge request
-[diff annotations](../../user/project/merge_requests/test_coverage_visualization.md).
Cobertura was originally developed for Java, but there are many third-party ports for other languages such as
JavaScript, Python, and Ruby.
-## `artifacts:reports:coverage_report`
-
-> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/344533) in GitLab 14.10.
-
-Use `coverage_report` to collect coverage report in Cobertura format, similar to `artifacts:reports:cobertura`.
-
-NOTE:
-`artifacts:reports:coverage_report` cannot be used at the same time with `artifacts:reports:cobertura`.
-
```yaml
artifacts:
reports:
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 434693a0e11..5f1e02c9da6 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -698,7 +698,7 @@ Properties of customer critical merge requests:
- It is required that the reviewer(s) and maintainer(s) involved with a customer critical merge request are engaged as soon as this decision is made.
- It is required to prioritize work for those involved on a customer critical merge request so that they have the time available necessary to focus on it.
- It is required to adhere to GitLab [values](https://about.gitlab.com/handbook/values/) and processes when working on customer critical merge requests, taking particular note of family and friends first/work second, definition of done, iteration, and release when it's ready.
-- Customer critical merge requests are required to not reduce security, introduce data-loss risk, reduce availability, nor break existing functionality per the process for [prioritizing technical decisions](https://about.gitlab.com/handbook/engineering/principles/#prioritizing-technical-decisions).
+- Customer critical merge requests are required to not reduce security, introduce data-loss risk, reduce availability, nor break existing functionality per the process for [prioritizing technical decisions](https://about.gitlab.com/handbook/engineering/development/principles/#prioritizing-technical-decisions).
- On customer critical requests, it is _recommended_ that those involved _consider_ coordinating synchronously (Zoom, Slack) in addition to asynchronously (merge requests comments) if they believe this may reduce the elapsed time to merge even though this _may_ sacrifice [efficiency](https://about.gitlab.com/company/culture/all-remote/asynchronous/#evaluating-efficiency.md).
- After a customer critical merge request is merged, a retrospective must be completed with the intention of reducing the frequency of future customer critical merge requests.
diff --git a/doc/development/dangerbot.md b/doc/development/dangerbot.md
index fd9378f6d7d..28609153ed3 100644
--- a/doc/development/dangerbot.md
+++ b/doc/development/dangerbot.md
@@ -66,7 +66,7 @@ continue to apply. However, there are a few things that deserve special emphasis
Danger is a powerful tool and flexible tool, but not always the most appropriate
way to solve a given problem or workflow.
-First, be aware of the GitLab [commitment to dogfooding](https://about.gitlab.com/handbook/engineering/principles/#dogfooding).
+First, be aware of the GitLab [commitment to dogfooding](https://about.gitlab.com/handbook/engineering/development/principles/#dogfooding).
The code we write for Danger is GitLab-specific, and it **may not** be most
appropriate place to implement functionality that addresses a need we encounter.
Our users, customers, and even our own satellite projects, such as [Gitaly](https://gitlab.com/gitlab-org/gitaly),
diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md
index 9f222f157a1..0affc11de02 100644
--- a/doc/development/documentation/styleguide/word_list.md
+++ b/doc/development/documentation/styleguide/word_list.md
@@ -539,7 +539,7 @@ When writing about licenses:
- Do not use variations such as **cloud license**, **offline license**, or **legacy license**.
- Do not use interchangeably with **subscription**:
- - A license grants users access to the subscription they purchased, and contains information such as the number of seats and subscription dates.
+ - A license grants users access to the subscription they purchased, and contains information such as the number of seats they purchased and subscription dates.
- A subscription is the subscription tier that the user purchases.
Use:
diff --git a/doc/development/fe_guide/design_anti_patterns.md b/doc/development/fe_guide/design_anti_patterns.md
index 76825d6ff18..b7238bb2813 100644
--- a/doc/development/fe_guide/design_anti_patterns.md
+++ b/doc/development/fe_guide/design_anti_patterns.md
@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
Anti-patterns may seem like good approaches at first, but it has been shown that they bring more ills than benefits. These should
generally be avoided.
-Throughout the GitLab codebase, there may be historic uses of these anti-patterns. Please [use discretion](https://about.gitlab.com/handbook/engineering/principles/#balance-refactoring-and-velocity)
+Throughout the GitLab codebase, there may be historic uses of these anti-patterns. Please [use discretion](https://about.gitlab.com/handbook/engineering/development/principles/#balance-refactoring-and-velocity)
when figuring out whether or not to refactor, when touching code that uses one of these legacy patterns.
NOTE:
diff --git a/doc/development/fips_compliance.md b/doc/development/fips_compliance.md
index 64dfbc9c10d..389c01e9a3f 100644
--- a/doc/development/fips_compliance.md
+++ b/doc/development/fips_compliance.md
@@ -98,6 +98,20 @@ virtual machine:
fips-mode-setup --disable
```
+#### Detect FIPS enablement in code
+
+You can query `GitLab::FIPS` in Ruby code to determine if the instance is FIPS-enabled:
+
+```ruby
+def default_min_key_size(name)
+ if Gitlab::FIPS.enabled?
+ Gitlab::SSHPublicKey.supported_sizes(name).select(&:positive?).min || -1
+ else
+ 0
+ end
+end
+```
+
## Set up a FIPS-enabled cluster
You can use the [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) to spin
diff --git a/doc/development/pipelines.md b/doc/development/pipelines.md
index 2fe295bfedb..cb1e224f062 100644
--- a/doc/development/pipelines.md
+++ b/doc/development/pipelines.md
@@ -12,7 +12,7 @@ which itself includes files under
[`.gitlab/ci/`](https://gitlab.com/gitlab-org/gitlab/-/tree/master/.gitlab/ci)
for easier maintenance.
-We're striving to [dogfood](https://about.gitlab.com/handbook/engineering/principles/#dogfooding)
+We're striving to [dogfood](https://about.gitlab.com/handbook/engineering/development/principles/#dogfooding)
GitLab [CI/CD features and best-practices](../ci/yaml/index.md)
as much as possible.
diff --git a/doc/development/ruby_upgrade.md b/doc/development/ruby_upgrade.md
index a208a93e300..551f8dd081e 100644
--- a/doc/development/ruby_upgrade.md
+++ b/doc/development/ruby_upgrade.md
@@ -272,4 +272,4 @@ and merged back independently.
- **Give yourself enough time to fix problems ahead of a milestone release.** GitLab moves fast.
As a Ruby upgrade requires many MRs to be sent and reviewed, make sure all changes are merged at least a week
before the 22nd. This gives us extra time to act if something breaks. If in doubt, it is better to
-postpone the upgrade to the following month, as we [prioritize availability over velocity](https://about.gitlab.com/handbook/engineering/principles/#prioritizing-technical-decisions).
+postpone the upgrade to the following month, as we [prioritize availability over velocity](https://about.gitlab.com/handbook/engineering/development/principles/#prioritizing-technical-decisions).
diff --git a/doc/development/service_ping/implement.md b/doc/development/service_ping/implement.md
index 1bbc65a0300..48d72431ddc 100644
--- a/doc/development/service_ping/implement.md
+++ b/doc/development/service_ping/implement.md
@@ -289,6 +289,8 @@ Enabled by default in GitLab 13.7 and later.
To increment the values, the related feature `usage_data_<event_name>` must be enabled.
+ Feature flags are required for this API and they can't be removed, they can be set to `default_enabled: true`.
+
```plaintext
POST /usage_data/increment_counter
```
diff --git a/doc/topics/git/troubleshooting_git.md b/doc/topics/git/troubleshooting_git.md
index 0aadde7f7c2..13962ad0376 100644
--- a/doc/topics/git/troubleshooting_git.md
+++ b/doc/topics/git/troubleshooting_git.md
@@ -214,7 +214,7 @@ apply more than one:
```shell
omnibus_gitconfig['system'] = {
# Set the http.postBuffer size, in bytes
- "http" => ["postBuffer => 524288000"]
+ "http" => ["postBuffer = 524288000"]
}
```
diff --git a/doc/user/project/merge_requests/test_coverage_visualization.md b/doc/user/project/merge_requests/test_coverage_visualization.md
index 156802d2164..c237452c01d 100644
--- a/doc/user/project/merge_requests/test_coverage_visualization.md
+++ b/doc/user/project/merge_requests/test_coverage_visualization.md
@@ -28,7 +28,7 @@ between pipeline completion and the visualization loading on the page.
For the coverage analysis to work, you have to provide a properly formatted
[Cobertura XML](https://cobertura.github.io/cobertura/) report to
-[`artifacts:reports:cobertura`](../../../ci/yaml/artifacts_reports.md#artifactsreportscobertura-deprecated).
+[`artifacts:reports:coverage_report`](../../../ci/yaml/artifacts_reports.md#artifactsreportscoverage_report).
This format was originally developed for Java, but most coverage analysis frameworks
for other languages have plugins to add support for it, like:
diff --git a/lib/gitlab/ci/config/entry/reports.rb b/lib/gitlab/ci/config/entry/reports.rb
index 606814c72ad..d5d204bb995 100644
--- a/lib/gitlab/ci/config/entry/reports.rb
+++ b/lib/gitlab/ci/config/entry/reports.rb
@@ -15,7 +15,7 @@ module Gitlab
ALLOWED_KEYS =
%i[junit codequality sast secret_detection dependency_scanning container_scanning
dast performance browser_performance load_performance license_scanning metrics lsif
- dotenv cobertura terraform accessibility
+ dotenv terraform accessibility
requirements coverage_fuzzing api_fuzzing cluster_image_scanning
coverage_report].freeze
@@ -45,13 +45,10 @@ module Gitlab
validates :metrics, array_of_strings_or_string: true
validates :lsif, array_of_strings_or_string: true
validates :dotenv, array_of_strings_or_string: true
- validates :cobertura, array_of_strings_or_string: true
validates :terraform, array_of_strings_or_string: true
validates :accessibility, array_of_strings_or_string: true
validates :requirements, array_of_strings_or_string: true
end
-
- validates :config, mutually_exclusive_keys: [:coverage_report, :cobertura]
end
def value
diff --git a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
index 83f9f7e533b..64a063388b2 100644
--- a/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
+++ b/lib/gitlab/ci/templates/MATLAB.gitlab-ci.yml
@@ -84,7 +84,9 @@ test_artifacts:
artifacts:
reports:
junit: "./artifacts/results.xml"
- cobertura: "./artifacts/cobertura.xml"
+ coverage_report:
+ coverage_format: cobertura
+ path: "./artifacts/cobertura.xml"
paths:
- "./artifacts"
diff --git a/lib/gitlab/usage/service_ping_report.rb b/lib/gitlab/usage/service_ping_report.rb
index 3e653b186a0..e73200cbd4a 100644
--- a/lib/gitlab/usage/service_ping_report.rb
+++ b/lib/gitlab/usage/service_ping_report.rb
@@ -3,6 +3,8 @@
module Gitlab
module Usage
class ServicePingReport
+ CACHE_KEY = 'usage_data'
+
class << self
def for(output:, cached: false)
case output.to_sym
@@ -26,7 +28,7 @@ module Gitlab
end
def all_metrics_values(cached)
- Rails.cache.fetch('usage_data', force: !cached, expires_in: 2.weeks) do
+ Rails.cache.fetch(CACHE_KEY, force: !cached, expires_in: 2.weeks) do
Gitlab::UsageData.data
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index b1824e17c03..d90273ef8db 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -5545,6 +5545,15 @@ msgstr ""
msgid "Background color"
msgstr ""
+msgid "BackgroundMigrations|Background Migrations"
+msgstr ""
+
+msgid "BackgroundMigrations|Background migrations are used to perform data migrations whenever a migration exceeds the time limits in our guidelines. %{linkStart}Learn more%{linkEnd}"
+msgstr ""
+
+msgid "BackgroundMigrations|Database"
+msgstr ""
+
msgid "Badges"
msgstr ""
@@ -11327,9 +11336,18 @@ msgstr ""
msgid "DastProfiles|New site profile"
msgstr ""
+msgid "DastProfiles|No scanner profile selected"
+msgstr ""
+
+msgid "DastProfiles|No scanner profile selected."
+msgstr ""
+
msgid "DastProfiles|No scanner profiles created yet"
msgstr ""
+msgid "DastProfiles|No site profile selected"
+msgstr ""
+
msgid "DastProfiles|No site profiles created yet"
msgstr ""
@@ -11378,9 +11396,27 @@ msgstr ""
msgid "DastProfiles|Scanner name"
msgstr ""
+msgid "DastProfiles|Scanner profile"
+msgstr ""
+
+msgid "DastProfiles|Scanner profiles define the configuration details of a security scanner. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
+msgid "DastProfiles|Select a scanner profile to run a DAST scan"
+msgstr ""
+
+msgid "DastProfiles|Select a site profile to run a DAST scan"
+msgstr ""
+
msgid "DastProfiles|Select branch"
msgstr ""
+msgid "DastProfiles|Select scanner profile"
+msgstr ""
+
+msgid "DastProfiles|Select site profile"
+msgstr ""
+
msgid "DastProfiles|Show debug messages"
msgstr ""
@@ -11393,6 +11429,9 @@ msgstr ""
msgid "DastProfiles|Site name"
msgstr ""
+msgid "DastProfiles|Site profiles define the attributes and configuration details of your deployed application, website, or API. %{linkStart}Learn more%{linkEnd}."
+msgstr ""
+
msgid "DastProfiles|Site type"
msgstr ""
diff --git a/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb b/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
index 2434fecf51a..2b48945137c 100644
--- a/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
+++ b/qa/qa/specs/features/api/4_verify/api_variable_inheritance_with_forward_pipeline_variables_spec.rb
@@ -29,7 +29,8 @@ module QA
it(
'is determined based on forward:pipeline_variables condition',
:aggregate_failures,
- testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360745'
+ testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/360745',
+ quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/361400', type: :investigating }
) do
# Is inheritable when true
expect(child1_pipeline).to have_variable(key: key, value: value),
diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb
index a18ebe9c9a0..874eabd1733 100644
--- a/spec/controllers/admin/application_settings_controller_spec.rb
+++ b/spec/controllers/admin/application_settings_controller_spec.rb
@@ -66,6 +66,26 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set
sign_in(admin)
end
+ context 'when there are recent ServicePing reports' do
+ it 'attempts to use prerecorded data' do
+ create(:raw_usage_data)
+
+ expect(Gitlab::Usage::ServicePingReport).not_to receive(:for)
+
+ get :usage_data, format: :json
+ end
+ end
+
+ context 'when there are NO recent ServicePing reports' do
+ it 'calculates data on the fly' do
+ allow(Gitlab::Usage::ServicePingReport).to receive(:for).and_call_original
+
+ get :usage_data, format: :json
+
+ expect(Gitlab::Usage::ServicePingReport).to have_received(:for)
+ end
+ end
+
it 'returns HTML data' do
get :usage_data, format: :html
@@ -368,4 +388,37 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set
expect(response).to redirect_to("https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf")
end
end
+
+ describe 'GET #service_usage_data' do
+ before do
+ stub_usage_data_connections
+ stub_database_flavor_check
+ sign_in(admin)
+ end
+
+ it 'assigns truthy value if there are recent ServicePing reports in database' do
+ create(:raw_usage_data)
+
+ get :service_usage_data, format: :html
+
+ expect(assigns(:service_ping_data_present)).to be_truthy
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'assigns truthy value if there are recent ServicePing reports in cache', :use_clean_rails_memory_store_caching do
+ Rails.cache.write('usage_data', true)
+
+ get :service_usage_data, format: :html
+
+ expect(assigns(:service_ping_data_present)).to be_truthy
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'assigns falsey value if there are NO recent ServicePing reports' do
+ get :service_usage_data, format: :html
+
+ expect(assigns(:service_ping_data_present)).to be_falsey
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+ end
end
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
index 032e3cc9dc0..fcb5910b85e 100644
--- a/spec/features/admin/admin_sees_background_migrations_spec.rb
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -77,6 +77,17 @@ RSpec.describe "Admin > Admin sees background migrations" do
end
end
+ it 'can fire an action with a database param' do
+ visit admin_background_migrations_path(database: 'main')
+
+ within '#content-body' do
+ tab = find_link 'Failed'
+ tab.click
+
+ expect(page).to have_selector("[method='post'][action='/admin/background_migrations/#{failed_migration.id}/retry?database=main']")
+ end
+ end
+
it 'can view and retry them' do
visit admin_background_migrations_path
@@ -120,4 +131,83 @@ RSpec.describe "Admin > Admin sees background migrations" do
expect(page).to have_content(finished_migration.status_name.to_s)
end
end
+
+ it 'can change tabs and retain database param' do
+ visit admin_background_migrations_path(database: 'ci')
+
+ within '#content-body' do
+ tab = find_link 'Finished'
+ expect(tab[:class]).not_to include('gl-tab-nav-item-active')
+
+ tab.click
+
+ expect(page).to have_current_path(admin_background_migrations_path(tab: 'finished', database: 'ci'))
+ expect(tab[:class]).to include('gl-tab-nav-item-active')
+ end
+ end
+
+ it 'can view documentation from Learn more link' do
+ visit admin_background_migrations_path
+
+ within '#content-body' do
+ expect(page).to have_link('Learn more', href: help_page_path('development/database/batched_background_migrations'))
+ end
+ end
+
+ describe 'selected database toggle', :js do
+ context 'when multi database is not enabled' do
+ before do
+ allow(Gitlab::Database).to receive(:db_config_names).and_return(['main'])
+ end
+
+ it 'does not render the database listbox' do
+ visit admin_background_migrations_path
+
+ expect(page).not_to have_selector('[data-testid="database-listbox"]')
+ end
+ end
+
+ context 'when multi database is enabled' do
+ before do
+ allow(Gitlab::Database).to receive(:db_config_names).and_return(%w[main ci])
+ end
+
+ it 'does render the database listbox' do
+ visit admin_background_migrations_path
+
+ expect(page).to have_selector('[data-testid="database-listbox"]')
+ end
+
+ it 'defaults to main when no parameter is passed' do
+ visit admin_background_migrations_path
+
+ listbox = page.find('[data-testid="database-listbox"]')
+
+ expect(listbox).to have_text('main')
+ end
+
+ it 'shows correct database when a parameter is passed' do
+ visit admin_background_migrations_path(database: 'ci')
+
+ listbox = page.find('[data-testid="database-listbox"]')
+
+ expect(listbox).to have_text('ci')
+ end
+
+ it 'updates the path to correct database when clicking on listbox option' do
+ visit admin_background_migrations_path
+
+ listbox = page.find('[data-testid="database-listbox"]')
+ expect(listbox).to have_text('main')
+
+ listbox.find('button').click
+ listbox.find('li', text: 'ci').click
+ wait_for_requests
+
+ expect(page).to have_current_path(admin_background_migrations_path(database: 'ci'))
+ listbox = page.find('[data-testid="database-listbox"]')
+ expect(listbox).to have_text('ci')
+ end
+ end
+ end
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
index 68ad1e25b47..32ae9c00c9e 100644
--- a/spec/features/admin/admin_settings_spec.rb
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -834,10 +834,9 @@ RSpec.describe 'Admin updates settings' do
stub_database_flavor_check
end
- context 'when service data cached', :clean_gitlab_redis_cache do
+ context 'when service data cached', :use_clean_rails_memory_store_caching do
before do
- allow(Rails.cache).to receive(:exist?).with('usage_data').and_return(true)
-
+ visit usage_data_admin_application_settings_path
visit service_usage_data_admin_application_settings_path
end
diff --git a/spec/fixtures/api/schemas/graphql/container_repository.json b/spec/fixtures/api/schemas/graphql/container_repository.json
index 04e67f73844..2bb598a14cb 100644
--- a/spec/fixtures/api/schemas/graphql/container_repository.json
+++ b/spec/fixtures/api/schemas/graphql/container_repository.json
@@ -1,6 +1,6 @@
{
"type": "object",
- "required": ["id", "name", "path", "location", "createdAt", "updatedAt", "tagsCount", "canDelete", "expirationPolicyCleanupStatus", "project"],
+ "required": ["id", "name", "path", "location", "createdAt", "updatedAt", "tagsCount", "canDelete", "expirationPolicyCleanupStatus", "project", "lastCleanupDeletedTagsCount"],
"properties": {
"id": {
"type": "string"
@@ -38,6 +38,9 @@
},
"project": {
"type": "object"
+ },
+ "lastCleanupDeletedTagsCount": {
+ "type": ["string", "null"]
}
}
}
diff --git a/spec/frontend/admin/background_migrations/components/database_listbox_spec.js b/spec/frontend/admin/background_migrations/components/database_listbox_spec.js
new file mode 100644
index 00000000000..3778943872e
--- /dev/null
+++ b/spec/frontend/admin/background_migrations/components/database_listbox_spec.js
@@ -0,0 +1,57 @@
+import { GlListbox } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import BackgroundMigrationsDatabaseListbox from '~/admin/background_migrations/components/database_listbox.vue';
+import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
+import { MOCK_DATABASES, MOCK_SELECTED_DATABASE } from '../mock_data';
+
+jest.mock('~/lib/utils/url_utility', () => ({
+ visitUrl: jest.fn(),
+ setUrlParams: jest.fn(),
+}));
+
+describe('BackgroundMigrationsDatabaseListbox', () => {
+ let wrapper;
+
+ const defaultProps = {
+ databases: MOCK_DATABASES,
+ selectedDatabase: MOCK_SELECTED_DATABASE,
+ };
+
+ const createComponent = (props = {}) => {
+ wrapper = shallowMount(BackgroundMigrationsDatabaseListbox, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ const findGlListbox = () => wrapper.findComponent(GlListbox);
+
+ describe('template always', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders GlListbox', () => {
+ expect(findGlListbox().exists()).toBe(true);
+ });
+ });
+
+ describe('actions', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('selecting a listbox item fires visitUrl with the database param', () => {
+ findGlListbox().vm.$emit('select', MOCK_DATABASES[1].value);
+
+ expect(setUrlParams).toHaveBeenCalledWith({ database: MOCK_DATABASES[1].value });
+ expect(visitUrl).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/admin/background_migrations/mock_data.js b/spec/frontend/admin/background_migrations/mock_data.js
new file mode 100644
index 00000000000..fbb1718f6b8
--- /dev/null
+++ b/spec/frontend/admin/background_migrations/mock_data.js
@@ -0,0 +1,6 @@
+export const MOCK_DATABASES = [
+ { value: 'main', text: 'main' },
+ { value: 'ci', text: 'ci' },
+];
+
+export const MOCK_SELECTED_DATABASE = 'main';
diff --git a/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js b/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js
index 35f5b381c75..3a15ea45f40 100644
--- a/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js
+++ b/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js
@@ -124,7 +124,7 @@ describe('content_editor/components/bubble_menus/code_block', () => {
describe('when dropdown item is clicked', () => {
beforeEach(async () => {
- jest.spyOn(codeBlockLanguageLoader, 'loadLanguages').mockResolvedValue();
+ jest.spyOn(codeBlockLanguageLoader, 'loadLanguage').mockResolvedValue();
findDropdownItems().at(1).vm.$emit('click');
@@ -132,7 +132,7 @@ describe('content_editor/components/bubble_menus/code_block', () => {
});
it('loads language', () => {
- expect(codeBlockLanguageLoader.loadLanguages).toHaveBeenCalledWith(['java']);
+ expect(codeBlockLanguageLoader.loadLanguage).toHaveBeenCalledWith('java');
});
it('sets code block', () => {
diff --git a/spec/frontend/content_editor/components/wrappers/frontmatter_spec.js b/spec/frontend/content_editor/components/wrappers/code_block_spec.js
index 415f1314a36..a564959a3a6 100644
--- a/spec/frontend/content_editor/components/wrappers/frontmatter_spec.js
+++ b/spec/frontend/content_editor/components/wrappers/code_block_spec.js
@@ -1,20 +1,33 @@
+import { nextTick } from 'vue';
import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2';
import { shallowMount } from '@vue/test-utils';
-import FrontmatterWrapper from '~/content_editor/components/wrappers/frontmatter.vue';
+import CodeBlockWrapper from '~/content_editor/components/wrappers/code_block.vue';
+import codeBlockLanguageLoader from '~/content_editor/services/code_block_language_loader';
-describe('content/components/wrappers/frontmatter', () => {
+jest.mock('~/content_editor/services/code_block_language_loader');
+
+describe('content/components/wrappers/code_block', () => {
+ const language = 'yaml';
let wrapper;
+ let updateAttributesFn;
+
+ const createWrapper = async (nodeAttrs = { language }) => {
+ updateAttributesFn = jest.fn();
- const createWrapper = async (nodeAttrs = { language: 'yaml' }) => {
- wrapper = shallowMount(FrontmatterWrapper, {
+ wrapper = shallowMount(CodeBlockWrapper, {
propsData: {
node: {
attrs: nodeAttrs,
},
+ updateAttributes: updateAttributesFn,
},
});
};
+ beforeEach(() => {
+ codeBlockLanguageLoader.findLanguageBySyntax.mockReturnValue({ syntax: language });
+ });
+
afterEach(() => {
wrapper.destroy();
});
@@ -38,11 +51,21 @@ describe('content/components/wrappers/frontmatter', () => {
});
it('renders label indicating that code block is frontmatter', () => {
- createWrapper();
+ createWrapper({ isFrontmatter: true, language });
const label = wrapper.find('[data-testid="frontmatter-label"]');
expect(label.text()).toEqual('frontmatter:yaml');
expect(label.classes()).toEqual(['gl-absolute', 'gl-top-0', 'gl-right-3']);
});
+
+ it('loads code block’s syntax highlight language', async () => {
+ createWrapper();
+
+ expect(codeBlockLanguageLoader.loadLanguage).toHaveBeenCalledWith(language);
+
+ await nextTick();
+
+ expect(updateAttributesFn).toHaveBeenCalledWith({ language });
+ });
});
diff --git a/spec/frontend/content_editor/extensions/code_block_highlight_spec.js b/spec/frontend/content_editor/extensions/code_block_highlight_spec.js
index 02e5b1dc271..fc8460c7f84 100644
--- a/spec/frontend/content_editor/extensions/code_block_highlight_spec.js
+++ b/spec/frontend/content_editor/extensions/code_block_highlight_spec.js
@@ -1,4 +1,5 @@
import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
+import languageLoader from '~/content_editor/services/code_block_language_loader';
import { createTestEditor, createDocBuilder, triggerNodeInputRule } from '../test_utils';
const CODE_BLOCK_HTML = `<pre class="code highlight js-syntax-highlight language-javascript" lang="javascript" v-pre="true">
@@ -9,20 +10,20 @@ const CODE_BLOCK_HTML = `<pre class="code highlight js-syntax-highlight language
</code>
</pre>`;
+jest.mock('~/content_editor/services/code_block_language_loader');
+
describe('content_editor/extensions/code_block_highlight', () => {
let parsedCodeBlockHtmlFixture;
let tiptapEditor;
let doc;
let codeBlock;
- let languageLoader;
const parseHTML = (html) => new DOMParser().parseFromString(html, 'text/html');
const preElement = () => parsedCodeBlockHtmlFixture.querySelector('pre');
beforeEach(() => {
- languageLoader = { loadLanguages: jest.fn() };
tiptapEditor = createTestEditor({
- extensions: [CodeBlockHighlight.configure({ languageLoader })],
+ extensions: [CodeBlockHighlight],
});
({
@@ -70,6 +71,8 @@ describe('content_editor/extensions/code_block_highlight', () => {
const language = 'javascript';
beforeEach(() => {
+ languageLoader.loadLanguageFromInputRule.mockReturnValueOnce({ language });
+
triggerNodeInputRule({
tiptapEditor,
inputRuleText: `${inputRule}${language} `,
@@ -83,7 +86,9 @@ describe('content_editor/extensions/code_block_highlight', () => {
});
it('loads language when language loader is available', () => {
- expect(languageLoader.loadLanguages).toHaveBeenCalledWith([language]);
+ expect(languageLoader.loadLanguageFromInputRule).toHaveBeenCalledWith(
+ expect.arrayContaining([`${inputRule}${language} `, language]),
+ );
});
});
});
diff --git a/spec/frontend/content_editor/extensions/diagram_spec.js b/spec/frontend/content_editor/extensions/diagram_spec.js
new file mode 100644
index 00000000000..b8d9e0b5aeb
--- /dev/null
+++ b/spec/frontend/content_editor/extensions/diagram_spec.js
@@ -0,0 +1,16 @@
+import Diagram from '~/content_editor/extensions/diagram';
+import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight';
+
+describe('content_editor/extensions/diagram', () => {
+ it('inherits from code block highlight extension', () => {
+ expect(Diagram.parent).toBe(CodeBlockHighlight);
+ });
+
+ it('sets isDiagram attribute to true by default', () => {
+ expect(Diagram.config.addAttributes()).toEqual(
+ expect.objectContaining({
+ isDiagram: { default: true },
+ }),
+ );
+ });
+});
diff --git a/spec/frontend/content_editor/extensions/frontmatter_spec.js b/spec/frontend/content_editor/extensions/frontmatter_spec.js
index 4f80c2cb81a..9bd29070858 100644
--- a/spec/frontend/content_editor/extensions/frontmatter_spec.js
+++ b/spec/frontend/content_editor/extensions/frontmatter_spec.js
@@ -22,6 +22,10 @@ describe('content_editor/extensions/frontmatter', () => {
}));
});
+ it('inherits from code block highlight extension', () => {
+ expect(Frontmatter.parent).toBe(CodeBlockHighlight);
+ });
+
it('does not insert a frontmatter block when executing code block input rule', () => {
const expectedDoc = doc(codeBlock({ language: 'plaintext' }, ''));
const inputRuleText = '``` ';
@@ -31,6 +35,14 @@ describe('content_editor/extensions/frontmatter', () => {
expect(tiptapEditor.getJSON()).toEqual(expectedDoc.toJSON());
});
+ it('sets isFrontmatter attribute to true by default', () => {
+ expect(Frontmatter.config.addAttributes()).toEqual(
+ expect.objectContaining({
+ isFrontmatter: { default: true },
+ }),
+ );
+ });
+
it.each`
command | result | resultDesc
${'toggleCodeBlock'} | ${() => doc(codeBlock(''))} | ${'code block element'}
diff --git a/spec/frontend/content_editor/services/code_block_language_loader_spec.js b/spec/frontend/content_editor/services/code_block_language_loader_spec.js
index 55f4e0ed4e3..943de327762 100644
--- a/spec/frontend/content_editor/services/code_block_language_loader_spec.js
+++ b/spec/frontend/content_editor/services/code_block_language_loader_spec.js
@@ -53,23 +53,19 @@ describe('content_editor/services/code_block_language_loader', () => {
});
});
- describe('loadLanguages', () => {
+ describe('loadLanguage', () => {
it('loads highlight.js language packages identified by a list of languages', async () => {
- const languages = ['javascript', 'ruby'];
+ const language = 'javascript';
- await languageLoader.loadLanguages(languages);
+ await languageLoader.loadLanguage(language);
- languages.forEach((language) => {
- expect(lowlight.registerLanguage).toHaveBeenCalledWith(language, expect.any(Function));
- });
+ expect(lowlight.registerLanguage).toHaveBeenCalledWith(language, expect.any(Function));
});
describe('when language is already registered', () => {
it('does not load the language again', async () => {
- const languages = ['javascript'];
-
- await languageLoader.loadLanguages(languages);
- await languageLoader.loadLanguages(languages);
+ await languageLoader.loadLanguage('javascript');
+ await languageLoader.loadLanguage('javascript');
expect(lowlight.registerLanguage).toHaveBeenCalledTimes(1);
});
@@ -94,7 +90,7 @@ describe('content_editor/services/code_block_language_loader', () => {
expect(languageLoader.isLanguageLoaded(language)).toBe(false);
- await languageLoader.loadLanguages([language]);
+ await languageLoader.loadLanguage(language);
expect(languageLoader.isLanguageLoaded(language)).toBe(true);
});
diff --git a/spec/frontend/content_editor/services/content_editor_spec.js b/spec/frontend/content_editor/services/content_editor_spec.js
index fde4f8f6282..a3553e612ca 100644
--- a/spec/frontend/content_editor/services/content_editor_spec.js
+++ b/spec/frontend/content_editor/services/content_editor_spec.js
@@ -11,7 +11,6 @@ describe('content_editor/services/content_editor', () => {
let contentEditor;
let serializer;
let deserializer;
- let languageLoader;
let eventHub;
let doc;
let p;
@@ -28,14 +27,12 @@ describe('content_editor/services/content_editor', () => {
serializer = { serialize: jest.fn() };
deserializer = { deserialize: jest.fn() };
- languageLoader = { loadLanguages: jest.fn() };
eventHub = eventHubFactory();
contentEditor = new ContentEditor({
tiptapEditor,
serializer,
deserializer,
eventHub,
- languageLoader,
});
});
@@ -77,12 +74,6 @@ describe('content_editor/services/content_editor', () => {
expect(contentEditor.tiptapEditor.state.doc.toJSON()).toEqual(document.toJSON());
});
-
- it('passes deserialized DOM document to language loader', async () => {
- await contentEditor.setSerializedContent(testMarkdown);
-
- expect(languageLoader.loadLanguages).toHaveBeenCalledWith(languages);
- });
});
describe('when setSerializedContent fails', () => {
diff --git a/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js b/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js
index e399c1f6bea..5458a42532f 100644
--- a/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js
+++ b/spec/frontend/content_editor/services/gl_api_markdown_deserializer_spec.js
@@ -46,10 +46,6 @@ describe('content_editor/services/gl_api_markdown_deserializer', () => {
expect(result.document.toJSON()).toEqual(document.toJSON());
});
-
- it('returns languages of code blocks found in the document', () => {
- expect(result.languages).toEqual(['javascript']);
- });
});
describe('when the render function returns an empty value', () => {
diff --git a/spec/frontend/content_editor/services/remark_markdown_deserializer_spec.js b/spec/frontend/content_editor/services/remark_markdown_deserializer_spec.js
index 66ca1587ec6..4521d2c1949 100644
--- a/spec/frontend/content_editor/services/remark_markdown_deserializer_spec.js
+++ b/spec/frontend/content_editor/services/remark_markdown_deserializer_spec.js
@@ -273,7 +273,7 @@ two
markdown: `
const fn = () => 'GitLab';
`,
- doc: doc(codeBlock({ language: '' }, "const fn = () => 'GitLab';\n")),
+ doc: doc(codeBlock({ language: null }, "const fn = () => 'GitLab';")),
},
{
markdown: `
@@ -281,14 +281,14 @@ two
const fn = () => 'GitLab';
\`\`\`\
`,
- doc: doc(codeBlock({ language: 'javascript' }, " const fn = () => 'GitLab';\n")),
+ doc: doc(codeBlock({ language: 'javascript' }, " const fn = () => 'GitLab';")),
},
{
markdown: `
\`\`\`
\`\`\`\
`,
- doc: doc(codeBlock({ language: '' }, '')),
+ doc: doc(codeBlock({ language: null }, '')),
},
{
markdown: `
@@ -298,7 +298,7 @@ two
\`\`\`\
`,
- doc: doc(codeBlock({ language: 'javascript' }, " const fn = () => 'GitLab';\n\n\n")),
+ doc: doc(codeBlock({ language: 'javascript' }, " const fn = () => 'GitLab';\n\n")),
},
])('deserializes %s correctly', async ({ markdown, doc: expectedDoc }) => {
const { schema } = tiptapEditor;
diff --git a/spec/frontend/editor/schema/ci/json_tests/positive_tests/gitlab-ci.json b/spec/frontend/editor/schema/ci/json_tests/positive_tests/gitlab-ci.json
index 89420bbc35f..666a4852957 100644
--- a/spec/frontend/editor/schema/ci/json_tests/positive_tests/gitlab-ci.json
+++ b/spec/frontend/editor/schema/ci/json_tests/positive_tests/gitlab-ci.json
@@ -97,7 +97,10 @@
"expire_in": "1 week",
"reports": {
"junit": "result.xml",
- "cobertura": "cobertura-coverage.xml",
+ "coverage_report": {
+ "coverage_format": "cobertura",
+ "path": "cobertura-coverage.xml"
+ },
"codequality": "codequality.json",
"sast": "sast.json",
"dependency_scanning": "scan.json",
@@ -147,7 +150,10 @@
"artifacts": {
"reports": {
"junit": ["result.xml"],
- "cobertura": ["cobertura-coverage.xml"],
+ "coverage_report": {
+ "coverage_format": "cobertura",
+ "path": "cobertura-coverage.xml"
+ },
"codequality": ["codequality.json"],
"sast": ["sast.json"],
"dependency_scanning": ["scan.json"],
diff --git a/spec/graphql/types/container_repository_details_type_spec.rb b/spec/graphql/types/container_repository_details_type_spec.rb
index d94516c6fce..62e72089e09 100644
--- a/spec/graphql/types/container_repository_details_type_spec.rb
+++ b/spec/graphql/types/container_repository_details_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'] do
fields = %i[id name path location created_at updated_at expiration_policy_started_at
status tags_count can_delete expiration_policy_cleanup_status tags size
- project migration_state]
+ project migration_state last_cleanup_deleted_tags_count]
it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') }
diff --git a/spec/graphql/types/container_repository_type_spec.rb b/spec/graphql/types/container_repository_type_spec.rb
index 9815449dd68..bc92fa24050 100644
--- a/spec/graphql/types/container_repository_type_spec.rb
+++ b/spec/graphql/types/container_repository_type_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
RSpec.describe GitlabSchema.types['ContainerRepository'] do
fields = %i[id name path location created_at updated_at expiration_policy_started_at
status tags_count can_delete expiration_policy_cleanup_status project
- migration_state]
+ migration_state last_cleanup_deleted_tags_count]
it { expect(described_class.graphql_name).to eq('ContainerRepository') }
diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
index ff3ec6196f0..051cccb4833 100644
--- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb
@@ -45,7 +45,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports do
:load_performance | 'load-performance.json'
:lsif | 'lsif.json'
:dotenv | 'build.dotenv'
- :cobertura | 'cobertura-coverage.xml'
:terraform | 'tfplan.json'
:accessibility | 'gl-accessibility.json'
end
@@ -89,18 +88,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports do
expect(entry.value).to eq({ coverage_report: coverage_report, dast: ['gl-dast-report.json'] })
end
end
-
- context 'and a direct coverage report format is specified' do
- let(:config) { { coverage_report: coverage_report, cobertura: 'cobertura-coverage.xml' } }
-
- it 'is not valid' do
- expect(entry).not_to be_valid
- end
-
- it 'reports error' do
- expect(entry.errors).to include /please use only one the following keys: coverage_report, cobertura/
- end
- end
end
end
diff --git a/spec/models/raw_usage_data_spec.rb b/spec/models/raw_usage_data_spec.rb
index 6ff4c6eb19b..95b98279a27 100644
--- a/spec/models/raw_usage_data_spec.rb
+++ b/spec/models/raw_usage_data_spec.rb
@@ -3,6 +3,31 @@
require 'spec_helper'
RSpec.describe RawUsageData do
+ context 'scopes' do
+ describe '.for_current_reporting_cycle' do
+ subject(:recent_service_ping_reports) { described_class.for_current_reporting_cycle }
+
+ before_all do
+ create(:raw_usage_data, created_at: (described_class::REPORTING_CADENCE + 1.day).ago)
+ end
+
+ it 'returns nil where no records match filter criteria' do
+ expect(recent_service_ping_reports).to be_empty
+ end
+
+ context 'with records matching filtering criteria' do
+ let_it_be(:fresh_record) { create(:raw_usage_data) }
+ let_it_be(:record_at_edge_of_time_range) do
+ create(:raw_usage_data, created_at: described_class::REPORTING_CADENCE.ago)
+ end
+
+ it 'return records within reporting cycle time range ordered by creation time' do
+ expect(recent_service_ping_reports).to eq [fresh_record, record_at_edge_of_time_range]
+ end
+ end
+ end
+ end
+
describe 'validations' do
it { is_expected.to validate_presence_of(:payload) }
it { is_expected.to validate_presence_of(:recorded_at) }