diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-21 09:08:52 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-21 09:08:52 +0000 |
commit | ea037b91577f1b645267df9e034f6da3e389626c (patch) | |
tree | 4cf78baf7034278157a4faa9d37409b0cf299a24 | |
parent | 25c07d7230471a8cc7062e83662a300fb4902fce (diff) | |
download | gitlab-ce-ea037b91577f1b645267df9e034f6da3e389626c.tar.gz |
Add latest changes from gitlab-org/gitlab@master
47 files changed, 728 insertions, 146 deletions
diff --git a/.gitlab/issue_templates/Adoption Engineering.md b/.gitlab/issue_templates/Adoption Engineering.md new file mode 100644 index 00000000000..01e9d0ea033 --- /dev/null +++ b/.gitlab/issue_templates/Adoption Engineering.md @@ -0,0 +1,14 @@ +#Design +<!-- This should include the contexts that determine the reproducibility (stickiness) of an experiment. This means that if you want the same behavior for a user, the context would be user, or if you want all users when viewing a specific project, the context would be the project being viewed, etc. --> + + +#Rollout strategy +<!-- This is currently called A/B test, which isn't accurate for multi-variants. Let's call this rollout strategy. It should outline the percentages for variants and if there's more than one step to this, each of those steps and the timing for those steps (e.g. 30 days after initial rollout). --> + +#Inclusions and exclusions +<!-- These would be the rules for which given context (and are limited to context or resolvable at experiment time details) is included or excluded from the test. An example of this would be to only run an experiment on groups less than N number of days old. --> + +#Segmentation +<!-- Rules for always saying context with these criteria always get this variant. For instance, if you want to always give groups less than N number of days old the experiment experience, they are specified here. This is different from the exclusion rules above. --> + +#Tracking diff --git a/app/controllers/whats_new_controller.rb b/app/controllers/whats_new_controller.rb index cba86c65848..9d9811d792d 100644 --- a/app/controllers/whats_new_controller.rb +++ b/app/controllers/whats_new_controller.rb @@ -5,7 +5,6 @@ class WhatsNewController < ApplicationController skip_before_action :authenticate_user! - before_action :check_feature_flag before_action :check_valid_page_param, :set_pagination_headers, unless: -> { has_version_param? } feature_category :navigation @@ -20,10 +19,6 @@ class WhatsNewController < ApplicationController private - def check_feature_flag - render_404 unless Feature.enabled?(:whats_new_drawer, current_user) - end - def check_valid_page_param render_404 if current_page < 1 end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 64b8223a1f0..725a8edbcda 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -270,8 +270,7 @@ class MergeRequest < ApplicationRecord by_commit_sha(sha), by_squash_commit_sha(sha), by_merge_commit_sha(sha) - ], - remove_duplicates: false + ] ) end scope :by_cherry_pick_sha, -> (sha) do diff --git a/app/views/admin/application_settings/general.html.haml b/app/views/admin/application_settings/general.html.haml index 8f15dcac40a..794e02787f5 100644 --- a/app/views/admin/application_settings/general.html.haml +++ b/app/views/admin/application_settings/general.html.haml @@ -104,7 +104,6 @@ = f.submit _('Save changes'), class: "gl-button btn btn-success" = render_if_exists 'admin/application_settings/maintenance_mode_settings_form' -= render_if_exists 'admin/application_settings/elasticsearch_form' = render 'admin/application_settings/gitpod' = render 'admin/application_settings/kroki' = render 'admin/application_settings/plantuml' diff --git a/app/views/admin/application_settings/integrations.html.haml b/app/views/admin/application_settings/integrations.html.haml index 6ed6709eca8..949908b09a7 100644 --- a/app/views/admin/application_settings/integrations.html.haml +++ b/app/views/admin/application_settings/integrations.html.haml @@ -9,7 +9,7 @@ = sprite_icon('close', css_class: 'gl-icon') .gl-alert-body %h4.gl-alert-title= s_('AdminSettings|Some settings have moved') - = html_escape_once(s_('AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General.')).html_safe + = html_escape_once(s_('AdminSettings|PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General.')).html_safe .gl-alert-actions = link_to s_('AdminSettings|Go to General Settings'), general_admin_application_settings_path, class: 'btn gl-alert-action btn-info gl-button' diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index f7e93182ca2..ecadc9c466e 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -120,8 +120,7 @@ = sprite_icon('ellipsis_h', size: 12, css_class: 'more-icon js-navbar-toggle-right') = sprite_icon('close', size: 12, css_class: 'close-icon js-navbar-toggle-left') -- if ::Feature.enabled?(:whats_new_drawer, current_user) - #whats-new-app{ data: { storage_key: whats_new_storage_key, versions: whats_new_versions, gitlab_dot_com: Gitlab.dev_env_org_or_com? } } +#whats-new-app{ data: { storage_key: whats_new_storage_key, versions: whats_new_versions, gitlab_dot_com: Gitlab.dev_env_org_or_com? } } - if can?(current_user, :update_user_status, current_user) .js-set-status-modal-wrapper{ data: user_status_data } diff --git a/app/views/layouts/header/_help_dropdown.html.haml b/app/views/layouts/header/_help_dropdown.html.haml index 40bf45db80d..c3769dd2993 100644 --- a/app/views/layouts/header/_help_dropdown.html.haml +++ b/app/views/layouts/header/_help_dropdown.html.haml @@ -1,6 +1,6 @@ %ul - if current_user_menu?(:help) - = render_if_exists 'layouts/header/whats_new_dropdown_item' + = render 'layouts/header/whats_new_dropdown_item' %li = link_to _("Help"), help_path %li diff --git a/app/views/layouts/header/_whats_new_dropdown_item.html.haml b/app/views/layouts/header/_whats_new_dropdown_item.html.haml new file mode 100644 index 00000000000..f79b741ced0 --- /dev/null +++ b/app/views/layouts/header/_whats_new_dropdown_item.html.haml @@ -0,0 +1,5 @@ +%li + %button.gl-justify-content-space-between.gl-align-items-center.js-whats-new-trigger{ type: 'button', data: { storage_key: whats_new_storage_key }, class: 'gl-display-flex!' } + = _("What's new") + %span.js-whats-new-notification-count.whats-new-notification-count + = whats_new_most_recent_release_items_count diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index da16be707eb..323cbcdb24d 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -260,6 +260,9 @@ = link_to general_admin_application_settings_path, title: _('General'), class: 'qa-admin-settings-general-item' do %span = _('General') + + = render_if_exists 'layouts/nav/sidebar/advanced_search', class: 'qa-admin-settings-advanced-search' + - if instance_level_integrations? = nav_link(path: ['application_settings#integrations', 'integrations#edit']) do = link_to integrations_admin_application_settings_path, title: _('Integrations'), data: { qa_selector: 'integration_settings_link' } do diff --git a/changelogs/unreleased/212322-remove-duplicate-vulnerabilities.yml b/changelogs/unreleased/212322-remove-duplicate-vulnerabilities.yml new file mode 100644 index 00000000000..4e8fd48b152 --- /dev/null +++ b/changelogs/unreleased/212322-remove-duplicate-vulnerabilities.yml @@ -0,0 +1,5 @@ +--- +title: Remove duplicates from vulnerability_occurrences +merge_request: 49937 +author: +type: other diff --git a/changelogs/unreleased/21686_filter_duplicates.yml b/changelogs/unreleased/21686_filter_duplicates.yml new file mode 100644 index 00000000000..b1e0da45806 --- /dev/null +++ b/changelogs/unreleased/21686_filter_duplicates.yml @@ -0,0 +1,5 @@ +--- +title: Remove duplicates from related_commit_sha query +merge_request: 51888 +author: +type: fixed diff --git a/changelogs/unreleased/292714-allow-reviewers-to-be-updated-via-api.yml b/changelogs/unreleased/292714-allow-reviewers-to-be-updated-via-api.yml new file mode 100644 index 00000000000..aa491ecfdcb --- /dev/null +++ b/changelogs/unreleased/292714-allow-reviewers-to-be-updated-via-api.yml @@ -0,0 +1,5 @@ +--- +title: Allow reviewers to be updated via MergeRequest API +merge_request: 51186 +author: +type: added diff --git a/changelogs/unreleased/jswain_whats_new_remove_feature_flag.yml b/changelogs/unreleased/jswain_whats_new_remove_feature_flag.yml new file mode 100644 index 00000000000..36c20c4eb09 --- /dev/null +++ b/changelogs/unreleased/jswain_whats_new_remove_feature_flag.yml @@ -0,0 +1,5 @@ +--- +title: Add "What's new" item to the help dropdown +merge_request: 52020 +author: +type: changed diff --git a/changelogs/unreleased/philipcunningham-create-dast-scan-model-295243.yml b/changelogs/unreleased/philipcunningham-create-dast-scan-model-295243.yml new file mode 100644 index 00000000000..2aaebc076d5 --- /dev/null +++ b/changelogs/unreleased/philipcunningham-create-dast-scan-model-295243.yml @@ -0,0 +1,5 @@ +--- +title: Add dast_profiles database table +merge_request: 51296 +author: +type: added diff --git a/changelogs/unreleased/ui-text-protected-environments.yml b/changelogs/unreleased/ui-text-protected-environments.yml new file mode 100644 index 00000000000..9f8fa029993 --- /dev/null +++ b/changelogs/unreleased/ui-text-protected-environments.yml @@ -0,0 +1,5 @@ +--- +title: Updated UI text to match style guidelines +merge_request: 52152 +author: +type: other diff --git a/config/metrics/counts_28d/deployments.yml b/config/metrics/counts_28d/deployments.yml index dabd50ef5be..85fdc407156 100644 --- a/config/metrics/counts_28d/deployments.yml +++ b/config/metrics/counts_28d/deployments.yml @@ -1,11 +1,8 @@ -name: deployments +key_path: counts_monthy.deployments description: Total deployments count for recent 28 days value_type: integer stage: release status: data_available -default_generation: generation_1 -full_path: - generation_1: counts_monthy.deployments milestone: 13.2 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35493 group: 'group::ops release' diff --git a/config/metrics/counts_7d/g_project_management_issue_title_changed_weekly.yml b/config/metrics/counts_7d/g_project_management_issue_title_changed_weekly.yml index 997263f9e30..5f8492f13c1 100644 --- a/config/metrics/counts_7d/g_project_management_issue_title_changed_weekly.yml +++ b/config/metrics/counts_7d/g_project_management_issue_title_changed_weekly.yml @@ -1,12 +1,9 @@ -name: g_project_management_issue_title_changed_weekly +key_path: redis_hll_counters.issues_edit.g_project_management_issue_title_changed_weekly description: Distinct users count that changed issue title in a group for last recent week value_type: integer product_category: issue_tracking stage: plan status: data_available -default_generation: generation_1 -full_path: - generation_1: redis_hll_counters.issues_edit.g_project_management_issue_title_changed_weekly milestone: 13.6 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229918 group: 'group::project management' diff --git a/config/metrics/counts_all/deployments.yml b/config/metrics/counts_all/deployments.yml index bb78e8d6144..abddb09c3dd 100644 --- a/config/metrics/counts_all/deployments.yml +++ b/config/metrics/counts_all/deployments.yml @@ -1,11 +1,8 @@ -name: deployments +key_path: counts.deployments description: Total deployments count value_type: integer stage: release status: data_available -default_generation: generation_1 -full_path: - generation_1: counts.deployments milestone: 8.12 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/735 group: 'group::ops release' diff --git a/config/metrics/license/recorded_at.yml b/config/metrics/license/recorded_at.yml index 5b2b3b37290..0ffb65de671 100644 --- a/config/metrics/license/recorded_at.yml +++ b/config/metrics/license/recorded_at.yml @@ -1,12 +1,9 @@ -name: recorded_at +key_path: recorded_at description: When the Usage Ping computation was started value_type: string product_category: collection stage: growth status: data_available -default_generation: generation_1 -full_path: - generation_1: recorded_at milestone: 8.10 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/557 group: group::product analytics diff --git a/config/metrics/license/uuid.yml b/config/metrics/license/uuid.yml index 38e0d74fc22..86b38a26cbc 100644 --- a/config/metrics/license/uuid.yml +++ b/config/metrics/license/uuid.yml @@ -1,13 +1,9 @@ -name: uuid +key_path: uuid description: GitLab instance unique identifier value_type: string product_category: collection stage: growth status: data_available -default_generation: generation_1 -full_path: - generation_1: uuid - generation_2: license.uuid milestone: 9.1 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1521 group: group::product analytics diff --git a/config/metrics/schema.json b/config/metrics/schema.json index 4d1120a7d8d..634c74982cc 100644 --- a/config/metrics/schema.json +++ b/config/metrics/schema.json @@ -1,8 +1,8 @@ { "type": "object", - "required": ["name", "description", "value_type", "status", "default_generation", "full_path", "group", "time_frame", "data_source", "distribution", "tier"], + "required": ["key_path", "description", "value_type", "status", "group", "time_frame", "data_source", "distribution", "tier"], "properties": { - "name": { + "key_path": { "type": "string" }, "description": { @@ -22,12 +22,6 @@ "type": ["string"], "enum": ["data_available", "planned", "in_progress", "implmented"] }, - "default_generation": { - "type": "string" - }, - "full_path": { - "type": "object" - }, "milestone": { "type": ["number", "null"] }, diff --git a/config/metrics/settings/database_adapter.yml b/config/metrics/settings/database_adapter.yml index b24fc933a08..b80906ab025 100644 --- a/config/metrics/settings/database_adapter.yml +++ b/config/metrics/settings/database_adapter.yml @@ -1,12 +1,9 @@ -name: adapter +key_path: database.adapter description: This metric only returns a value of PostgreSQL in supported versions of GitLab. It could be removed from the usage ping. Historically MySQL was also supported. value_type: string product_category: collection stage: growth status: data_available -default_generation: generation_1 -full_path: - generation_1: database.adapter group: group::enablement distribution time_frame: none data_source: database diff --git a/db/migrate/20210111051045_create_dast_profiles.rb b/db/migrate/20210111051045_create_dast_profiles.rb new file mode 100644 index 00000000000..f2667e1222e --- /dev/null +++ b/db/migrate/20210111051045_create_dast_profiles.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +class CreateDastProfiles < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + def up + table_comment = { owner: 'group::dynamic analysis', description: 'Profile used to run a DAST on-demand scan' } + + create_table_with_constraints :dast_profiles, comment: table_comment.to_json do |t| # rubocop:disable Migration/AddLimitToTextColumns + t.references :project, null: false, foreign_key: false, index: false + t.references :dast_site_profile, null: false, foreign_key: { on_delete: :cascade } + t.references :dast_scanner_profile, null: false, foreign_key: { on_delete: :cascade } + + t.timestamps_with_timezone + + # rubocop:disable Migration/AddLimitToTextColumns + t.text :name, null: false + t.text :description, null: false + # rubocop:enable Migration/AddLimitToTextColumns + + t.index [:project_id, :name], unique: true + + t.text_limit :name, 255 + t.text_limit :description, 255 + end + end + + def down + with_lock_retries do + drop_table :dast_profiles + end + end +end diff --git a/db/migrate/20210111053308_add_project_fk_for_dast_profile.rb b/db/migrate/20210111053308_add_project_fk_for_dast_profile.rb new file mode 100644 index 00000000000..5dc057b5f70 --- /dev/null +++ b/db/migrate/20210111053308_add_project_fk_for_dast_profile.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddProjectFkForDastProfile < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + disable_ddl_transaction! + + def up + add_concurrent_foreign_key :dast_profiles, :projects, column: :project_id, on_delete: :cascade + end + + def down + with_lock_retries do + remove_foreign_key :dast_profiles, column: :project_id + end + end +end diff --git a/db/post_migrate/20201112130710_schedule_remove_duplicate_vulnerabilities_findings.rb b/db/post_migrate/20201112130710_schedule_remove_duplicate_vulnerabilities_findings.rb new file mode 100644 index 00000000000..d05516bd255 --- /dev/null +++ b/db/post_migrate/20201112130710_schedule_remove_duplicate_vulnerabilities_findings.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +class ScheduleRemoveDuplicateVulnerabilitiesFindings < ActiveRecord::Migration[6.0] + include Gitlab::Database::MigrationHelpers + + DOWNTIME = false + + INDEX_NAME = 'tmp_idx_deduplicate_vulnerability_occurrences' + + MIGRATION = 'RemoveDuplicateVulnerabilitiesFindings' + DELAY_INTERVAL = 2.minutes.to_i + BATCH_SIZE = 5_000 + + disable_ddl_transaction! + + class VulnerabilitiesFinding < ActiveRecord::Base + include ::EachBatch + self.table_name = "vulnerability_occurrences" + end + + def up + add_concurrent_index :vulnerability_occurrences, + %i[project_id report_type location_fingerprint primary_identifier_id id], + name: INDEX_NAME + + say "Scheduling #{MIGRATION} jobs" + queue_background_migration_jobs_by_range_at_intervals( + VulnerabilitiesFinding, + MIGRATION, + DELAY_INTERVAL, + batch_size: BATCH_SIZE + ) + end + + def down + remove_concurrent_index_by_name(:vulnerability_occurrences, INDEX_NAME) + end +end diff --git a/db/schema_migrations/20201112130710 b/db/schema_migrations/20201112130710 new file mode 100644 index 00000000000..a13668cf3ce --- /dev/null +++ b/db/schema_migrations/20201112130710 @@ -0,0 +1 @@ +322d7270e942c161cc8b50b8c3f531c93b6e6e938e415c1b6010a70b630bf82e
\ No newline at end of file diff --git a/db/schema_migrations/20210111051045 b/db/schema_migrations/20210111051045 new file mode 100644 index 00000000000..842c164fc20 --- /dev/null +++ b/db/schema_migrations/20210111051045 @@ -0,0 +1 @@ +6075e469081fcca124c0c4b485071a086545b502c398314cca05052765072caf
\ No newline at end of file diff --git a/db/schema_migrations/20210111053308 b/db/schema_migrations/20210111053308 new file mode 100644 index 00000000000..b7968a03c32 --- /dev/null +++ b/db/schema_migrations/20210111053308 @@ -0,0 +1 @@ +a98ca25378df3fc798b6ae361b3a47b697f6b853796975221329db023cb98466
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 2cdd93c8405..9c0e7e49208 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -11589,6 +11589,30 @@ CREATE SEQUENCE custom_emoji_id_seq ALTER SEQUENCE custom_emoji_id_seq OWNED BY custom_emoji.id; +CREATE TABLE dast_profiles ( + id bigint NOT NULL, + project_id bigint NOT NULL, + dast_site_profile_id bigint NOT NULL, + dast_scanner_profile_id bigint NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + name text NOT NULL, + description text NOT NULL, + CONSTRAINT check_5fcf73bf61 CHECK ((char_length(name) <= 255)), + CONSTRAINT check_c34e505c24 CHECK ((char_length(description) <= 255)) +); + +COMMENT ON TABLE dast_profiles IS '{"owner":"group::dynamic analysis","description":"Profile used to run a DAST on-demand scan"}'; + +CREATE SEQUENCE dast_profiles_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + +ALTER SEQUENCE dast_profiles_id_seq OWNED BY dast_profiles.id; + CREATE TABLE dast_scanner_profiles ( id bigint NOT NULL, created_at timestamp with time zone NOT NULL, @@ -18574,6 +18598,8 @@ ALTER TABLE ONLY csv_issue_imports ALTER COLUMN id SET DEFAULT nextval('csv_issu ALTER TABLE ONLY custom_emoji ALTER COLUMN id SET DEFAULT nextval('custom_emoji_id_seq'::regclass); +ALTER TABLE ONLY dast_profiles ALTER COLUMN id SET DEFAULT nextval('dast_profiles_id_seq'::regclass); + ALTER TABLE ONLY dast_scanner_profiles ALTER COLUMN id SET DEFAULT nextval('dast_scanner_profiles_id_seq'::regclass); ALTER TABLE ONLY dast_site_profiles ALTER COLUMN id SET DEFAULT nextval('dast_site_profiles_id_seq'::regclass); @@ -19723,6 +19749,9 @@ ALTER TABLE ONLY csv_issue_imports ALTER TABLE ONLY custom_emoji ADD CONSTRAINT custom_emoji_pkey PRIMARY KEY (id); +ALTER TABLE ONLY dast_profiles + ADD CONSTRAINT dast_profiles_pkey PRIMARY KEY (id); + ALTER TABLE ONLY dast_scanner_profiles ADD CONSTRAINT dast_scanner_profiles_pkey PRIMARY KEY (id); @@ -21546,6 +21575,12 @@ CREATE UNIQUE INDEX index_custom_emoji_on_namespace_id_and_name ON custom_emoji CREATE UNIQUE INDEX index_daily_build_group_report_results_unique_columns ON ci_daily_build_group_report_results USING btree (project_id, ref_path, date, group_name); +CREATE INDEX index_dast_profiles_on_dast_scanner_profile_id ON dast_profiles USING btree (dast_scanner_profile_id); + +CREATE INDEX index_dast_profiles_on_dast_site_profile_id ON dast_profiles USING btree (dast_site_profile_id); + +CREATE UNIQUE INDEX index_dast_profiles_on_project_id_and_name ON dast_profiles USING btree (project_id, name); + CREATE UNIQUE INDEX index_dast_scanner_profiles_on_project_id_and_name ON dast_scanner_profiles USING btree (project_id, name); CREATE INDEX index_dast_site_profiles_on_dast_site_id ON dast_site_profiles USING btree (dast_site_id); @@ -23380,6 +23415,8 @@ CREATE INDEX temporary_index_vulnerabilities_on_id ON vulnerabilities USING btre CREATE UNIQUE INDEX term_agreements_unique_index ON term_agreements USING btree (user_id, term_id); +CREATE INDEX tmp_idx_deduplicate_vulnerability_occurrences ON vulnerability_occurrences USING btree (project_id, report_type, location_fingerprint, primary_identifier_id, id); + CREATE INDEX tmp_index_oauth_applications_on_id_where_trusted ON oauth_applications USING btree (id) WHERE (trusted = true); CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING btree (id) WHERE (state <> 2); @@ -24095,6 +24132,9 @@ ALTER TABLE ONLY merge_requests ALTER TABLE ONLY epics ADD CONSTRAINT fk_aa5798e761 FOREIGN KEY (closed_by_id) REFERENCES users(id) ON DELETE SET NULL; +ALTER TABLE ONLY dast_profiles + ADD CONSTRAINT fk_aa76ef30e9 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; + ALTER TABLE ONLY alert_management_alerts ADD CONSTRAINT fk_aad61aedca FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE SET NULL; @@ -24569,6 +24609,9 @@ ALTER TABLE ONLY service_desk_settings ALTER TABLE ONLY saml_group_links ADD CONSTRAINT fk_rails_22e312c530 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; +ALTER TABLE ONLY dast_profiles + ADD CONSTRAINT fk_rails_23cae5abe1 FOREIGN KEY (dast_scanner_profile_id) REFERENCES dast_scanner_profiles(id) ON DELETE CASCADE; + ALTER TABLE ONLY group_custom_attributes ADD CONSTRAINT fk_rails_246e0db83a FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE; @@ -25643,6 +25686,9 @@ ALTER TABLE ONLY alert_management_alert_user_mentions ALTER TABLE ONLY snippet_statistics ADD CONSTRAINT fk_rails_ebc283ccf1 FOREIGN KEY (snippet_id) REFERENCES snippets(id) ON DELETE CASCADE; +ALTER TABLE ONLY dast_profiles + ADD CONSTRAINT fk_rails_ed1e66fbbf FOREIGN KEY (dast_site_profile_id) REFERENCES dast_site_profiles(id) ON DELETE CASCADE; + ALTER TABLE ONLY project_security_settings ADD CONSTRAINT fk_rails_ed4abe1338 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE; diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 6879b510ec8..b6ae62dc47a 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -15,6 +15,7 @@ type: reference, api > - `reference` was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20354) in GitLab 12.10 in favour of `references`. > - `with_merge_status_recheck` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31890) in GitLab 13.0. > - `reviewer_username` and `reviewer_id` were [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/49341) in GitLab 13.8. +> - `reviewer_ids` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/51186) in GitLab 13.8. Every API call to merge requests must be authenticated. @@ -1060,6 +1061,8 @@ POST /projects/:id/merge_requests | `title` | string | yes | Title of MR. | | `assignee_id` | integer | no | Assignee user ID. | | `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. | +| `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. If set to `0` or left empty, there will be no assignees added. | +| `reviewer_ids` | integer array | no | The ID of the user(s) added as a reviewer to the MR. If set to `0` or left empty, there will be no reviewers added. | | `description` | string | no | Description of MR. Limited to 1,048,576 characters. | | `target_project_id` | integer | no | The target project (numeric ID). | | `labels` | string | no | Labels for MR as a comma-separated list. | @@ -1208,6 +1211,7 @@ PUT /projects/:id/merge_requests/:merge_request_iid | `title` | string | no | Title of MR. | | `assignee_id` | integer | no | The ID of the user to assign the merge request to. Set to `0` or provide an empty value to unassign all assignees. | | `assignee_ids` | integer array | no | The ID of the user(s) to assign the MR to. Set to `0` or provide an empty value to unassign all assignees. | +| `reviewer_ids` | integer array | no | The ID of the user(s) set as a reviewer to the MR. Set the value to `0` or provide an empty value to unset all reviewers. | | `milestone_id` | integer | no | The global ID of a milestone to assign the merge request to. Set to `0` or provide an empty value to unassign a milestone.| | `labels` | string | no | Comma-separated label names for a merge request. Set to an empty string to unassign all labels. | | `add_labels` | string | no | Comma-separated label names to add to a merge request. | diff --git a/doc/development/feature_flags/development.md b/doc/development/feature_flags/development.md index dd732a08c72..a1da284ec8f 100644 --- a/doc/development/feature_flags/development.md +++ b/doc/development/feature_flags/development.md @@ -321,6 +321,28 @@ Feature.enabled?(:feature_flag, group) Feature.enabled?(:feature_flag, user) ``` +#### Selectively disable by actor + +By default you cannot selectively disable a feature flag by actor. + +```shell +# This will not work how you would expect. +/chatops run feature set some_feature true +/chatops run feature set --project=gitlab-org/gitlab some_feature false +``` + +However, if you add two feature flags, you can write your conditional statement in such a way that the equivalent selective disable is possible. + +```ruby +Feature.enabled?(:a_feature, project) && Feature.disabled?(:a_feature_override, project) +``` + +```shell +# This will enable a feature flag globally, except for gitlab-org/gitlab +/chatops run feature set a_feature true +/chatops run feature set --project=gitlab-org/gitlab a_feature_override true +``` + ### Enable additional objects as actors To use feature gates based on actors, the model needs to respond to diff --git a/doc/development/usage_ping/metrics_dictionary.md b/doc/development/usage_ping/metrics_dictionary.md index bae79689f3b..1faa6aa0923 100644 --- a/doc/development/usage_ping/metrics_dictionary.md +++ b/doc/development/usage_ping/metrics_dictionary.md @@ -15,7 +15,7 @@ We are using [JSON Schema](https://gitlab.com/gitlab-org/gitlab/-/blob/master/co This process is meant to ensure consistent and valid metrics defined for Usage Ping. All metrics *must*: - Comply with the definied [JSON schema](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/schema.json). -- Have a unique `full_path` . +- Have a unique `key_path` . - Have an owner. All metrics are stored in YAML files: @@ -26,12 +26,10 @@ Each metric is definied in a separate YAML file consisting of a number of fields | Field | Required | Additional information | |---------------------|----------|----------------------------------------------------------------| -| `name` | yes | | +| `key_path` | yes | JSON key path for the metric, location in Usage Ping payload. | | `description` | yes | | | `value_type` | yes | | | `status` | yes | | -| `default_generation`| yes | Default generation path of the metric. One full_path value. (1) | -| `full_path` | yes | Full path of the metric for one or multiple generations. Path of the metric in Usage Ping payload. (1) | | `group` | yes | The [group](https://about.gitlab.com/handbook/product/categories/#devops-stages) that owns the metric. | | `time_frame` | yes | `string`; may be set to a value like "7d" | | `data_source` | yes | `string`: may be set to a value like `database` or `redis_hll`. | @@ -43,9 +41,6 @@ Each metric is definied in a separate YAML file consisting of a number of fields | `milestone_removed` | no | The milestone when the metric is removed. | | `introduced_by_url` | no | The URL to the Merge Request that introduced the metric. | -1. The default generation path is the location of the metric in the Usage Ping payload. - The `full_path` is the list locations for multiple Usage Ping generaations. - ### Example metric definition The linked [`uuid`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/license/uuid.yml) @@ -53,16 +48,12 @@ YAML file includes an example metric definition, where the `uuid` metric is the instance unique identifier. ```yaml -name: uuid +key_path: uuid description: GitLab instance unique identifier value_type: string product_category: collection stage: growth status: data_available -default_generation: generation_1 -full_path: - generation_1: uuid - generation_2: license.uuid milestone: 9.1 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1521 group: group::product intelligence diff --git a/doc/integration/elasticsearch.md b/doc/integration/elasticsearch.md index b1fc2573bb0..162ce1f8e76 100644 --- a/doc/integration/elasticsearch.md +++ b/doc/integration/elasticsearch.md @@ -175,8 +175,7 @@ instances](#indexing-large-instances) below. To enable Advanced Search, you need to have admin access to GitLab: -1. Navigate to **Admin Area**, then **Settings > General** - and expand the **Advanced Search** section. +1. Navigate to **Admin Area**, then **Settings > Advanced Search**. NOTE: To see the Advanced Search section, you need an active Starter @@ -186,7 +185,7 @@ To enable Advanced Search, you need to have admin access to GitLab: your Elasticsearch cluster. Do not enable **Search with Elasticsearch enabled** yet. 1. Now enable **Elasticsearch indexing** in **Admin Area > Settings > - General > Advanced Search** and click **Save changes**. This will create + Advanced Search** and click **Save changes**. This will create an empty index if one does not already exist. 1. Click **Index all projects**. 1. Click **Check progress** in the confirmation message to see the status of @@ -202,7 +201,7 @@ To enable Advanced Search, you need to have admin access to GitLab: ``` 1. After the indexing has completed, enable **Search with Elasticsearch enabled** in - **Admin Area > Settings > General > Advanced Search** and click **Save + **Admin Area > Settings > Advanced Search** and click **Save changes**. NOTE: @@ -265,8 +264,8 @@ You can improve the language support for Chinese and Japanese languages by utili To enable language(s) support: 1. Install the desired plugin(s), please refer to [Elasticsearch documentation](https://www.elastic.co/guide/en/elasticsearch/plugins/7.9/installation.html) for plugins installation instructions. The plugin(s) must be installed on every node in the cluster, and each node must be restarted after installation. For a list of plugins, see the table later in this section. -1. Navigate to the **Admin Area**, then **Settings > General**.. -1. Expand the **Advanced Search** section and locate **Custom analyzers: language support**. +1. Navigate to the **Admin Area**, then **Settings > Advanced Search**.. +1. Locate **Custom analyzers: language support**. 1. Enable plugin(s) support for **Indexing**. 1. Click **Save changes** for the changes to take effect. 1. Trigger [Zero downtime reindexing](#zero-downtime-reindexing) or reindex everything from scratch to create a new index with updated mappings. @@ -285,9 +284,8 @@ For guidance on what to install, see the following Elasticsearch language plugin To disable the Elasticsearch integration: -1. Navigate to the **Admin Area**, then **Settings > General**. -1. Expand the **Advanced Search** section and uncheck **Elasticsearch indexing** - and **Search with Elasticsearch enabled**. +1. Navigate to the **Admin Area**, then **Settings > Advanced Search**. +1. Uncheck **Elasticsearch indexing** and **Search with Elasticsearch enabled**. 1. Click **Save changes** for the changes to take effect. 1. (Optional) Delete the existing indexes: @@ -315,7 +313,7 @@ used by the GitLab Advanced Search integration. ### Pause the indexing -In the **Admin Area > Settings > General > Advanced Search** section, select the +In the **Admin Area > Settings > Advanced Search** section, select the **Pause Elasticsearch Indexing** setting, and then save your change. With this, all updates that should happen on your Elasticsearch index will be buffered and caught up once unpaused. @@ -332,7 +330,7 @@ This process involves several shell commands and curl invocations, so a good initial setup will help for later: ```shell -# You can find this value under Admin Area > Settings > General > Advanced Search > URL +# You can find this value under Admin Area > Settings > Advanced Search > URL export CLUSTER_URL="http://localhost:9200" export PRIMARY_INDEX="gitlab-production" export SECONDARY_INDEX="gitlab-production-$(date +%s)" @@ -433,14 +431,14 @@ To trigger the re-index from `primary` index: 1. Unpause the indexing - Under **Admin Area > Settings > General > Advanced Search**, uncheck the **Pause Elasticsearch Indexing** setting and save. + Under **Admin Area > Settings > Advanced Search**, uncheck the **Pause Elasticsearch Indexing** setting and save. ### Trigger the reindex via the Advanced Search administration > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/34069) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2. > - A scheduled index deletion and the ability to cancel it was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38914) in GitLab Starter 13.3. -Under **Admin Area > Settings > General > Advanced Search > Elasticsearch zero-downtime reindexing**, click on **Trigger cluster reindexing**. +Under **Admin Area > Settings > Advanced Search > Elasticsearch zero-downtime reindexing**, click on **Trigger cluster reindexing**. Reindexing can be a lengthy process depending on the size of your Elasticsearch cluster. @@ -463,7 +461,7 @@ Sometimes, you might want to abandon the unfinished reindex job and unpause the bundle exec rake gitlab:elastic:mark_reindex_failed RAILS_ENV=production ``` -1. Uncheck the "Pause Elasticsearch indexing" checkbox in **Admin Area > Settings > General > Advanced Search**. +1. Uncheck the "Pause Elasticsearch indexing" checkbox in **Admin Area > Settings > Advanced Search**. ## Background migrations @@ -823,7 +821,7 @@ There are a couple of ways to achieve that: This is always correctly identifying whether the current project/namespace being searched is using Elasticsearch. -- From the admin area under **Settings > General > Advanced Search** check that the +- From the admin area under **Settings > Advanced Search** check that the Advanced Search settings are checked. Those same settings there can be obtained from the Rails console if necessary: diff --git a/doc/subscriptions/index.md b/doc/subscriptions/index.md index 383ba471df4..8df30fa4f76 100644 --- a/doc/subscriptions/index.md +++ b/doc/subscriptions/index.md @@ -76,7 +76,7 @@ With the [Customers Portal](https://customers.gitlab.com/) you can: - [Change your company details](#change-your-company-details) - [Change your payment method](#change-your-payment-method) - [Change the linked account](#change-the-linked-account) -- [Change the associated namespace](#change-the-associated-namespace) +- [Change the namespace the subscription is linked to](#change-the-linked-namespace) - [Change customers portal account password](#change-customers-portal-account-password) ### Change your personal details @@ -130,8 +130,7 @@ method as the default: ### Change the linked account -To change the GitLab.com account associated with your Customers Portal -account: +To change the GitLab.com account linked to your Customers Portal account: 1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in). @@ -142,15 +141,16 @@ account: 1. Log in to the [GitLab.com](https://gitlab.com) account you want to link to the Customers Portal account. -### Change the associated namespace +### Change the linked namespace -With a linked GitLab.com account: +To change the namespace linked to a subscription: -1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in). +1. Log in to the [Customers Portal](https://customers.gitlab.com/customers/sign_in) with a + [linked](#change-the-linked-account) GitLab.com account. 1. Navigate to the **Manage Purchases** page. -1. Click **Change linked namespace**. +1. Select **Change linked namespace**. 1. Select the desired group from the **This subscription is for** dropdown. -1. Click **Proceed to checkout**. +1. Select **Proceed to checkout**. Subscription charges are calculated based on the total number of users in a group, including its subgroups and nested projects. If the total number of users exceeds the number of seats in your subscription, your account is charged for the additional users. diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb index ab0e9b95e4a..d31c64ce7db 100644 --- a/lib/api/merge_requests.rb +++ b/lib/api/merge_requests.rb @@ -26,6 +26,7 @@ module API %i[ assignee_id assignee_ids + reviewer_ids description labels add_labels @@ -160,7 +161,8 @@ module API helpers do params :optional_params do optional :assignee_id, type: Integer, desc: 'The ID of a user to assign the merge request' - optional :assignee_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'The array of user IDs to assign issue' + optional :assignee_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Comma-separated list of assignee ids' + optional :reviewer_ids, type: Array[Integer], coerce_with: ::API::Validations::Types::CommaSeparatedToIntegerArray.coerce, desc: 'Comma-separated list of reviewer ids' optional :description, type: String, desc: 'The description of the merge request' optional :labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names' optional :add_labels, type: Array[String], coerce_with: Validations::Types::CommaSeparatedToArray.coerce, desc: 'Comma-separated list of label names' diff --git a/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings.rb b/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings.rb new file mode 100644 index 00000000000..ca61118a06c --- /dev/null +++ b/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +# rubocop: disable Style/Documentation +class Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindings + DELETE_BATCH_SIZE = 100 + + # rubocop:disable Gitlab/NamespacedClass + class VulnerabilitiesFinding < ActiveRecord::Base + self.table_name = "vulnerability_occurrences" + end + # rubocop:enable Gitlab/NamespacedClass + + def perform(start_id, end_id) + batch = VulnerabilitiesFinding.where(id: start_id..end_id) + + cte = Gitlab::SQL::CTE.new(:batch, batch.select(:report_type, :location_fingerprint, :primary_identifier_id, :project_id)) + + query = VulnerabilitiesFinding + .select('batch.report_type', 'batch.location_fingerprint', 'batch.primary_identifier_id', 'batch.project_id', 'array_agg(id) as ids') + .distinct + .with(cte.to_arel) + .from(cte.alias_to(Arel.sql('batch'))) + .joins( + %( + INNER JOIN + vulnerability_occurrences ON + vulnerability_occurrences.report_type = batch.report_type AND + vulnerability_occurrences.location_fingerprint = batch.location_fingerprint AND + vulnerability_occurrences.primary_identifier_id = batch.primary_identifier_id AND + vulnerability_occurrences.project_id = batch.project_id + )).group('batch.report_type', 'batch.location_fingerprint', 'batch.primary_identifier_id', 'batch.project_id') + .having('COUNT(*) > 1') + + ids_to_delete = [] + + query.to_a.each do |record| + # We want to keep the latest finding since it might have recent metadata + duplicate_ids = record.ids.uniq.sort + duplicate_ids.pop + ids_to_delete.concat(duplicate_ids) + + if ids_to_delete.size == DELETE_BATCH_SIZE + VulnerabilitiesFinding.where(id: ids_to_delete).delete_all + ids_to_delete.clear + end + end + + VulnerabilitiesFinding.where(id: ids_to_delete).delete_all if ids_to_delete.any? + end +end diff --git a/lib/gitlab/usage/metric.rb b/lib/gitlab/usage/metric.rb index e1648c78168..f3469209f48 100644 --- a/lib/gitlab/usage/metric.rb +++ b/lib/gitlab/usage/metric.rb @@ -7,16 +7,16 @@ module Gitlab InvalidMetricError = Class.new(RuntimeError) - attr_accessor :default_generation_path, :value + attr_accessor :key_path, :value - validates :default_generation_path, presence: true + validates :key_path, presence: true def definition - self.class.definitions[default_generation_path] + self.class.definitions[key_path] end - def unflatten_default_path - unflatten(default_generation_path.split('.'), value) + def unflatten_key_path + unflatten(key_path.split('.'), value) end class << self diff --git a/lib/gitlab/usage/metric_definition.rb b/lib/gitlab/usage/metric_definition.rb index 96e572bb3db..dea29b4465f 100644 --- a/lib/gitlab/usage/metric_definition.rb +++ b/lib/gitlab/usage/metric_definition.rb @@ -13,9 +13,8 @@ module Gitlab @attributes = opts end - # The key is defined by default_generation and full_path def key - full_path[default_generation.to_sym] + key_path end def to_h diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 978d471d41d..ffdb0ea9e4b 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2023,9 +2023,6 @@ msgstr "" msgid "AdminSettings|Disable feed token" msgstr "" -msgid "AdminSettings|Elasticsearch, PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General." -msgstr "" - msgid "AdminSettings|Enable shared runners for new projects" msgstr "" @@ -2047,6 +2044,9 @@ msgstr "" msgid "AdminSettings|No required pipeline" msgstr "" +msgid "AdminSettings|PlantUML, Slack application, Third party offers, Snowplow, Amazon EKS have moved to Settings > General." +msgstr "" + msgid "AdminSettings|Required pipeline configuration" msgstr "" @@ -23073,6 +23073,9 @@ msgstr "" msgid "ProtectedEnvironment|Environment" msgstr "" +msgid "ProtectedEnvironment|Only specified users can execute deployments in a protected environment." +msgstr "" + msgid "ProtectedEnvironment|Protect" msgstr "" @@ -23082,9 +23085,6 @@ msgstr "" msgid "ProtectedEnvironment|Protected Environment (%{protected_environments_count})" msgstr "" -msgid "ProtectedEnvironment|Protecting an environment restricts the users who can execute deployments." -msgstr "" - msgid "ProtectedEnvironment|Select an environment" msgstr "" @@ -23094,7 +23094,7 @@ msgstr "" msgid "ProtectedEnvironment|Select users to deploy and manage Feature Flag settings" msgstr "" -msgid "ProtectedEnvironment|There are currently no protected environments, protect an environment with the form above." +msgid "ProtectedEnvironment|There are currently no protected environments. Protect an environment with this form." msgstr "" msgid "ProtectedEnvironment|Unprotect" diff --git a/spec/features/whats_new_spec.rb b/spec/features/whats_new_spec.rb new file mode 100644 index 00000000000..7c5625486f5 --- /dev/null +++ b/spec/features/whats_new_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe "renders a `whats new` dropdown item", :js do + let_it_be(:user) { create(:user) } + + before do + sign_in(user) + end + + it 'shows notification dot and count and removes it once viewed' do + visit root_dashboard_path + + page.within '.header-help' do + expect(page).to have_selector('.notification-dot', visible: true) + + find('.header-help-dropdown-toggle').click + + expect(page).to have_button(text: "What's new") + expect(page).to have_selector('.js-whats-new-notification-count') + + find('button', text: "What's new").click + end + + find('.whats-new-drawer .gl-drawer-close-button').click + find('.header-help-dropdown-toggle').click + + page.within '.header-help' do + expect(page).not_to have_selector('.notification-dot', visible: true) + expect(page).to have_button(text: "What's new") + expect(page).not_to have_selector('.js-whats-new-notification-count') + end + end +end diff --git a/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb b/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb new file mode 100644 index 00000000000..47e1d4620cd --- /dev/null +++ b/spec/lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings_spec.rb @@ -0,0 +1,135 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::RemoveDuplicateVulnerabilitiesFindings do + let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } + let(:users) { table(:users) } + let(:user) { create_user! } + let(:project) { table(:projects).create!(id: 123, namespace_id: namespace.id) } + let(:scanners) { table(:vulnerability_scanners) } + let!(:scanner) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } + let!(:scanner2) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') } + let!(:scanner3) { scanners.create!(project_id: project.id, external_id: 'test 3', name: 'test scanner 3') } + let!(:unrelated_scanner) { scanners.create!(project_id: project.id, external_id: 'unreleated_scanner', name: 'unrelated scanner') } + let(:vulnerabilities) { table(:vulnerabilities) } + let(:vulnerability_findings) { table(:vulnerability_occurrences) } + let(:vulnerability_identifiers) { table(:vulnerability_identifiers) } + let(:vulnerability_identifier) do + vulnerability_identifiers.create!( + project_id: project.id, + external_type: 'vulnerability-identifier', + external_id: 'vulnerability-identifier', + fingerprint: '7e394d1b1eb461a7406d7b1e08f057a1cf11287a', + name: 'vulnerability identifier') + end + + let!(:first_finding) do + create_finding!( + uuid: "test1", + vulnerability_id: nil, + report_type: 0, + location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: scanner.id, + project_id: project.id + ) + end + + let!(:first_duplicate) do + create_finding!( + uuid: "test2", + vulnerability_id: nil, + report_type: 0, + location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: scanner2.id, + project_id: project.id + ) + end + + let!(:second_duplicate) do + create_finding!( + uuid: "test3", + vulnerability_id: nil, + report_type: 0, + location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: scanner3.id, + project_id: project.id + ) + end + + let!(:unrelated_finding) do + create_finding!( + uuid: "unreleated_finding", + vulnerability_id: nil, + report_type: 1, + location_fingerprint: 'random_location_fingerprint', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: unrelated_scanner.id, + project_id: project.id + ) + end + + subject { described_class.new.perform(first_finding.id, unrelated_finding.id) } + + before do + stub_const("#{described_class}::DELETE_BATCH_SIZE", 1) + end + + it "removes entries which would result in duplicate UUIDv5" do + expect(vulnerability_findings.count).to eq(4) + + expect { subject }.to change { vulnerability_findings.count }.from(4).to(2) + + expect(vulnerability_findings.pluck(:id)).to eq([second_duplicate.id, unrelated_finding.id]) + end + + private + + def create_vulnerability!(project_id:, author_id:, title: 'test', severity: 7, confidence: 7, report_type: 0) + vulnerabilities.create!( + project_id: project_id, + author_id: author_id, + title: title, + severity: severity, + confidence: confidence, + report_type: report_type + ) + end + + # rubocop:disable Metrics/ParameterLists + def create_finding!( + vulnerability_id:, project_id:, scanner_id:, primary_identifier_id:, + name: "test", severity: 7, confidence: 7, report_type: 0, + project_fingerprint: '123qweasdzxc', location_fingerprint: 'test', + metadata_version: 'test', raw_metadata: 'test', uuid: 'test') + vulnerability_findings.create!( + vulnerability_id: vulnerability_id, + project_id: project_id, + name: name, + severity: severity, + confidence: confidence, + report_type: report_type, + project_fingerprint: project_fingerprint, + scanner_id: scanner_id, + primary_identifier_id: vulnerability_identifier.id, + location_fingerprint: location_fingerprint, + metadata_version: metadata_version, + raw_metadata: raw_metadata, + uuid: uuid + ) + end + # rubocop:enable Metrics/ParameterLists + + def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.zone.now, confirmed_at: Time.zone.now) + users.create!( + name: name, + email: email, + username: name, + projects_limit: 0, + user_type: user_type, + confirmed_at: confirmed_at + ) + end +end diff --git a/spec/lib/gitlab/usage/metric_definition_spec.rb b/spec/lib/gitlab/usage/metric_definition_spec.rb index e101f837324..c50760317f5 100644 --- a/spec/lib/gitlab/usage/metric_definition_spec.rb +++ b/spec/lib/gitlab/usage/metric_definition_spec.rb @@ -5,17 +5,13 @@ require 'spec_helper' RSpec.describe Gitlab::Usage::MetricDefinition do let(:attributes) do { - name: 'uuid', description: 'GitLab instance unique identifier', value_type: 'string', product_category: 'collection', stage: 'growth', status: 'data_available', default_generation: 'generation_1', - full_path: { - generation_1: 'uuid', - generation_2: 'license.uuid' - }, + key_path: 'uuid', group: 'group::product analytics', time_frame: 'none', data_source: 'database', @@ -44,12 +40,11 @@ RSpec.describe Gitlab::Usage::MetricDefinition do using RSpec::Parameterized::TableSyntax where(:attribute, :value) do - :name | nil :description | nil :value_type | nil :value_type | 'test' :status | nil - :default_generation | nil + :key_path | nil :group | nil :time_frame | nil :time_frame | '29d' diff --git a/spec/lib/gitlab/usage/metric_spec.rb b/spec/lib/gitlab/usage/metric_spec.rb index 40671d980d6..d4a789419a4 100644 --- a/spec/lib/gitlab/usage/metric_spec.rb +++ b/spec/lib/gitlab/usage/metric_spec.rb @@ -4,15 +4,15 @@ require 'spec_helper' RSpec.describe Gitlab::Usage::Metric do describe '#definition' do - it 'returns generation_1 metric definiton' do - expect(described_class.new(default_generation_path: 'uuid').definition).to be_an(Gitlab::Usage::MetricDefinition) + it 'returns key_path metric definiton' do + expect(described_class.new(key_path: 'uuid').definition).to be_an(Gitlab::Usage::MetricDefinition) end end describe '#unflatten_default_path' do using RSpec::Parameterized::TableSyntax - where(:default_generation_path, :value, :expected_hash) do + where(:key_path, :value, :expected_hash) do 'uuid' | nil | { uuid: nil } 'uuid' | '1111' | { uuid: '1111' } 'counts.issues' | nil | { counts: { issues: nil } } @@ -21,7 +21,7 @@ RSpec.describe Gitlab::Usage::Metric do end with_them do - subject { described_class.new(default_generation_path: default_generation_path, value: value).unflatten_default_path } + subject { described_class.new(key_path: key_path, value: value).unflatten_key_path } it { is_expected.to eq(expected_hash) } end diff --git a/spec/migrations/20201112130710_schedule_remove_duplicate_vulnerabilities_findings_spec.rb b/spec/migrations/20201112130710_schedule_remove_duplicate_vulnerabilities_findings_spec.rb new file mode 100644 index 00000000000..ff27bdcf12d --- /dev/null +++ b/spec/migrations/20201112130710_schedule_remove_duplicate_vulnerabilities_findings_spec.rb @@ -0,0 +1,140 @@ +# frozen_string_literal: true +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20201112130710_schedule_remove_duplicate_vulnerabilities_findings.rb') + +RSpec.describe ScheduleRemoveDuplicateVulnerabilitiesFindings, :migration do + let(:namespace) { table(:namespaces).create!(name: 'user', path: 'user') } + let(:users) { table(:users) } + let(:user) { create_user! } + let(:project) { table(:projects).create!(id: 123, namespace_id: namespace.id) } + let(:scanners) { table(:vulnerability_scanners) } + let!(:scanner) { scanners.create!(project_id: project.id, external_id: 'test 1', name: 'test scanner 1') } + let!(:scanner2) { scanners.create!(project_id: project.id, external_id: 'test 2', name: 'test scanner 2') } + let!(:scanner3) { scanners.create!(project_id: project.id, external_id: 'test 3', name: 'test scanner 3') } + let!(:unrelated_scanner) { scanners.create!(project_id: project.id, external_id: 'unreleated_scanner', name: 'unrelated scanner') } + let(:vulnerabilities) { table(:vulnerabilities) } + let(:vulnerability_findings) { table(:vulnerability_occurrences) } + let(:vulnerability_identifiers) { table(:vulnerability_identifiers) } + let(:vulnerability_identifier) do + vulnerability_identifiers.create!( + project_id: project.id, + external_type: 'vulnerability-identifier', + external_id: 'vulnerability-identifier', + fingerprint: '7e394d1b1eb461a7406d7b1e08f057a1cf11287a', + name: 'vulnerability identifier') + end + + let!(:first_finding) do + create_finding!( + uuid: "test1", + vulnerability_id: nil, + report_type: 0, + location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: scanner.id, + project_id: project.id + ) + end + + let!(:first_duplicate) do + create_finding!( + uuid: "test2", + vulnerability_id: nil, + report_type: 0, + location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: scanner2.id, + project_id: project.id + ) + end + + let!(:second_duplicate) do + create_finding!( + uuid: "test3", + vulnerability_id: nil, + report_type: 0, + location_fingerprint: '2bda3014914481791847d8eca38d1a8d13b6ad76', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: scanner3.id, + project_id: project.id + ) + end + + let!(:unrelated_finding) do + create_finding!( + uuid: "unreleated_finding", + vulnerability_id: nil, + report_type: 1, + location_fingerprint: 'random_location_fingerprint', + primary_identifier_id: vulnerability_identifier.id, + scanner_id: unrelated_scanner.id, + project_id: project.id + ) + end + + before do + stub_const("#{described_class}::BATCH_SIZE", 1) + end + + around do |example| + freeze_time { Sidekiq::Testing.fake! { example.run } } + end + + it 'schedules background migration' do + migrate! + + expect(BackgroundMigrationWorker.jobs.size).to eq(4) + expect(described_class::MIGRATION).to be_scheduled_migration(first_finding.id, first_finding.id) + expect(described_class::MIGRATION).to be_scheduled_migration(first_duplicate.id, first_duplicate.id) + expect(described_class::MIGRATION).to be_scheduled_migration(second_duplicate.id, second_duplicate.id) + expect(described_class::MIGRATION).to be_scheduled_migration(unrelated_finding.id, unrelated_finding.id) + end + + private + + def create_vulnerability!(project_id:, author_id:, title: 'test', severity: 7, confidence: 7, report_type: 0) + vulnerabilities.create!( + project_id: project_id, + author_id: author_id, + title: title, + severity: severity, + confidence: confidence, + report_type: report_type + ) + end + + # rubocop:disable Metrics/ParameterLists + def create_finding!( + vulnerability_id:, project_id:, scanner_id:, primary_identifier_id:, + name: "test", severity: 7, confidence: 7, report_type: 0, + project_fingerprint: '123qweasdzxc', location_fingerprint: 'test', + metadata_version: 'test', raw_metadata: 'test', uuid: 'test') + vulnerability_findings.create!( + vulnerability_id: vulnerability_id, + project_id: project_id, + name: name, + severity: severity, + confidence: confidence, + report_type: report_type, + project_fingerprint: project_fingerprint, + scanner_id: scanner_id, + primary_identifier_id: vulnerability_identifier.id, + location_fingerprint: location_fingerprint, + metadata_version: metadata_version, + raw_metadata: raw_metadata, + uuid: uuid + ) + end + # rubocop:enable Metrics/ParameterLists + + def create_user!(name: "Example User", email: "user@example.com", user_type: nil, created_at: Time.now, confirmed_at: Time.now) + users.create!( + name: name, + email: email, + username: name, + projects_limit: 0, + user_type: user_type, + confirmed_at: confirmed_at + ) + end +end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index b8a3f3bef6e..094bb370100 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -451,6 +451,17 @@ RSpec.describe MergeRequest, factory_default: :keep do it { is_expected.to be_empty } end + + context 'when commit is part of the merge request and a squash commit at the same time' do + let!(:merge_request) { create(:merge_request, :with_diffs) } + let(:sha) { merge_request.commits.first.id } + + before do + merge_request.update!(squash_commit_sha: sha) + end + + it { is_expected.to eq([merge_request]) } + end end describe '.by_cherry_pick_sha' do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 3a3eae73932..c7d2f50fde2 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -1736,6 +1736,36 @@ RSpec.describe API::MergeRequests do end end + context 'accepts reviewer_ids' do + let(:params) do + { + title: 'Test merge request', + source_branch: 'feature_conflict', + target_branch: 'master', + author_id: user.id, + reviewer_ids: [user2.id] + } + end + + it 'creates a new merge request with a reviewer' do + post api("/projects/#{project.id}/merge_requests", user), params: params + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['title']).to eq('Test merge request') + expect(json_response['reviewers'].first['name']).to eq(user2.name) + end + + it 'creates a new merge request with no reviewer' do + params[:reviewer_ids] = [] + + post api("/projects/#{project.id}/merge_requests", user), params: params + + expect(response).to have_gitlab_http_status(:created) + expect(json_response['title']).to eq('Test merge request') + expect(json_response['reviewers']).to be_empty + end + end + context 'between branches projects' do context 'different labels' do let(:params) do @@ -2081,6 +2111,34 @@ RSpec.describe API::MergeRequests do it_behaves_like 'issuable update endpoint' do let(:entity) { merge_request } end + + context 'accepts reviewer_ids' do + let(:params) do + { + title: 'Updated merge request', + reviewer_ids: [user2.id] + } + end + + it 'adds a reviewer to the existing merge request' do + put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['title']).to eq('Updated merge request') + expect(json_response['reviewers'].first['name']).to eq(user2.name) + end + + it 'removes a reviewer from the existing merge request' do + merge_request.reviewers = [user2] + params[:reviewer_ids] = [] + + put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), params: params + + expect(response).to have_gitlab_http_status(:ok) + expect(json_response['title']).to eq('Updated merge request') + expect(json_response['reviewers']).to be_empty + end + end end describe "POST /projects/:id/merge_requests/:merge_request_iid/context_commits" do diff --git a/spec/requests/whats_new_controller_spec.rb b/spec/requests/whats_new_controller_spec.rb index 8005d38dbb0..d91a0685bd0 100644 --- a/spec/requests/whats_new_controller_spec.rb +++ b/spec/requests/whats_new_controller_spec.rb @@ -7,59 +7,41 @@ RSpec.describe WhatsNewController do let(:item) { double(:item) } let(:highlights) { double(:highlight, items: [item], map: [item].map, next_page: 2) } - context 'with whats_new_drawer feature enabled' do - before do - stub_feature_flags(whats_new_drawer: true) - end - - context 'with no page param' do - it 'responds with paginated data and headers' do - allow(ReleaseHighlight).to receive(:paginated).with(page: 1).and_return(highlights) - allow(Gitlab::WhatsNew::ItemPresenter).to receive(:present).with(item).and_return(item) + context 'with no page param' do + it 'responds with paginated data and headers' do + allow(ReleaseHighlight).to receive(:paginated).with(page: 1).and_return(highlights) + allow(Gitlab::WhatsNew::ItemPresenter).to receive(:present).with(item).and_return(item) - get whats_new_path, xhr: true + get whats_new_path, xhr: true - expect(response.body).to eq(highlights.items.to_json) - expect(response.headers['X-Next-Page']).to eq(2) - end + expect(response.body).to eq(highlights.items.to_json) + expect(response.headers['X-Next-Page']).to eq(2) end + end - context 'with page param' do - it 'passes the page parameter' do - expect(ReleaseHighlight).to receive(:paginated).with(page: 2).and_call_original - - get whats_new_path(page: 2), xhr: true - end - - it 'returns a 404 if page param is negative' do - get whats_new_path(page: -1), xhr: true + context 'with page param' do + it 'passes the page parameter' do + expect(ReleaseHighlight).to receive(:paginated).with(page: 2).and_call_original - expect(response).to have_gitlab_http_status(:not_found) - end + get whats_new_path(page: 2), xhr: true end - context 'with version param' do - it 'returns items without pagination headers' do - allow(ReleaseHighlight).to receive(:for_version).with(version: '42').and_return(highlights) - allow(Gitlab::WhatsNew::ItemPresenter).to receive(:present).with(item).and_return(item) + it 'returns a 404 if page param is negative' do + get whats_new_path(page: -1), xhr: true - get whats_new_path(version: 42), xhr: true - - expect(response.body).to eq(highlights.items.to_json) - expect(response.headers['X-Next-Page']).to be_nil - end + expect(response).to have_gitlab_http_status(:not_found) end end - context 'with whats_new_drawer feature disabled' do - before do - stub_feature_flags(whats_new_drawer: false) - end + context 'with version param' do + it 'returns items without pagination headers' do + allow(ReleaseHighlight).to receive(:for_version).with(version: '42').and_return(highlights) + allow(Gitlab::WhatsNew::ItemPresenter).to receive(:present).with(item).and_return(item) - it 'returns a 404' do - get whats_new_path, xhr: true + get whats_new_path(version: 42), xhr: true - expect(response).to have_gitlab_http_status(:not_found) + expect(response.body).to eq(highlights.items.to_json) + expect(response.headers['X-Next-Page']).to be_nil end end end |