diff options
| author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-23 22:34:10 +0000 |
|---|---|---|
| committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-23 22:34:10 +0000 |
| commit | 96855c4214715fe718c02a308ddd0e4a3265b5d1 (patch) | |
| tree | 1dd318ede0a420effd7d0eb41a980c4adc24fae5 | |
| parent | 5248069bd6ee923a76047fa74dee46155c40fa2b (diff) | |
| download | gitlab-ce-96855c4214715fe718c02a308ddd0e4a3265b5d1.tar.gz | |
Add latest changes from gitlab-org/gitlab@master
79 files changed, 872 insertions, 203 deletions
diff --git a/app/assets/javascripts/content_editor/components/wrappers/frontmatter.vue b/app/assets/javascripts/content_editor/components/wrappers/frontmatter.vue new file mode 100644 index 00000000000..97b69afd12e --- /dev/null +++ b/app/assets/javascripts/content_editor/components/wrappers/frontmatter.vue @@ -0,0 +1,32 @@ +<script> +import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2'; +import { __ } from '~/locale'; + +export default { + name: 'FrontMatter', + components: { + NodeViewWrapper, + NodeViewContent, + }, + props: { + node: { + type: Object, + required: true, + }, + }, + i18n: { + frontmatter: __('frontmatter'), + }, +}; +</script> +<template> + <node-view-wrapper class="gl-relative code highlight" as="pre"> + <span + data-testid="frontmatter-label" + class="gl-absolute gl-top-0 gl-right-3" + contenteditable="false" + >{{ $options.i18n.frontmatter }}:{{ node.attrs.language }}</span + > + <node-view-content as="code" /> + </node-view-wrapper> +</template> 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 25f5837d2a6..1ed1ab0315f 100644 --- a/app/assets/javascripts/content_editor/extensions/code_block_highlight.js +++ b/app/assets/javascripts/content_editor/extensions/code_block_highlight.js @@ -11,7 +11,8 @@ export default CodeBlockLowlight.extend({ parseHTML: (element) => extractLanguage(element), }, class: { - default: 'code highlight js-syntax-highlight', + // eslint-disable-next-line @gitlab/require-i18n-strings + default: 'code highlight', }, }; }, diff --git a/app/assets/javascripts/content_editor/extensions/frontmatter.js b/app/assets/javascripts/content_editor/extensions/frontmatter.js new file mode 100644 index 00000000000..64c84fe046b --- /dev/null +++ b/app/assets/javascripts/content_editor/extensions/frontmatter.js @@ -0,0 +1,20 @@ +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', + parseHTML() { + return [ + { + tag: 'pre[data-lang-params="frontmatter"]', + preserveWhitespace: 'full', + priority: PARSE_HTML_PRIORITY_HIGHEST, + }, + ]; + }, + addNodeView() { + return new VueNodeViewRenderer(FrontmatterWrapper); + }, +}); diff --git a/app/assets/javascripts/content_editor/extensions/word_break.js b/app/assets/javascripts/content_editor/extensions/word_break.js new file mode 100644 index 00000000000..93b42466850 --- /dev/null +++ b/app/assets/javascripts/content_editor/extensions/word_break.js @@ -0,0 +1,29 @@ +import { Node, mergeAttributes, nodeInputRule } from '@tiptap/core'; + +export const inputRegex = /^<wbr>$/; + +export default Node.create({ + name: 'wordBreak', + inline: true, + group: 'inline', + selectable: false, + atom: true, + + defaultOptions: { + HTMLAttributes: { + class: 'gl-display-inline-flex gl-px-1 gl-bg-blue-100 gl-rounded-base gl-font-sm', + }, + }, + + parseHTML() { + return [{ tag: 'wbr' }]; + }, + + renderHTML({ HTMLAttributes }) { + return ['span', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), '-']; + }, + + addInputRules() { + return [nodeInputRule(inputRegex, this.type)]; + }, +}); 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 855f561a739..0471adf67e9 100644 --- a/app/assets/javascripts/content_editor/services/create_content_editor.js +++ b/app/assets/javascripts/content_editor/services/create_content_editor.js @@ -16,6 +16,7 @@ import Dropcursor from '../extensions/dropcursor'; import Emoji from '../extensions/emoji'; import Figure from '../extensions/figure'; import FigureCaption from '../extensions/figure_caption'; +import Frontmatter from '../extensions/frontmatter'; import Gapcursor from '../extensions/gapcursor'; import HardBreak from '../extensions/hard_break'; import Heading from '../extensions/heading'; @@ -43,6 +44,7 @@ import TaskItem from '../extensions/task_item'; import TaskList from '../extensions/task_list'; import Text from '../extensions/text'; import Video from '../extensions/video'; +import WordBreak from '../extensions/word_break'; import { ContentEditor } from './content_editor'; import createMarkdownSerializer from './markdown_serializer'; import trackInputRulesAndShortcuts from './track_input_rules_and_shortcuts'; @@ -85,6 +87,7 @@ export const createContentEditor = ({ Emoji, Figure, FigureCaption, + Frontmatter, Gapcursor, HardBreak, Heading, @@ -112,6 +115,7 @@ export const createContentEditor = ({ TaskList, Text, Video, + WordBreak, ]; const allExtensions = [...builtInContentEditorExtensions, ...extensions]; diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js index 0c2f8d281c3..19b67f6fde8 100644 --- a/app/assets/javascripts/content_editor/services/markdown_serializer.js +++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js @@ -15,6 +15,7 @@ import Division from '../extensions/division'; import Emoji from '../extensions/emoji'; import Figure from '../extensions/figure'; import FigureCaption from '../extensions/figure_caption'; +import Frontmatter from '../extensions/frontmatter'; import HardBreak from '../extensions/hard_break'; import Heading from '../extensions/heading'; import HorizontalRule from '../extensions/horizontal_rule'; @@ -39,6 +40,7 @@ import TaskItem from '../extensions/task_item'; import TaskList from '../extensions/task_list'; import Text from '../extensions/text'; import Video from '../extensions/video'; +import WordBreak from '../extensions/word_break'; import { isPlainURL, renderHardBreak, @@ -136,6 +138,20 @@ const defaultSerializerConfig = { state.write(`:${name}:`); }, + [Frontmatter.name]: (state, node) => { + const { language } = node.attrs; + const syntax = { + toml: '+++', + json: ';;;', + yaml: '---', + }[language]; + + state.write(`${syntax}\n`); + state.text(node.textContent, false); + state.ensureNewLine(); + state.write(syntax); + state.closeBlock(node); + }, [Figure.name]: renderHTMLNode('figure'), [FigureCaption.name]: renderHTMLNode('figcaption'), [HardBreak.name]: renderHardBreak, @@ -166,6 +182,7 @@ const defaultSerializerConfig = { }, [Text.name]: defaultMarkdownSerializer.nodes.text, [Video.name]: renderPlayable, + [WordBreak.name]: (state) => state.write('<wbr>'), }, }; diff --git a/app/assets/javascripts/error_tracking_settings/components/app.vue b/app/assets/javascripts/error_tracking_settings/components/app.vue index e12d9cc2b07..4808cd1d1c0 100644 --- a/app/assets/javascripts/error_tracking_settings/components/app.vue +++ b/app/assets/javascripts/error_tracking_settings/components/app.vue @@ -1,6 +1,14 @@ <script> -import { GlButton, GlFormGroup, GlFormCheckbox, GlFormRadioGroup, GlFormRadio } from '@gitlab/ui'; +import { + GlButton, + GlFormGroup, + GlFormCheckbox, + GlFormRadioGroup, + GlFormRadio, + GlFormInputGroup, +} from '@gitlab/ui'; import { mapActions, mapGetters, mapState } from 'vuex'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ErrorTrackingForm from './error_tracking_form.vue'; import ProjectDropdown from './project_dropdown.vue'; @@ -12,7 +20,9 @@ export default { GlFormGroup, GlFormRadioGroup, GlFormRadio, + GlFormInputGroup, ProjectDropdown, + ClipboardButton, }, props: { initialApiHost: { @@ -46,6 +56,11 @@ export default { type: String, required: true, }, + gitlabDsn: { + type: String, + required: false, + default: null, + }, }, computed: { ...mapGetters([ @@ -63,6 +78,9 @@ export default { 'settingsLoading', 'token', ]), + showGitlabDsnSetting() { + return this.integrated && this.enabled && this.gitlabDsn; + }, }, created() { this.setInitialState({ @@ -119,6 +137,17 @@ export default { </gl-form-radio> </gl-form-radio-group> </gl-form-group> + <gl-form-group + v-if="showGitlabDsnSetting" + :label="__('Paste this DSN into your Sentry SDK')" + data-testid="gitlab-dsn-setting-form" + > + <gl-form-input-group readonly :value="gitlabDsn"> + <template #append> + <clipboard-button :text="gitlabDsn" :title="__('Copy')" /> + </template> + </gl-form-input-group> + </gl-form-group> <div v-if="!integrated" class="js-sentry-setting-form" data-testid="sentry-setting-form"> <error-tracking-form /> <div class="form-group"> diff --git a/app/assets/javascripts/error_tracking_settings/index.js b/app/assets/javascripts/error_tracking_settings/index.js index 324b3292834..69388329e1c 100644 --- a/app/assets/javascripts/error_tracking_settings/index.js +++ b/app/assets/javascripts/error_tracking_settings/index.js @@ -13,6 +13,7 @@ export default () => { token, listProjectsEndpoint, operationsSettingsEndpoint, + gitlabDsn, }, } = formContainerEl; @@ -29,6 +30,7 @@ export default () => { initialToken: token, listProjectsEndpoint, operationsSettingsEndpoint, + gitlabDsn, }, }); }, diff --git a/app/assets/javascripts/ide/stores/modules/commit/getters.js b/app/assets/javascripts/ide/stores/modules/commit/getters.js index f5e367e16f5..05e3601f381 100644 --- a/app/assets/javascripts/ide/stores/modules/commit/getters.js +++ b/app/assets/javascripts/ide/stores/modules/commit/getters.js @@ -1,14 +1,13 @@ -import { sprintf, n__, __ } from '../../../../locale'; +import { __ } from '../../../../locale'; import { COMMIT_TO_NEW_BRANCH } from './constants'; const BRANCH_SUFFIX_COUNT = 5; const createTranslatedTextForFiles = (files, text) => { if (!files.length) return null; - return sprintf(n__('%{text} %{files}', '%{text} %{files} files', files.length), { - files: files.reduce((acc, val) => acc.concat(val.path), []).join(', '), - text, - }); + const filesPart = files.reduce((acc, val) => acc.concat(val.path), []).join(', '); + + return `${text} ${filesPart}`; }; export const discardDraftButtonDisabled = (state) => diff --git a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue index 6b3a4424a5b..6ef507126ec 100644 --- a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue +++ b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue @@ -136,7 +136,13 @@ export default { <template> <gl-button-group> <template v-if="canReadJob"> - <gl-button v-if="isActive" icon="cancel" :title="$options.CANCEL" @click="cancelJob()" /> + <gl-button + v-if="isActive" + data-testid="cancel-button" + icon="cancel" + :title="$options.CANCEL" + @click="cancelJob()" + /> <template v-else-if="isScheduled"> <gl-button icon="planning" disabled data-testid="countdown"> <gl-countdown :end-date-string="scheduledAt" /> diff --git a/app/controllers/admin/serverless/domains_controller.rb b/app/controllers/admin/serverless/domains_controller.rb index 49cd9f7a36d..99eea8c35b4 100644 --- a/app/controllers/admin/serverless/domains_controller.rb +++ b/app/controllers/admin/serverless/domains_controller.rb @@ -4,7 +4,7 @@ class Admin::Serverless::DomainsController < Admin::ApplicationController before_action :check_feature_flag before_action :domain, only: [:update, :verify, :destroy] - feature_category :serverless + feature_category :not_owned def index @domain = PagesDomain.instance_serverless.first_or_initialize diff --git a/app/controllers/projects/serverless/functions_controller.rb b/app/controllers/projects/serverless/functions_controller.rb index 4168880001c..3fc379a135a 100644 --- a/app/controllers/projects/serverless/functions_controller.rb +++ b/app/controllers/projects/serverless/functions_controller.rb @@ -5,7 +5,7 @@ module Projects class FunctionsController < Projects::ApplicationController before_action :authorize_read_cluster! - feature_category :serverless + feature_category :not_owned def index respond_to do |format| diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb index dd5ce9f7387..25f812645b1 100644 --- a/app/models/error_tracking/project_error_tracking_setting.rb +++ b/app/models/error_tracking/project_error_tracking_setting.rb @@ -46,6 +46,11 @@ module ErrorTracking after_save :clear_reactive_cache! + # When a user enables the integrated error tracking + # we want to immediately provide them with a first + # working client key so they have a DSN for Sentry SDK. + after_save :create_client_key! + def sentry_enabled enabled && !integrated_client? end @@ -54,6 +59,12 @@ module ErrorTracking integrated end + def gitlab_dsn + strong_memoize(:gitlab_dsn) do + client_key&.sentry_dsn + end + end + def api_url=(value) super clear_memoization(:api_url_slugs) @@ -236,5 +247,19 @@ module ErrorTracking errors.add(:project, 'is a required field') end end + + def client_key + # Project can have multiple client keys. + # However for UI simplicity we render the first active one for user. + # In future we should make it possible to manage client keys from UI. + # Issue https://gitlab.com/gitlab-org/gitlab/-/issues/329596 + project.error_tracking_client_keys.active.first + end + + def create_client_key! + if enabled? && integrated_client? && !client_key + project.error_tracking_client_keys.create! + end + end end end diff --git a/app/policies/namespace_policy.rb b/app/policies/namespace_policy.rb index dcbeda9f5d3..0cf1bcb9737 100644 --- a/app/policies/namespace_policy.rb +++ b/app/policies/namespace_policy.rb @@ -1,26 +1,9 @@ # frozen_string_literal: true -class NamespacePolicy < BasePolicy - rule { anonymous }.prevent_all - - condition(:personal_project, scope: :subject) { @subject.kind == 'user' } - condition(:can_create_personal_project, scope: :user) { @user.can_create_project? } - condition(:owner) { @subject.owner == @user } - - rule { owner | admin }.policy do - enable :owner_access - enable :create_projects - enable :admin_namespace - enable :read_namespace - enable :read_statistics - enable :create_jira_connect_subscription - enable :create_package_settings - enable :read_package_settings - end - - rule { personal_project & ~can_create_personal_project }.prevent :create_projects - - rule { (owner | admin) & can?(:create_projects) }.enable :transfer_projects +class NamespacePolicy < ::Namespaces::UserNamespacePolicy + # NamespacePolicy has been traditionally for user namespaces. + # So these policies have been moved into Namespaces::UserNamespacePolicy. + # Once the user namespace conversion is complete, we can look at + # either removing this file or locating common namespace policy items + # here. end - -NamespacePolicy.prepend_mod_with('NamespacePolicy') diff --git a/app/policies/namespaces/user_namespace_policy.rb b/app/policies/namespaces/user_namespace_policy.rb new file mode 100644 index 00000000000..f8b285e5312 --- /dev/null +++ b/app/policies/namespaces/user_namespace_policy.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Namespaces + class UserNamespacePolicy < BasePolicy + rule { anonymous }.prevent_all + + condition(:personal_project, scope: :subject) { @subject.kind == 'user' } + condition(:can_create_personal_project, scope: :user) { @user.can_create_project? } + condition(:owner) { @subject.owner == @user } + + rule { owner | admin }.policy do + enable :owner_access + enable :create_projects + enable :admin_namespace + enable :read_namespace + enable :read_statistics + enable :create_jira_connect_subscription + enable :create_package_settings + enable :read_package_settings + end + + rule { personal_project & ~can_create_personal_project }.prevent :create_projects + + rule { (owner | admin) & can?(:create_projects) }.enable :transfer_projects + end +end + +Namespaces::UserNamespacePolicy.prepend_mod_with('Namespaces::UserNamespacePolicy') diff --git a/app/services/ci/retry_build_service.rb b/app/services/ci/retry_build_service.rb index a465116000e..07cfbb9ce3c 100644 --- a/app/services/ci/retry_build_service.rb +++ b/app/services/ci/retry_build_service.rb @@ -17,7 +17,7 @@ module Ci def execute(build) build.ensure_scheduling_type! - reprocess!(build).tap do |new_build| + clone!(build).tap do |new_build| check_assignable_runners!(new_build) next if new_build.failed? @@ -31,7 +31,7 @@ module Ci end # rubocop: disable CodeReuse/ActiveRecord - def reprocess!(build) + def clone!(build) # Cloning a build requires a strict type check to ensure # the attributes being used for the clone are taken straight # from the model and not overridden by other abstractions. diff --git a/app/services/ci/retry_pipeline_service.rb b/app/services/ci/retry_pipeline_service.rb index 02ee40d2cf6..e10feb46271 100644 --- a/app/services/ci/retry_pipeline_service.rb +++ b/app/services/ci/retry_pipeline_service.rb @@ -9,17 +9,12 @@ module Ci raise Gitlab::Access::AccessDeniedError end - needs = Set.new - pipeline.ensure_scheduling_type! builds_relation(pipeline).find_each do |build| next unless can_be_retried?(build) - Ci::RetryBuildService.new(project, current_user) - .reprocess!(build) - - needs += build.needs.map(&:name) + Ci::RetryBuildService.new(project, current_user).clone!(build) end pipeline.builds.latest.skipped.find_each do |skipped| diff --git a/app/views/projects/issues/_nav_btns.html.haml b/app/views/projects/issues/_nav_btns.html.haml index 0d69f6f69aa..ade48695ddc 100644 --- a/app/views/projects/issues/_nav_btns.html.haml +++ b/app/views/projects/issues/_nav_btns.html.haml @@ -9,7 +9,7 @@ - if show_feed_buttons = render 'shared/issuable/feed_buttons' - .js-csv-import-export-buttons{ data: { show_export_button: show_export_button.to_s, show_import_button: show_import_button.to_s, issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_issues_path(@project, request.query_parameters), import_csv_issues_path: import_csv_namespace_project_issues_path, container_class: 'gl-mr-3', can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project) } } + .js-csv-import-export-buttons{ data: { show_export_button: show_export_button.to_s, show_import_button: show_import_button.to_s, issuable_type: issuable_type, issuable_count: issuables_count_for_state(issuable_type.to_sym, params[:state]), email: notification_email, export_csv_path: export_csv_project_issues_path(@project, request.query_parameters), import_csv_issues_path: import_csv_namespace_project_issues_path, container_class: 'gl-mr-3', can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes) } } - if @can_bulk_update = button_tag _("Edit issues"), class: "gl-button btn btn-default gl-mr-3 js-bulk-update-toggle" diff --git a/app/views/projects/settings/operations/_error_tracking.html.haml b/app/views/projects/settings/operations/_error_tracking.html.haml index 6b2a1468eec..23b1ec4dea3 100644 --- a/app/views/projects/settings/operations/_error_tracking.html.haml +++ b/app/views/projects/settings/operations/_error_tracking.html.haml @@ -18,4 +18,5 @@ api_host: setting.api_host, enabled: setting.enabled.to_json, integrated: setting.integrated.to_json, + gitlab_dsn: setting.gitlab_dsn, token: setting.token.present? ? '*' * 12 : nil } } diff --git a/config/feature_categories.yml b/config/feature_categories.yml index 1ecf217dd92..e61048a6427 100644 --- a/config/feature_categories.yml +++ b/config/feature_categories.yml @@ -33,6 +33,7 @@ - continuous_integration_scaling - database - dataops +- delivery - delivery_management - dependency_firewall - dependency_proxy @@ -53,16 +54,15 @@ - five_minute_production_app - foundations - fuzz_testing -- gdk - geo_replication - git_lfs - gitaly - gitlab_docs - global_search - helm_chart_registry +- horse - importers - incident_management -- infrastructure - infrastructure_as_code - insider_threat - integrations @@ -103,12 +103,12 @@ - roadmaps - runbooks - runner +- scalability - secret_detection - secrets_management - security_benchmarking - security_orchestration - self_monitoring -- serverless - service_desk - service_ping - sharding diff --git a/config/feature_flags/development/vulnerability_location_image_filter.yml b/config/feature_flags/development/vulnerability_location_image_filter.yml new file mode 100644 index 00000000000..4b373b76ff6 --- /dev/null +++ b/config/feature_flags/development/vulnerability_location_image_filter.yml @@ -0,0 +1,8 @@ +--- +name: vulnerability_location_image_filter +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69867 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/340915 +milestone: '14.4' +type: development +group: group::container security +default_enabled: false diff --git a/db/post_migrate/20210922021816_drop_int4_columns_for_ci_job_artifacts.rb b/db/post_migrate/20210922021816_drop_int4_columns_for_ci_job_artifacts.rb new file mode 100644 index 00000000000..e45d6ed34aa --- /dev/null +++ b/db/post_migrate/20210922021816_drop_int4_columns_for_ci_job_artifacts.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +class DropInt4ColumnsForCiJobArtifacts < Gitlab::Database::Migration[1.0] + enable_lock_retries! + + def change + remove_column :ci_job_artifacts, :id_convert_to_bigint, :integer, null: false, default: 0 + remove_column :ci_job_artifacts, :job_id_convert_to_bigint, :integer, null: false, default: 0 + end +end diff --git a/db/post_migrate/20210922082019_drop_int4_column_for_events.rb b/db/post_migrate/20210922082019_drop_int4_column_for_events.rb new file mode 100644 index 00000000000..a34d54e11e3 --- /dev/null +++ b/db/post_migrate/20210922082019_drop_int4_column_for_events.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class DropInt4ColumnForEvents < Gitlab::Database::Migration[1.0] + enable_lock_retries! + + def change + remove_column :events, :id_convert_to_bigint, :integer, null: false, default: 0 + end +end diff --git a/db/schema_migrations/20210922021816 b/db/schema_migrations/20210922021816 new file mode 100644 index 00000000000..8286647353d --- /dev/null +++ b/db/schema_migrations/20210922021816 @@ -0,0 +1 @@ +1d18e061cb5bcdaa7d3fcea93e58d65a6f2c8b557fe53ba461b6cfa570f565be
\ No newline at end of file diff --git a/db/schema_migrations/20210922082019 b/db/schema_migrations/20210922082019 new file mode 100644 index 00000000000..c987f19e595 --- /dev/null +++ b/db/schema_migrations/20210922082019 @@ -0,0 +1 @@ +011b714ee5d4389a5a172ae687eea3a814915fb39a5e5eae38b6ee423a903eaf
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 1a1e34bf50f..b91b6afddf9 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11506,9 +11506,7 @@ CREATE SEQUENCE ci_instance_variables_id_seq ALTER SEQUENCE ci_instance_variables_id_seq OWNED BY ci_instance_variables.id; CREATE TABLE ci_job_artifacts ( - id_convert_to_bigint integer DEFAULT 0 NOT NULL, project_id integer NOT NULL, - job_id_convert_to_bigint integer DEFAULT 0 NOT NULL, file_type integer NOT NULL, size bigint, created_at timestamp with time zone NOT NULL, @@ -13705,7 +13703,6 @@ CREATE SEQUENCE error_tracking_errors_id_seq ALTER SEQUENCE error_tracking_errors_id_seq OWNED BY error_tracking_errors.id; CREATE TABLE events ( - id_convert_to_bigint integer DEFAULT 0 NOT NULL, project_id integer, author_id integer NOT NULL, target_id integer, diff --git a/doc/administration/file_hooks.md b/doc/administration/file_hooks.md index f73c961f541..dcda293992e 100644 --- a/doc/administration/file_hooks.md +++ b/doc/administration/file_hooks.md @@ -67,7 +67,7 @@ message is logged to: - `log/file_hook.log` in a source installation. NOTE: -Before 14.0 release, the file name was `plugin.log` +Before 14.0 release, the filename was `plugin.log` ## Creating file hooks diff --git a/doc/administration/geo/replication/multiple_servers.md b/doc/administration/geo/replication/multiple_servers.md index 7db210d31f4..87b1aa7fc44 100644 --- a/doc/administration/geo/replication/multiple_servers.md +++ b/doc/administration/geo/replication/multiple_servers.md @@ -199,7 +199,7 @@ then make the following modifications: ## `application_role` already enables this. You only need this line if ## you selectively enable individual services that depend on Rails, like - ## `puma`, `sidekiq`, `geo-logcursor`, etc. + ## `puma`, `sidekiq`, `geo-logcursor`, and so on. gitlab_rails['enable'] = true ## diff --git a/doc/administration/index.md b/doc/administration/index.md index 9412994edb7..ee17edc35fc 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -41,7 +41,7 @@ Learn how to install, configure, update, and maintain your GitLab instance. ### Configuring GitLab -- [Adjust your instance's timezone](timezone.md): Customize the default time zone of GitLab. +- [Adjust your instance's time zone](timezone.md): Customize the default time zone of GitLab. - [System hooks](../system_hooks/system_hooks.md): Notifications when users, projects and keys are changed. - [Security](../security/index.md): Learn what you can do to further secure your GitLab instance. - [Usage statistics, version check, and Service Ping](../user/admin_area/settings/usage_statistics.md): Enable or disable information about your instance to be sent to GitLab, Inc. diff --git a/doc/administration/job_logs.md b/doc/administration/job_logs.md index 64d9248cb16..f2748305c24 100644 --- a/doc/administration/job_logs.md +++ b/doc/administration/job_logs.md @@ -146,9 +146,9 @@ a background job archives the job log. The log is moved to `/var/opt/gitlab/gitl by default, or to object storage if configured. In a [scaled-out architecture](reference_architectures/index.md) with Rails and Sidekiq running on more than one -server, these two locations on the filesystem have to be shared using NFS. +server, these two locations on the file system have to be shared using NFS. -To eliminate both filesystem requirements: +To eliminate both file system requirements: - [Enable the incremental logging feature](#enable-or-disable-incremental-logging), which uses Redis instead of disk space for temporary caching of job logs. - Configure [object storage](job_artifacts.md#object-storage-settings) for storing archived job logs. diff --git a/doc/administration/package_information/deprecation_policy.md b/doc/administration/package_information/deprecation_policy.md index cc16661442a..dd2f8734e1c 100644 --- a/doc/administration/package_information/deprecation_policy.md +++ b/doc/administration/package_information/deprecation_policy.md @@ -60,7 +60,7 @@ We should aim to not remove sensitive configuration in the *next major* release See the table below for some examples: -| Config. type | Deprecation announced | Final minor release | Remove | +| Configuration type | Deprecation announced | Final minor release | Remove | | -------- | -------- | -------- | -------- | | Sensitive | 10.1.0 | 10.9.0 | 11.0.0 | | Sensitive | 10.7.0 | 10.9.0 | 12.0.0 | @@ -90,6 +90,6 @@ the feature will continue working the same way as if you had `gitlab_rails['bett However, setting the old version of configuration will print out a deprecation notice at the end of installation/upgrade/reconfigure run. -With GitLab 11, `gitlab_rails['configuration'] = true` will no longer work and you will have to manually change the configuration in `/etc/gitlab/gitlab.rb` to the new valid config. +With GitLab 11, `gitlab_rails['configuration'] = true` will no longer work and you will have to manually change the configuration in `/etc/gitlab/gitlab.rb` to the new valid configuration. **Note** If this configuration option is sensitive and can put integrity of the installation or data in danger, installation/upgrade will be aborted. diff --git a/doc/api/deploy_tokens.md b/doc/api/deploy_tokens.md index 3de7ff4ac44..c7189586230 100644 --- a/doc/api/deploy_tokens.md +++ b/doc/api/deploy_tokens.md @@ -10,7 +10,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21811) in GitLab 12.9. -Get a list of all deploy tokens across the GitLab instance. This endpoint requires administrator access. +Get a list of all deploy tokens across the GitLab instance. This endpoint requires the Administrator role. ```plaintext GET /deploy_tokens diff --git a/doc/api/freeze_periods.md b/doc/api/freeze_periods.md index 6ca69d047da..6dc4e8745d6 100644 --- a/doc/api/freeze_periods.md +++ b/doc/api/freeze_periods.md @@ -94,7 +94,7 @@ POST /projects/:id/freeze_periods | `id` | integer or string | yes | The ID or [URL-encoded path of the project](index.md#namespaced-path-encoding). | | `freeze_start` | string | yes | Start of the Freeze Period in [cron](https://crontab.guru/) format. | | `freeze_end` | string | yes | End of the Freeze Period in [cron](https://crontab.guru/) format. | -| `cron_timezone` | string | no | The timezone for the cron fields, defaults to UTC if not provided. | +| `cron_timezone` | string | no | The time zone for the cron fields, defaults to UTC if not provided. | Example request: @@ -131,7 +131,7 @@ PUT /projects/:id/freeze_periods/:freeze_period_id | `freeze_period_id` | integer or string | yes | The database ID of the Freeze Period. | | `freeze_start` | string | no | Start of the Freeze Period in [cron](https://crontab.guru/) format. | | `freeze_end` | string | no | End of the Freeze Period in [cron](https://crontab.guru/) format. | -| `cron_timezone` | string | no | The timezone for the cron fields. | +| `cron_timezone` | string | no | The time zone for the cron fields. | Example request: diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 93e165208fb..6ffc4de5eff 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -469,6 +469,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | ---- | ---- | ----------- | | <a id="queryvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. | | <a id="queryvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. | +| <a id="queryvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. | | <a id="queryvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. | | <a id="queryvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. | | <a id="queryvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. | @@ -10527,6 +10528,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | ---- | ---- | ----------- | | <a id="groupvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. | | <a id="groupvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. | +| <a id="groupvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. | | <a id="groupvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. | | <a id="groupvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. | | <a id="groupvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. | @@ -13203,6 +13205,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | ---- | ---- | ----------- | | <a id="projectvulnerabilitieshasissues"></a>`hasIssues` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have linked issues. | | <a id="projectvulnerabilitieshasresolution"></a>`hasResolution` | [`Boolean`](#boolean) | Returns only the vulnerabilities which have been resolved on default branch. | +| <a id="projectvulnerabilitiesimage"></a>`image` | [`[String!]`](#string) | Filter vulnerabilities by location image. When this filter is present, the response only matches entries for a `reportType` that includes `container_scanning`, `cluster_image_scanning`. | | <a id="projectvulnerabilitiesprojectid"></a>`projectId` | [`[ID!]`](#id) | Filter vulnerabilities by project. | | <a id="projectvulnerabilitiesreporttype"></a>`reportType` | [`[VulnerabilityReportType!]`](#vulnerabilityreporttype) | Filter vulnerabilities by report type. | | <a id="projectvulnerabilitiesscanner"></a>`scanner` | [`[String!]`](#string) | Filter vulnerabilities by VulnerabilityScanner.externalId. | diff --git a/doc/api/groups.md b/doc/api/groups.md index bd4c7de567c..7efecfc2c9c 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -830,7 +830,7 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \ ## Transfer project to group -Transfer a project to the Group namespace. Available only to instance administrators, although an [alternative API endpoint](projects.md#transfer-a-project-to-a-new-namespace) is available which does not require instance administrator access. Transferring projects may fail when tagged packages exist in the project's repository. +Transfer a project to the Group namespace. Available only to instance administrators, although an [alternative API endpoint](projects.md#transfer-a-project-to-a-new-namespace) is available which does not require instance administrator role. Transferring projects may fail when tagged packages exist in the project's repository. ```plaintext POST /groups/:id/projects/:project_id diff --git a/doc/api/instance_clusters.md b/doc/api/instance_clusters.md index 4e0ec3bd433..92a7ba861a3 100644 --- a/doc/api/instance_clusters.md +++ b/doc/api/instance_clusters.md @@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w Instance-level Kubernetes clusters allow you to connect a Kubernetes cluster to the GitLab instance, which enables you to use the same cluster across multiple projects. [More information](../user/instance/clusters/index.md) NOTE: -Users need administrator access to use these endpoints. +Users need the Administrator role to use these endpoints. ## List instance clusters diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md index fcb7477f226..75647a5ab56 100644 --- a/doc/api/oauth2.md +++ b/doc/api/oauth2.md @@ -5,15 +5,15 @@ group: Access 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/#designated-technical-writers --- -# GitLab as an OAuth 2.0 provider **(FREE)** +# OAuth 2.0 identity provider API **(FREE)** -This document covers using the [OAuth2](https://oauth.net/2/) protocol to allow -other services to access GitLab resources on user's behalf. +GitLab provides an API to allow third-party services to access GitLab resources on a user's behalf +with the [OAuth2](https://oauth.net/2/) protocol. -If you want GitLab to be an OAuth authentication service provider to sign into -other services, see the [OAuth2 authentication service provider](../integration/oauth_provider.md) -documentation. This functionality is based on the -[doorkeeper Ruby gem](https://github.com/doorkeeper-gem/doorkeeper). +To configure GitLab for this, see +[Configure GitLab as an OAuth 2.0 authentication identity provider](../integration/oauth_provider.md). + +This functionality is based on the [doorkeeper Ruby gem](https://github.com/doorkeeper-gem/doorkeeper). ## Supported OAuth 2.0 flows @@ -25,7 +25,7 @@ GitLab supports the following authorization flows: - **Authorization code:** Secure and common flow. Recommended option for secure server-side apps. - **Implicit grant:** Originally designed for user-agent only apps, such as - single page web apps running on GitLab Pages). + single page web apps running on GitLab Pages. The [Internet Engineering Task Force (IETF)](https://tools.ietf.org/html/draft-ietf-oauth-security-topics-09#section-2.1.2) recommends against Implicit grant flow. - **Resource owner password credentials:** To be used **only** for securely diff --git a/doc/api/packages/debian.md b/doc/api/packages/debian.md index 154c99d7e0a..66377850c49 100644 --- a/doc/api/packages/debian.md +++ b/doc/api/packages/debian.md @@ -78,7 +78,7 @@ GET projects/:id/packages/debian/pool/:distribution/:letter/:package_name/:packa | `letter` | string | yes | The Debian Classification (first-letter or lib-first-letter). | | `package_name` | string | yes | The source package name. | | `package_version` | string | yes | The source package version. | -| `file_name` | string | yes | The file name. | +| `file_name` | string | yes | The filename. | ```shell curl --header "Private-Token: <personal_access_token>" "https://gitlab.example.com/api/v4/projects/1/packages/pool/my-distro/a/my-pkg/1.0.0/example_1.0.0~alpha2_amd64.deb" @@ -92,7 +92,7 @@ curl --header "Private-Token: <personal_access_token>" \ --remote-name ``` -This writes the downloaded file using the remote file name in the current directory. +This writes the downloaded file using the remote filename in the current directory. ## Route prefix @@ -150,7 +150,7 @@ curl --header "Private-Token: <personal_access_token>" \ --remote-name ``` -This writes the downloaded file using the remote file name in the current directory. +This writes the downloaded file using the remote filename in the current directory. ## Download a signed distribution Release file @@ -178,7 +178,7 @@ curl --header "Private-Token: <personal_access_token>" \ --remote-name ``` -This writes the downloaded file using the remote file name in the current directory. +This writes the downloaded file using the remote filename in the current directory. ## Download a release file signature @@ -206,7 +206,7 @@ curl --header "Private-Token: <personal_access_token>" \ --remote-name ``` -This writes the downloaded file using the remote file name in the current directory. +This writes the downloaded file using the remote filename in the current directory. ## Download a binary file's index @@ -236,4 +236,4 @@ curl --header "Private-Token: <personal_access_token>" \ --remote-name ``` -This writes the downloaded file using the remote file name in the current directory. +This writes the downloaded file using the remote filename in the current directory. diff --git a/doc/api/packages/helm.md b/doc/api/packages/helm.md index 8c3b9869368..82b3f5225b0 100644 --- a/doc/api/packages/helm.md +++ b/doc/api/packages/helm.md @@ -63,7 +63,7 @@ GET projects/:id/packages/helm/:channel/charts/:file_name.tgz | ----------- | ------ | -------- | ----------- | | `id` | string | yes | The ID or full path of the project. | | `channel` | string | yes | Helm repository channel. | -| `file_name` | string | yes | Chart file name. | +| `file_name` | string | yes | Chart filename. | ```shell curl --user <username>:<personal_access_token> \ diff --git a/doc/api/pipeline_schedules.md b/doc/api/pipeline_schedules.md index 74f96e5374e..625a92f9b89 100644 --- a/doc/api/pipeline_schedules.md +++ b/doc/api/pipeline_schedules.md @@ -115,7 +115,7 @@ POST /projects/:id/pipeline_schedules | `description` | string | yes | The description of the pipeline schedule. | | `ref` | string | yes | The branch or tag name that is triggered. | | `cron` | string | yes | The [cron](https://en.wikipedia.org/wiki/Cron) schedule, for example: `0 1 * * *`. | -| `cron_timezone` | string | no | The timezone supported by `ActiveSupport::TimeZone`, for example: `Pacific Time (US & Canada)` (default: `UTC`). | +| `cron_timezone` | string | no | The time zone supported by `ActiveSupport::TimeZone`, for example: `Pacific Time (US & Canada)` (default: `UTC`). | | `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule is initially deactivated (default: `true`). | ```shell @@ -162,7 +162,7 @@ PUT /projects/:id/pipeline_schedules/:pipeline_schedule_id | `description` | string | no | The description of the pipeline schedule. | | `ref` | string | no | The branch or tag name that is triggered. | | `cron` | string | no | The [cron](https://en.wikipedia.org/wiki/Cron) schedule, for example: `0 1 * * *`. | -| `cron_timezone` | string | no | The timezone supported by `ActiveSupport::TimeZone` (for example `Pacific Time (US & Canada)`), or `TZInfo::Timezone` (for example `America/Los_Angeles`). | +| `cron_timezone` | string | no | The time zone supported by `ActiveSupport::TimeZone` (for example `Pacific Time (US & Canada)`), or `TZInfo::Timezone` (for example `America/Los_Angeles`). | | `active` | boolean | no | The activation of pipeline schedule. If false is set, the pipeline schedule is initially deactivated. | ```shell diff --git a/doc/api/plan_limits.md b/doc/api/plan_limits.md index 52152dd6e14..8bd87f5a896 100644 --- a/doc/api/plan_limits.md +++ b/doc/api/plan_limits.md @@ -14,7 +14,7 @@ The existing plans depend on the GitLab edition. In the Community Edition, only is available. In the Enterprise Edition, additional plans are available as well. NOTE: -Administrator access is required to use this API. +The Administrator role is required to use this API. ## Get current plan limits diff --git a/doc/api/releases/index.md b/doc/api/releases/index.md index 72627783947..ded47b24c12 100644 --- a/doc/api/releases/index.md +++ b/doc/api/releases/index.md @@ -729,3 +729,5 @@ Example response: A release with a `released_at` attribute set to a future date is labeled as an **Upcoming Release** [in the UI](../../user/project/releases/index.md#upcoming-releases). + +Additionally, if a [release is requested from the API](#list-releases), for each release with a `release_at` attribute set to a future date, an additional attribute `upcoming_release` (set to true) will be returned as part of the response. diff --git a/doc/api/search.md b/doc/api/search.md index d3a2f9c41b6..d3f0cba9234 100644 --- a/doc/api/search.md +++ b/doc/api/search.md @@ -1161,7 +1161,7 @@ Blobs searches are performed on both filenames and contents. Search results: times in the content. ```shell -curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/6/search?scope=blobs&search=installation&ref=feature" +curl --request GET --header "PRIVATE-TOKEN: <your_access_token>" https://gitlab.example.com/api/v4/projects/6/search?scope=blobs&search=keyword%20filename:*.py ``` Example response: @@ -1175,7 +1175,7 @@ Example response: "path": "README.md", "filename": "README.md", "id": null, - "ref": "feature", + "ref": "master", "startline": 46, "project_id": 6 } diff --git a/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md b/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md index 095eaaec23f..e0e0dd90892 100644 --- a/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md +++ b/doc/architecture/blueprints/composable_codebase_using_rails_engines/index.md @@ -514,7 +514,7 @@ Today, loading GraphQL requires a bunch of [dependencies](https://gitlab.com/git GraphQL only needs to run in a specific context. If we could limit when it is being loaded we could effectively improve application efficiency, by reducing application load time and required memory. This, for example, is applicable for every size installation. -A potential challenge with GraphQL and Websockets is that at some point we might want to use Action Cable subscriptions and push GraphQL/API payload from Sidekiq to clients. This would likely utilize Redis to pass data through. Where Sidekiq would publish information on Redis and ActionCable Node would pass through that information to connected clients. This way of working is possible in the above model, but we would have to use GraphQL or API (over HTTP endpoint) to calculate what should be sent. +A potential challenge with GraphQL and Websockets is that at some point we might want to use Action Cable subscriptions and push GraphQL/API payload from Sidekiq to clients. This would likely use Redis to pass data through. Where Sidekiq would publish information on Redis and ActionCable Node would pass through that information to connected clients. This way of working is possible in the above model, but we would have to use GraphQL or API (over HTTP endpoint) to calculate what should be sent. An alternative way is to use a notification system that would always make an `ActionCable` node (the one handling WebSockets) generate a payload based on a send query instead of performing passthrough. This could be applicable since `ActionCable` is the one handling a given connection for a client. This could have a downside of having to recalculate the same payload if many clients would be watching the same resource. However, this behavior of system might still be desired for security purposes, as generated payload might be dependent on permission of watching client (we would show different for anonymous, and different for the member of the project). diff --git a/doc/architecture/blueprints/consolidating_groups_and_projects/index.md b/doc/architecture/blueprints/consolidating_groups_and_projects/index.md index fab886808e2..a8d87e5f967 100644 --- a/doc/architecture/blueprints/consolidating_groups_and_projects/index.md +++ b/doc/architecture/blueprints/consolidating_groups_and_projects/index.md @@ -32,7 +32,7 @@ they all live on their own. A few more problems with this approach: - Features are coupled to their container. In practice it is not straight forward to decouple a feature from its container. The degree of coupling varies across features. -- Naive duplication of features will result in a more complex and fragile code base. +- Naive duplication of features will result in a more complex and fragile codebase. - Generalizing solutions across groups and projects may degrade system performance. - The range of features span across many teams, and these changes will need to manage development interference. diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 4379f545f04..4ad94a14125 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -454,7 +454,8 @@ FLAG: On self-managed GitLab, by default this feature is available. To hide the feature per project or for your entire instance, ask an administrator to [disable the `ci_include_rules` flag](../../administration/feature_flags.md). On GitLab.com, this feature is available. You can use [`rules`](#rules) with `include` to conditionally include other configuration files. -You can only use `rules:if` in `include` with [certain variables](#variables-with-include). +You can only use [`if` rules](#rulesif) in `include`, and only with [certain variables](#variables-with-include). +`rules` keywords such as `changes` and `exists` are not supported. ```yaml include: @@ -1178,6 +1179,7 @@ job: all rules. You can't mix `when` at the job-level with `when` in rules. - Unlike variables in [`script`](../variables/index.md#use-cicd-variables-in-job-scripts) sections, variables in rules expressions are always formatted as `$VARIABLE`. + - You can use `rules:if` with `include` to [conditionally include other configuration files](#rules-with-include). **Related topics**: diff --git a/doc/development/documentation/index.md b/doc/development/documentation/index.md index bb27469c7bf..73670a3f676 100644 --- a/doc/development/documentation/index.md +++ b/doc/development/documentation/index.md @@ -142,7 +142,7 @@ Nanoc layout), which is displayed at the top of the page if defined. The `type` metadata parameter is deprecated but still exists in documentation pages. You can safely remove the `type` metadata parameter and its values. -## Move or rename a page +## Move, rename, or delete a page See [redirects](redirects.md). diff --git a/doc/development/documentation/redirects.md b/doc/development/documentation/redirects.md index eb6878f5870..ef94c33a276 100644 --- a/doc/development/documentation/redirects.md +++ b/doc/development/documentation/redirects.md @@ -15,13 +15,26 @@ description: Learn how to contribute to GitLab Documentation. # Redirects in GitLab documentation -Moving or renaming a document is the same as changing its location. Be sure -to assign a technical writer to any merge request that renames or moves a page. -Technical Writers can help with any questions and can review your change. +When you move, rename, or delete a page, you must add a redirect. Redirects reduce +how often users get 404s when visiting the documentation site from out-of-date links, like: + +- Bookmarks +- Links from external sites +- Links from old blog posts +- Links in the documentation site global navigation + +Add a redirect to ensure: -When moving or renaming a page, you must redirect browsers to the new page. -This ensures users find the new page, and have the opportunity to update their -bookmarks. +- Users see the new page and can update or delete their bookmark. +- External sites can update their links, especially sites that have automation that + check for redirecting links. +- The documentation site global navigation does not link to a missing page. + + The links in the global navigation are already tested in the `gitlab-docs` project. + If the redirect is missing, the `gitlab-docs` project's `main` branch might break. + +Be sure to assign a technical writer to any merge request that moves, renames, or deletes a page. +Technical Writers can help with any questions and can review your change. There are two types of redirects: diff --git a/doc/development/elasticsearch.md b/doc/development/elasticsearch.md index 6d3388d521f..68d8b424331 100644 --- a/doc/development/elasticsearch.md +++ b/doc/development/elasticsearch.md @@ -233,6 +233,11 @@ Any data or index cleanup needed to support migration retries should be handled will re-enqueue itself with a delay which is set using the `throttle_delay` option described below. The batching must be handled within the `migrate` method, this setting controls the re-enqueuing only. +- `batch_size` - Sets the number of documents modified during a `batched!` migration run. This size should be set to a value which allows the updates +enough time to finish. This can be tuned in combination with the `throttle_delay` option described below. The batching +must be handled within a custom `migrate` method or by using the [`Elastic::MigrationBackfillHelper`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/concerns/elastic/migration_backfill_helper.rb) +`migrate` method which uses this setting. Default value is 1000 documents. + - `throttle_delay` - Sets the wait time in between batch runs. This time should be set high enough to allow each migration batch enough time to finish. Additionally, the time should be less than 30 minutes since that is how often the [`Elastic::MigrationWorker`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/workers/elastic/migration_worker.rb) diff --git a/doc/development/integrations/secure.md b/doc/development/integrations/secure.md index d37ce29e353..05fa3a0439e 100644 --- a/doc/development/integrations/secure.md +++ b/doc/development/integrations/secure.md @@ -534,15 +534,24 @@ affecting version `2.50.3-2+deb9u1` of Debian package `glib2.0`: }, "version": "2.50.3-2+deb9u1", "operating_system": "debian:9", - "image": "index.docker.io/library/nginx:1.18" + "image": "index.docker.io/library/nginx:1.18", + "kubernetes_resource": { + "namespace": "production", + "kind": "Deployment", + "name": "nginx-ingress", + "container": "nginx", + "agent_id": "1" + } } ``` -The affected package is found when scanning the image of the pod `index.docker.io/library/nginx:1.18`. +The affected package is found when scanning a deployment using the `index.docker.io/library/nginx:1.18` image. The location fingerprint of a Cluster Image Scanning vulnerability combines the -`operating_system` and the package `name`, so these attributes are mandatory. The `image` is also -mandatory. All other attributes are optional. +`namespace`, `kind`, `name`, and `container` fields from the `kubernetes_resource`, +as well as the package `name`, so these fields are required. The `image` field is also mandatory. +The `cluster_id` and `agent_id` are mutually exclusive, and one of them must be present. +All other fields are optional. #### SAST diff --git a/doc/install/docker.md b/doc/install/docker.md index b611f87938e..b3e7e758ec3 100644 --- a/doc/install/docker.md +++ b/doc/install/docker.md @@ -103,7 +103,7 @@ sudo docker run --detach \ ``` This will ensure that the Docker process has enough permissions to create the -config files in the mounted volumes. +configuration files in the mounted volumes. If you're using the [Kerberos integration](../integration/kerberos.md) **(PREMIUM ONLY)**, you must also publish your Kerberos port (for example, `--publish 8443:8443`). @@ -573,7 +573,7 @@ sudo docker restart gitlab This error occurs when using Docker Toolbox with VirtualBox on Windows or Mac, and making use of Docker volumes. The `/c/Users` volume is mounted as a -VirtualBox Shared Folder, and does not support the all POSIX filesystem features. +VirtualBox Shared Folder, and does not support the all POSIX file system features. The directory ownership and permissions cannot be changed without remounting, and GitLab fails. diff --git a/doc/install/next_steps.md b/doc/install/next_steps.md index e25241f0378..b5cfbfc9bbb 100644 --- a/doc/install/next_steps.md +++ b/doc/install/next_steps.md @@ -52,7 +52,7 @@ installation. Activate all GitLab Enterprise Edition functionality with a license. - [Pricing](https://about.gitlab.com/pricing/): Pricing for the different tiers. -## Cross-repo Code Search +## Cross-repository Code Search - [Advanced Search](../integration/elasticsearch.md): Leverage Elasticsearch for faster, more advanced code search across your entire GitLab instance. diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 4ced5d01447..c136fb21a90 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -169,7 +169,7 @@ of GitLab Support or other GitLab engineers. operations to manage partitioned tables. - You should not modify the GitLab schema (for example, adding triggers or modifying tables). - Database migrations are tested against the schema definition in the GitLab code base. GitLab + Database migrations are tested against the schema definition in the GitLab codebase. GitLab version upgrades may fail if the schema is modified. ## Puma settings diff --git a/doc/integration/jenkins.md b/doc/integration/jenkins.md index 18ae71a7059..2bbda74533f 100644 --- a/doc/integration/jenkins.md +++ b/doc/integration/jenkins.md @@ -64,8 +64,8 @@ Grant a GitLab user access to the select GitLab projects. 1. Grant the user permission to the GitLab projects. - If you're integrating Jenkins with many GitLab projects, consider granting the user global - Administrator permission. Otherwise, add the user to each project, and grant the Developer role. + If you're integrating Jenkins with many GitLab projects, consider granting the user the global + Administrator role. Otherwise, add the user to each project, and grant the Developer role. ## Configure GitLab API access diff --git a/doc/integration/oauth_provider.md b/doc/integration/oauth_provider.md index 12ce2314206..31d0ed8c7b0 100644 --- a/doc/integration/oauth_provider.md +++ b/doc/integration/oauth_provider.md @@ -4,18 +4,16 @@ group: Access 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 --- -# GitLab as an OAuth 2.0 authentication service provider +# Configure GitLab as an OAuth 2.0 authentication identity provider -This document describes how you can use GitLab as an OAuth 2.0 -authentication service provider. +This document describes how you can use GitLab as an OAuth 2.0 authentication identity provider. -If you want to use: - -- The [OAuth 2.0](https://oauth.net/2/) protocol to access GitLab resources on - a user's behalf, see [OAuth 2.0 provider](../api/oauth2.md). -- Other OAuth 2.0 authentication service providers to sign in to - GitLab, see the [OAuth 2.0 client documentation](omniauth.md). -- The related API, see [Applications API](../api/applications.md). +- OAuth 2 applications can be created and managed using the GitLab UI (described below) + or managed using the [Applications API](../api/applications.md). +- After an application is created, external services can manage access tokens using the + [OAuth 2 API](../api/oauth2.md). +- To allow users to sign in to GitLab using third-party OAuth 2 providers, see + [OmniAuth documentation](omniauth.md). ## Introduction to OAuth diff --git a/doc/operations/incident_management/oncall_schedules.md b/doc/operations/incident_management/oncall_schedules.md index 9e736f2cdec..329ea9a714a 100644 --- a/doc/operations/incident_management/oncall_schedules.md +++ b/doc/operations/incident_management/oncall_schedules.md @@ -31,7 +31,7 @@ To create an on-call schedule: 1. On the top bar, select **Menu > Projects** and find your project. 1. On the left sidebar, select **Monitor > On-call Schedules**. 1. Select **Add a schedule**. -1. Enter the schedule's name and description and select a timezone. +1. Enter the schedule's name and description and select a time zone. 1. Select **Add schedule**. You now have an empty schedule with no rotations. This renders as an empty state, prompting you to diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md index 25e6e590f77..da96e88bb21 100644 --- a/doc/topics/authentication/index.md +++ b/doc/topics/authentication/index.md @@ -43,7 +43,7 @@ This page gathers all the resources for the topic **Authentication** within GitL - [Personal access tokens](../../api/index.md#personalproject-access-tokens) - [Project access tokens](../../api/index.md#personalproject-access-tokens) - [Impersonation tokens](../../api/index.md#impersonation-tokens) -- [GitLab as an OAuth2 provider](../../api/oauth2.md#gitlab-as-an-oauth-20-provider) +- [OAuth 2.0 identity provider API](../../api/oauth2.md) ## Third-party resources diff --git a/doc/user/index.md b/doc/user/index.md index d6eaad469c1..6c0f3c77344 100644 --- a/doc/user/index.md +++ b/doc/user/index.md @@ -13,10 +13,10 @@ Welcome to GitLab! We're glad to have you here! As a GitLab user you have access to all the features your [subscription](https://about.gitlab.com/pricing/) includes, except [GitLab administrator](../administration/index.md) -settings, unless you have admin privileges to install, configure, +settings, unless you have administrator privileges to install, configure, and upgrade your GitLab instance. -Admin privileges for [GitLab.com](https://gitlab.com/) are restricted to the GitLab team. +Administrator privileges for [GitLab.com](https://gitlab.com/) are restricted to the GitLab team. For more information on configuring GitLab self-managed instances, see the [Administrator documentation](../administration/index.md). @@ -78,7 +78,7 @@ There are several types of users in GitLab: - Regular users and GitLab.com users. <!-- Note: further description TBA --> - [Groups](group/index.md) of users. -- GitLab [admin area](admin_area/index.md) user. +- GitLab [administrator area](admin_area/index.md) user. - [GitLab Administrator](../administration/index.md) with full access to self-managed instances' features and settings. - [Internal users](../development/internal_users.md). diff --git a/doc/user/project/clusters/runbooks/index.md b/doc/user/project/clusters/runbooks/index.md index 7357fc850e5..9d623518f72 100644 --- a/doc/user/project/clusters/runbooks/index.md +++ b/doc/user/project/clusters/runbooks/index.md @@ -63,8 +63,9 @@ information. Follow this step-by-step guide to configure an executable runbook in GitLab using the components outlined above and the pre-loaded demo runbook. -1. Create an [OAuth Application for JupyterHub](../../../../integration/oauth_provider.md#gitlab-as-an-oauth-20-authentication-service-provider). -1. When [installing JupyterHub with Helm](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/installation.html), use the following values +1. Create an [OAuth application for JupyterHub](../../../../integration/oauth_provider.md). +1. When [installing JupyterHub with Helm](https://zero-to-jupyterhub.readthedocs.io/en/latest/jupyterhub/installation.html), + use the following values: ```yaml #----------------------------------------------------------------------------- diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index b2e2b013947..d56f2a4b0e3 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -61,6 +61,7 @@ module Gitlab def self.databases @databases ||= database_base_models .transform_values { |connection_class| Connection.new(connection_class) } + .with_indifferent_access .freeze end diff --git a/lib/gitlab/metrics/requests_rack_middleware.rb b/lib/gitlab/metrics/requests_rack_middleware.rb index 8ab94eee5db..071645c2c14 100644 --- a/lib/gitlab/metrics/requests_rack_middleware.rb +++ b/lib/gitlab/metrics/requests_rack_middleware.rb @@ -116,7 +116,7 @@ module Gitlab def record_apdex_if_needed(elapsed) return unless Gitlab::Metrics::RailsSlis.request_apdex_counters_enabled? - Gitlab::Metrics::Sli[:rails_request_apdex].increment( + Gitlab::Metrics::RailsSlis.request_apdex.increment( labels: labels_from_context, # hardcoded 1s here will be replaced by a per-endpoint value. # https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/1223 diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb index 7133b360ce2..e63164efc94 100644 --- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb +++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/duplicate_job.rb @@ -64,9 +64,9 @@ module Gitlab Sidekiq.redis do |redis| redis.multi do |multi| - redis.set(idempotency_key, jid, ex: expiry, nx: true) - read_wal_locations = check_existing_wal_locations!(redis, expiry) - read_jid = redis.get(idempotency_key) + multi.set(idempotency_key, jid, ex: expiry, nx: true) + read_wal_locations = check_existing_wal_locations!(multi, expiry) + read_jid = multi.get(idempotency_key) end end @@ -81,9 +81,9 @@ module Gitlab return unless job_wal_locations.present? Sidekiq.redis do |redis| - redis.multi do + redis.multi do |multi| job_wal_locations.each do |connection_name, location| - redis.eval(LUA_SET_WAL_SCRIPT, keys: [wal_location_key(connection_name)], argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL]) + multi.eval(LUA_SET_WAL_SCRIPT, keys: [wal_location_key(connection_name)], argv: [location, pg_wal_lsn_diff(connection_name).to_i, WAL_LOCATION_TTL]) end end end @@ -96,9 +96,9 @@ module Gitlab read_wal_locations = {} Sidekiq.redis do |redis| - redis.multi do + redis.multi do |multi| job_wal_locations.keys.each do |connection_name| - read_wal_locations[connection_name] = redis.lindex(wal_location_key(connection_name), 0) + read_wal_locations[connection_name] = multi.lindex(wal_location_key(connection_name), 0) end end end @@ -110,8 +110,8 @@ module Gitlab def delete! Sidekiq.redis do |redis| redis.multi do |multi| - redis.del(idempotency_key) - delete_wal_locations!(redis) + multi.del(idempotency_key) + delete_wal_locations!(multi) end end end @@ -147,7 +147,7 @@ module Gitlab private - attr_accessor :existing_wal_locations + attr_writer :existing_wal_locations attr_reader :queue_name, :job attr_writer :existing_jid @@ -155,6 +155,31 @@ module Gitlab @worker_klass ||= worker_class_name.to_s.safe_constantize end + def delete_wal_locations!(redis) + job_wal_locations.keys.each do |connection_name| + redis.del(wal_location_key(connection_name)) + redis.del(existing_wal_location_key(connection_name)) + end + end + + def check_existing_wal_locations!(redis, expiry) + read_wal_locations = {} + + job_wal_locations.each do |connection_name, location| + key = existing_wal_location_key(connection_name) + redis.set(key, location, ex: expiry, nx: true) + read_wal_locations[connection_name] = redis.get(key) + end + + read_wal_locations + end + + def job_wal_locations + return {} unless preserve_wal_location? + + job['wal_locations'] || {} + end + def pg_wal_lsn_diff(connection_name) Gitlab::Database.databases[connection_name].pg_wal_lsn_diff(job_wal_locations[connection_name], existing_wal_locations[connection_name]) end @@ -179,12 +204,6 @@ module Gitlab job['jid'] end - def job_wal_locations - return {} unless preserve_wal_location? - - job['wal_locations'] || {} - end - def existing_wal_location_key(connection_name) "#{idempotency_key}:#{connection_name}:existing_wal_location" end @@ -209,23 +228,8 @@ module Gitlab "#{worker_class_name}:#{Sidekiq.dump_json(arguments)}" end - def delete_wal_locations!(redis) - job_wal_locations.keys.each do |connection_name| - redis.del(wal_location_key(connection_name)) - redis.del(existing_wal_location_key(connection_name)) - end - end - - def check_existing_wal_locations!(redis, expiry) - read_wal_locations = {} - - job_wal_locations.each do |connection_name, location| - key = existing_wal_location_key(connection_name) - redis.set(key, location, ex: expiry, nx: true) - read_wal_locations[connection_name] = redis.get(key) - end - - read_wal_locations + def existing_wal_locations + @existing_wal_locations ||= {} end def preserve_wal_location? diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb index fc58d4f5323..b0da85b74a6 100644 --- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb +++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/deduplicates_when_scheduling.rb @@ -4,11 +4,15 @@ module Gitlab module SidekiqMiddleware module DuplicateJobs module Strategies - module DeduplicatesWhenScheduling + class DeduplicatesWhenScheduling < Base + extend ::Gitlab::Utils::Override + + override :initialize def initialize(duplicate_job) @duplicate_job = duplicate_job end + override :schedule def schedule(job) if deduplicatable_job? && check! && duplicate_job.duplicate? job['duplicate-of'] = duplicate_job.existing_jid @@ -25,6 +29,7 @@ module Gitlab yield end + override :perform def perform(job) update_job_wal_location!(job) end diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executed.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executed.rb index 5164b994267..25f1b8b7c51 100644 --- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executed.rb +++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executed.rb @@ -7,11 +7,7 @@ module Gitlab # This strategy takes a lock before scheduling the job in a queue and # removes the lock after the job has executed preventing a new job to be queued # while a job is still executing. - class UntilExecuted < Base - extend ::Gitlab::Utils::Override - - include DeduplicatesWhenScheduling - + class UntilExecuted < DeduplicatesWhenScheduling override :perform def perform(job) super diff --git a/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executing.rb b/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executing.rb index 1f7e3a4ea30..693e404af73 100644 --- a/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executing.rb +++ b/lib/gitlab/sidekiq_middleware/duplicate_jobs/strategies/until_executing.rb @@ -7,11 +7,7 @@ module Gitlab # This strategy takes a lock before scheduling the job in a queue and # removes the lock before the job starts allowing a new job to be queued # while a job is still executing. - class UntilExecuting < Base - extend ::Gitlab::Utils::Override - - include DeduplicatesWhenScheduling - + class UntilExecuting < DeduplicatesWhenScheduling override :perform def perform(job) super diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 13f4ce69d01..0bd07235078 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -968,11 +968,6 @@ msgstr "" msgid "%{template_project_id} is unknown or invalid" msgstr "" -msgid "%{text} %{files}" -msgid_plural "%{text} %{files} files" -msgstr[0] "" -msgstr[1] "" - msgid "%{text} is available" msgstr "" @@ -24460,6 +24455,9 @@ msgstr "" msgid "Paste project path (i.e. gitlab-org/gitlab)" msgstr "" +msgid "Paste this DSN into your Sentry SDK" +msgstr "" + msgid "Paste your public SSH key, which is usually contained in the file '~/.ssh/id_ed25519.pub' or '~/.ssh/id_rsa.pub' and begins with 'ssh-ed25519' or 'ssh-rsa'. Do not paste your private SSH key, as that can compromise your identity." msgstr "" @@ -39997,6 +39995,9 @@ msgid_plural "from %d jobs" msgstr[0] "" msgstr[1] "" +msgid "frontmatter" +msgstr "" + msgid "group" msgstr "" diff --git a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb index bf1d2a04dba..10b1ea18c1c 100644 --- a/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb +++ b/qa/qa/specs/features/browser_ui/5_package/maven_repository_spec.rb @@ -183,7 +183,7 @@ module QA another_project.remove_via_api! end - it 'pushes and pulls a Maven package via CI and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1627' do + it 'pushes and pulls a Maven package via CI and deletes it', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1627', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341414', type: :investigating } do Resource::Repository::Commit.fabricate_via_api! do |commit| commit.project = project commit.commit_message = 'Add .gitlab-ci.yml' @@ -256,7 +256,7 @@ module QA Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_disabled) end - it 'prevents users from publishing duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1830' do + it 'prevents users from publishing duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1830', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209', type: :investigating } do with_fixtures([pom_xml, settings_xml]) do |dir| Service::DockerRun::Maven.new(dir).publish! end @@ -301,7 +301,7 @@ module QA Page::Group::Settings::PackageRegistries.perform(&:set_allow_duplicates_enabled) end - it 'allows users to publish duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1829' do + it 'allows users to publish duplicate Maven packages at the group level', testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/quality/test_cases/1829', quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/341209', type: :investigating } do with_fixtures([pom_xml, settings_xml]) do |dir| Service::DockerRun::Maven.new(dir).publish! end diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb index dbcd7b5caf5..8538b894869 100644 --- a/spec/features/projects/jobs/user_browses_jobs_spec.rb +++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb @@ -2,36 +2,276 @@ require 'spec_helper' +def visit_jobs_page + visit(project_jobs_path(project)) + + wait_for_requests +end + RSpec.describe 'User browses jobs' do - let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) } - let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } - let(:project) { create(:project, :repository, namespace: user.namespace) } - let(:user) { create(:user) } + describe 'with jobs_table_vue feature flag turned off' do + let!(:build) { create(:ci_build, :coverage, pipeline: pipeline) } + let(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.sha, ref: 'master') } + let(:project) { create(:project, :repository, namespace: user.namespace) } + let(:user) { create(:user) } - before do - stub_feature_flags(jobs_table_vue: false) - project.add_maintainer(user) - project.enable_ci - project.update_attribute(:build_coverage_regex, /Coverage (\d+)%/) + before do + stub_feature_flags(jobs_table_vue: false) + project.add_maintainer(user) + project.enable_ci + project.update_attribute(:build_coverage_regex, /Coverage (\d+)%/) - sign_in(user) + sign_in(user) - visit(project_jobs_path(project)) - end + visit(project_jobs_path(project)) + end - it 'shows the coverage' do - page.within('td.coverage') do - expect(page).to have_content('99.9%') + it 'shows the coverage' do + page.within('td.coverage') do + expect(page).to have_content('99.9%') + end + end + + context 'with a failed job' do + let!(:build) { create(:ci_build, :coverage, :failed, pipeline: pipeline) } + + it 'displays a tooltip with the failure reason' do + page.within('.ci-table') do + failed_job_link = page.find('.ci-failed') + expect(failed_job_link[:title]).to eq('Failed - (unknown failure)') + end + end end end - context 'with a failed job' do - let!(:build) { create(:ci_build, :coverage, :failed, pipeline: pipeline) } + describe 'with jobs_table_vue feature flag turned on', :js do + let(:project) { create(:project, :repository) } + let(:user) { create(:user) } + + before do + stub_feature_flags(jobs_table_vue: true) + + project.add_maintainer(user) + project.enable_ci + + sign_in(user) + end + + describe 'header tabs' do + before do + visit_jobs_page + end + + it 'shows a tab for All jobs and count' do + expect(page.find('[data-testid="jobs-all-tab"]').text).to include('All') + expect(page.find('[data-testid="jobs-all-tab"] .badge').text).to include('0') + end + + it 'shows a tab for Pending jobs and count' do + expect(page.find('[data-testid="jobs-pending-tab"]').text).to include('Pending') + expect(page.find('[data-testid="jobs-pending-tab"] .badge').text).to include('0') + end + + it 'shows a tab for Running jobs and count' do + expect(page.find('[data-testid="jobs-running-tab"]').text).to include('Running') + expect(page.find('[data-testid="jobs-running-tab"] .badge').text).to include('0') + end + + it 'shows a tab for Finished jobs and count' do + expect(page.find('[data-testid="jobs-finished-tab"]').text).to include('Finished') + expect(page.find('[data-testid="jobs-finished-tab"] .badge').text).to include('0') + end + + it 'updates the content when tab is clicked' do + page.find('[data-testid="jobs-finished-tab"]').click + wait_for_requests + + expect(page).to have_content('No jobs to show') + end + end + + describe 'Empty state' do + before do + visit_jobs_page + end + + it 'renders an empty state' do + expect(page).to have_content 'Use jobs to automate your tasks' + expect(page).to have_content 'Create CI/CD configuration file' + end + end + + describe 'Job actions' do + let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: 'master') } + + context 'when a job can be canceled' do + let!(:job) do + create(:ci_build, pipeline: pipeline, + stage: 'test') + end + + before do + job.run + + visit_jobs_page + end + + it 'cancels a job successfully' do + page.find('[data-testid="cancel-button"]').click + + wait_for_requests + + expect(page).to have_selector('.ci-canceled') + end + end + + context 'when a job can be retried' do + let!(:job) do + create(:ci_build, pipeline: pipeline, + stage: 'test') + end + + before do + job.drop + + visit_jobs_page + end + + it 'retries a job successfully' do + page.find('[data-testid="retry"]').click + + wait_for_requests + + expect(page).to have_selector('.ci-pending') + end + end + + context 'with a scheduled job' do + let!(:scheduled_job) { create(:ci_build, :scheduled, pipeline: pipeline, name: 'build') } + + before do + visit_jobs_page + end + + it 'plays a job successfully' do + page.find('[data-testid="play-scheduled"]').click + + page.within '#play-job-modal' do + page.find_button('OK').click + end + + wait_for_requests + + expect(page).to have_selector('.ci-pending') + end + + it 'unschedules a job successfully' do + page.find('[data-testid="unschedule"]').click + + wait_for_requests + + expect(page).to have_selector('.ci-manual') + end + end + + context 'with downloadable artifacts' do + let!(:with_artifacts) do + build = create(:ci_build, :success, + pipeline: pipeline, + name: 'rspec tests', + stage: 'test') + + create(:ci_job_artifact, :codequality, job: build) + end + + before do + visit_jobs_page + end + + it 'shows the download artifacts button' do + expect(page).to have_selector('[data-testid="download-artifacts"]') + end + end + + context 'with artifacts expired' do + let!(:with_artifacts_expired) do + create(:ci_build, :expired, :success, + pipeline: pipeline, + name: 'rspec', + stage: 'test') + end + + before do + visit_jobs_page + end + + it 'does not show the download artifacts button' do + expect(page).not_to have_selector('[data-testid="download-artifacts"]') + end + end + end + + describe 'Jobs table' do + let!(:pipeline) { create(:ci_empty_pipeline, project: project, sha: project.commit.id, ref: 'master') } + + context 'column links' do + let!(:job) do + create(:ci_build, pipeline: pipeline, + stage: 'test') + end + + before do + job.run + + visit_jobs_page + end + + it 'contains a link to the pipeline' do + expect(page.find('[data-testid="pipeline-id"]')).to have_content "##{pipeline.id}" + end + + it 'contains a link to the job sha' do + expect(page.find('[data-testid="job-sha"]')).to have_content "#{job.sha[0..7]}" + end + + it 'contains a link to the job id' do + expect(page.find('[data-testid="job-id-link"]')).to have_content "#{job.id}" + end + + it 'contains a link to the job ref' do + expect(page.find('[data-testid="job-ref"]')).to have_content "#{job.ref}" + end + end + end + + describe 'when user is not logged in' do + before do + sign_out(user) + end + + context 'when project is public' do + let(:public_project) { create(:project, :public, :repository) } + + context 'without jobs' do + it 'shows an empty state' do + visit project_jobs_path(public_project) + wait_for_requests + + expect(page).to have_content 'Use jobs to automate your tasks' + end + end + end + + context 'when project is private' do + let(:private_project) { create(:project, :private, :repository) } + + it 'redirects the user to sign_in and displays the flash alert' do + visit project_jobs_path(private_project) + wait_for_requests - it 'displays a tooltip with the failure reason' do - page.within('.ci-table') do - failed_job_link = page.find('.ci-failed') - expect(failed_job_link[:title]).to eq('Failed - (unknown failure)') + expect(page).to have_content 'You need to sign in' + expect(page.current_path).to eq("/users/sign_in") + end end end end diff --git a/spec/features/projects/settings/monitor_settings_spec.rb b/spec/features/projects/settings/monitor_settings_spec.rb index e3d75c30e5e..bf2e814ae25 100644 --- a/spec/features/projects/settings/monitor_settings_spec.rb +++ b/spec/features/projects/settings/monitor_settings_spec.rb @@ -175,6 +175,12 @@ RSpec.describe 'Projects > Settings > For a forked project', :js do wait_for_requests assert_text('Your changes have been saved') + + within '.js-error-tracking-settings' do + click_button('Expand') + end + + expect(page).to have_content('Paste this DSN into your Sentry SDK') end end end diff --git a/spec/frontend/content_editor/components/wrappers/frontmatter_spec.js b/spec/frontend/content_editor/components/wrappers/frontmatter_spec.js new file mode 100644 index 00000000000..de8f8efd260 --- /dev/null +++ b/spec/frontend/content_editor/components/wrappers/frontmatter_spec.js @@ -0,0 +1,43 @@ +import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2'; +import { shallowMount } from '@vue/test-utils'; +import FrontmatterWrapper from '~/content_editor/components/wrappers/frontmatter.vue'; + +describe('content/components/wrappers/frontmatter', () => { + let wrapper; + + const createWrapper = async (nodeAttrs = { language: 'yaml' }) => { + wrapper = shallowMount(FrontmatterWrapper, { + propsData: { + node: { + attrs: nodeAttrs, + }, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + it('renders a node-view-wrapper as a pre element', () => { + createWrapper(); + + expect(wrapper.findComponent(NodeViewWrapper).props().as).toBe('pre'); + expect(wrapper.findComponent(NodeViewWrapper).classes()).toContain('gl-relative'); + }); + + it('renders a node-view-content as a code element', () => { + createWrapper(); + + expect(wrapper.findComponent(NodeViewContent).props().as).toBe('code'); + }); + + it('renders label indicating that code block is frontmatter', () => { + createWrapper(); + + 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']); + }); +}); diff --git a/spec/frontend/error_tracking_settings/components/app_spec.js b/spec/frontend/error_tracking_settings/components/app_spec.js index 30541ba68a5..844faff64a1 100644 --- a/spec/frontend/error_tracking_settings/components/app_spec.js +++ b/spec/frontend/error_tracking_settings/components/app_spec.js @@ -1,7 +1,8 @@ -import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui'; +import { GlFormRadioGroup, GlFormRadio, GlFormInputGroup } from '@gitlab/ui'; import { createLocalVue, shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; import Vuex from 'vuex'; +import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import { TEST_HOST } from 'helpers/test_constants'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import ErrorTrackingSettings from '~/error_tracking_settings/components/app.vue'; @@ -12,6 +13,8 @@ import createStore from '~/error_tracking_settings/store'; const localVue = createLocalVue(); localVue.use(Vuex); +const TEST_GITLAB_DSN = 'https://gitlab.example.com/123456'; + describe('error tracking settings app', () => { let store; let wrapper; @@ -29,6 +32,10 @@ describe('error tracking settings app', () => { initialProject: null, listProjectsEndpoint: TEST_HOST, operationsSettingsEndpoint: TEST_HOST, + gitlabDsn: TEST_GITLAB_DSN, + }, + stubs: { + GlFormInputGroup, // we need this non-shallow to query for a component within a slot }, }), ); @@ -41,6 +48,12 @@ describe('error tracking settings app', () => { findBackendSettingsRadioGroup().findAllComponents(GlFormRadio); const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text); const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form'); + const findDsnSettings = () => wrapper.findByTestId('gitlab-dsn-setting-form'); + + const enableGitLabErrorTracking = async () => { + findBackendSettingsRadioGroup().vm.$emit('change', true); + await nextTick(); + }; beforeEach(() => { store = createStore(); @@ -93,17 +106,35 @@ describe('error tracking settings app', () => { expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1); }); - it('toggles the sentry-settings section when sentry is selected as a tracking-backend', async () => { + it('hides the Sentry settings when GitLab is selected as a tracking-backend', async () => { expect(findSentrySettings().exists()).toBe(true); - // set the "integrated" setting to "true" - findBackendSettingsRadioGroup().vm.$emit('change', true); - - await nextTick(); + await enableGitLabErrorTracking(); expect(findSentrySettings().exists()).toBe(false); }); + describe('GitLab DSN section', () => { + it('is visible when GitLab is selected as a tracking-backend and DSN is present', async () => { + expect(findDsnSettings().exists()).toBe(false); + + await enableGitLabErrorTracking(); + + expect(findDsnSettings().exists()).toBe(true); + }); + + it('contains copy-to-clipboard functionality for the GitLab DSN string', async () => { + await enableGitLabErrorTracking(); + + const clipBoardInput = findDsnSettings().findComponent(GlFormInputGroup); + const clipBoardButton = findDsnSettings().findComponent(ClipboardButton); + + expect(clipBoardInput.props('value')).toBe(TEST_GITLAB_DSN); + expect(clipBoardInput.attributes('readonly')).toBeTruthy(); + expect(clipBoardButton.props('text')).toBe(TEST_GITLAB_DSN); + }); + }); + it.each([true, false])( 'calls the `updateIntegrated` action when the setting changes to `%s`', (integrated) => { diff --git a/spec/frontend/fixtures/api_markdown.yml b/spec/frontend/fixtures/api_markdown.yml index bc3a0b624dc..332cc14d1e4 100644 --- a/spec/frontend/fixtures/api_markdown.yml +++ b/spec/frontend/fixtures/api_markdown.yml @@ -219,3 +219,22 @@ # Sit amit ### I don't know +- name: word_break + markdown: Fernstraßen<wbr>bau<wbr>privat<wbr>finanzierungs<wbr>gesetz +- name: frontmatter_yaml + markdown: |- + --- + title: Page title + --- +- name: frontmatter_toml + markdown: |- + +++ + title = "Page title" + +++ +- name: frontmatter_json + markdown: |- + ;;; + { + "title": "Page title" + } + ;;; diff --git a/spec/frontend/ide/stores/modules/commit/getters_spec.js b/spec/frontend/ide/stores/modules/commit/getters_spec.js index 7a07ed05201..1e34087b290 100644 --- a/spec/frontend/ide/stores/modules/commit/getters_spec.js +++ b/spec/frontend/ide/stores/modules/commit/getters_spec.js @@ -126,7 +126,7 @@ describe('IDE commit module getters', () => { ); expect(getters.preBuiltCommitMessage(state, null, rootState)).toBe( - 'Update test-file, index.js files', + 'Update test-file, index.js', ); }); diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index c00fa3541e9..0c1b61428f9 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -15,6 +15,13 @@ RSpec.describe Gitlab::Database do end end + describe '.databases' do + it 'stores connections as a HashWithIndifferentAccess' do + expect(described_class.databases.has_key?('main')).to be true + expect(described_class.databases.has_key?(:main)).to be true + end + end + describe '.default_pool_size' do before do allow(Gitlab::Runtime).to receive(:max_threads).and_return(7) diff --git a/spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb b/spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb new file mode 100644 index 00000000000..cf326cf0c0a --- /dev/null +++ b/spec/migrations/20210922021816_drop_int4_columns_for_ci_job_artifacts_spec.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration!('drop_int4_columns_for_ci_job_artifacts') + +RSpec.describe DropInt4ColumnsForCiJobArtifacts do + let(:ci_job_artifacts) { table(:ci_job_artifacts) } + + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + expect(ci_job_artifacts.column_names).to include('id_convert_to_bigint') + expect(ci_job_artifacts.column_names).to include('job_id_convert_to_bigint') + } + + migration.after -> { + ci_job_artifacts.reset_column_information + expect(ci_job_artifacts.column_names).not_to include('id_convert_to_bigint') + expect(ci_job_artifacts.column_names).not_to include('job_id_convert_to_bigint') + } + end + end +end diff --git a/spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb b/spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb new file mode 100644 index 00000000000..412556fc283 --- /dev/null +++ b/spec/migrations/20210922082019_drop_int4_column_for_events_spec.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration!('drop_int4_column_for_events') + +RSpec.describe DropInt4ColumnForEvents do + let(:events) { table(:events) } + + it 'correctly migrates up and down' do + reversible_migration do |migration| + migration.before -> { + expect(events.column_names).to include('id_convert_to_bigint') + } + + migration.after -> { + events.reset_column_information + expect(events.column_names).not_to include('id_convert_to_bigint') + } + end + end +end diff --git a/spec/models/error_tracking/project_error_tracking_setting_spec.rb b/spec/models/error_tracking/project_error_tracking_setting_spec.rb index 29255e53fcf..d17541b4a6c 100644 --- a/spec/models/error_tracking/project_error_tracking_setting_spec.rb +++ b/spec/models/error_tracking/project_error_tracking_setting_spec.rb @@ -79,6 +79,46 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do end end + describe 'Callbacks' do + describe 'after_save :create_client_key!' do + subject { build(:project_error_tracking_setting, :integrated, project: project) } + + context 'no client key yet' do + it 'creates a new client key' do + expect { subject.save! }.to change { ErrorTracking::ClientKey.count }.by(1) + end + + context 'sentry backend' do + before do + subject.integrated = false + end + + it 'does not create a new client key' do + expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count } + end + end + + context 'feature disabled' do + before do + subject.enabled = false + end + + it 'does not create a new client key' do + expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count } + end + end + end + + context 'client key already exists' do + let!(:client_key) { create(:error_tracking_client_key, project: project) } + + it 'does not create a new client key' do + expect { subject.save! }.not_to change { ErrorTracking::ClientKey.count } + end + end + end + end + describe '.extract_sentry_external_url' do subject { described_class.extract_sentry_external_url(sentry_url) } @@ -494,4 +534,10 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do it { expect(subject.sentry_enabled).to eq(sentry_enabled) } end end + + describe '#gitlab_dsn' do + let!(:client_key) { create(:error_tracking_client_key, project: project) } + + it { expect(subject.gitlab_dsn).to eq(client_key.sentry_dsn) } + end end diff --git a/spec/policies/namespace_policy_spec.rb b/spec/policies/namespaces/user_namespace_policy_spec.rb index b9823273de8..02eda31bfa7 100644 --- a/spec/policies/namespace_policy_spec.rb +++ b/spec/policies/namespaces/user_namespace_policy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe NamespacePolicy do +RSpec.describe Namespaces::UserNamespacePolicy do let(:user) { create(:user) } let(:owner) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 3e810d8f596..15c88c9f657 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -277,15 +277,15 @@ RSpec.describe Ci::RetryBuildService do end end - describe '#reprocess' do + describe '#clone!' do let(:new_build) do travel_to(1.second.from_now) do - service.reprocess!(build) + service.clone!(build) end end it 'raises an error when an unexpected class is passed' do - expect { service.reprocess!(create(:ci_build).present) }.to raise_error(TypeError) + expect { service.clone!(create(:ci_build).present) }.to raise_error(TypeError) end context 'when user has ability to execute build' do @@ -343,7 +343,7 @@ RSpec.describe Ci::RetryBuildService do let(:user) { reporter } it 'raises an error' do - expect { service.reprocess!(build) } + expect { service.clone!(build) } .to raise_error Gitlab::Access::AccessDeniedError end end |
