From 2bc1877c51a50980bcc58d005d36d2248602b84c Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 29 Mar 2024 21:10:06 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../javascripts/observability/client.js | 6 +- .../organizations/index/components/app.vue | 5 +- .../jira_connect/app_descriptor_controller.rb | 11 +- .../jira_connect/repositories_controller.rb | 4 - .../jira_connect/workspaces_controller.rb | 4 - .../organizations/organizations_controller.rb | 3 + app/helpers/environments_helper.rb | 7 +- app/helpers/search_helper.rb | 16 +-- app/models/project.rb | 4 + app/presenters/clusters/cluster_presenter.rb | 5 - app/services/organizations/create_service.rb | 6 + ...el.yml => allow_organization_creation.yml} | 10 +- ...it_events_streaming_event_type_filters.yml | 21 +++- db/docs/audit_events_streaming_headers.yml | 21 +++- .../dedicated/create_instance.md | 2 +- doc/ci/yaml/index.md | 2 +- .../documentation/styleguide/index.md | 25 ++++ doc/user/ai_features.md | 2 +- doc/user/free_user_limit.md | 2 +- lib/container_registry/client.rb | 4 + lib/gitlab/search/params.rb | 20 ++- locale/gitlab.pot | 5 +- qa/gdk/Dockerfile.gdk | 2 +- qa/qa/page/project/pipeline/show.rb | 5 + .../import/import_github_repo_spec.rb | 6 +- .../run_component_in_project_pipeline_spec.rb | 115 ++++++++++++++++++ qa/qa/support/matchers/have_matcher.rb | 1 + .../app_descriptor_controller_spec.rb | 17 --- spec/frontend/observability/client_spec.js | 4 +- .../index/components/app_spec.js | 78 +++++++++--- spec/helpers/environments_helper_spec.rb | 4 - spec/helpers/search_helper_spec.rb | 45 +------ spec/lib/container_registry/client_spec.rb | 26 ++++ spec/lib/gitlab/search/params_spec.rb | 86 ++++++++++--- spec/models/project_spec.rb | 12 ++ .../clusters/cluster_presenter_spec.rb | 5 - .../repositories_controller_spec.rb | 22 ---- .../workspaces_controller_spec.rb | 11 -- .../organizations/create_service_spec.rb | 13 ++ 39 files changed, 436 insertions(+), 201 deletions(-) rename config/feature_flags/development/{atlassian_new_app_based_auth_model.yml => allow_organization_creation.yml} (59%) create mode 100644 qa/qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb diff --git a/app/assets/javascripts/observability/client.js b/app/assets/javascripts/observability/client.js index 9510efb5953..71d323108e9 100644 --- a/app/assets/javascripts/observability/client.js +++ b/app/assets/javascripts/observability/client.js @@ -315,13 +315,13 @@ async function fetchMetrics(metricsUrl, { filters = {}, limit } = {}) { const params = new URLSearchParams(); if (Array.isArray(filters.search)) { - const searchPrefix = filters.search + const search = filters.search .map((f) => f.value) .join(' ') .trim(); - if (searchPrefix) { - params.append('starts_with', searchPrefix); + if (search) { + params.append('search', search); if (limit) { params.append('limit', limit); } diff --git a/app/assets/javascripts/organizations/index/components/app.vue b/app/assets/javascripts/organizations/index/components/app.vue index 9a4abdaefa5..0f7badaf2da 100644 --- a/app/assets/javascripts/organizations/index/components/app.vue +++ b/app/assets/javascripts/organizations/index/components/app.vue @@ -49,6 +49,9 @@ export default { showHeader() { return this.loading || this.organizations.nodes?.length; }, + showNewOrganizationButton() { + return gon.features?.allowOrganizationCreation; + }, loading() { return this.$apollo.queries.organizations.loading; }, @@ -79,7 +82,7 @@ export default {

{{ $options.i18n.organizations }}

- {{ + {{ $options.i18n.newOrganization }}
diff --git a/app/controllers/jira_connect/app_descriptor_controller.rb b/app/controllers/jira_connect/app_descriptor_controller.rb index 4659b51d5ae..2e0949a584e 100644 --- a/app/controllers/jira_connect/app_descriptor_controller.rb +++ b/app/controllers/jira_connect/app_descriptor_controller.rb @@ -131,15 +131,10 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController end def actions - actions = { + { createBranch: { templateUrl: "#{new_jira_connect_branch_url}?issue_key={issue.key}&issue_summary={issue.summary}" - } - } - - return actions unless Feature.enabled?(:atlassian_new_app_based_auth_model) - - actions.merge( + }, searchConnectedWorkspaces: { templateUrl: search_jira_connect_workspaces_url }, @@ -149,6 +144,6 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController associateRepository: { templateUrl: associate_jira_connect_repositories_url } - ) + } end end diff --git a/app/controllers/jira_connect/repositories_controller.rb b/app/controllers/jira_connect/repositories_controller.rb index 12fa80d5881..eeaa459f015 100644 --- a/app/controllers/jira_connect/repositories_controller.rb +++ b/app/controllers/jira_connect/repositories_controller.rb @@ -2,10 +2,6 @@ module JiraConnect class RepositoriesController < JiraConnect::ApplicationController - before_action do - render_404 if Feature.disabled?(:atlassian_new_app_based_auth_model) - end - feature_category :integrations def search diff --git a/app/controllers/jira_connect/workspaces_controller.rb b/app/controllers/jira_connect/workspaces_controller.rb index 47adb9ba506..4aaf752fe7d 100644 --- a/app/controllers/jira_connect/workspaces_controller.rb +++ b/app/controllers/jira_connect/workspaces_controller.rb @@ -2,10 +2,6 @@ module JiraConnect class WorkspacesController < JiraConnect::ApplicationController - before_action do - render_404 if Feature.disabled?(:atlassian_new_app_based_auth_model) - end - feature_category :integrations def search diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 11988da8104..48e9d785721 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -11,6 +11,9 @@ module Organizations before_action :event_filter, only: [:activity] before_action :authorize_read_organization!, only: [:activity, :show, :groups_and_projects] + before_action only: [:index] do + push_frontend_feature_flag(:allow_organization_creation, current_user) + end skip_before_action :authenticate_user!, only: [:activity, :show, :groups_and_projects] diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 66f29e84f66..018109b2d4a 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -79,12 +79,7 @@ module EnvironmentsHelper def static_metrics_data { 'documentation_path' => help_page_path('administration/monitoring/prometheus/index'), - 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project'), - 'empty_getting_started_svg_path' => image_path('illustrations/monitoring/getting_started.svg'), - 'empty_loading_svg_path' => image_path('illustrations/monitoring/loading.svg'), - 'empty_no_data_svg_path' => image_path('illustrations/monitoring/no_data.svg'), - 'empty_no_data_small_svg_path' => image_path('illustrations/chart-empty-state-small.svg'), - 'empty_unable_to_connect_svg_path' => image_path('illustrations/monitoring/unable_to_connect.svg') + 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project') } end end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 78377537ebd..3c444aee644 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -161,7 +161,7 @@ module SearchHelper end def search_service - @search_service ||= ::SearchService.new(current_user, sanitized_search_params) + @search_service ||= ::SearchService.new(current_user, params) end def search_sort_options @@ -588,20 +588,6 @@ module SearchHelper issuable.target_branch unless issuable.target_branch == issuable.project.default_branch end - def sanitized_search_params - sanitized_params = params.dup - - if sanitized_params.key?(:confidential) - sanitized_params[:confidential] = Gitlab::Utils.to_boolean(sanitized_params[:confidential]) - end - - if sanitized_params.key?(:include_archived) - sanitized_params[:include_archived] = Gitlab::Utils.to_boolean(sanitized_params[:include_archived]) - end - - sanitized_params - end - def wiki_blob_link(wiki_blob) project_wiki_path(wiki_blob.project, wiki_blob.basename) end diff --git a/app/models/project.rb b/app/models/project.rb index 2ff713fbfae..a5b92571bf8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -815,6 +815,10 @@ class Project < ApplicationRecord scope :in_organization, -> (organization) { where(organization: organization) } + scope :not_a_fork, -> { + left_outer_joins(:fork_network_member).where(fork_network_member: { forked_from_project_id: nil }) + } + enum auto_cancel_pending_pipelines: { disabled: 0, enabled: 1 } chronic_duration_attr :build_timeout_human_readable, :build_timeout, diff --git a/app/presenters/clusters/cluster_presenter.rb b/app/presenters/clusters/cluster_presenter.rb index 5765d08dfb3..06ca392851f 100644 --- a/app/presenters/clusters/cluster_presenter.rb +++ b/app/presenters/clusters/cluster_presenter.rb @@ -62,11 +62,6 @@ module Clusters 'dashboard-endpoint': clusterable.metrics_dashboard_path(cluster), 'documentation-path': help_page_path('user/infrastructure/clusters/manage/clusters_health'), 'add-dashboard-documentation-path': help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project'), - 'empty-getting-started-svg-path': image_path('illustrations/monitoring/getting_started.svg'), - 'empty-loading-svg-path': image_path('illustrations/monitoring/loading.svg'), - 'empty-no-data-svg-path': image_path('illustrations/monitoring/no_data.svg'), - 'empty-no-data-small-svg-path': image_path('illustrations/chart-empty-state-small.svg'), - 'empty-unable-to-connect-svg-path': image_path('illustrations/monitoring/unable_to_connect.svg'), 'settings-path': '', 'project-path': '', 'tags-path': '' diff --git a/app/services/organizations/create_service.rb b/app/services/organizations/create_service.rb index d58ea875310..59f88196559 100644 --- a/app/services/organizations/create_service.rb +++ b/app/services/organizations/create_service.rb @@ -4,6 +4,7 @@ module Organizations class CreateService < ::Organizations::BaseService def execute return error_no_permissions unless can?(current_user, :create_organization) + return error_feature_flag unless Feature.enabled?(:allow_organization_creation, current_user) add_organization_owner_attributes organization = Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification @@ -35,5 +36,10 @@ module Organizations ServiceResponse.error(message: Array(message)) end + + def error_feature_flag + # Don't translate feature flag error because it's temporary. + ServiceResponse.error(message: ['Feature flag `allow_organization_creation` is not enabled for this user.']) + end end end diff --git a/config/feature_flags/development/atlassian_new_app_based_auth_model.yml b/config/feature_flags/development/allow_organization_creation.yml similarity index 59% rename from config/feature_flags/development/atlassian_new_app_based_auth_model.yml rename to config/feature_flags/development/allow_organization_creation.yml index 6b0e270d4c6..b528338b818 100644 --- a/config/feature_flags/development/atlassian_new_app_based_auth_model.yml +++ b/config/feature_flags/development/allow_organization_creation.yml @@ -1,8 +1,8 @@ --- -name: atlassian_new_app_based_auth_model -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142316 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/442334 -milestone: '16.10' -group: group::import and integrate +name: allow_organization_creation +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147930 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/452062 +milestone: '16.11' type: development +group: group::tenant scale default_enabled: false diff --git a/db/docs/audit_events_streaming_event_type_filters.yml b/db/docs/audit_events_streaming_event_type_filters.yml index fe36fbf5a5a..dd4e805c950 100644 --- a/db/docs/audit_events_streaming_event_type_filters.yml +++ b/db/docs/audit_events_streaming_event_type_filters.yml @@ -1,10 +1,25 @@ --- table_name: audit_events_streaming_event_type_filters classes: - - AuditEvents::Streaming::EventTypeFilter +- AuditEvents::Streaming::EventTypeFilter feature_categories: - - audit_events +- audit_events description: Represents a event type filter for audit event streaming introduced_by_url: milestone: '15.6' -gitlab_schema: gitlab_main +gitlab_schema: gitlab_main_cell +allow_cross_joins: +- gitlab_main_clusterwide +allow_cross_transactions: +- gitlab_main_clusterwide +allow_cross_foreign_keys: +- gitlab_main_clusterwide +desired_sharding_key: + group_id: + references: namespaces + backfill_via: + parent: + foreign_key: external_audit_event_destination_id + table: audit_events_external_audit_event_destinations + sharding_key: namespace_id + belongs_to: external_audit_event_destination diff --git a/db/docs/audit_events_streaming_headers.yml b/db/docs/audit_events_streaming_headers.yml index 4f0ef9f20b5..f33c48caa73 100644 --- a/db/docs/audit_events_streaming_headers.yml +++ b/db/docs/audit_events_streaming_headers.yml @@ -1,10 +1,25 @@ --- table_name: audit_events_streaming_headers classes: - - AuditEvents::Streaming::Header +- AuditEvents::Streaming::Header feature_categories: - - audit_events +- audit_events description: Represents a HTTP header sent with streaming audit events introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/88063 milestone: '15.1' -gitlab_schema: gitlab_main +gitlab_schema: gitlab_main_cell +allow_cross_joins: +- gitlab_main_clusterwide +allow_cross_transactions: +- gitlab_main_clusterwide +allow_cross_foreign_keys: +- gitlab_main_clusterwide +desired_sharding_key: + group_id: + references: namespaces + backfill_via: + parent: + foreign_key: external_audit_event_destination_id + table: audit_events_external_audit_event_destinations + sharding_key: namespace_id + belongs_to: external_audit_event_destination diff --git a/doc/administration/dedicated/create_instance.md b/doc/administration/dedicated/create_instance.md index b89d4beca87..d13b5981174 100644 --- a/doc/administration/dedicated/create_instance.md +++ b/doc/administration/dedicated/create_instance.md @@ -237,7 +237,7 @@ Where **T** is the date of a [minor GitLab release](../../policy/maintenance.md) 1. At T+6 calendar days: Tenant instances in the `APAC` maintenance window are upgraded. 1. At T+10 calendar days: Tenant instances in the `AMER Option 2` maintenance window are upgraded. -For example, GitLab 16.9 released on 2024-02-15. Therefore, tenant instances in the `EMEA` and `AMER Option 1` maintenance window are upgraded on 2024-04-20. +For example, GitLab 16.9 released on 2024-02-15. Therefore, tenant instances in the `EMEA` and `AMER Option 1` maintenance window are upgraded to 16.8 on 2024-02-20. #### Emergency maintenance diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index c1558525861..3f813d824fe 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -1295,7 +1295,7 @@ Use `expire_in` to specify how long [job artifacts](../jobs/job_artifacts.md) ar they expire and are deleted. The `expire_in` setting does not affect: - Artifacts from the latest job, unless keeping the latest job artifacts is disabled - [at the project level](../jobs/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs). + [at the project level](../jobs/job_artifacts.md#keep-artifacts-from-most-recent-successful-jobs) or [instance-wide](../../administration/settings/continuous_integration.md#keep-the-latest-artifacts-for-all-jobs-in-the-latest-successful-pipelines). After their expiry, artifacts are deleted hourly by default (using a cron job), and are not diff --git a/doc/development/documentation/styleguide/index.md b/doc/development/documentation/styleguide/index.md index af6a445d465..0dc404224a0 100644 --- a/doc/development/documentation/styleguide/index.md +++ b/doc/development/documentation/styleguide/index.md @@ -1740,6 +1740,31 @@ For status, choose one: Generally available features should not have a status. +##### Duplicating tier, offering, or status on subheadings + +If a subheading has the same tier, offering, or status as its parent +topic, you don't need to repeat the information in the subheading's +badge. + +For example, if the heading 1 is: + +```markdown +# My title + +DETAILS: +**Offering:** GitLab.com +**Tier:** Premium, Ultimate +``` + +Any lower-level heading that applies to a different tier but same offering would be: + +```markdown +## My title + +DETAILS: +**Tier:** Ultimate +``` + ##### Inline tier badges Do not add tier badges inline with other text. diff --git a/doc/user/ai_features.md b/doc/user/ai_features.md index a3bf4a99fa5..91ffbe28fc1 100644 --- a/doc/user/ai_features.md +++ b/doc/user/ai_features.md @@ -21,7 +21,7 @@ Some features are still in development. View details about [support for each sta | Helps you write code more efficiently by showing code suggestions as you type.

[Watch overview](https://www.youtube.com/watch?v=hCAyCTacdAQ) | [Code Suggestions](project/repository/code_suggestions/index.md) | **Tier:** Premium or Ultimate with [GitLab Duo Pro](../subscriptions/subscription-add-ons.md)
**Offering:** GitLab.com, Self-managed, GitLab Dedicated | | Processes and generates text and code in a conversational manner. Helps you quickly identify useful information in large volumes of text in issues, epics, code, and GitLab documentation. | [Chat](gitlab_duo_chat.md) | **Tier:** Premium, Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Status:** Beta (Subject to the [Testing Agreement](https://handbook.gitlab.com/handbook/legal/testing-agreement/)) | | Helps you discover or recall Git commands when and where you need them. | [Git suggestions](../editor_extensions/gitlab_cli/index.md#gitlab-duo-commands) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | -| Assists with quickly getting everyone up to speed on lengthy conversations to help ensure you are all on the same page. | [Discussion summary](#summarize-issue-discussions-with-discussion-summary) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | +| Assists with quickly getting everyone up to speed on lengthy conversations to help ensure you are all on the same page.

[Watch overview](https://www.youtube.com/watch?v=IcdxLfTIUgc) | [Discussion summary](#summarize-issue-discussions-with-discussion-summary) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | | Generates issue descriptions. | [Issue description generation](#summarize-an-issue-with-issue-description-generation) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | | Automates repetitive tasks and helps catch bugs early. | [Test generation](gitlab_duo_chat.md#write-tests-in-the-ide) | **Tier:** Ultimate
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
**Status:** Beta | | Generates a description for the merge request based on the contents of the template. | [Merge request template population](project/merge_requests/ai_in_merge_requests.md#fill-in-merge-request-templates) | **Tier:** Ultimate
**Offering:** GitLab.com
**Status:** Experiment | diff --git a/doc/user/free_user_limit.md b/doc/user/free_user_limit.md index f0b3d93d55c..63c8d947623 100644 --- a/doc/user/free_user_limit.md +++ b/doc/user/free_user_limit.md @@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Free user limit DETAILS: -**Tier:** Free, Premium, Ultimate +**Tier:** Free **Offering:** GitLab.com A five-user limit applies to newly created top-level namespaces with diff --git a/lib/container_registry/client.rb b/lib/container_registry/client.rb index 580ba2bdc0d..ff16b79e6f0 100644 --- a/lib/container_registry/client.rb +++ b/lib/container_registry/client.rb @@ -58,6 +58,10 @@ module ContainerRegistry } end + def connected? + !registry_info.empty? + end + def repository_tags(name, page_size: DEFAULT_TAGS_PAGE_SIZE) response = faraday.get("/v2/#{name}/tags/list") do |req| req.params['n'] = page_size diff --git a/lib/gitlab/search/params.rb b/lib/gitlab/search/params.rb index a7896b7d80d..d61e7997aff 100644 --- a/lib/gitlab/search/params.rb +++ b/lib/gitlab/search/params.rb @@ -18,7 +18,7 @@ module Gitlab alias_method :term, :query_string def initialize(params, detect_abuse: true) - @raw_params = params.is_a?(Hash) ? params.with_indifferent_access : params.dup + @raw_params = convert_all_boolean_params(params) @query_string = strip_surrounding_whitespace(@raw_params[:search] || @raw_params[:term]) @detect_abuse = detect_abuse @abuse_detection = AbuseDetection.new(self) if @detect_abuse @@ -93,6 +93,24 @@ module Gitlab def strip_surrounding_whitespace(obj) obj.to_s.strip end + + def convert_all_boolean_params(params) + converted_params = params.is_a?(Hash) ? params.with_indifferent_access : params.dup + + if converted_params.key?(:confidential) + converted_params[:confidential] = Gitlab::Utils.to_boolean(converted_params[:confidential]) + end + + if converted_params.key?(:include_archived) + converted_params[:include_archived] = Gitlab::Utils.to_boolean(converted_params[:include_archived]) + end + + if converted_params.key?(:include_forked) + converted_params[:include_forked] = Gitlab::Utils.to_boolean(converted_params[:include_forked]) + end + + converted_params + end end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 8e5d97f247b..9735df9edd5 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -34635,7 +34635,7 @@ msgstr "" msgid "ObservabilityMetrics|Search" msgstr "" -msgid "ObservabilityMetrics|Search metrics starting with..." +msgid "ObservabilityMetrics|Search metrics..." msgstr "" msgid "ObservabilityMetrics|Select attributes" @@ -45826,6 +45826,9 @@ msgstr "" msgid "SecurityOrchestration|Failed to load images." msgstr "" +msgid "SecurityOrchestration|Fetching" +msgstr "" + msgid "SecurityOrchestration|Fetching the scope information." msgstr "" diff --git a/qa/gdk/Dockerfile.gdk b/qa/gdk/Dockerfile.gdk index de8f106a5d1..7b5f315e2b6 100644 --- a/qa/gdk/Dockerfile.gdk +++ b/qa/gdk/Dockerfile.gdk @@ -1,4 +1,4 @@ -ARG GDK_SHA=5c935ca5fabd2f0de85aee3e8799aee95b371123 +ARG GDK_SHA=a2f71be9f31d963372199010b9682bdfbab11b10 # Use tag prefix when running on 'stable' branch to make sure 'protected' image is used which is not deleted by registry cleanup ARG GDK_BASE_TAG_PREFIX diff --git a/qa/qa/page/project/pipeline/show.rb b/qa/qa/page/project/pipeline/show.rb index 151df85af3d..9961082e5f7 100644 --- a/qa/qa/page/project/pipeline/show.rb +++ b/qa/qa/page/project/pipeline/show.rb @@ -32,6 +32,7 @@ module QA view 'app/assets/javascripts/ci/pipeline_details/graph/components/stage_column_component.vue' do element 'job-item-container', required: true + element 'stage-column-title' end def running?(wait: 0) @@ -134,6 +135,10 @@ module QA end end end + + def has_stage?(name) + has_element?('stage-column-title', text: name) + end end end end diff --git a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb index 2fe6e0ca714..2e648f8d7d5 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/import/import_github_repo_spec.rb @@ -2,7 +2,11 @@ module QA RSpec.describe 'Manage', :github, :requires_admin, product_group: :import_and_integrate do - describe 'GitHub import' do + describe 'GitHub import', + quarantine: { + type: :investigating, + issue: "https://gitlab.com/gitlab-org/gitlab/-/issues/452419" + } do include_context 'with github import' context 'when imported via UI' do diff --git a/qa/qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb new file mode 100644 index 00000000000..7f7addf482d --- /dev/null +++ b/qa/qa/specs/features/browser_ui/4_verify/ci_components_catalog/run_component_in_project_pipeline_spec.rb @@ -0,0 +1,115 @@ +# frozen_string_literal: true + +module QA + RSpec.describe 'Verify', :runner, :skip_live_env, product_group: :pipeline_authoring do + describe 'CI component' do + let(:executor) { "qa-runner-#{Faker::Alphanumeric.alphanumeric(number: 8)}" } + let(:tag) { '1.0.0' } + let(:domain_name) { Runtime::Scenario.gitlab_address.split("/").last } + let(:test_stage) { 'test' } + let(:test_phrase) { 'this is NOT secret!!!!!!!' } + + let(:component_project) do + create(:project, :with_readme, name: 'component-project', description: 'This is a project with CI component.') + end + + let(:test_project) do + create(:project, :with_readme, name: 'project-to-test-component') + end + + let!(:runner) do + Resource::ProjectRunner.fabricate! do |runner| + runner.project = test_project + runner.name = executor + runner.tags = [executor] + end + end + + let(:component_content) do + <<~YAML + spec: + inputs: + secret-phrase: + default: 'this is secret' + stage: + default: "#{test_stage}" + --- + my-component: + script: echo $[[ inputs.secret-phrase ]] + YAML + end + + let(:ci_yml_content) do + <<~YAML + default: + tags: ["#{executor}"] + + include: + - component: "#{domain_name}/#{component_project.full_path}/new-component@#{tag}" + inputs: + secret-phrase: #{test_phrase} + + cat: + stage: deploy + script: echo 'Meow' + YAML + end + + let(:pipeline) do + create(:pipeline, project: test_project, id: test_project.latest_pipeline[:id]) + end + + before do + Flow::Login.sign_in + + enable_catalog_resource_feature + add_ci_file(component_project, 'templates/new-component.yml', component_content) + component_project.create_release(tag) + + test_project.visit! + add_ci_file(test_project, '.gitlab-ci.yml', ci_yml_content) + end + + after do + runner.remove_via_api! + end + + it 'runs in project pipeline with correct inputs', :aggregate_failures, + testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/451582' do + Flow::Pipeline.visit_latest_pipeline(status: 'Passed') + + Page::Project::Pipeline::Show.perform do |show| + expect(show).to have_stage(test_stage), "Expected pipeline to have stage #{test_stage} but not found." + end + + Flow::Pipeline.visit_pipeline_job_page(job_name: 'my-component', pipeline: pipeline) + + Page::Project::Job::Show.perform do |show| + expect(show.output).to have_content(test_phrase), + "Component job failed to use custom phrase #{test_phrase}." + end + end + + private + + def enable_catalog_resource_feature + component_project.visit! + + Page::Project::Menu.perform(&:go_to_general_settings) + Page::Project::Settings::Main.perform do |settings| + settings.expand_visibility_project_features_permissions(&:enable_ci_cd_catalog_resource) + end + end + + def add_ci_file(project, file_path, content) + create(:commit, project: project, commit_message: 'Add CI yml file', actions: [ + { + action: 'create', + file_path: file_path, + content: content + } + ]) + end + end + end +end diff --git a/qa/qa/support/matchers/have_matcher.rb b/qa/qa/support/matchers/have_matcher.rb index b8c63166068..a2b9c740f97 100644 --- a/qa/qa/support/matchers/have_matcher.rb +++ b/qa/qa/support/matchers/have_matcher.rb @@ -30,6 +30,7 @@ module QA security_configuration_history_link skipped_job_in_group snippet_description + stage system_note tag variable diff --git a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb index 0d438cd4dce..e23b76146af 100644 --- a/spec/controllers/jira_connect/app_descriptor_controller_spec.rb +++ b/spec/controllers/jira_connect/app_descriptor_controller_spec.rb @@ -100,23 +100,6 @@ RSpec.describe JiraConnect::AppDescriptorController, feature_category: :integrat ) ) end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(atlassian_new_app_based_auth_model: false) - end - - it 'returns JSON app descriptior with createBranch action' do - get :show - - expect(response).to have_gitlab_http_status(:ok) - expect(descriptor[:modules][:jiraDevelopmentTool][:actions]).to include( - createBranch: { - templateUrl: 'http://test.host/-/jira_connect/branches/new?issue_key={issue.key}&issue_summary={issue.summary}' - } - ) - end - end end end end diff --git a/spec/frontend/observability/client_spec.js b/spec/frontend/observability/client_spec.js index 9e35735d155..6aca976c3a9 100644 --- a/spec/frontend/observability/client_spec.js +++ b/spec/frontend/observability/client_spec.js @@ -732,7 +732,7 @@ describe('buildClient', () => { await client.fetchMetrics({ filters: { search: [{ value: 'foo' }, { value: 'bar' }, { value: ' ' }] }, }); - expect(getQueryParam()).toBe('starts_with=foo+bar'); + expect(getQueryParam()).toBe('search=foo+bar'); }); it('ignores empty search', async () => { @@ -769,7 +769,7 @@ describe('buildClient', () => { filters: { search: [{ value: 'foo' }] }, limit: 50, }); - expect(getQueryParam()).toBe('starts_with=foo&limit=50'); + expect(getQueryParam()).toBe('search=foo&limit=50'); }); it('does not add the search limit param if the search filter is missing', async () => { diff --git a/spec/frontend/organizations/index/components/app_spec.js b/spec/frontend/organizations/index/components/app_spec.js index 5d86ff36349..0b607cc5902 100644 --- a/spec/frontend/organizations/index/components/app_spec.js +++ b/spec/frontend/organizations/index/components/app_spec.js @@ -90,34 +90,76 @@ describe('OrganizationsIndexApp', () => { }); }; - describe('when API call is loading', () => { + describe('`allowOrganizationCreation` is enabled', () => { beforeEach(() => { - createComponent(jest.fn().mockReturnValue(new Promise(() => {}))); + gon.features = { allowOrganizationCreation: true }; }); - itRendersHeaderText(); - itRendersNewOrganizationButton(); - itDoesNotRenderErrorMessage(); + describe('when API call is loading', () => { + beforeEach(() => { + createComponent(jest.fn().mockResolvedValue({})); + }); - it('renders the organizations view with loading prop set to true', () => { - expect(findOrganizationsView().props('loading')).toBe(true); + itRendersHeaderText(); + itRendersNewOrganizationButton(); + itDoesNotRenderErrorMessage(); + + it('renders the organizations view with loading prop set to true', () => { + expect(findOrganizationsView().props('loading')).toBe(true); + }); + }); + describe('when API call is successful', () => { + beforeEach(async () => { + createComponent(); + await waitForPromises(); + }); + + itRendersHeaderText(); + itRendersNewOrganizationButton(); + itDoesNotRenderErrorMessage(); + + it('passes organizations to view component', () => { + expect(findOrganizationsView().props()).toMatchObject({ + loading: false, + organizations, + }); + }); }); }); - describe('when API call is successful', () => { - beforeEach(async () => { - createComponent(); - await waitForPromises(); + describe('`allowOrganizationCreation` is disabled', () => { + beforeEach(() => { + gon.features = { allowOrganizationCreation: false }; }); - itRendersHeaderText(); - itRendersNewOrganizationButton(); - itDoesNotRenderErrorMessage(); + describe('when API call is loading', () => { + beforeEach(() => { + createComponent(jest.fn().mockResolvedValue({})); + }); - it('passes organizations to view component', () => { - expect(findOrganizationsView().props()).toMatchObject({ - loading: false, - organizations, + itRendersHeaderText(); + itDoesNotRenderNewOrganizationButton(); + itDoesNotRenderErrorMessage(); + + it('renders the organizations view with loading prop set to true', () => { + expect(findOrganizationsView().props('loading')).toBe(true); + }); + }); + describe('when API call is successful', () => { + beforeEach(() => { + createComponent(); + return waitForPromises(); + }); + + itRendersHeaderText(); + itDoesNotRenderNewOrganizationButton(); + itDoesNotRenderErrorMessage(); + + it('passes organizations to view component', () => { + expect(findOrganizationsView().props()).toMatchObject({ + loading: false, + organizations, + }); }); }); }); diff --git a/spec/helpers/environments_helper_spec.rb b/spec/helpers/environments_helper_spec.rb index 2aae7b61bd1..512b5c8b316 100644 --- a/spec/helpers/environments_helper_spec.rb +++ b/spec/helpers/environments_helper_spec.rb @@ -28,10 +28,6 @@ RSpec.describe EnvironmentsHelper, feature_category: :environment_management do 'current_environment_name' => environment.name, 'documentation_path' => help_page_path('administration/monitoring/prometheus/index'), 'add_dashboard_documentation_path' => help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project'), - 'empty_getting_started_svg_path' => match_asset_path('/assets/illustrations/monitoring/getting_started.svg'), - 'empty_loading_svg_path' => match_asset_path('/assets/illustrations/monitoring/loading.svg'), - 'empty_no_data_svg_path' => match_asset_path('/assets/illustrations/monitoring/no_data.svg'), - 'empty_unable_to_connect_svg_path' => match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'), 'deployments_endpoint' => project_environment_deployments_path(project, environment, format: :json), 'default_branch' => 'master', 'project_path' => project_path(project), diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index e8c412cc892..5c6b646d5d5 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -789,53 +789,16 @@ RSpec.describe SearchHelper, feature_category: :global_search do end describe '#search_service' do - using RSpec::Parameterized::TableSyntax - - subject { search_service } + let(:params) { { include_archived: true } } before do allow(self).to receive(:current_user).and_return(:the_current_user) end - shared_context 'with inputs' do - where(:input, :expected) do - '0' | false - '1' | true - 'yes' | true - 'no' | false - 'true' | true - 'false' | false - true | true - false | false - end - end + it 'instantiates a new SearchService with current_user and params' do + expect(::SearchService).to receive(:new).with(:the_current_user, { include_archived: true }) - describe 'for confidential' do - let(:params) { { confidential: input } } - - include_context 'with inputs' - - with_them do - it 'transforms param' do - expect(::SearchService).to receive(:new).with(:the_current_user, { confidential: expected }) - - subject - end - end - end - - describe 'for include_archived' do - let(:params) { { include_archived: input } } - - include_context 'with inputs' - - with_them do - it 'transforms param' do - expect(::SearchService).to receive(:new).with(:the_current_user, { include_archived: expected }) - - subject - end - end + search_service end end diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb index 37161119744..c8f835b9704 100644 --- a/spec/lib/container_registry/client_spec.rb +++ b/spec/lib/container_registry/client_spec.rb @@ -468,6 +468,32 @@ RSpec.describe ContainerRegistry::Client, feature_category: :container_registry it_behaves_like 'handling registry info' end + describe '#connected?' do + subject { client.connected? } + + context 'with a valid connection' do + before do + stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key') + stub_registry_info + end + + it 'returns true' do + expect(subject).to be true + end + end + + context 'with an invalid connection' do + before do + stub_container_registry_config(enabled: true, api_url: registry_api_url, key: 'spec/fixtures/x509_certificate_pk.key') + stub_registry_info(status: 500) + end + + it 'returns false' do + expect(subject).to be false + end + end + end + def stub_upload(path, content, digest, status = 200) stub_request(:post, "#{registry_api_url}/v2/#{path}/blobs/uploads/") .with(headers: headers_with_accept_types) diff --git a/spec/lib/gitlab/search/params_spec.rb b/spec/lib/gitlab/search/params_spec.rb index 3c64082aeeb..3f2ec8b178d 100644 --- a/spec/lib/gitlab/search/params_spec.rb +++ b/spec/lib/gitlab/search/params_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::Search::Params, feature_category: :global_search do - subject { described_class.new(params, detect_abuse: detect_abuse) } + subject(:search_params) { described_class.new(params, detect_abuse: detect_abuse) } let(:search) { 'search' } let(:group_id) { 123 } @@ -18,13 +18,14 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do it 'uses AbuseDetection by default' do expect(Gitlab::Search::AbuseDetection).to receive(:new).at_least(:once).and_call_original - described_class.new(params) + + search_params end end describe '#[]' do it 'feels like regular params' do - expect(subject[:group_id]).to eq(params[:group_id]) + expect(search_params[:group_id]).to eq(params[:group_id]) end it 'has indifferent access' do @@ -34,7 +35,7 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do end it 'also works on attr_reader attributes' do - expect(subject[:query_string]).to eq(subject.query_string) + expect(search_params[:query_string]).to eq(search_params.query_string) end end @@ -57,7 +58,7 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do end it 'strips surrounding whitespace from query string' do - params = described_class.new({ search: ' ' + search + ' ' }) + params = described_class.new({ search: " #{search} " }) expect(params.query_string).to eq(search) end end @@ -68,13 +69,13 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do it 'does NOT validate AbuseDetector' do expect(Gitlab::Search::AbuseDetection).not_to receive(:new) - subject.validate + search_params.validate end end it 'validates AbuseDetector on validation' do expect(Gitlab::Search::AbuseDetection).to receive(:new).at_least(:once).and_call_original - subject.validate + search_params.validate end context 'when query has too many terms' do @@ -96,13 +97,13 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do it 'does NOT validate AbuseDetector' do expect(Gitlab::Search::AbuseDetection).not_to receive(:new) - subject.valid? + search_params.valid? end end it 'validates AbuseDetector on validation' do expect(Gitlab::Search::AbuseDetection).to receive(:new).at_least(:once).and_call_original - subject.valid? + search_params.valid? end end @@ -110,7 +111,7 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do let(:abuse_detection) { instance_double(Gitlab::Search::AbuseDetection) } before do - allow(subject).to receive(:abuse_detection).and_return abuse_detection + allow(search_params).to receive(:abuse_detection).and_return abuse_detection allow(abuse_detection).to receive(:errors).and_return abuse_errors end @@ -118,7 +119,7 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do let(:abuse_errors) { { foo: ['bar'] } } it 'is considered abusive' do - expect(subject).to be_abusive + expect(search_params).to be_abusive end end @@ -127,20 +128,20 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do context 'and there are other validation errors' do it 'is NOT considered abusive' do - allow(subject).to receive(:valid?) do - subject.errors.add :project_id, 'validation error unrelated to abuse' + allow(search_params).to receive(:valid?) do + search_params.errors.add :project_id, 'validation error unrelated to abuse' false end - expect(subject).not_to be_abusive + expect(search_params).not_to be_abusive end end context 'and there are NO other validation errors' do it 'is NOT considered abusive' do - allow(subject).to receive(:valid?).and_return(true) + allow(search_params).to receive(:valid?).and_return(true) - expect(subject).not_to be_abusive + expect(search_params).not_to be_abusive end end end @@ -153,4 +154,57 @@ RSpec.describe Gitlab::Search::Params, feature_category: :global_search do expect(described_class.new({ search: 'foo bar' })).not_to be_email_lookup end end + + describe 'converts boolean params' do + using RSpec::Parameterized::TableSyntax + + shared_context 'with inputs' do + where(:input, :expected) do + '0' | false + '1' | true + 'yes' | true + 'no' | false + 'true' | true + 'false' | false + true | true + false | false + end + end + + describe 'for confidential' do + let(:params) { { group_id: 123, search: search, confidential: input } } + + include_context 'with inputs' + + with_them do + it 'transforms param' do + expect(search_params[:confidential]).to eq(expected) + end + end + end + + describe 'for include_archived' do + let(:params) { { group_id: 123, search: search, include_archived: input } } + + include_context 'with inputs' + + with_them do + it 'transforms param' do + expect(search_params[:include_archived]).to eq(expected) + end + end + end + + describe 'for include_forked' do + let(:params) { { group_id: 123, search: search, include_forked: input } } + + include_context 'with inputs' + + with_them do + it 'transforms param' do + expect(search_params[:include_forked]).to eq(expected) + end + end + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 0d4609a89ed..858d4f5512a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -7038,6 +7038,18 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr end end + describe '.not_a_fork' do + let_it_be(:project) { create(:project, :public) } + + subject(:not_a_fork) { described_class.not_a_fork } + + it 'returns projects which are not forks' do + fork_project(project) + + expect(not_a_fork).to contain_exactly(project) + end + end + describe '.deployments' do subject { project.deployments } diff --git a/spec/presenters/clusters/cluster_presenter_spec.rb b/spec/presenters/clusters/cluster_presenter_spec.rb index aacb696a88e..6027d9d3f31 100644 --- a/spec/presenters/clusters/cluster_presenter_spec.rb +++ b/spec/presenters/clusters/cluster_presenter_spec.rb @@ -124,11 +124,6 @@ RSpec.describe Clusters::ClusterPresenter do 'dashboard-endpoint': clusterable_presenter.metrics_dashboard_path(cluster), 'documentation-path': help_page_path('user/infrastructure/clusters/manage/clusters_health'), 'add-dashboard-documentation-path': help_page_path('operations/metrics/dashboards/index', anchor: 'add-a-new-dashboard-to-your-project'), - 'empty-getting-started-svg-path': match_asset_path('/assets/illustrations/monitoring/getting_started.svg'), - 'empty-loading-svg-path': match_asset_path('/assets/illustrations/monitoring/loading.svg'), - 'empty-no-data-svg-path': match_asset_path('/assets/illustrations/monitoring/no_data.svg'), - 'empty-no-data-small-svg-path': match_asset_path('illustrations/chart-empty-state-small.svg'), - 'empty-unable-to-connect-svg-path': match_asset_path('/assets/illustrations/monitoring/unable_to_connect.svg'), 'settings-path': '', 'project-path': '', 'tags-path': '' diff --git a/spec/requests/jira_connect/repositories_controller_spec.rb b/spec/requests/jira_connect/repositories_controller_spec.rb index 7397f3ba60d..61ffa95241e 100644 --- a/spec/requests/jira_connect/repositories_controller_spec.rb +++ b/spec/requests/jira_connect/repositories_controller_spec.rb @@ -65,17 +65,6 @@ RSpec.describe JiraConnect::RepositoriesController, feature_category: :integrati expect(json_response).to include('containers' => [expected_response]) end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(atlassian_new_app_based_auth_model: false) - get '/-/jira_connect/repositories/search', params: { jwt: jwt, searchQuery: search_query } - end - - it 'returns 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - end end end @@ -115,17 +104,6 @@ RSpec.describe JiraConnect::RepositoriesController, feature_category: :integrati expect(json_response).to include(expected_response) end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(atlassian_new_app_based_auth_model: false) - post '/-/jira_connect/repositories/associate', params: { jwt: jwt, id: id } - end - - it 'returns 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - end end end end diff --git a/spec/requests/jira_connect/workspaces_controller_spec.rb b/spec/requests/jira_connect/workspaces_controller_spec.rb index b07dd769bbc..487816a610b 100644 --- a/spec/requests/jira_connect/workspaces_controller_spec.rb +++ b/spec/requests/jira_connect/workspaces_controller_spec.rb @@ -60,17 +60,6 @@ RSpec.describe JiraConnect::WorkspacesController, feature_category: :integration expect(json_response).to include(expected_response) end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(atlassian_new_app_based_auth_model: false) - get '/-/jira_connect/workspaces/search', params: { jwt: jwt, searchQuery: search_query } - end - - it 'returns 404' do - expect(response).to have_gitlab_http_status(:not_found) - end - end end end end diff --git a/spec/services/organizations/create_service_spec.rb b/spec/services/organizations/create_service_spec.rb index bbc0f3d7515..3ebce5fe8f4 100644 --- a/spec/services/organizations/create_service_spec.rb +++ b/spec/services/organizations/create_service_spec.rb @@ -65,5 +65,18 @@ RSpec.describe Organizations::CreateService, feature_category: :cell do end end end + + context 'when `allow_organization_creation` FF is disabled' do + before do + stub_feature_flags(allow_organization_creation: false) + end + + it 'returns an error' do + expect(response).to be_error + + expect(response.message) + .to match_array(['Feature flag `allow_organization_creation` is not enabled for this user.']) + end + end end end