Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-07-27 12:10:42 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-07-27 12:10:42 +0300
commit5add82515889cf332b65bbf59394079222dc66b3 (patch)
tree95c6e3092407fb86a39dab4ffafc930a6fb95bec
parent1d9c7ebdadc0c011b997bc8e0032281b939de4e7 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_tabs.vue2
-rw-r--r--app/assets/javascripts/pipelines/utils.js12
-rw-r--r--app/models/concerns/time_trackable.rb11
-rw-r--r--app/models/group.rb2
-rw-r--r--app/models/sent_notification.rb4
-rw-r--r--app/services/projects/destroy_service.rb6
-rw-r--r--app/views/projects/_deletion_failed.html.haml4
-rw-r--r--config/feature_categories.yml5
-rw-r--r--db/docs/product_analytics_events_experimental.yml2
-rw-r--r--doc/development/import_export.md7
-rw-r--r--doc/integration/jira/connect-app.md5
-rw-r--r--doc/integration/jira/jira_server_configuration.md2
-rw-r--r--doc/user/usage_quotas.md2
-rw-r--r--lib/gitlab/checks/diff_check.rb2
-rw-r--r--lib/gitlab/quick_actions/issue_and_merge_request_actions.rb6
-rw-r--r--locale/gitlab.pot12
-rw-r--r--spec/controllers/concerns/product_analytics_tracking_spec.rb2
-rw-r--r--spec/frontend/pipelines/pipeline_graph/utils_spec.js6
-rw-r--r--spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb2
-rw-r--r--spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb2
-rw-r--r--spec/lib/gitlab/internal_events/event_definitions_spec.rb2
-rw-r--r--spec/lib/gitlab/internal_events_spec.rb2
-rw-r--r--spec/lib/product_analytics/settings_spec.rb2
-rw-r--r--spec/migrations/20221219122320_copy_clickhouse_connection_string_to_encrypted_var_spec.rb2
-rw-r--r--spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb2
-rw-r--r--spec/models/group_spec.rb7
-rw-r--r--spec/services/notes/quick_actions_service_spec.rb56
-rw-r--r--spec/services/product_analytics/build_activity_graph_service_spec.rb2
-rw-r--r--spec/services/product_analytics/build_graph_service_spec.rb2
-rw-r--r--spec/services/projects/destroy_service_spec.rb17
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb14
31 files changed, 158 insertions, 46 deletions
diff --git a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
index d2ec3c352fe..e14644ae0d5 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_tabs.vue
@@ -52,6 +52,8 @@ export default {
return tabName === this.activeTab;
},
navigateTo(tabName) {
+ if (this.isActive(tabName)) return;
+
this.$router.push({ name: tabName });
},
},
diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js
index b8276327843..38be5becfb8 100644
--- a/app/assets/javascripts/pipelines/utils.js
+++ b/app/assets/javascripts/pipelines/utils.js
@@ -1,7 +1,12 @@
import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash';
import { parseUrlPathname } from '~/lib/utils/url_utility';
-import { NEEDS_PROPERTY, SUPPORTED_FILTER_PARAMETERS, validPipelineTabNames } from './constants';
+import {
+ NEEDS_PROPERTY,
+ SUPPORTED_FILTER_PARAMETERS,
+ validPipelineTabNames,
+ pipelineTabName,
+} from './constants';
/*
The following functions are the main engine in transforming the data as
received from the endpoint into the format the d3 graph expects.
@@ -144,9 +149,8 @@ export const getPipelineDefaultTab = (url) => {
const regexp = /\w*$/;
const [tabName] = strippedUrl.match(regexp);
- if (tabName && validPipelineTabNames.includes(tabName)) {
- return tabName;
- }
+ if (tabName && validPipelineTabNames.includes(tabName)) return tabName;
+ if (tabName === '') return pipelineTabName;
return null;
};
diff --git a/app/models/concerns/time_trackable.rb b/app/models/concerns/time_trackable.rb
index 2b7447dc700..0f361e70a91 100644
--- a/app/models/concerns/time_trackable.rb
+++ b/app/models/concerns/time_trackable.rb
@@ -17,8 +17,8 @@ module TimeTrackable
attribute :time_estimate, default: 0
- validates :time_estimate, numericality: { message: 'has an invalid format' }, allow_nil: false
- validate :check_negative_time_spent
+ validate :check_time_estimate
+ validate :check_negative_time_spent
has_many :timelogs, dependent: :destroy, autosave: true # rubocop:disable Cop/ActiveRecordDependent
after_initialize :set_time_estimate_default_value
@@ -106,4 +106,11 @@ module TimeTrackable
def original_total_time_spent
@original_total_time_spent ||= total_time_spent
end
+
+ def check_time_estimate
+ return unless new_record? || time_estimate_changed?
+ return if time_estimate.is_a?(Numeric) && time_estimate >= 0
+
+ errors.add(:time_estimate, _('must have a valid format and be greater than or equal to zero.'))
+ end
end
diff --git a/app/models/group.rb b/app/models/group.rb
index 7a9eb12db4e..b0b9c852d11 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -397,7 +397,7 @@ class Group < Namespace
end
def visibility_level_allowed_by_projects?(level = self.visibility_level)
- !projects.where('visibility_level > ?', level).exists?
+ !projects.without_deleted.where('visibility_level > ?', level).exists?
end
def visibility_level_allowed_by_sub_groups?(level = self.visibility_level)
diff --git a/app/models/sent_notification.rb b/app/models/sent_notification.rb
index c2fd8b20942..f3a0479d3b7 100644
--- a/app/models/sent_notification.rb
+++ b/app/models/sent_notification.rb
@@ -1,10 +1,6 @@
# frozen_string_literal: true
class SentNotification < ApplicationRecord
- include IgnorableColumns
-
- ignore_column %i[line_code note_type position], remove_with: '16.3', remove_after: '2023-07-22'
-
belongs_to :project
belongs_to :noteable, polymorphic: true # rubocop:disable Cop/PolymorphicAssociations
belongs_to :recipient, class_name: "User"
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
index a5c12384b59..0ae6fcb4d97 100644
--- a/app/services/projects/destroy_service.rb
+++ b/app/services/projects/destroy_service.rb
@@ -114,7 +114,11 @@ module Projects
# It's possible that the project was destroyed, but some after_commit
# hook failed and caused us to end up here. A destroyed model will be a frozen hash,
# which cannot be altered.
- project.update(delete_error: message, pending_delete: false) unless project.destroyed?
+ unless project.destroyed?
+ # Restrict project visibility if the parent group visibility was made more restrictive while the project was scheduled for deletion.
+ visibility_level = project.visibility_level_allowed_by_group? ? project.visibility_level : project.group.visibility_level
+ project.update(delete_error: message, pending_delete: false, visibility_level: visibility_level)
+ end
log_error("Deletion failed on #{project.full_path} with the following message: #{message}")
end
diff --git a/app/views/projects/_deletion_failed.html.haml b/app/views/projects/_deletion_failed.html.haml
index 29551505a7e..7ddb80c90f9 100644
--- a/app/views/projects/_deletion_failed.html.haml
+++ b/app/views/projects/_deletion_failed.html.haml
@@ -5,5 +5,7 @@
dismissible: false,
alert_options: { class: 'project-deletion-failed-message' }) do |c|
- c.with_body do
- This project was scheduled for deletion, but failed with the following message:
+ = _('This project was scheduled for deletion, but failed with the following message:')
= project.delete_error
+ %br
+ = _('The project visibility may have been made more restrictive if the parent group\'s visibility changed while the deletion was scheduled.')
diff --git a/config/feature_categories.yml b/config/feature_categories.yml
index 048d7384937..5095fa36dd1 100644
--- a/config/feature_categories.yml
+++ b/config/feature_categories.yml
@@ -8,6 +8,7 @@
#
---
- advisory_database
+- ai_abstraction_layer
- api
- api_security
- application_instrumentation
@@ -67,6 +68,7 @@
- gitaly
- gitlab_cli
- gitlab_docs
+- gitlab_duo_chat
- global_search
- groups_and_projects
- helm_chart_registry
@@ -96,7 +98,8 @@
- pages
- pipeline_composition
- portfolio_management
-- product_analytics
+- product_analytics_data_management
+- product_analytics_visualization
- pubsec_services
- purchase
- quality_management
diff --git a/db/docs/product_analytics_events_experimental.yml b/db/docs/product_analytics_events_experimental.yml
index 347a3ef88ac..371305ba2f8 100644
--- a/db/docs/product_analytics_events_experimental.yml
+++ b/db/docs/product_analytics_events_experimental.yml
@@ -3,7 +3,7 @@ table_name: product_analytics_events_experimental
classes:
- ProductAnalyticsEvent
feature_categories:
-- product_analytics
+- product_analytics_data_management
description: Product analytic events, experimental feature.
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/commit/fc6c53e6f7b47dc22c8619a5a6fe491d29778d3f
milestone: '13.2'
diff --git a/doc/development/import_export.md b/doc/development/import_export.md
index 9a7944ae308..11bddf190fa 100644
--- a/doc/development/import_export.md
+++ b/doc/development/import_export.md
@@ -12,10 +12,11 @@ General development guidelines and tips for the [Import/Export feature](../user/
## Security
-The Import/Export feature is constantly updated (adding new things to export), however
-the code hasn't been refactored in a long time. We should perform a code audit (see
-[confidential issue](../user/project/issues/confidential_issues.md) `https://gitlab.com/gitlab-org/gitlab/-/issues/20720`).
+The Import/Export feature is constantly updated (adding new things to export). However,
+the code hasn't been refactored in a long time. We should perform a code audit
to make sure its dynamic nature does not increase the number of security concerns.
+GitLab team members can view more information in this confidential issue:
+`https://gitlab.com/gitlab-org/gitlab/-/issues/20720`.
### Security in the code
diff --git a/doc/integration/jira/connect-app.md b/doc/integration/jira/connect-app.md
index 49dbc60bfd7..10b1f3ff082 100644
--- a/doc/integration/jira/connect-app.md
+++ b/doc/integration/jira/connect-app.md
@@ -32,7 +32,7 @@ To install the GitLab for Jira Cloud app:
1. In Jira, on the top bar, select **Apps > Explore more apps** and search for `GitLab for Jira Cloud`.
1. Select **GitLab for Jira Cloud**, then select **Get it now**.
- Alternatively, [get the app directly from the Atlassian Marketplace](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?tab=overview&hosting=cloud).
+Alternatively, [get the app directly from the Atlassian Marketplace](https://marketplace.atlassian.com/apps/1221011/gitlab-com-for-jira-cloud?tab=overview&hosting=cloud).
You can now [configure the GitLab for Jira Cloud app](#configure-the-gitlab-for-jira-cloud-app).
@@ -75,6 +75,7 @@ The following data is synced:
Most updates to the app are automatic. For more information, see the
[Atlassian documentation](https://developer.atlassian.com/platform/marketplace/upgrading-and-versioning-cloud-apps/).
+
If the app requires additional permissions, [you must manually approve the update in Jira](https://developer.atlassian.com/platform/marketplace/upgrading-and-versioning-cloud-apps/#changes-that-require-manual-customer-approval).
## Set up OAuth authentication for self-managed instances **(FREE SELF)**
@@ -382,6 +383,6 @@ Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remot
A `403` status code is returned if:
- The user information cannot be fetched from Jira.
-- The authenticated Jira user does not have administrator access.
+- The authenticated Jira user does not have [site administrator](https://support.atlassian.com/user-management/docs/give-users-admin-permissions/#Make-someone-a-site-admin) access.
To resolve this issue, ensure the authenticated user is a Jira site administrator and try again.
diff --git a/doc/integration/jira/jira_server_configuration.md b/doc/integration/jira/jira_server_configuration.md
index 373fe137046..289af32b0db 100644
--- a/doc/integration/jira/jira_server_configuration.md
+++ b/doc/integration/jira/jira_server_configuration.md
@@ -17,7 +17,7 @@ To create Jira credentials, here's what we're going to do:
Prerequisite:
-- You must have administrator access to the Jira instance.
+- You must have [site administrator](https://support.atlassian.com/user-management/docs/give-users-admin-permissions/#Make-someone-a-site-admin) access to the Jira instance.
## Create a Jira user
diff --git a/doc/user/usage_quotas.md b/doc/user/usage_quotas.md
index d119044930a..a2f436c74dc 100644
--- a/doc/user/usage_quotas.md
+++ b/doc/user/usage_quotas.md
@@ -161,7 +161,7 @@ example, no additional storage has yet been purchased.
To remove the read-only state from the Red and Green projects, 50 GB additional storage is purchased.
Assuming the Green and Red projects' repositories and LFS grow past the 10 GB quota, the purchased storage
-available decreases. All projects remain read-only because 40 GB purchased storage is available:
+available decreases. All projects no longer have the read-only status because 40 GB purchased storage is available:
50 GB (purchased storage) - 10 GB (total excess storage used).
| Repository | Storage used | Excess storage | Quota | Status |
diff --git a/lib/gitlab/checks/diff_check.rb b/lib/gitlab/checks/diff_check.rb
index faf5a764725..15b38188f13 100644
--- a/lib/gitlab/checks/diff_check.rb
+++ b/lib/gitlab/checks/diff_check.rb
@@ -46,7 +46,7 @@ module Gitlab
init_commit = objects.last
diff_tree = Gitlab::Git::DiffTree.from_commit(init_commit)
- objects.prepend(diff_tree) if diff_tree
+ return [diff_tree] + objects if diff_tree
objects
end
diff --git a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
index e01be4e0604..597312edcd5 100644
--- a/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
+++ b/lib/gitlab/quick_actions/issue_and_merge_request_actions.rb
@@ -159,12 +159,10 @@ module Gitlab
current_user.can?(:"admin_#{quick_action_target.to_ability_name}", project)
end
parse_params do |raw_duration|
- Gitlab::TimeTrackingFormatter.parse(raw_duration)
+ Gitlab::TimeTrackingFormatter.parse(raw_duration, keep_zero: true)
end
command :estimate, :estimate_time do |time_estimate|
- if time_estimate
- @updates[:time_estimate] = time_estimate
- end
+ @updates[:time_estimate] = time_estimate
end
desc { _('Add or subtract spent time') }
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 774157e5795..ddf2e681513 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -13164,6 +13164,9 @@ msgstr ""
msgid "Could not restore the group"
msgstr ""
+msgid "Could not retrieve the list of branches. Use the YAML editor mode, or refresh this page later. To view the list of branches, go to %{boldStart}Code - Branches%{boldEnd}"
+msgstr ""
+
msgid "Could not retrieve the list of protected branches. Use the YAML editor mode, or refresh this page later. To view the list of protected branches, go to %{boldStart}Settings - Branches%{boldEnd} and expand %{boldStart}Protected branches%{boldEnd}."
msgstr ""
@@ -46720,6 +46723,9 @@ msgstr ""
msgid "The project size exceeds the export limit."
msgstr ""
+msgid "The project visibility may have been made more restrictive if the parent group's visibility changed while the deletion was scheduled."
+msgstr ""
+
msgid "The project was successfully forked."
msgstr ""
@@ -47815,6 +47821,9 @@ msgstr ""
msgid "This project reached the limit of custom domains. (Max %d)"
msgstr ""
+msgid "This project was scheduled for deletion, but failed with the following message:"
+msgstr ""
+
msgid "This project will be deleted on %{date}"
msgstr ""
@@ -55681,6 +55690,9 @@ msgstr ""
msgid "must have a repository"
msgstr ""
+msgid "must have a valid format and be greater than or equal to zero."
+msgstr ""
+
msgid "must match %{association}.project_id"
msgstr ""
diff --git a/spec/controllers/concerns/product_analytics_tracking_spec.rb b/spec/controllers/concerns/product_analytics_tracking_spec.rb
index 65c2c77c027..0f18a4fed9e 100644
--- a/spec/controllers/concerns/product_analytics_tracking_spec.rb
+++ b/spec/controllers/concerns/product_analytics_tracking_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_analytics do
+RSpec.describe ProductAnalyticsTracking, :snowplow, feature_category: :product_analytics_data_management do
include TrackingHelpers
include SnowplowHelpers
diff --git a/spec/frontend/pipelines/pipeline_graph/utils_spec.js b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
index 41b020189d0..96b18fcf96f 100644
--- a/spec/frontend/pipelines/pipeline_graph/utils_spec.js
+++ b/spec/frontend/pipelines/pipeline_graph/utils_spec.js
@@ -1,5 +1,5 @@
import { createJobsHash, generateJobNeedsDict, getPipelineDefaultTab } from '~/pipelines/utils';
-import { validPipelineTabNames } from '~/pipelines/constants';
+import { validPipelineTabNames, pipelineTabName } from '~/pipelines/constants';
describe('utils functions', () => {
const jobName1 = 'build_1';
@@ -173,8 +173,8 @@ describe('utils functions', () => {
describe('getPipelineDefaultTab', () => {
const baseUrl = 'http://gitlab.com/user/multi-projects-small/-/pipelines/332/';
- it('returns null if there is only the base url', () => {
- expect(getPipelineDefaultTab(baseUrl)).toBe(null);
+ it('returns pipeline tab name if there is only the base url', () => {
+ expect(getPipelineDefaultTab(baseUrl)).toBe(pipelineTabName);
});
it('returns null if there was no valid last url part', () => {
diff --git a/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb b/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
index 6826006949e..62a52ee5fb9 100644
--- a/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
+++ b/spec/lib/generators/gitlab/snowplow_event_definition_generator_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout, feature_category: :product_analytics do
+RSpec.describe Gitlab::SnowplowEventDefinitionGenerator, :silence_stdout, feature_category: :product_analytics_data_management do
let(:ce_temp_dir) { Dir.mktmpdir }
let(:ee_temp_dir) { Dir.mktmpdir }
let(:timestamp) { Time.now.utc.strftime('%Y%m%d%H%M%S') }
diff --git a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
index 24248c557bd..df0e4fb92a0 100644
--- a/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
+++ b/spec/lib/gitlab/analytics/cycle_analytics/stage_events/stage_event_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent, feature_category: :product_analytics do
+RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::StageEvent, feature_category: :product_analytics_data_management do
let(:instance) { described_class.new({}) }
it { expect(described_class).to respond_to(:name) }
diff --git a/spec/lib/gitlab/internal_events/event_definitions_spec.rb b/spec/lib/gitlab/internal_events/event_definitions_spec.rb
index 0eba3cdbcb3..924845504ca 100644
--- a/spec/lib/gitlab/internal_events/event_definitions_spec.rb
+++ b/spec/lib/gitlab/internal_events/event_definitions_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Gitlab::InternalEvents::EventDefinitions, feature_category: :product_analytics do
+RSpec.describe Gitlab::InternalEvents::EventDefinitions, feature_category: :product_analytics_data_management do
after(:all) do
described_class.instance_variable_set(:@events, nil)
end
diff --git a/spec/lib/gitlab/internal_events_spec.rb b/spec/lib/gitlab/internal_events_spec.rb
index 86215434ba4..c2615e0f22c 100644
--- a/spec/lib/gitlab/internal_events_spec.rb
+++ b/spec/lib/gitlab/internal_events_spec.rb
@@ -2,7 +2,7 @@
require "spec_helper"
-RSpec.describe Gitlab::InternalEvents, :snowplow, feature_category: :product_analytics do
+RSpec.describe Gitlab::InternalEvents, :snowplow, feature_category: :product_analytics_data_management do
include TrackingHelpers
include SnowplowHelpers
diff --git a/spec/lib/product_analytics/settings_spec.rb b/spec/lib/product_analytics/settings_spec.rb
index 9c33b8068d1..9ba5dbfc8fc 100644
--- a/spec/lib/product_analytics/settings_spec.rb
+++ b/spec/lib/product_analytics/settings_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProductAnalytics::Settings, feature_category: :product_analytics do
+RSpec.describe ProductAnalytics::Settings, feature_category: :product_analytics_data_management do
let_it_be(:project) { create(:project) }
subject { described_class.for_project(project) }
diff --git a/spec/migrations/20221219122320_copy_clickhouse_connection_string_to_encrypted_var_spec.rb b/spec/migrations/20221219122320_copy_clickhouse_connection_string_to_encrypted_var_spec.rb
index 7ff033ab0c2..48702e866e0 100644
--- a/spec/migrations/20221219122320_copy_clickhouse_connection_string_to_encrypted_var_spec.rb
+++ b/spec/migrations/20221219122320_copy_clickhouse_connection_string_to_encrypted_var_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
require_migration!
-RSpec.describe CopyClickhouseConnectionStringToEncryptedVar, feature_category: :product_analytics do
+RSpec.describe CopyClickhouseConnectionStringToEncryptedVar, feature_category: :product_analytics_data_management do
let!(:migration) { described_class.new }
let(:setting) { table(:application_settings).create!(clickhouse_connection_string: 'https://example.com/test') }
diff --git a/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb b/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb
index 253512c9194..05cc065e6c3 100644
--- a/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb
+++ b/spec/migrations/20230327123333_backfill_product_analytics_data_collector_host_spec.rb
@@ -3,7 +3,7 @@
require "spec_helper"
require_migration!
-RSpec.describe BackfillProductAnalyticsDataCollectorHost, feature_category: :product_analytics do
+RSpec.describe BackfillProductAnalyticsDataCollectorHost, feature_category: :product_analytics_data_management do
let!(:application_settings) { table(:application_settings) }
describe '#up' do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index db5750b2019..eb604456511 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -390,6 +390,13 @@ RSpec.describe Group, feature_category: :groups_and_projects do
expect(internal_group).to be_invalid
expect(internal_group.errors[:visibility_level]).to include('private is not allowed since this group contains projects with higher visibility.')
end
+
+ it 'is valid if higher visibility project is deleted' do
+ internal_project.update_attribute(:pending_delete, true)
+ internal_group.visibility_level = Gitlab::VisibilityLevel::PRIVATE
+
+ expect(internal_group).to be_valid
+ end
end
context 'when group has a higher visibility' do
diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb
index c51e381014d..0065fd639b8 100644
--- a/spec/services/notes/quick_actions_service_spec.rb
+++ b/spec/services/notes/quick_actions_service_spec.rb
@@ -132,13 +132,59 @@ RSpec.describe Notes::QuickActionsService, feature_category: :team_planning do
end
describe '/estimate' do
- let(:note_text) { '/estimate 1h' }
+ before do
+ # reset to 10 minutes before each test
+ note.noteable.update!(time_estimate: 600)
+ end
+
+ shared_examples 'does not update time_estimate and displays the correct error message' do
+ it 'shows validation error message' do
+ content = execute(note)
+
+ expect(content).to be_empty
+ expect(note.noteable.errors[:time_estimate]).to include('must have a valid format and be greater than or equal to zero.')
+ expect(note.noteable.reload.time_estimate).to eq(600)
+ end
+ end
+
+ context 'when the time estimate is valid' do
+ let(:note_text) { '/estimate 1h' }
+
+ it 'adds time estimate to noteable' do
+ content = execute(note)
+
+ expect(content).to be_empty
+ expect(note.noteable.reload.time_estimate).to eq(3600)
+ end
+ end
+
+ context 'when the time estimate is 0' do
+ let(:note_text) { '/estimate 0' }
+
+ it 'adds time estimate to noteable' do
+ content = execute(note)
+
+ expect(content).to be_empty
+ expect(note.noteable.reload.time_estimate).to eq(0)
+ end
+ end
+
+ context 'when the time estimate is invalid' do
+ let(:note_text) { '/estimate a' }
+
+ include_examples "does not update time_estimate and displays the correct error message"
+ end
+
+ context 'when the time estimate is partially invalid' do
+ let(:note_text) { '/estimate 1d 3id' }
+
+ include_examples "does not update time_estimate and displays the correct error message"
+ end
- it 'adds time estimate to noteable' do
- content = execute(note)
+ context 'when the time estimate is negative' do
+ let(:note_text) { '/estimate -1h' }
- expect(content).to be_empty
- expect(note.noteable.time_estimate).to eq(3600)
+ include_examples "does not update time_estimate and displays the correct error message"
end
end
diff --git a/spec/services/product_analytics/build_activity_graph_service_spec.rb b/spec/services/product_analytics/build_activity_graph_service_spec.rb
index cd1bc42e156..2eb35523da7 100644
--- a/spec/services/product_analytics/build_activity_graph_service_spec.rb
+++ b/spec/services/product_analytics/build_activity_graph_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProductAnalytics::BuildActivityGraphService, feature_category: :product_analytics do
+RSpec.describe ProductAnalytics::BuildActivityGraphService, feature_category: :product_analytics_data_management do
let_it_be(:project) { create(:project) }
let_it_be(:time_now) { Time.zone.now }
let_it_be(:time_ago) { Time.zone.now - 5.days }
diff --git a/spec/services/product_analytics/build_graph_service_spec.rb b/spec/services/product_analytics/build_graph_service_spec.rb
index ee0e2190501..13c7206241c 100644
--- a/spec/services/product_analytics/build_graph_service_spec.rb
+++ b/spec/services/product_analytics/build_graph_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe ProductAnalytics::BuildGraphService, feature_category: :product_analytics do
+RSpec.describe ProductAnalytics::BuildGraphService, feature_category: :product_analytics_data_management do
let_it_be(:project) { create(:project) }
let_it_be(:events) do
diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb
index ccf58964c71..0210e101e5f 100644
--- a/spec/services/projects/destroy_service_spec.rb
+++ b/spec/services/projects/destroy_service_spec.rb
@@ -115,6 +115,23 @@ RSpec.describe Projects::DestroyService, :aggregate_failures, :event_store_publi
expect(project.reload.delete_error).to be_present
expect(project.delete_error).to match(error_message)
end
+
+ context 'when parent group visibility was made more restrictive while project was marked "pending deletion"' do
+ let!(:group) { create(:group, :public) }
+ let!(:project) { create(:project, :repository, :public, namespace: group) }
+
+ it 'sets the project visibility level to that of the parent group' do
+ group.add_owner(user)
+ project.group.update_attribute(:visibility_level, Gitlab::VisibilityLevel::INTERNAL)
+
+ expect(project.reload.visibility_level).to be(Gitlab::VisibilityLevel::PUBLIC)
+ expect(project.group.visibility_level).to be(Gitlab::VisibilityLevel::INTERNAL)
+
+ destroy_project(project, user, {})
+
+ expect(project.reload.visibility_level).to be(Gitlab::VisibilityLevel::INTERNAL)
+ end
+ end
end
context "deleting a project with merge requests" do
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index 186b532233e..86e2340b9fb 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1454,9 +1454,21 @@ RSpec.describe QuickActions::InterpretService, feature_category: :team_planning
let(:issuable) { issue }
end
- it_behaves_like 'failed command' do
+ context 'when provided an invalid estimate' do
let(:content) { '/estimate abc' }
let(:issuable) { issue }
+
+ it 'populates {} if content contains an unsupported command' do
+ _, updates, _ = service.execute(content, issuable)
+
+ expect(updates[:time_estimate]).to be_nil
+ end
+
+ it "returns empty message" do
+ _, _, message = service.execute(content, issuable)
+
+ expect(message).to be_empty
+ end
end
it_behaves_like 'spend command' do