summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml2
-rw-r--r--.rubocop_manual_todo.yml1
-rw-r--r--Gemfile.lock2
-rw-r--r--app/assets/images/mailers/in_product_marketing/experience-0.pngbin0 -> 66492 bytes
-rw-r--r--app/assets/javascripts/emoji/components/picker.vue6
-rw-r--r--app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue4
-rw-r--r--app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue50
-rw-r--r--app/controllers/admin/background_migrations_controller.rb23
-rw-r--r--app/controllers/groups/email_campaigns_controller.rb7
-rw-r--r--app/controllers/jira_connect/app_descriptor_controller.rb2
-rw-r--r--app/graphql/types/snippets/visibility_scopes_enum.rb6
-rw-r--r--app/helpers/admin/background_migrations_helper.rb27
-rw-r--r--app/helpers/issues_helper.rb2
-rw-r--r--app/helpers/nav_helper.rb2
-rw-r--r--app/mailers/emails/in_product_marketing.rb5
-rw-r--r--app/models/onboarding_progress.rb4
-rw-r--r--app/models/users/in_product_marketing_email.rb3
-rw-r--r--app/services/namespaces/in_product_marketing_emails_service.rb45
-rw-r--r--app/views/admin/background_migrations/_migration.html.haml10
-rw-r--r--app/views/admin/background_migrations/index.html.haml35
-rw-r--r--app/views/layouts/nav/sidebar/_admin.html.haml6
-rw-r--r--app/views/notify/in_product_marketing_email.html.haml29
-rw-r--r--app/views/notify/in_product_marketing_email.text.erb9
-rw-r--r--changelogs/unreleased/326760-batched-migrations-admin-panel.yml5
-rw-r--r--changelogs/unreleased/326791-removing-redundant-update.yml5
-rw-r--r--changelogs/unreleased/add-ease-score-onboarding-email.yml5
-rw-r--r--config/metrics/counts_28d/20210216183638_unique_users_all_imports.yml14
-rw-r--r--config/metrics/counts_28d/20210216183644_gitlab_project.yml12
-rw-r--r--config/metrics/counts_28d/20210216183646_gitlab.yml12
-rw-r--r--config/metrics/counts_28d/20210216183648_github.yml18
-rw-r--r--config/metrics/counts_28d/20210216183650_bitbucket.yml18
-rw-r--r--config/metrics/counts_28d/20210216183652_bitbucket_server.yml18
-rw-r--r--config/metrics/counts_28d/20210216183653_gitea.yml16
-rw-r--r--config/metrics/counts_28d/20210216183655_git.yml14
-rw-r--r--config/metrics/counts_28d/20210216183657_manifest.yml12
-rw-r--r--config/metrics/counts_28d/20210216183659_gitlab_migration.yml12
-rw-r--r--config/metrics/counts_28d/20210216183709_group_import.yml18
-rw-r--r--config/metrics/counts_28d/20210216183720_bitbucket.yml16
-rw-r--r--config/metrics/counts_28d/20210216183722_bitbucket_server.yml14
-rw-r--r--config/metrics/counts_28d/20210216183737_groups_imported.yml6
-rw-r--r--config/metrics/counts_all/20210216180638_gitlab_project.yml6
-rw-r--r--config/metrics/counts_all/20210216180639_gitlab.yml6
-rw-r--r--config/metrics/counts_all/20210216180641_github.yml6
-rw-r--r--config/metrics/counts_all/20210216180643_bitbucket.yml6
-rw-r--r--config/metrics/counts_all/20210216180645_bitbucket_server.yml6
-rw-r--r--config/metrics/counts_all/20210216180647_gitea.yml6
-rw-r--r--config/metrics/counts_all/20210216180649_git.yml6
-rw-r--r--config/metrics/counts_all/20210216180650_manifest.yml6
-rw-r--r--config/metrics/counts_all/20210216180652_gitlab_migration.yml6
-rw-r--r--config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml2
-rw-r--r--config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml21
-rw-r--r--config/routes/admin.rb1
-rw-r--r--doc/api/graphql/reference/index.md6
-rw-r--r--doc/api/project_snippets.md2
-rw-r--r--doc/development/usage_ping/dictionary.md102
-rw-r--r--doc/update/index.md6
-rw-r--r--doc/user/analytics/ci_cd_analytics.md23
-rw-r--r--lib/api/commit_statuses.rb6
-rw-r--r--lib/gitlab/database/background_migration/batched_job.rb2
-rw-r--r--lib/gitlab/database/background_migration/batched_migration.rb10
-rw-r--r--lib/gitlab/email/message/in_product_marketing.rb4
-rw-r--r--lib/gitlab/email/message/in_product_marketing/base.rb13
-rw-r--r--lib/gitlab/email/message/in_product_marketing/experience.rb80
-rw-r--r--lib/gitlab/gon_helper.rb1
-rw-r--r--lib/gitlab/usage_data.rb5
-rw-r--r--locale/gitlab.pot39
-rw-r--r--qa/qa/resource/group_base.rb24
-rw-r--r--qa/qa/specs/features/browser_ui/1_manage/group/bulk_import_group_spec.rb4
-rw-r--r--spec/factories/projects.rb2
-rw-r--r--spec/factories_spec.rb2
-rw-r--r--spec/features/admin/admin_sees_background_migrations_spec.rb84
-rw-r--r--spec/features/profiles/user_edit_profile_spec.rb2
-rw-r--r--spec/fixtures/product_intelligence/survey_response_schema.json8
-rw-r--r--spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js20
-rw-r--r--spec/helpers/admin/background_migrations_helper_spec.rb67
-rw-r--r--spec/helpers/issues_helper_spec.rb2
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_job_spec.rb10
-rw-r--r--spec/lib/gitlab/database/background_migration/batched_migration_spec.rb32
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb11
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb3
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/experience_spec.rb64
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb3
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb3
-rw-r--r--spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb3
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb6
-rw-r--r--spec/mailers/emails/in_product_marketing_spec.rb36
-rw-r--r--spec/models/namespace_spec.rb6
-rw-r--r--spec/models/onboarding_progress_spec.rb22
-rw-r--r--spec/models/project_spec.rb4
-rw-r--r--spec/requests/api/commit_statuses_spec.rb66
-rw-r--r--spec/requests/api/project_repository_storage_moves_spec.rb2
-rw-r--r--spec/requests/groups/email_campaigns_controller_spec.rb9
-rw-r--r--spec/services/namespaces/in_product_marketing_emails_service_spec.rb29
-rw-r--r--spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb2
-rw-r--r--spec/services/projects/transfer_service_spec.rb2
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb2
-rw-r--r--spec/workers/project_schedule_bulk_repository_shard_moves_worker_spec.rb2
-rw-r--r--spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb2
98 files changed, 1083 insertions, 323 deletions
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 5decc83da2b..6f33057a057 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -111,8 +111,8 @@ review-stop:
.review-qa-base:
extends:
- - .default-retry
- .use-docker-in-docker
+ retry: 1 # This is confusing but this means "2 runs at max".
image: registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7
stage: qa
needs: ["review-deploy"]
diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml
index e5cb55488d7..b301a54e6ac 100644
--- a/.rubocop_manual_todo.yml
+++ b/.rubocop_manual_todo.yml
@@ -14,7 +14,6 @@
Graphql/Descriptions:
Exclude:
- 'app/graphql/types/snippets/blob_action_enum.rb'
- - 'app/graphql/types/snippets/visibility_scopes_enum.rb'
- 'ee/app/graphql/ee/types/list_limit_metric_enum.rb'
- 'ee/app/graphql/types/epic_state_enum.rb'
- 'ee/app/graphql/types/health_status_enum.rb'
diff --git a/Gemfile.lock b/Gemfile.lock
index f6d6e07d3a3..fcf5acf6c29 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -622,7 +622,7 @@ GEM
http-cookie (1.0.3)
domain_name (~> 0.5)
http-form_data (2.3.0)
- http-parser (1.2.1)
+ http-parser (1.2.3)
ffi-compiler (>= 1.0, < 2.0)
httparty (0.16.4)
mime-types (~> 3.0)
diff --git a/app/assets/images/mailers/in_product_marketing/experience-0.png b/app/assets/images/mailers/in_product_marketing/experience-0.png
new file mode 100644
index 00000000000..346204d1db1
--- /dev/null
+++ b/app/assets/images/mailers/in_product_marketing/experience-0.png
Binary files differ
diff --git a/app/assets/javascripts/emoji/components/picker.vue b/app/assets/javascripts/emoji/components/picker.vue
index e08d294b8c5..35f0a1a3818 100644
--- a/app/assets/javascripts/emoji/components/picker.vue
+++ b/app/assets/javascripts/emoji/components/picker.vue
@@ -23,6 +23,11 @@ export default {
required: false,
default: () => [],
},
+ dropdownClass: {
+ type: [Array, String, Object],
+ required: false,
+ default: () => [],
+ },
},
data() {
return {
@@ -78,6 +83,7 @@ export default {
ref="dropdown"
:toggle-class="toggleClass"
:boundary="getBoundaryElement()"
+ :class="dropdownClass"
menu-class="dropdown-extended-height"
category="tertiary"
no-flip
diff --git a/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue b/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue
index 93d8bcc4c19..11e9b25f9a3 100644
--- a/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue
+++ b/app/assets/javascripts/integrations/edit/components/jira_trigger_fields.vue
@@ -37,7 +37,7 @@ const issueTransitionOptions = [
help: s__(
'JiraService|Automatically transitions Jira issues to the "Done" category. %{linkStart}Learn more%{linkEnd}',
),
- link: helpPagePath('user/project/integrations/jira.html', {
+ link: helpPagePath('integration/jira/index.html', {
anchor: 'automatic-issue-transitions',
}),
},
@@ -47,7 +47,7 @@ const issueTransitionOptions = [
help: s__(
'JiraService|Set a custom final state by using transition IDs. %{linkStart}Learn about transition IDs%{linkEnd}',
),
- link: helpPagePath('user/project/integrations/jira.html', {
+ link: helpPagePath('integration/jira/index.html', {
anchor: 'custom-issue-transitions',
}),
},
diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
index c754af5c7de..758a799b37f 100644
--- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
+++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue
@@ -18,6 +18,7 @@ import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants';
import { __, s__, sprintf } from '~/locale';
import { updateUserStatus } from '~/rest_api';
import { timeRanges } from '~/vue_shared/constants';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import EmojiMenuInModal from './emoji_menu_in_modal';
import { isUserBusy } from './utils';
@@ -44,10 +45,12 @@ export default {
GlFormCheckbox,
GlDropdown,
GlDropdownItem,
+ EmojiPicker: () => import('~/emoji/components/picker.vue'),
},
directives: {
GlTooltip: GlTooltipDirective,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
defaultEmoji: {
type: String,
@@ -102,7 +105,9 @@ export default {
this.$root.$emit(BV_SHOW_MODAL, this.modalId);
},
beforeDestroy() {
- this.emojiMenu.destroy();
+ if (this.emojiMenu) {
+ this.emojiMenu.destroy();
+ }
},
methods: {
closeModal() {
@@ -121,13 +126,16 @@ export default {
this.noEmoji = this.emoji === '';
this.defaultEmojiTag = Emoji.glEmojiTag(this.defaultEmoji);
- this.emojiMenu = new EmojiMenuInModal(
- Emoji,
- toggleEmojiMenuButtonSelector,
- emojiMenuClass,
- this.setEmoji,
- this.$refs.userStatusForm,
- );
+ if (!this.glFeatures.improvedEmojiPicker) {
+ this.emojiMenu = new EmojiMenuInModal(
+ Emoji,
+ toggleEmojiMenuButtonSelector,
+ emojiMenuClass,
+ this.setEmoji,
+ this.$refs.userStatusForm,
+ );
+ }
+
this.setDefaultEmoji();
})
.catch(() => createFlash(__('Failed to load emoji list.')));
@@ -164,7 +172,12 @@ export default {
this.emoji = emoji;
this.noEmoji = false;
this.clearEmoji();
- this.emojiTag = emojiTag;
+
+ if (this.glFeatures.improvedEmojiPicker) {
+ this.emojiTag = Emoji.glEmojiTag(this.emoji);
+ } else {
+ this.emojiTag = emojiTag;
+ }
},
clearEmoji() {
if (this.emojiTag) {
@@ -241,7 +254,26 @@ export default {
<div ref="userStatusForm" class="form-group position-relative m-0">
<div class="input-group gl-mb-5">
<span class="input-group-prepend">
+ <emoji-picker
+ v-if="glFeatures.improvedEmojiPicker"
+ dropdown-class="gl-h-full"
+ toggle-class="btn emoji-menu-toggle-button gl-px-4! gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
+ @click="setEmoji"
+ >
+ <template #button-content>
+ <span v-html="emojiTag"></span>
+ <span
+ v-show="noEmoji"
+ class="js-no-emoji-placeholder no-emoji-placeholder position-relative"
+ >
+ <gl-icon name="slight-smile" class="award-control-icon-neutral" />
+ <gl-icon name="smiley" class="award-control-icon-positive" />
+ <gl-icon name="smile" class="award-control-icon-super-positive" />
+ </span>
+ </template>
+ </emoji-picker>
<button
+ v-else
ref="toggleEmojiMenuButton"
v-gl-tooltip.bottom.hover
:title="s__('SetStatusModal|Add status emoji')"
diff --git a/app/controllers/admin/background_migrations_controller.rb b/app/controllers/admin/background_migrations_controller.rb
new file mode 100644
index 00000000000..c1dffbf423d
--- /dev/null
+++ b/app/controllers/admin/background_migrations_controller.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class Admin::BackgroundMigrationsController < Admin::ApplicationController
+ feature_category :database
+
+ def index
+ @relations_by_tab = {
+ 'queued' => batched_migration_class.queued.queue_order,
+ 'failed' => batched_migration_class.failed.queue_order,
+ 'finished' => batched_migration_class.finished.queue_order.reverse_order
+ }
+
+ @current_tab = @relations_by_tab.key?(params[:tab]) ? params[:tab] : 'queued'
+ @migrations = @relations_by_tab[@current_tab].page(params[:page])
+ @successful_rows_counts = batched_migration_class.successful_rows_counts(@migrations.map(&:id))
+ end
+
+ private
+
+ def batched_migration_class
+ Gitlab::Database::BackgroundMigration::BatchedMigration
+ end
+end
diff --git a/app/controllers/groups/email_campaigns_controller.rb b/app/controllers/groups/email_campaigns_controller.rb
index c1e3ce519cc..8ebb15559f0 100644
--- a/app/controllers/groups/email_campaigns_controller.rb
+++ b/app/controllers/groups/email_campaigns_controller.rb
@@ -16,7 +16,7 @@ class Groups::EmailCampaignsController < Groups::ApplicationController
def track_click
if Gitlab.com?
- message = Gitlab::Email::Message::InProductMarketing.for(@track).new(group: group, series: @series)
+ message = Gitlab::Email::Message::InProductMarketing.for(@track).new(group: group, user: current_user, series: @series)
data = {
namespace_id: group.id,
@@ -58,8 +58,9 @@ class Groups::EmailCampaignsController < Groups::ApplicationController
@series = params[:series]&.to_i
track_valid = @track.in?(Namespaces::InProductMarketingEmailsService::TRACKS.keys)
- series_valid = @series.in?(0..Namespaces::InProductMarketingEmailsService::INTERVAL_DAYS.size - 1)
+ return render_404 unless track_valid
- render_404 unless track_valid && series_valid
+ series_valid = @series.in?(0..Namespaces::InProductMarketingEmailsService::TRACKS[@track][:interval_days].size - 1)
+ render_404 unless series_valid
end
end
diff --git a/app/controllers/jira_connect/app_descriptor_controller.rb b/app/controllers/jira_connect/app_descriptor_controller.rb
index 137f830e40b..a6415daef68 100644
--- a/app/controllers/jira_connect/app_descriptor_controller.rb
+++ b/app/controllers/jira_connect/app_descriptor_controller.rb
@@ -39,7 +39,7 @@ class JiraConnect::AppDescriptorController < JiraConnect::ApplicationController
private
HOME_URL = 'https://gitlab.com'
- DOC_URL = 'https://docs.gitlab.com/ee/user/project/integrations/jira.html#gitlab-jira-integration'
+ DOC_URL = 'https://docs.gitlab.com/ee/integration/jira/'
def modules
modules = {
diff --git a/app/graphql/types/snippets/visibility_scopes_enum.rb b/app/graphql/types/snippets/visibility_scopes_enum.rb
index 5488e05b95d..ddcc005eaf2 100644
--- a/app/graphql/types/snippets/visibility_scopes_enum.rb
+++ b/app/graphql/types/snippets/visibility_scopes_enum.rb
@@ -3,9 +3,9 @@
module Types
module Snippets
class VisibilityScopesEnum < BaseEnum
- value 'private', value: 'are_private'
- value 'internal', value: 'are_internal'
- value 'public', value: 'are_public'
+ value 'private', description: 'The snippet is visible only to the snippet creator.', value: 'are_private'
+ value 'internal', description: 'The snippet is visible for any logged in user except external users.', value: 'are_internal'
+ value 'public', description: 'The snippet can be accessed without any authentication.', value: 'are_public'
end
end
end
diff --git a/app/helpers/admin/background_migrations_helper.rb b/app/helpers/admin/background_migrations_helper.rb
new file mode 100644
index 00000000000..698d81cc8a2
--- /dev/null
+++ b/app/helpers/admin/background_migrations_helper.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+module Admin
+ module BackgroundMigrationsHelper
+ def batched_migration_status_badge_class_name(migration)
+ class_names = {
+ 'active' => 'badge-info',
+ 'paused' => 'badge-warning',
+ 'failed' => 'badge-danger',
+ 'finished' => 'badge-success'
+ }
+
+ class_names[migration.status]
+ end
+
+ # The extra logic here is needed because total_tuple_count is just
+ # an estimate and completed_rows also does not account for last jobs
+ # whose batch size is likely larger than the actual number of rows processed
+ def batched_migration_progress(migration, completed_rows)
+ return 100 if migration.finished?
+ return 0 unless completed_rows.to_i > 0
+ return unless migration.total_tuple_count.to_i > 0
+
+ [100 * completed_rows / migration.total_tuple_count, 99].min
+ end
+ end
+end
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 1449725fb2b..80b8b5922e6 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -197,7 +197,7 @@ module IssuesHelper
initial_email: project.new_issuable_address(current_user, 'issue'),
is_signed_in: current_user.present?.to_s,
issues_path: project_issues_path(project),
- jira_integration_path: help_page_url('user/project/integrations/jira', anchor: 'view-jira-issues'),
+ jira_integration_path: help_page_url('integration/jira/', anchor: 'view-jira-issues'),
markdown_help_path: help_page_path('user/markdown'),
max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes),
new_issue_path: new_project_issue_path(project, issue: { assignee_id: finder.assignee.try(:id), milestone_id: finder.milestones.first.try(:id) }),
diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb
index aab1a44bdfb..f03c4356015 100644
--- a/app/helpers/nav_helper.rb
+++ b/app/helpers/nav_helper.rb
@@ -61,7 +61,7 @@ module NavHelper
end
def admin_monitoring_nav_links
- %w(system_info background_jobs health_check requests_profiles)
+ %w(system_info background_migrations background_jobs health_check requests_profiles)
end
def admin_analytics_nav_links
diff --git a/app/mailers/emails/in_product_marketing.rb b/app/mailers/emails/in_product_marketing.rb
index 97243660512..e745cd51a55 100644
--- a/app/mailers/emails/in_product_marketing.rb
+++ b/app/mailers/emails/in_product_marketing.rb
@@ -14,8 +14,9 @@ module Emails
def in_product_marketing_email(recipient_id, group_id, track, series)
group = Group.find(group_id)
- email = User.find(recipient_id).notification_email_for(group)
- @message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, series: series)
+ user = User.find(recipient_id)
+ email = user.notification_email_for(group)
+ @message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, user: user, series: series)
mail_to(to: email, subject: @message.subject_line)
end
diff --git a/app/models/onboarding_progress.rb b/app/models/onboarding_progress.rb
index be76c3dbf9d..9185547d7cd 100644
--- a/app/models/onboarding_progress.rb
+++ b/app/models/onboarding_progress.rb
@@ -85,6 +85,10 @@ class OnboardingProgress < ApplicationRecord
end
end
+ def number_of_completed_actions
+ attributes.extract!(*ACTIONS.map { |action| self.class.column_name(action).to_s }).compact!.size
+ end
+
private
def namespace_is_root_namespace
diff --git a/app/models/users/in_product_marketing_email.rb b/app/models/users/in_product_marketing_email.rb
index 195cfe162ac..3e5e7b259d8 100644
--- a/app/models/users/in_product_marketing_email.rb
+++ b/app/models/users/in_product_marketing_email.rb
@@ -18,7 +18,8 @@ module Users
create: 0,
verify: 1,
trial: 2,
- team: 3
+ team: 3,
+ experience: 4
}, _suffix: true
scope :without_track_and_series, -> (track, series) do
diff --git a/app/services/namespaces/in_product_marketing_emails_service.rb b/app/services/namespaces/in_product_marketing_emails_service.rb
index 61d5ed3bdf4..3461362b48c 100644
--- a/app/services/namespaces/in_product_marketing_emails_service.rb
+++ b/app/services/namespaces/in_product_marketing_emails_service.rb
@@ -4,17 +4,37 @@ module Namespaces
class InProductMarketingEmailsService
include Gitlab::Experimentation::GroupTypes
- INTERVAL_DAYS = [1, 5, 10].freeze
TRACKS = {
- create: :git_write,
- verify: :pipeline_created,
- trial: :trial_started,
- team: :user_added
+ create: {
+ interval_days: [1, 5, 10],
+ completed_actions: [:created],
+ incomplete_actions: [:git_write]
+ },
+ verify: {
+ interval_days: [1, 5, 10],
+ completed_actions: [:git_write],
+ incomplete_actions: [:pipeline_created]
+ },
+ trial: {
+ interval_days: [1, 5, 10],
+ completed_actions: [:git_write, :pipeline_created],
+ incomplete_actions: [:trial_started]
+ },
+ team: {
+ interval_days: [1, 5, 10],
+ completed_actions: [:git_write, :pipeline_created, :trial_started],
+ incomplete_actions: [:user_added]
+ },
+ experience: {
+ interval_days: [30],
+ completed_actions: [:created, :git_write],
+ incomplete_actions: []
+ }
}.freeze
def self.send_for_all_tracks_and_intervals
TRACKS.each_key do |track|
- INTERVAL_DAYS.each do |interval|
+ TRACKS[track][:interval_days].each do |interval|
new(track, interval).execute
end
end
@@ -69,7 +89,7 @@ module Namespaces
def groups_for_track
onboarding_progress_scope = OnboardingProgress
.completed_actions_with_latest_in_range(completed_actions, range)
- .incomplete_actions(incomplete_action)
+ .incomplete_actions(incomplete_actions)
# Filtering out sub-groups is a temporary fix to prevent calling
# `.root_ancestor` on groups that are not root groups.
@@ -103,6 +123,8 @@ module Namespaces
user.can?(:start_trial, group)
when :team
user.can?(:admin_group_member, group)
+ when :experience
+ true
end
end
@@ -111,8 +133,7 @@ module Namespaces
end
def completed_actions
- index = TRACKS.keys.index(track)
- index == 0 ? [:created] : TRACKS.values[0..index - 1]
+ TRACKS[track][:completed_actions]
end
def range
@@ -120,12 +141,12 @@ module Namespaces
date.beginning_of_day..date.end_of_day
end
- def incomplete_action
- TRACKS[track]
+ def incomplete_actions
+ TRACKS[track][:incomplete_actions]
end
def series
- INTERVAL_DAYS.index(interval)
+ TRACKS[track][:interval_days].index(interval)
end
def save_tracked_emails!
diff --git a/app/views/admin/background_migrations/_migration.html.haml b/app/views/admin/background_migrations/_migration.html.haml
new file mode 100644
index 00000000000..40860ea9400
--- /dev/null
+++ b/app/views/admin/background_migrations/_migration.html.haml
@@ -0,0 +1,10 @@
+%tr{ role: 'row' }
+ %td{ role: 'cell', data: { label: _('Migration') } }= migration.job_class_name + ': ' + migration.table_name
+ %td{ role: 'cell', data: { label: _('Progress') } }
+ - progress = batched_migration_progress(migration, @successful_rows_counts[migration.id])
+ - if progress
+ = number_to_percentage(progress, precision: 2)
+ - else
+ = _('Unknown')
+ %td{ role: 'cell', data: { label: _('Status') } }
+ %span.badge.badge-pill.gl-badge.sm{ class: batched_migration_status_badge_class_name(migration) }= migration.status.humanize
diff --git a/app/views/admin/background_migrations/index.html.haml b/app/views/admin/background_migrations/index.html.haml
new file mode 100644
index 00000000000..2a372c89912
--- /dev/null
+++ b/app/views/admin/background_migrations/index.html.haml
@@ -0,0 +1,35 @@
+- page_title _('Background Migrations')
+
+.tabs.gl-tabs
+ %div
+ %ul.nav.gl-tabs-nav{ role: 'tablist' }
+ - active_tab_classes = ['gl-tab-nav-item-active', 'gl-tab-nav-item-active-indigo']
+
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link.gl-tab-nav-item{ href: admin_background_migrations_path, class: (active_tab_classes if @current_tab == 'queued'), role: 'tab' }
+ = _('Queued')
+ %span.badge.gl-tab-counter-badge.badge-muted.badge-pill.gl-badge.sm
+ = limited_counter_with_delimiter(@relations_by_tab['queued'])
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link.gl-tab-nav-item{ href: admin_background_migrations_path(tab: 'failed'), class: (active_tab_classes if @current_tab == 'failed'), role: 'tab' }
+ = _('Failed')
+ %span.badge.gl-tab-counter-badge.badge-muted.badge-pill.gl-badge.sm
+ = limited_counter_with_delimiter(@relations_by_tab['failed'])
+ %li.nav-item{ role: 'presentation' }
+ %a.nav-link.gl-tab-nav-item{ href: admin_background_migrations_path(tab: 'finished'), class: (active_tab_classes if @current_tab == 'finished'), role: 'tab' }
+ = _('Finished')
+ %span.badge.gl-tab-counter-badge.badge-muted.badge-pill.gl-badge.sm
+ = limited_counter_with_delimiter(@relations_by_tab['finished'])
+
+ .tab-content.gl-tab-content
+ .tab-pane.active{ role: 'tabpanel' }
+ %table.table.b-table.gl-table.b-table-stacked-md{ role: 'table' }
+ %thead{ role: 'rowgroup' }
+ %tr{ role: 'row' }
+ %th.table-th-transparent.border-bottom{ role: 'cell' }= _('Migration')
+ %th.table-th-transparent.border-bottom{ role: 'cell' }= _('Progress')
+ %th.table-th-transparent.border-bottom{ role: 'cell' }= _('Status')
+ %tbody{ role: 'rowgroup' }
+ = render partial: 'migration', collection: @migrations
+
+ = paginate_collection @migrations
diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml
index b71866c9138..a7263ae2576 100644
--- a/app/views/layouts/nav/sidebar/_admin.html.haml
+++ b/app/views/layouts/nav/sidebar/_admin.html.haml
@@ -78,7 +78,7 @@
= _('Monitoring')
%ul.sidebar-sub-level-items{ data: { qa_selector: 'admin_sidebar_monitoring_submenu_content' } }
- = nav_link(controller: %w(system_info background_jobs health_check requests_profiles), html_options: { class: "fly-out-top-item" } ) do
+ = nav_link(controller: admin_monitoring_nav_links, html_options: { class: "fly-out-top-item" } ) do
= link_to admin_system_info_path do
%strong.fly-out-top-item-name
= _('Monitoring')
@@ -87,6 +87,10 @@
= link_to admin_system_info_path, title: _('System Info') do
%span
= _('System Info')
+ = nav_link(controller: :background_migrations) do
+ = link_to admin_background_migrations_path, title: _('Background Migrations') do
+ %span
+ = _('Background Migrations')
= nav_link(controller: :background_jobs) do
= link_to admin_background_jobs_path, title: _('Background Jobs') do
%span
diff --git a/app/views/notify/in_product_marketing_email.html.haml b/app/views/notify/in_product_marketing_email.html.haml
index a1c3ecfb87e..45b002757e3 100644
--- a/app/views/notify/in_product_marketing_email.html.haml
+++ b/app/views/notify/in_product_marketing_email.html.haml
@@ -184,9 +184,32 @@
- @message.body_line2&.tap do |line|
%p{ style: "margin: 0 0 20px 0;" }
= line.html_safe
- %tr
- %td{ align: "center", style: "padding: 10px 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
- .cta_link= @message.cta_link
+ - if @message.cta_text
+ %tr
+ %td{ align: "center", style: "padding: 10px 20px 80px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif;" }
+ .cta_link= @message.cta_link
+ - else
+ %tr
+ %td{ style: "padding: 10px 20px 10px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 16px; line-height: 20px;" }
+ %table{ border: "0", cellpadding: "0", cellspacing: "0", width: "100%", style: "width: 100%; min-width: 100%;" }
+ %tr
+ %td{ width: "50%", style: "width: 50%; min-width: 50%; color: #000000; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; font-size: 16px; line-height: 100%; padding-bottom: 16px; text-align: left;", align: "left" }
+ = @message.feedback_ratings(1)
+ %td{ width: "50%", style: "width: 50%; min-width: 50%; color: #000000; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; font-size: 16px; line-height: 100%; padding-bottom: 16px; text-align: right;", align: "right" }
+ = @message.feedback_ratings(5)
+ %tr
+ %td{ align: "center", style: "padding: 10px 1px 30px 1px;" }
+ %table{ align: "center", cellpadding: "5", cellspacing: "0", width: "100%", style: "width: 100%; min-width: 100%; border: 1px solid #dae0ea; border-radius: 0; min-width: 100%; text-align: center; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; font-size: 16px;" }
+ %tr
+ - (1..5).each do |rating|
+ %td{ height: "54", style: "border-left: 1px solid #dae0ea; padding-bottom: 0; width: 9% !important;", width: "9%" }
+ %a{ href: @message.feedback_link(rating), style: "color: #424242; display: block; text-decoration: none;" }
+ %span{ height: "54", style: "display: block; font-size: 18px; height: 22px; line-height: 22px; padding: 16px 0; width: 100%; text-decoration: none;" }
+ = rating
+ %tr
+ %td{ style: "padding: 10px 20px 30px 20px; font-family: 'Source Sans Pro', helvetica, arial, sans-serif; color:#000000; font-size: 18px; line-height: 24px;" }
+ %p{ style: "margin: 0 0 50px 0;" }
+ = @message.feedback_thanks
%tr{ style: "background-color: #ffffff;" }
%td{ align: "center", style: "padding:75px 20px 25px;" }
= about_link('gitlab_logo.png', 80)
diff --git a/app/views/notify/in_product_marketing_email.text.erb b/app/views/notify/in_product_marketing_email.text.erb
index 7d0fe7aec6d..6f0a2efa410 100644
--- a/app/views/notify/in_product_marketing_email.text.erb
+++ b/app/views/notify/in_product_marketing_email.text.erb
@@ -8,10 +8,19 @@
<%= @message.body_line2 %>
+<% if @message.cta_text %>
<%= @message.cta_link %>
+<% else %>
+<% (1..5).each do |rating| %>
+<%= "#{rating} - #{@message.feedback_ratings(rating).upcase} - #{@message.feedback_link(rating)}" %>
+<% end %>
+
+
+<%= @message.feedback_thanks %>
+<% end %>
diff --git a/changelogs/unreleased/326760-batched-migrations-admin-panel.yml b/changelogs/unreleased/326760-batched-migrations-admin-panel.yml
new file mode 100644
index 00000000000..d24e92f3952
--- /dev/null
+++ b/changelogs/unreleased/326760-batched-migrations-admin-panel.yml
@@ -0,0 +1,5 @@
+---
+title: Add admin page for batched background migrations
+merge_request: 60911
+author:
+type: added
diff --git a/changelogs/unreleased/326791-removing-redundant-update.yml b/changelogs/unreleased/326791-removing-redundant-update.yml
new file mode 100644
index 00000000000..1e57b2f2517
--- /dev/null
+++ b/changelogs/unreleased/326791-removing-redundant-update.yml
@@ -0,0 +1,5 @@
+---
+title: Remove the redundant update for API endpoint projects/:id/statuses/:sha
+merge_request: 61470
+author:
+type: performance
diff --git a/changelogs/unreleased/add-ease-score-onboarding-email.yml b/changelogs/unreleased/add-ease-score-onboarding-email.yml
new file mode 100644
index 00000000000..7be2a70f89c
--- /dev/null
+++ b/changelogs/unreleased/add-ease-score-onboarding-email.yml
@@ -0,0 +1,5 @@
+---
+title: Add ease score onboarding in-product marketing email
+merge_request: 61347
+author:
+type: changed
diff --git a/config/metrics/counts_28d/20210216183638_unique_users_all_imports.yml b/config/metrics/counts_28d/20210216183638_unique_users_all_imports.yml
index 6651dfa0146..670b8d555d8 100644
--- a/config/metrics/counts_28d/20210216183638_unique_users_all_imports.yml
+++ b/config/metrics/counts_28d/20210216183638_unique_users_all_imports.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.unique_users_all_imports
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+description: Number of users from projects imported
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183644_gitlab_project.yml b/config/metrics/counts_28d/20210216183644_gitlab_project.yml
index 166be23baac..03c2d993a6c 100644
--- a/config/metrics/counts_28d/20210216183644_gitlab_project.yml
+++ b/config/metrics/counts_28d/20210216183644_gitlab_project.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.gitlab_project
description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183646_gitlab.yml b/config/metrics/counts_28d/20210216183646_gitlab.yml
index 25bb788cc4f..5cfad29d4a1 100644
--- a/config/metrics/counts_28d/20210216183646_gitlab.yml
+++ b/config/metrics/counts_28d/20210216183646_gitlab.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.gitlab
description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183648_github.yml b/config/metrics/counts_28d/20210216183648_github.yml
index 6f79b49a37f..124ae696d68 100644
--- a/config/metrics/counts_28d/20210216183648_github.yml
+++ b/config/metrics/counts_28d/20210216183648_github.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.github
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Count of projects imported from GitHub
+product_section: dev
+product_stage: manage
+product_group: group::import
+product_category:
value_type: number
status: data_available
-time_frame: 28d
-data_source:
+time_frame: all
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183650_bitbucket.yml b/config/metrics/counts_28d/20210216183650_bitbucket.yml
index fc31e325278..9d8b9374e3f 100644
--- a/config/metrics/counts_28d/20210216183650_bitbucket.yml
+++ b/config/metrics/counts_28d/20210216183650_bitbucket.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.bitbucket
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Count of projects imported from Bitbucket
+product_section: dev
+product_stage: manage
+product_group: group::import
+product_category:
value_type: number
status: data_available
-time_frame: 28d
-data_source:
+time_frame: all
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183652_bitbucket_server.yml b/config/metrics/counts_28d/20210216183652_bitbucket_server.yml
index fd0b64933b1..e84adc3aba8 100644
--- a/config/metrics/counts_28d/20210216183652_bitbucket_server.yml
+++ b/config/metrics/counts_28d/20210216183652_bitbucket_server.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.bitbucket_server
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Count of projects imported from Bitbucket Server
+product_section: dev
+product_stage: manage
+product_group: group::import
+product_category:
value_type: number
status: data_available
-time_frame: 28d
-data_source:
+time_frame: all
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183653_gitea.yml b/config/metrics/counts_28d/20210216183653_gitea.yml
index a09fdc9d610..46087d194da 100644
--- a/config/metrics/counts_28d/20210216183653_gitea.yml
+++ b/config/metrics/counts_28d/20210216183653_gitea.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.gitea
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Count of projects imported from Gitea
+product_section: dev
+product_stage: manage
+product_group: group::import
+product_category:
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183655_git.yml b/config/metrics/counts_28d/20210216183655_git.yml
index b17900f534d..e0f3a1da4e1 100644
--- a/config/metrics/counts_28d/20210216183655_git.yml
+++ b/config/metrics/counts_28d/20210216183655_git.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.git
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+description: Count of projects imported from Git
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183657_manifest.yml b/config/metrics/counts_28d/20210216183657_manifest.yml
index 49fcefb3a45..3bc9b639a59 100644
--- a/config/metrics/counts_28d/20210216183657_manifest.yml
+++ b/config/metrics/counts_28d/20210216183657_manifest.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.manifest
description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183659_gitlab_migration.yml b/config/metrics/counts_28d/20210216183659_gitlab_migration.yml
index 700fe4b4881..1304ea7b166 100644
--- a/config/metrics/counts_28d/20210216183659_gitlab_migration.yml
+++ b/config/metrics/counts_28d/20210216183659_gitlab_migration.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.project_imports.gitlab_migration
description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183709_group_import.yml b/config/metrics/counts_28d/20210216183709_group_import.yml
index 9116a242811..eca3eada4d4 100644
--- a/config/metrics/counts_28d/20210216183709_group_import.yml
+++ b/config/metrics/counts_28d/20210216183709_group_import.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.group_imports.group_import
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+description: Number of group import states
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: data_available
time_frame: 28d
-data_source:
+data_source: database
distribution:
-- ce
+ - ce
+ - ee
tier:
-- free
-skip_validation: true
+ - free
+ - premium
+ - ultimate
diff --git a/config/metrics/counts_28d/20210216183720_bitbucket.yml b/config/metrics/counts_28d/20210216183720_bitbucket.yml
index e05c607f202..b3b34c95800 100644
--- a/config/metrics/counts_28d/20210216183720_bitbucket.yml
+++ b/config/metrics/counts_28d/20210216183720_bitbucket.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.projects_imported.bitbucket
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
-product_category: ''
+description: Count of projects imported from Bitbucket
+product_section: dev
+product_stage: manage
+product_group: group::import
+product_category:
value_type: number
status: deprecated
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183722_bitbucket_server.yml b/config/metrics/counts_28d/20210216183722_bitbucket_server.yml
index c7f2a18f1b1..1a8ace962e0 100644
--- a/config/metrics/counts_28d/20210216183722_bitbucket_server.yml
+++ b/config/metrics/counts_28d/20210216183722_bitbucket_server.yml
@@ -1,16 +1,18 @@
---
key_path: usage_activity_by_stage_monthly.manage.projects_imported.bitbucket_server
-description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+description: Count of projects imported from Bitbucket Server
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: deprecated
time_frame: 28d
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_28d/20210216183737_groups_imported.yml b/config/metrics/counts_28d/20210216183737_groups_imported.yml
index 3b668e6cac6..10ffa325a11 100644
--- a/config/metrics/counts_28d/20210216183737_groups_imported.yml
+++ b/config/metrics/counts_28d/20210216183737_groups_imported.yml
@@ -1,9 +1,9 @@
---
key_path: usage_activity_by_stage_monthly.manage.groups_imported
description: ''
-product_section: ''
-product_stage: ''
-product_group: ''
+product_section: dev
+product_stage: manage
+product_group: group::import
product_category: ''
value_type: number
status: deprecated
diff --git a/config/metrics/counts_all/20210216180638_gitlab_project.yml b/config/metrics/counts_all/20210216180638_gitlab_project.yml
index a9d167f7363..624b004155d 100644
--- a/config/metrics/counts_all/20210216180638_gitlab_project.yml
+++ b/config/metrics/counts_all/20210216180638_gitlab_project.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180639_gitlab.yml b/config/metrics/counts_all/20210216180639_gitlab.yml
index 3fef2ce3b85..39a878962d2 100644
--- a/config/metrics/counts_all/20210216180639_gitlab.yml
+++ b/config/metrics/counts_all/20210216180639_gitlab.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180641_github.yml b/config/metrics/counts_all/20210216180641_github.yml
index 530e9b05e14..c7ce1a7f1b3 100644
--- a/config/metrics/counts_all/20210216180641_github.yml
+++ b/config/metrics/counts_all/20210216180641_github.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180643_bitbucket.yml b/config/metrics/counts_all/20210216180643_bitbucket.yml
index 6490c8ffb55..e05e4e526ff 100644
--- a/config/metrics/counts_all/20210216180643_bitbucket.yml
+++ b/config/metrics/counts_all/20210216180643_bitbucket.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180645_bitbucket_server.yml b/config/metrics/counts_all/20210216180645_bitbucket_server.yml
index bfbee0b3433..88f618ac228 100644
--- a/config/metrics/counts_all/20210216180645_bitbucket_server.yml
+++ b/config/metrics/counts_all/20210216180645_bitbucket_server.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180647_gitea.yml b/config/metrics/counts_all/20210216180647_gitea.yml
index 74b4fd36714..d70b478659d 100644
--- a/config/metrics/counts_all/20210216180647_gitea.yml
+++ b/config/metrics/counts_all/20210216180647_gitea.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180649_git.yml b/config/metrics/counts_all/20210216180649_git.yml
index b7dd7ca8d7e..19c19e6cc63 100644
--- a/config/metrics/counts_all/20210216180649_git.yml
+++ b/config/metrics/counts_all/20210216180649_git.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180650_manifest.yml b/config/metrics/counts_all/20210216180650_manifest.yml
index 4ef7823ee67..6c89c68b34c 100644
--- a/config/metrics/counts_all/20210216180650_manifest.yml
+++ b/config/metrics/counts_all/20210216180650_manifest.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216180652_gitlab_migration.yml b/config/metrics/counts_all/20210216180652_gitlab_migration.yml
index 3df4472c9a7..d1c84d6c795 100644
--- a/config/metrics/counts_all/20210216180652_gitlab_migration.yml
+++ b/config/metrics/counts_all/20210216180652_gitlab_migration.yml
@@ -8,9 +8,11 @@ product_category:
value_type: number
status: data_available
time_frame: all
-data_source:
+data_source: database
distribution:
- ce
+- ee
tier:
- free
-skip_validation: true
+- premium
+- ultimate
diff --git a/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml b/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml
index 321273f800e..df04f5d0669 100644
--- a/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml
+++ b/config/metrics/counts_all/20210216181259_jira_imports_projects_count.yml
@@ -15,4 +15,4 @@ distribution:
tier:
- free
- premium
-- ultimate \ No newline at end of file
+- ultimate
diff --git a/config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml b/config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml
new file mode 100644
index 00000000000..816fee89f4c
--- /dev/null
+++ b/config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml
@@ -0,0 +1,21 @@
+---
+key_path: counts.in_product_marketing_email_experience_0_sent
+name: "count_sent_first_email_of_the_experience_track_for_in_product_marketing_emails"
+description: Total sent emails of the experience track's first email
+product_section:
+product_stage: growth
+product_group: group::activation
+product_category: onboarding
+value_type: number
+status: implemented
+milestone: "13.12"
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61347
+time_frame: all
+data_source: database
+distribution:
+- ce
+- ee
+tier:
+- free
+- premium
+- ultimate
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 2ba00e3bf66..e929bb297d3 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -95,6 +95,7 @@ namespace :admin do
get :instance_review, to: 'instance_review#index'
+ resources :background_migrations, only: [:index]
resource :health_check, controller: 'health_check', only: [:show]
resource :background_jobs, controller: 'background_jobs', only: [:show]
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index 7f496e1aded..792e10e85b7 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -14668,9 +14668,9 @@ Possible states of a user.
| Value | Description |
| ----- | ----------- |
-| <a id="visibilityscopesenuminternal"></a>`internal` | |
-| <a id="visibilityscopesenumprivate"></a>`private` | |
-| <a id="visibilityscopesenumpublic"></a>`public` | |
+| <a id="visibilityscopesenuminternal"></a>`internal` | The snippet is visible for any logged in user except external users. |
+| <a id="visibilityscopesenumprivate"></a>`private` | The snippet is visible only to the snippet creator. |
+| <a id="visibilityscopesenumpublic"></a>`public` | The snippet can be accessed without any authentication. |
### `VulnerabilityDismissalReason`
diff --git a/doc/api/project_snippets.md b/doc/api/project_snippets.md
index 070429eafd5..01ca5da3039 100644
--- a/doc/api/project_snippets.md
+++ b/doc/api/project_snippets.md
@@ -16,7 +16,7 @@ Constants for snippet visibility levels are:
| visibility | Description |
| ---------- | ----------- |
-| `private` | The snippet is visible only the snippet creator |
+| `private` | The snippet is visible only to the snippet creator |
| `internal` | The snippet is visible for any logged in user except [external users](../user/permissions.md#external-users) |
| `public` | The snippet can be accessed without any authentication |
diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md
index 75d65f8e5df..083520eccd3 100644
--- a/doc/development/usage_ping/dictionary.md
+++ b/doc/development/usage_ping/dictionary.md
@@ -2446,6 +2446,18 @@ Status: `implemented`
Tiers: `free`, `premium`, `ultimate`
+### `counts.in_product_marketing_email_experience_0_sent`
+
+Total sent emails of the experience track's first email
+
+[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_all/20210518081225_in_product_marketing_email_experience_0_sent.yml)
+
+Group: `group::activation`
+
+Status: `implemented`
+
+Tiers: `free`, `premium`, `ultimate`
+
### `counts.in_review_folder`
Missing description
@@ -16366,7 +16378,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.bitbucket_server`
@@ -16378,7 +16390,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.git`
@@ -16390,7 +16402,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.gitea`
@@ -16402,7 +16414,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.github`
@@ -16414,7 +16426,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.gitlab`
@@ -16426,7 +16438,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.gitlab_migration`
@@ -16438,7 +16450,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.gitlab_project`
@@ -16450,7 +16462,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.project_imports.manifest`
@@ -16462,7 +16474,7 @@ Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage.manage.projects_imported.bitbucket`
@@ -18088,15 +18100,15 @@ Tiers: `free`
### `usage_activity_by_stage_monthly.manage.group_imports.group_import`
-Missing description
+Number of group import states
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183709_group_import.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.group_saml_enabled`
@@ -18128,7 +18140,7 @@ Missing description
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183737_groups_imported.yml)
-Group: ``
+Group: `group::import`
Status: `deprecated`
@@ -18304,63 +18316,63 @@ Tiers: `free`
### `usage_activity_by_stage_monthly.manage.project_imports.bitbucket`
-Missing description
+Count of projects imported from Bitbucket
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183650_bitbucket.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.bitbucket_server`
-Missing description
+Count of projects imported from Bitbucket Server
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183652_bitbucket_server.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.git`
-Missing description
+Count of projects imported from Git
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183655_git.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.gitea`
-Missing description
+Count of projects imported from Gitea
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183653_gitea.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.github`
-Missing description
+Count of projects imported from GitHub
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183648_github.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.gitlab`
@@ -18368,11 +18380,11 @@ Missing description
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183646_gitlab.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.gitlab_migration`
@@ -18380,11 +18392,11 @@ Missing description
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183659_gitlab_migration.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.gitlab_project`
@@ -18392,11 +18404,11 @@ Missing description
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183644_gitlab_project.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.project_imports.manifest`
@@ -18404,35 +18416,35 @@ Missing description
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183657_manifest.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.projects_imported.bitbucket`
-Missing description
+Count of projects imported from Bitbucket
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183720_bitbucket.yml)
-Group: ``
+Group: `group::import`
Status: `deprecated`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.projects_imported.bitbucket_server`
-Missing description
+Count of projects imported from Bitbucket Server
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183722_bitbucket_server.yml)
-Group: ``
+Group: `group::import`
Status: `deprecated`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.projects_imported.git`
@@ -18532,15 +18544,15 @@ Tiers:
### `usage_activity_by_stage_monthly.manage.unique_users_all_imports`
-Missing description
+Number of users from projects imported
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/config/metrics/counts_28d/20210216183638_unique_users_all_imports.yml)
-Group: ``
+Group: `group::import`
Status: `data_available`
-Tiers: `free`
+Tiers: `free`, `premium`, `ultimate`
### `usage_activity_by_stage_monthly.manage.user_auth_by_provider.google_oauth2`
diff --git a/doc/update/index.md b/doc/update/index.md
index 4c4dfe79d03..693e5be38ed 100644
--- a/doc/update/index.md
+++ b/doc/update/index.md
@@ -342,10 +342,10 @@ possible.
## Version-specific upgrading instructions
-Each month, a major or minor release of GitLab is published along with a
+Each month, major, minor or patch releases of GitLab are published along with a
[release post](https://about.gitlab.com/releases/categories/releases/).
-You should check all the major and minor versions you're passing over.
-At the end of those release posts, there are three sections to look for:
+You should read the release posts for all versions you're passing over.
+At the end of major and minor release posts, there are three sections to look for specifically:
- Deprecations
- Removals
diff --git a/doc/user/analytics/ci_cd_analytics.md b/doc/user/analytics/ci_cd_analytics.md
index 284e87e9b35..b666b388eb8 100644
--- a/doc/user/analytics/ci_cd_analytics.md
+++ b/doc/user/analytics/ci_cd_analytics.md
@@ -4,12 +4,11 @@ group: Release
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
-# CI/CD Analytics
+# CI/CD Analytics **(FREE)**
-## Pipeline success and duration charts **(FREE)**
+## Pipeline success and duration charts
-> - Introduced in GitLab 3.1.1 as Commit Stats, and later renamed to Pipeline Charts.
-> - [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/38318) to CI/CD Analytics in GitLab 12.8.
+> [Renamed](https://gitlab.com/gitlab-org/gitlab/-/issues/38318) to CI/CD Analytics in GitLab 12.8.
GitLab tracks the history of your pipeline successes and failures, as well as how long each pipeline
ran. To view this information, go to **Analytics > CI/CD Analytics**.
@@ -48,14 +47,14 @@ performance indicators for software development teams:
The following table shows the supported metrics, at which level they are supported, and which GitLab version (API and UI) they were introduced:
-| Metric | Level | API version | Chart (UI) version | Comments |
-| --------------- | ----------- | --------------- | ---------- | ------- |
-| `deployment_frequency` | Project-level | [13.7+](../../api/dora/metrics.md) | [13.8+](#deployment-frequency-charts) | The [old API endpoint](../../api/dora4_project_analytics.md) was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.10. |
-| `deployment_frequency` | Group-level | [13.10+](../../api/dora/metrics.md) | To be supported | |
-| `lead_time_for_changes` | Project-level | [13.10+](../../api/dora/metrics.md) | [13.11+](#lead-time-charts) | Unit in seconds. Aggregation method is median. |
-| `lead_time_for_changes` | Group-level | [13.10+](../../api/dora/metrics.md) | To be supported | Unit in seconds. Aggregation method is median. |
-| `change_failure_rate` | Project/Group-level | To be supported | To be supported | |
-| `time_to_restore_service` | Project/Group-level | To be supported | To be supported | |
+| Metric | Level | API version | Chart (UI) version | Comments |
+|---------------------------|---------------------|--------------------------------------|---------------------------------------|-----------|
+| `deployment_frequency` | Project-level | [13.7+](../../api/dora/metrics.md) | [13.8+](#deployment-frequency-charts) | The [old API endpoint](../../api/dora4_project_analytics.md) was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.10. |
+| `deployment_frequency` | Group-level | [13.10+](../../api/dora/metrics.md) | To be supported | |
+| `lead_time_for_changes` | Project-level | [13.10+](../../api/dora/metrics.md) | [13.11+](#lead-time-charts) | Unit in seconds. Aggregation method is median. |
+| `lead_time_for_changes` | Group-level | [13.10+](../../api/dora/metrics.md) | To be supported | Unit in seconds. Aggregation method is median. |
+| `change_failure_rate` | Project/Group-level | To be supported | To be supported | |
+| `time_to_restore_service` | Project/Group-level | To be supported | To be supported | |
### Deployment frequency charts **(ULTIMATE)**
diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb
index e199111c975..27fee7fdea2 100644
--- a/lib/api/commit_statuses.rb
+++ b/lib/api/commit_statuses.rb
@@ -96,10 +96,8 @@ module API
protected: user_project.protected_for?(ref)
)
- optional_attributes =
- attributes_for_keys(%w[target_url description coverage])
-
- status.update(optional_attributes) if optional_attributes.any?
+ updatable_optional_attributes = %w[target_url description coverage]
+ status.assign_attributes(attributes_for_keys(updatable_optional_attributes))
if status.valid?
status.update_older_statuses_retried! if Feature.enabled?(:ci_fix_commit_status_retried, user_project, default_enabled: :yaml)
diff --git a/lib/gitlab/database/background_migration/batched_job.rb b/lib/gitlab/database/background_migration/batched_job.rb
index 869b97b8ac0..9a1dc4ee17d 100644
--- a/lib/gitlab/database/background_migration/batched_job.rb
+++ b/lib/gitlab/database/background_migration/batched_job.rb
@@ -30,7 +30,7 @@ module Gitlab
scope :successful_in_execution_order, -> { where.not(finished_at: nil).succeeded.order(:finished_at) }
- delegate :aborted?, :job_class, :table_name, :column_name, :job_arguments,
+ delegate :job_class, :table_name, :column_name, :job_arguments,
to: :batched_migration, prefix: :migration
attribute :pause_ms, :integer, default: 100
diff --git a/lib/gitlab/database/background_migration/batched_migration.rb b/lib/gitlab/database/background_migration/batched_migration.rb
index e85162f355e..bf666a24a5b 100644
--- a/lib/gitlab/database/background_migration/batched_migration.rb
+++ b/lib/gitlab/database/background_migration/batched_migration.rb
@@ -15,11 +15,11 @@ module Gitlab
foreign_key: :batched_background_migration_id
scope :queue_order, -> { order(id: :asc) }
+ scope :queued, -> { where(status: [:active, :paused]) }
enum status: {
paused: 0,
active: 1,
- aborted: 2,
finished: 3,
failed: 4
}
@@ -30,6 +30,14 @@ module Gitlab
active.queue_order.first
end
+ def self.successful_rows_counts(migrations)
+ BatchedJob
+ .succeeded
+ .where(batched_background_migration_id: migrations)
+ .group(:batched_background_migration_id)
+ .sum(:batch_size)
+ end
+
def interval_elapsed?(variance: 0)
return true unless last_job
diff --git a/lib/gitlab/email/message/in_product_marketing.rb b/lib/gitlab/email/message/in_product_marketing.rb
index d538238f26f..fb4315e74b2 100644
--- a/lib/gitlab/email/message/in_product_marketing.rb
+++ b/lib/gitlab/email/message/in_product_marketing.rb
@@ -6,10 +6,8 @@ module Gitlab
module InProductMarketing
UnknownTrackError = Class.new(StandardError)
- TRACKS = [:create, :verify, :team, :trial].freeze
-
def self.for(track)
- raise UnknownTrackError unless TRACKS.include?(track)
+ raise UnknownTrackError unless Namespaces::InProductMarketingEmailsService::TRACKS.key?(track)
"Gitlab::Email::Message::InProductMarketing::#{track.to_s.classify}".constantize
end
diff --git a/lib/gitlab/email/message/in_product_marketing/base.rb b/lib/gitlab/email/message/in_product_marketing/base.rb
index 6341a7c7596..89acc058a46 100644
--- a/lib/gitlab/email/message/in_product_marketing/base.rb
+++ b/lib/gitlab/email/message/in_product_marketing/base.rb
@@ -10,10 +10,11 @@ module Gitlab
attr_accessor :format
- def initialize(group:, series:, format: :html)
+ def initialize(group:, user:, series:, format: :html)
raise ArgumentError, "Only #{total_series} series available for this track." unless series.between?(0, total_series - 1)
@group = group
+ @user = user
@series = series
@format = format
end
@@ -103,11 +104,7 @@ module Gitlab
protected
- attr_reader :group, :series
-
- def total_series
- 3
- end
+ attr_reader :group, :user, :series
private
@@ -115,6 +112,10 @@ module Gitlab
self.class.name.demodulize.downcase.to_sym
end
+ def total_series
+ Namespaces::InProductMarketingEmailsService::TRACKS[track][:interval_days].size
+ end
+
def unsubscribe_com
[
s_('InProductMarketing|If you no longer wish to receive marketing emails from us,'),
diff --git a/lib/gitlab/email/message/in_product_marketing/experience.rb b/lib/gitlab/email/message/in_product_marketing/experience.rb
new file mode 100644
index 00000000000..440c1029c09
--- /dev/null
+++ b/lib/gitlab/email/message/in_product_marketing/experience.rb
@@ -0,0 +1,80 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Email
+ module Message
+ module InProductMarketing
+ class Experience < Base
+ include Gitlab::Utils::StrongMemoize
+
+ EASE_SCORE_SURVEY_ID = 1
+
+ def subject_line
+ s_('InProductMarketing|Do you have a minute?')
+ end
+
+ def tagline
+ end
+
+ def title
+ s_('InProductMarketing|We want your GitLab experience to be great')
+ end
+
+ def subtitle
+ s_('InProductMarketing|Take this 1-question survey!')
+ end
+
+ def body_line1
+ s_('InProductMarketing|%{strong_start}Overall, how difficult or easy was it to get started with GitLab?%{strong_end}').html_safe % strong_options
+ end
+
+ def body_line2
+ s_('InProductMarketing|Click on the number below that corresponds with your answer — 1 being very difficult, 5 being very easy.')
+ end
+
+ def cta_text
+ end
+
+ def feedback_link(rating)
+ params = {
+ onboarding_progress: onboarding_progress,
+ response: rating,
+ show_invite_link: show_invite_link,
+ survey_id: EASE_SCORE_SURVEY_ID
+ }
+
+ "#{Gitlab::COM_URL}/-/survey_responses?#{params.to_query}"
+ end
+
+ def feedback_ratings(rating)
+ [
+ s_('InProductMarketing|Very difficult'),
+ s_('InProductMarketing|Difficult'),
+ s_('InProductMarketing|Neutral'),
+ s_('InProductMarketing|Easy'),
+ s_('InProductMarketing|Very easy')
+ ][rating - 1]
+ end
+
+ def feedback_thanks
+ s_('InProductMarketing|Feedback from users like you really improves our product. Thanks for your help!')
+ end
+
+ private
+
+ def onboarding_progress
+ strong_memoize(:onboarding_progress) do
+ group.onboarding_progress.number_of_completed_actions
+ end
+ end
+
+ def show_invite_link
+ strong_memoize(:show_invite_link) do
+ group.member_count > 1 && group.max_member_access_for_user(user) >= GroupMember::DEVELOPER && user.preferred_language == 'en'
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gon_helper.rb b/lib/gitlab/gon_helper.rb
index 1fd210c521e..14f9c7f2191 100644
--- a/lib/gitlab/gon_helper.rb
+++ b/lib/gitlab/gon_helper.rb
@@ -47,6 +47,7 @@ module Gitlab
push_frontend_feature_flag(:snippets_binary_blob, default_enabled: false)
push_frontend_feature_flag(:usage_data_api, type: :ops, default_enabled: :yaml)
push_frontend_feature_flag(:security_auto_fix, default_enabled: false)
+ push_frontend_feature_flag(:improved_emoji_picker, default_enabled: :yaml)
end
# Exposes the state of a feature flag to the frontend code.
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index b1ba529d4a4..f8441ad296c 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -852,17 +852,16 @@ module Gitlab
sent_emails = count(Users::InProductMarketingEmail.group(:track, :series))
clicked_emails = count(Users::InProductMarketingEmail.where.not(cta_clicked_at: nil).group(:track, :series))
- series_amount = Namespaces::InProductMarketingEmailsService::INTERVAL_DAYS.count
-
Users::InProductMarketingEmail.tracks.keys.each_with_object({}) do |track, result|
# rubocop: enable UsageData/LargeTable:
+ series_amount = Namespaces::InProductMarketingEmailsService::TRACKS[track.to_sym][:interval_days].count
0.upto(series_amount - 1).map do |series|
# When there is an error with the query and it's not the Hash we expect, we return what we got from `count`.
sent_count = sent_emails.is_a?(Hash) ? sent_emails.fetch([track, series], 0) : sent_emails
clicked_count = clicked_emails.is_a?(Hash) ? clicked_emails.fetch([track, series], 0) : clicked_emails
result["in_product_marketing_email_#{track}_#{series}_sent"] = sent_count
- result["in_product_marketing_email_#{track}_#{series}_cta_clicked"] = clicked_count
+ result["in_product_marketing_email_#{track}_#{series}_cta_clicked"] = clicked_count unless track == 'experience'
end
end
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index af1d2ea1221..a1379ad2761 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4871,6 +4871,9 @@ msgstr ""
msgid "Background Jobs"
msgstr ""
+msgid "Background Migrations"
+msgstr ""
+
msgid "Background color"
msgstr ""
@@ -16914,6 +16917,9 @@ msgstr ""
msgid "InProductMarketing|%{strong_start}Multiple approval roles%{strong_end} — including code owners and required merge approvals"
msgstr ""
+msgid "InProductMarketing|%{strong_start}Overall, how difficult or easy was it to get started with GitLab?%{strong_end}"
+msgstr ""
+
msgid "InProductMarketing|*GitLab*, noun: a synonym for efficient teams"
msgstr ""
@@ -16947,6 +16953,9 @@ msgstr ""
msgid "InProductMarketing|By enabling code owners and required merge approvals the right person will review the right MR. This is a win-win: cleaner code and a more efficient review process."
msgstr ""
+msgid "InProductMarketing|Click on the number below that corresponds with your answer — 1 being very difficult, 5 being very easy."
+msgstr ""
+
msgid "InProductMarketing|Code owners and required merge approvals are part of the paid tiers of GitLab. You can start a free 30-day trial of GitLab Ultimate and enable these features in less than 5 minutes with no credit card required."
msgstr ""
@@ -16959,9 +16968,18 @@ msgstr ""
msgid "InProductMarketing|Did you know teams that use GitLab are far more efficient?"
msgstr ""
+msgid "InProductMarketing|Difficult"
+msgstr ""
+
msgid "InProductMarketing|Dig in and create a project and a repo"
msgstr ""
+msgid "InProductMarketing|Do you have a minute?"
+msgstr ""
+
+msgid "InProductMarketing|Easy"
+msgstr ""
+
msgid "InProductMarketing|Explore GitLab CI/CD"
msgstr ""
@@ -16974,6 +16992,9 @@ msgstr ""
msgid "InProductMarketing|Facebook"
msgstr ""
+msgid "InProductMarketing|Feedback from users like you really improves our product. Thanks for your help!"
+msgstr ""
+
msgid "InProductMarketing|Feel the need for speed?"
msgstr ""
@@ -17100,6 +17121,9 @@ msgstr ""
msgid "InProductMarketing|Need an alternative to importing?"
msgstr ""
+msgid "InProductMarketing|Neutral"
+msgstr ""
+
msgid "InProductMarketing|Our tool brings all the things together"
msgstr ""
@@ -17139,6 +17163,9 @@ msgstr ""
msgid "InProductMarketing|Streamline code review, know at a glance who's unavailable, communicate in comments or in email and integrate with Slack so everyone's on the same page."
msgstr ""
+msgid "InProductMarketing|Take this 1-question survey!"
+msgstr ""
+
msgid "InProductMarketing|Take your first steps with GitLab"
msgstr ""
@@ -17193,9 +17220,18 @@ msgstr ""
msgid "InProductMarketing|Use GitLab CI/CD"
msgstr ""
+msgid "InProductMarketing|Very difficult"
+msgstr ""
+
+msgid "InProductMarketing|Very easy"
+msgstr ""
+
msgid "InProductMarketing|We know a thing or two about efficiency and we don't want to keep that to ourselves. Sign up for a free trial of GitLab Ultimate and your teams will be on it from day one."
msgstr ""
+msgid "InProductMarketing|We want your GitLab experience to be great"
+msgstr ""
+
msgid "InProductMarketing|What does our value stream timeline look like from product to development to review and production?"
msgstr ""
@@ -21155,6 +21191,9 @@ msgstr ""
msgid "Migrated %{success_count}/%{total_count} files."
msgstr ""
+msgid "Migration"
+msgstr ""
+
msgid "Migration has been scheduled to be retried"
msgstr ""
diff --git a/qa/qa/resource/group_base.rb b/qa/qa/resource/group_base.rb
index bdd442a1c8b..19df390a10f 100644
--- a/qa/qa/resource/group_base.rb
+++ b/qa/qa/resource/group_base.rb
@@ -58,15 +58,21 @@ module QA
def comparable_group
reload! if api_response.nil?
- api_resource.except(
- :id,
- :web_url,
- :visibility,
- :full_name,
- :full_path,
- :created_at,
- :parent_id,
- :runners_token
+ api_resource.slice(
+ :name,
+ :path,
+ :description,
+ :emails_disabled,
+ :lfs_enabled,
+ :mentions_disabled,
+ :project_creation_level,
+ :request_access_enabled,
+ :require_two_factor_authentication,
+ :share_with_group_lock,
+ :subgroup_creation_level,
+ :two_factor_grace_perion
+ # TODO: Add back visibility comparison once https://gitlab.com/gitlab-org/gitlab/-/issues/331252 is fixed
+ # :visibility
)
end
end
diff --git a/qa/qa/specs/features/browser_ui/1_manage/group/bulk_import_group_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/group/bulk_import_group_spec.rb
index 055300122d4..ccf13ac01da 100644
--- a/qa/qa/specs/features/browser_ui/1_manage/group/bulk_import_group_spec.rb
+++ b/qa/qa/specs/features/browser_ui/1_manage/group/bulk_import_group_spec.rb
@@ -70,7 +70,9 @@ module QA
it(
'performs bulk group import from another gitlab instance',
testcase: 'https://gitlab.com/gitlab-org/quality/testcases/-/issues/1785',
- exclude: { job: ['ce:relative_url', 'ee:relative_url'] } # https://gitlab.com/gitlab-org/gitlab/-/issues/330344
+ exclude: { job: ['ce:relative_url', 'ee:relative_url'] },
+ issue_1: "https://gitlab.com/gitlab-org/gitlab/-/issues/330344",
+ issue_2: "https://gitlab.com/gitlab-org/gitlab/-/issues/331252"
) do
Page::Group::BulkImport.perform do |import_page|
import_page.import_group(source_group.path, sandbox.path)
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index f4f1e1bcbda..3cb18f21a47 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -242,6 +242,8 @@ FactoryBot.define do
branch_name: evaluator.create_branch)
end
+
+ project.track_project_repository
end
end
diff --git a/spec/factories_spec.rb b/spec/factories_spec.rb
index 787e0540fda..994bf066cf0 100644
--- a/spec/factories_spec.rb
+++ b/spec/factories_spec.rb
@@ -74,6 +74,7 @@ RSpec.describe 'factories' do
milestone_release
namespace
project_broken_repo
+ project_repository
prometheus_alert
prometheus_alert_event
prometheus_metric
@@ -84,6 +85,7 @@ RSpec.describe 'factories' do
release
release_link
self_managed_prometheus_alert_event
+ shard
users_star_project
wiki_page
wiki_page_meta
diff --git a/spec/features/admin/admin_sees_background_migrations_spec.rb b/spec/features/admin/admin_sees_background_migrations_spec.rb
new file mode 100644
index 00000000000..d848a8352bc
--- /dev/null
+++ b/spec/features/admin/admin_sees_background_migrations_spec.rb
@@ -0,0 +1,84 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe "Admin > Admin sees background migrations" do
+ let_it_be(:admin) { create(:admin) }
+
+ let_it_be(:active_migration) { create(:batched_background_migration, table_name: 'active', status: :active) }
+ let_it_be(:failed_migration) { create(:batched_background_migration, table_name: 'failed', status: :failed, total_tuple_count: 100) }
+ let_it_be(:finished_migration) { create(:batched_background_migration, table_name: 'finished', status: :finished) }
+
+ before_all do
+ create(:batched_background_migration_job, batched_migration: failed_migration, batch_size: 30, status: :succeeded)
+ end
+
+ before do
+ sign_in(admin)
+ gitlab_enable_admin_mode_sign_in(admin)
+ end
+
+ it 'can navigate to background migrations' do
+ visit admin_root_path
+
+ within '.nav-sidebar' do
+ link = find_link 'Background Migrations'
+
+ link.click
+
+ expect(page).to have_current_path(admin_background_migrations_path)
+ expect(link).to have_ancestor(:css, 'li.active')
+ end
+ end
+
+ it 'can view queued migrations' do
+ visit admin_background_migrations_path
+
+ within '#content-body' do
+ expect(page).to have_selector('tbody tr', count: 1)
+
+ expect(page).to have_content(active_migration.job_class_name)
+ expect(page).to have_content(active_migration.table_name)
+ expect(page).to have_content('0.00%')
+ expect(page).to have_content(active_migration.status.humanize)
+ end
+ end
+
+ it 'can view failed migrations' do
+ visit admin_background_migrations_path
+
+ within '#content-body' do
+ tab = find_link 'Failed'
+ tab.click
+
+ expect(page).to have_current_path(admin_background_migrations_path(tab: 'failed'))
+ expect(tab[:class]).to include('gl-tab-nav-item-active', 'gl-tab-nav-item-active-indigo')
+
+ expect(page).to have_selector('tbody tr', count: 1)
+
+ expect(page).to have_content(failed_migration.job_class_name)
+ expect(page).to have_content(failed_migration.table_name)
+ expect(page).to have_content('30.00%')
+ expect(page).to have_content(failed_migration.status.humanize)
+ end
+ end
+
+ it 'can view finished migrations' do
+ visit admin_background_migrations_path
+
+ within '#content-body' do
+ tab = find_link 'Finished'
+ tab.click
+
+ expect(page).to have_current_path(admin_background_migrations_path(tab: 'finished'))
+ expect(tab[:class]).to include('gl-tab-nav-item-active', 'gl-tab-nav-item-active-indigo')
+
+ expect(page).to have_selector('tbody tr', count: 1)
+
+ expect(page).to have_content(finished_migration.job_class_name)
+ expect(page).to have_content(finished_migration.table_name)
+ expect(page).to have_content('100.00%')
+ expect(page).to have_content(finished_migration.status.humanize)
+ end
+ end
+end
diff --git a/spec/features/profiles/user_edit_profile_spec.rb b/spec/features/profiles/user_edit_profile_spec.rb
index dddca15ae24..d941988d12f 100644
--- a/spec/features/profiles/user_edit_profile_spec.rb
+++ b/spec/features/profiles/user_edit_profile_spec.rb
@@ -8,6 +8,8 @@ RSpec.describe 'User edit profile' do
let(:user) { create(:user) }
before do
+ stub_feature_flags(improved_emoji_picker: false)
+
sign_in(user)
visit(profile_path)
end
diff --git a/spec/fixtures/product_intelligence/survey_response_schema.json b/spec/fixtures/product_intelligence/survey_response_schema.json
index 11454116d83..03d2d170137 100644
--- a/spec/fixtures/product_intelligence/survey_response_schema.json
+++ b/spec/fixtures/product_intelligence/survey_response_schema.json
@@ -3,7 +3,7 @@
"self": {
"vendor": "com.gitlab",
"name": "survey_response",
- "version": "1-0-0",
+ "version": "1-0-1",
"format": "jsonschema"
},
"type": "object",
@@ -47,6 +47,12 @@
"description": "Username",
"type": ["string", "null"],
"maxLength": 255
+ },
+ "onboarding_progress": {
+ "description": "Onboarding progress",
+ "type": ["integer", "null"],
+ "minimum": 0,
+ "maximum": 2147483647
}
}
}
diff --git a/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js b/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js
index 82fc06e1166..318c565f068 100644
--- a/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js
+++ b/spec/frontend/set_status_modal/set_status_modal_wrapper_spec.js
@@ -2,6 +2,7 @@ import { GlModal, GlFormCheckbox } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import { initEmojiMock } from 'helpers/emoji';
import * as UserApi from '~/api/user_api';
+import EmojiPicker from '~/emoji/components/picker.vue';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import SetStatusModalWrapper, {
AVAILABILITY_STATUS,
@@ -25,7 +26,7 @@ describe('SetStatusModalWrapper', () => {
defaultEmoji,
};
- const createComponent = (props = {}) => {
+ const createComponent = (props = {}, improvedEmojiPicker = false) => {
return shallowMount(SetStatusModalWrapper, {
propsData: {
...defaultProps,
@@ -34,6 +35,9 @@ describe('SetStatusModalWrapper', () => {
mocks: {
$toast,
},
+ provide: {
+ glFeatures: { improvedEmojiPicker },
+ },
});
};
@@ -106,6 +110,20 @@ describe('SetStatusModalWrapper', () => {
});
});
+ describe('improvedEmojiPicker is true', () => {
+ beforeEach(async () => {
+ mockEmoji = await initEmojiMock();
+ wrapper = createComponent({}, true);
+ return initModal();
+ });
+
+ it('sets emojiTag when clicking in emoji picker', async () => {
+ await wrapper.findComponent(EmojiPicker).vm.$emit('click', 'thumbsup');
+
+ expect(wrapper.vm.emojiTag).toContain('data-name="thumbsup"');
+ });
+ });
+
describe('with no currentMessage set', () => {
beforeEach(async () => {
mockEmoji = await initEmojiMock();
diff --git a/spec/helpers/admin/background_migrations_helper_spec.rb b/spec/helpers/admin/background_migrations_helper_spec.rb
new file mode 100644
index 00000000000..8880a00755b
--- /dev/null
+++ b/spec/helpers/admin/background_migrations_helper_spec.rb
@@ -0,0 +1,67 @@
+# frozen_string_literal: true
+
+require "spec_helper"
+
+RSpec.describe Admin::BackgroundMigrationsHelper do
+ describe '#batched_migration_status_badge_class_name' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:status, :class_name) do
+ :active | 'badge-info'
+ :paused | 'badge-warning'
+ :failed | 'badge-danger'
+ :finished | 'badge-success'
+ end
+
+ subject { helper.batched_migration_status_badge_class_name(migration) }
+
+ with_them do
+ let(:migration) { build(:batched_background_migration, status: status) }
+
+ it { is_expected.to eq(class_name) }
+ end
+ end
+
+ describe '#batched_migration_progress' do
+ subject { helper.batched_migration_progress(migration, completed_rows) }
+
+ let(:migration) { build(:batched_background_migration, status: :active, total_tuple_count: 100) }
+ let(:completed_rows) { 25 }
+
+ it 'returns completion percentage' do
+ expect(subject).to eq(25)
+ end
+
+ context 'when migration is finished' do
+ let(:migration) { build(:batched_background_migration, status: :finished, total_tuple_count: nil) }
+
+ it 'returns 100 percent' do
+ expect(subject).to eq(100)
+ end
+ end
+
+ context 'when total_tuple_count is nil' do
+ let(:migration) { build(:batched_background_migration, status: :active, total_tuple_count: nil) }
+
+ it 'returns nil' do
+ expect(subject).to eq(nil)
+ end
+
+ context 'when there are no completed rows' do
+ let(:completed_rows) { 0 }
+
+ it 'returns 0 percent' do
+ expect(subject).to eq(0)
+ end
+ end
+ end
+
+ context 'when completed rows are greater than total count' do
+ let(:completed_rows) { 150 }
+
+ it 'returns 99 percent' do
+ expect(subject).to eq(99)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb
index 17e6c75ca27..17fe90c830e 100644
--- a/spec/helpers/issues_helper_spec.rb
+++ b/spec/helpers/issues_helper_spec.rb
@@ -309,7 +309,7 @@ RSpec.describe IssuesHelper do
initial_email: project.new_issuable_address(current_user, 'issue'),
is_signed_in: current_user.present?.to_s,
issues_path: project_issues_path(project),
- jira_integration_path: help_page_url('user/project/integrations/jira', anchor: 'view-jira-issues'),
+ jira_integration_path: help_page_url('integration/jira/', anchor: 'view-jira-issues'),
markdown_help_path: help_page_path('user/markdown'),
max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes),
new_issue_path: new_project_issue_path(project, issue: { assignee_id: finder.assignee.id, milestone_id: finder.milestones.first.id }),
diff --git a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
index 78e0b7627e9..2de784d3e16 100644
--- a/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_job_spec.rb
@@ -49,16 +49,6 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedJob, type: :model d
let(:batched_job) { build(:batched_background_migration_job) }
let(:batched_migration) { batched_job.batched_migration }
- describe '#migration_aborted?' do
- before do
- batched_migration.status = :aborted
- end
-
- it 'returns the migration aborted?' do
- expect(batched_job.migration_aborted?).to eq(batched_migration.aborted?)
- end
- end
-
describe '#migration_job_class' do
it 'returns the migration job_class' do
expect(batched_job.migration_job_class).to eq(batched_migration.job_class)
diff --git a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
index 43e34325419..e3507df5736 100644
--- a/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
+++ b/spec/lib/gitlab/database/background_migration/batched_migration_spec.rb
@@ -36,6 +36,38 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
it 'returns the first active migration according to queue order' do
expect(described_class.active_migration).to eq(migration2)
+ create(:batched_background_migration_job, batched_migration: migration1, batch_size: 1000, status: :succeeded)
+ end
+ end
+
+ describe '.queued' do
+ let!(:migration1) { create(:batched_background_migration, :finished) }
+ let!(:migration2) { create(:batched_background_migration, :paused) }
+ let!(:migration3) { create(:batched_background_migration, :active) }
+
+ it 'returns active and paused migrations' do
+ expect(described_class.queued).to contain_exactly(migration2, migration3)
+ end
+ end
+
+ describe '.successful_rows_counts' do
+ let!(:migration1) { create(:batched_background_migration) }
+ let!(:migration2) { create(:batched_background_migration) }
+ let!(:migration_without_jobs) { create(:batched_background_migration) }
+
+ before do
+ create(:batched_background_migration_job, batched_migration: migration1, batch_size: 1000, status: :succeeded)
+ create(:batched_background_migration_job, batched_migration: migration1, batch_size: 200, status: :failed)
+ create(:batched_background_migration_job, batched_migration: migration2, batch_size: 500, status: :succeeded)
+ create(:batched_background_migration_job, batched_migration: migration2, batch_size: 200, status: :running)
+ end
+
+ it 'returns totals from successful jobs' do
+ results = described_class.successful_rows_counts([migration1, migration2, migration_without_jobs])
+
+ expect(results[migration1.id]).to eq(1000)
+ expect(results[migration2.id]).to eq(500)
+ expect(results[migration_without_jobs.id]).to eq(nil)
end
end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb
index 42d84b3e4de..277f1158f8b 100644
--- a/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb
+++ b/spec/lib/gitlab/email/message/in_product_marketing/base_spec.rb
@@ -4,12 +4,13 @@ require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Base do
let_it_be(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
let(:series) { 0 }
let(:test_class) { Gitlab::Email::Message::InProductMarketing::Create }
describe 'initialize' do
- subject { test_class.new(group: group, series: series) }
+ subject { test_class.new(group: group, user: user, series: series) }
context 'when series does not exist' do
let(:series) { 3 }
@@ -29,13 +30,13 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Base do
end
describe '#logo_path' do
- subject { test_class.new(group: group, series: series).logo_path }
+ subject { test_class.new(group: group, user: user, series: series).logo_path }
it { is_expected.to eq('mailers/in_product_marketing/create-0.png') }
end
describe '#unsubscribe' do
- subject { test_class.new(group: group, series: series).unsubscribe }
+ subject { test_class.new(group: group, user: user, series: series).unsubscribe }
before do
allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
@@ -55,7 +56,7 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Base do
end
describe '#cta_link' do
- subject(:cta_link) { test_class.new(group: group, series: series).cta_link }
+ subject(:cta_link) { test_class.new(group: group, user: user, series: series).cta_link }
it 'renders link' do
expect(CGI.unescapeHTML(cta_link)).to include(Gitlab::Routing.url_helpers.group_email_campaigns_url(group, track: :create, series: series))
@@ -63,7 +64,7 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Base do
end
describe '#progress' do
- subject { test_class.new(group: group, series: series).progress }
+ subject { test_class.new(group: group, user: user, series: series).progress }
before do
allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb
index be8a33b18bd..35470ef3555 100644
--- a/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb
+++ b/spec/lib/gitlab/email/message/in_product_marketing/create_spec.rb
@@ -6,8 +6,9 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Create do
using RSpec::Parameterized::TableSyntax
let_it_be(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
- subject(:message) { described_class.new(group: group, series: series)}
+ subject(:message) { described_class.new(group: group, user: user, series: series)}
describe "public methods" do
where(series: [0, 1, 2])
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/experience_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/experience_spec.rb
new file mode 100644
index 00000000000..b742eff3f56
--- /dev/null
+++ b/spec/lib/gitlab/email/message/in_product_marketing/experience_spec.rb
@@ -0,0 +1,64 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Email::Message::InProductMarketing::Experience do
+ let_it_be(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
+
+ subject(:message) { described_class.new(group: group, user: user, series: series)}
+
+ describe 'public methods' do
+ context 'with series 0' do
+ let(:series) { 0 }
+
+ it 'returns value for series', :aggregate_failures do
+ expect(message.subject_line).to be_present
+ expect(message.tagline).to be_nil
+ expect(message.title).to be_present
+ expect(message.subtitle).to be_present
+ expect(message.body_line1).to be_present
+ expect(message.body_line2).to be_present
+ expect(message.cta_text).to be_nil
+ end
+
+ describe '#feedback_link' do
+ let(:member_count) { 2 }
+ let(:user_access) { GroupMember::DEVELOPER }
+ let(:preferred_language) { 'en' }
+
+ before do
+ allow(message).to receive(:onboarding_progress).and_return(1)
+ allow(group).to receive(:member_count).and_return(member_count)
+ allow(group).to receive(:max_member_access_for_user).and_return(user_access)
+ allow(user).to receive(:preferred_language).and_return(preferred_language)
+ end
+
+ subject do
+ uri = URI.parse(message.feedback_link(1))
+ Rack::Utils.parse_query(uri.query).with_indifferent_access[:show_invite_link]
+ end
+
+ it { is_expected.to eq('true') }
+
+ context 'with only one member' do
+ let(:member_count) { 1 }
+
+ it { is_expected.to eq('false') }
+ end
+
+ context 'with less than developer access' do
+ let(:user_access) { GroupMember::GUEST }
+
+ it { is_expected.to eq('false') }
+ end
+
+ context 'with preferred language other than English' do
+ let(:preferred_language) { 'nl' }
+
+ it { is_expected.to eq('false') }
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb
index 6251128f560..f72994fcce1 100644
--- a/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb
+++ b/spec/lib/gitlab/email/message/in_product_marketing/team_spec.rb
@@ -6,8 +6,9 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Team do
using RSpec::Parameterized::TableSyntax
let_it_be(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
- subject(:message) { described_class.new(group: group, series: series)}
+ subject(:message) { described_class.new(group: group, user: user, series: series)}
describe "public methods" do
where(series: [0, 1])
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb
index 2c435490765..5f7639a9ed6 100644
--- a/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb
+++ b/spec/lib/gitlab/email/message/in_product_marketing/trial_spec.rb
@@ -6,8 +6,9 @@ RSpec.describe Gitlab::Email::Message::InProductMarketing::Trial do
using RSpec::Parameterized::TableSyntax
let_it_be(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
- subject(:message) { described_class.new(group: group, series: series)}
+ subject(:message) { described_class.new(group: group, user: user, series: series)}
describe "public methods" do
where(series: [0, 1, 2])
diff --git a/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb b/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb
index 73252c0dbdf..a7da2e9553d 100644
--- a/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb
+++ b/spec/lib/gitlab/email/message/in_product_marketing/verify_spec.rb
@@ -4,8 +4,9 @@ require 'spec_helper'
RSpec.describe Gitlab::Email::Message::InProductMarketing::Verify do
let_it_be(:group) { build(:group) }
+ let_it_be(:user) { build(:user) }
- subject(:message) { described_class.new(group: group, series: series)}
+ subject(:message) { described_class.new(group: group, user: user, series: series)}
describe "public methods" do
context 'with series 0' do
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index d4b6ac09261..c91f567c3c9 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -1499,7 +1499,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
"in_product_marketing_email_team_1_sent" => -1,
"in_product_marketing_email_team_1_cta_clicked" => -1,
"in_product_marketing_email_team_2_sent" => -1,
- "in_product_marketing_email_team_2_cta_clicked" => -1
+ "in_product_marketing_email_team_2_cta_clicked" => -1,
+ "in_product_marketing_email_experience_0_sent" => -1
}
expect(subject).to eq(expected_data)
@@ -1537,7 +1538,8 @@ RSpec.describe Gitlab::UsageData, :aggregate_failures do
"in_product_marketing_email_team_1_sent" => 0,
"in_product_marketing_email_team_1_cta_clicked" => 0,
"in_product_marketing_email_team_2_sent" => 0,
- "in_product_marketing_email_team_2_cta_clicked" => 0
+ "in_product_marketing_email_team_2_cta_clicked" => 0,
+ "in_product_marketing_email_experience_0_sent" => 0
}
expect(subject).to eq(expected_data)
diff --git a/spec/mailers/emails/in_product_marketing_spec.rb b/spec/mailers/emails/in_product_marketing_spec.rb
index 3d17e16ef48..74354630ade 100644
--- a/spec/mailers/emails/in_product_marketing_spec.rb
+++ b/spec/mailers/emails/in_product_marketing_spec.rb
@@ -9,6 +9,8 @@ RSpec.describe Emails::InProductMarketing do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
+ let!(:onboarding_progress) { create(:onboarding_progress, namespace: group) }
+
describe '#in_product_marketing_email' do
using RSpec::Parameterized::TableSyntax
@@ -45,29 +47,35 @@ RSpec.describe Emails::InProductMarketing do
end
where(:track, :series) do
- :create | 0
- :create | 1
- :create | 2
- :verify | 0
- :verify | 1
- :verify | 2
- :trial | 0
- :trial | 1
- :trial | 2
- :team | 0
- :team | 1
- :team | 2
+ :create | 0
+ :create | 1
+ :create | 2
+ :verify | 0
+ :verify | 1
+ :verify | 2
+ :trial | 0
+ :trial | 1
+ :trial | 2
+ :team | 0
+ :team | 1
+ :team | 2
+ :experience | 0
end
with_them do
it 'has the correct subject and content' do
- message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, series: series)
+ message = Gitlab::Email::Message::InProductMarketing.for(track).new(group: group, user: user, series: series)
aggregate_failures do
is_expected.to have_subject(message.subject_line)
is_expected.to have_body_text(message.title)
is_expected.to have_body_text(message.subtitle)
- is_expected.to have_body_text(CGI.unescapeHTML(message.cta_link))
+
+ if track == :experience
+ is_expected.to have_body_text(CGI.unescapeHTML(message.feedback_link(1)))
+ else
+ is_expected.to have_body_text(CGI.unescapeHTML(message.cta_link))
+ end
end
end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 56afe49e15f..ec0507db1b3 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -804,9 +804,9 @@ RSpec.describe Namespace do
end
it 'updates the project storage location' do
- repository_project_in_parent_group = create(:project_repository, project: project_in_parent_group)
- repository_hashed_project_in_subgroup = create(:project_repository, project: hashed_project_in_subgroup)
- repository_legacy_project_in_subgroup = create(:project_repository, project: legacy_project_in_subgroup)
+ repository_project_in_parent_group = project_in_parent_group.project_repository
+ repository_hashed_project_in_subgroup = hashed_project_in_subgroup.project_repository
+ repository_legacy_project_in_subgroup = legacy_project_in_subgroup.project_repository
parent.update(path: 'mygroup_moved')
diff --git a/spec/models/onboarding_progress_spec.rb b/spec/models/onboarding_progress_spec.rb
index 779312c9fa0..deac8d29196 100644
--- a/spec/models/onboarding_progress_spec.rb
+++ b/spec/models/onboarding_progress_spec.rb
@@ -211,4 +211,26 @@ RSpec.describe OnboardingProgress do
it { is_expected.to eq(:subscription_created_at) }
end
+
+ describe '#number_of_completed_actions' do
+ subject { build(:onboarding_progress, actions.map { |x| { x => Time.current } }.inject(:merge)).number_of_completed_actions }
+
+ context '0 completed actions' do
+ let(:actions) { [:created_at, :updated_at] }
+
+ it { is_expected.to eq(0) }
+ end
+
+ context '1 completed action' do
+ let(:actions) { [:created_at, :subscription_created_at] }
+
+ it { is_expected.to eq(1) }
+ end
+
+ context '2 completed actions' do
+ let(:actions) { [:subscription_created_at, :git_write_at] }
+
+ it { is_expected.to eq(2) }
+ end
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index c57c2792f87..f7dace409aa 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2238,13 +2238,13 @@ RSpec.describe Project, factory_default: :keep do
end
context 'with projects on legacy storage' do
- let(:project) { create(:project, :repository, :legacy_storage) }
+ let(:project) { create(:project, :legacy_storage) }
it_behaves_like 'tracks storage location'
end
context 'with projects on hashed storage' do
- let(:project) { create(:project, :repository) }
+ let(:project) { create(:project) }
it_behaves_like 'tracks storage location'
end
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index ac125e81acd..ccc9f8c50c4 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -3,12 +3,12 @@
require 'spec_helper'
RSpec.describe API::CommitStatuses do
- let!(:project) { create(:project, :repository) }
- let(:commit) { project.repository.commit }
- let(:guest) { create_user(:guest) }
- let(:reporter) { create_user(:reporter) }
- let(:developer) { create_user(:developer) }
- let(:sha) { commit.id }
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:commit) { project.repository.commit }
+ let_it_be(:guest) { create_user(:guest) }
+ let_it_be(:reporter) { create_user(:reporter) }
+ let_it_be(:developer) { create_user(:developer) }
+ let_it_be(:sha) { commit.id }
describe "GET /projects/:id/repository/commits/:sha/statuses" do
let(:get_url) { "/projects/#{project.id}/repository/commits/#{sha}/statuses" }
@@ -233,27 +233,44 @@ RSpec.describe API::CommitStatuses do
end
end
- context 'when updatig a commit status' do
+ context 'when updating a commit status' do
+ let(:parameters) do
+ {
+ state: 'success',
+ name: 'coverage',
+ ref: 'master'
+ }
+ end
+
+ let(:updatable_optional_attributes) do
+ {
+ description: 'new description',
+ coverage: 90.0
+ }
+ end
+
+ # creating the initial commit status
before do
post api(post_url, developer), params: {
state: 'running',
context: 'coverage',
ref: 'master',
description: 'coverage test',
- coverage: 0.0,
+ coverage: 10.0,
target_url: 'http://gitlab.com/status'
}
+ end
+ subject(:send_request) do
post api(post_url, developer), params: {
- state: 'success',
- name: 'coverage',
- ref: 'master',
- description: 'new description',
- coverage: 90.0
+ **parameters,
+ **updatable_optional_attributes
}
end
it 'updates a commit status' do
+ send_request
+
expect(response).to have_gitlab_http_status(:created)
expect(json_response['sha']).to eq(commit.id)
expect(json_response['status']).to eq('success')
@@ -265,7 +282,28 @@ RSpec.describe API::CommitStatuses do
end
it 'does not create a new commit status' do
- expect(CommitStatus.count).to eq 1
+ expect { send_request }.not_to change { CommitStatus.count }
+ end
+
+ context 'when the `state` parameter is sent the same' do
+ let(:parameters) do
+ {
+ state: 'running',
+ name: 'coverage',
+ ref: 'master'
+ }
+ end
+
+ it 'does not update the commit status' do
+ send_request
+
+ expect(response).to have_gitlab_http_status(:bad_request)
+
+ commit_status = project.commit_statuses.find_by!(name: 'coverage')
+
+ expect(commit_status.description).to eq('coverage test')
+ expect(commit_status.coverage).to eq(10.0)
+ end
end
end
diff --git a/spec/requests/api/project_repository_storage_moves_spec.rb b/spec/requests/api/project_repository_storage_moves_spec.rb
index b40645ba2de..5b272121233 100644
--- a/spec/requests/api/project_repository_storage_moves_spec.rb
+++ b/spec/requests/api/project_repository_storage_moves_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe API::ProjectRepositoryStorageMoves do
it_behaves_like 'repository_storage_moves API', 'projects' do
- let_it_be(:container) { create(:project, :repository).tap { |project| project.track_project_repository } }
+ let_it_be(:container) { create(:project, :repository) }
let_it_be(:storage_move) { create(:project_repository_storage_move, :scheduled, container: container) }
let(:repository_storage_move_factory) { :project_repository_storage_move }
let(:bulk_worker_klass) { Projects::ScheduleBulkRepositoryShardMovesWorker }
diff --git a/spec/requests/groups/email_campaigns_controller_spec.rb b/spec/requests/groups/email_campaigns_controller_spec.rb
index 48297ec4cb6..290e6009ecb 100644
--- a/spec/requests/groups/email_campaigns_controller_spec.rb
+++ b/spec/requests/groups/email_campaigns_controller_spec.rb
@@ -9,10 +9,11 @@ RSpec.describe Groups::EmailCampaignsController do
let_it_be(:group) { create(:group) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:user) { create(:user) }
+
let(:track) { 'create' }
let(:series) { '0' }
let(:schema) { described_class::EMAIL_CAMPAIGNS_SCHEMA_URL }
- let(:subject_line_text) { Gitlab::Email::Message::InProductMarketing.for(track.to_sym).new(group: group, series: series.to_i).subject_line }
+ let(:subject_line_text) { Gitlab::Email::Message::InProductMarketing.for(track.to_sym).new(group: group, user: user, series: series.to_i).subject_line }
let(:data) do
{
namespace_id: group.id,
@@ -91,7 +92,7 @@ RSpec.describe Groups::EmailCampaignsController do
describe 'track parameter' do
context 'when valid' do
- where(track: Namespaces::InProductMarketingEmailsService::TRACKS.keys)
+ where(track: Namespaces::InProductMarketingEmailsService::TRACKS.keys.without(:experience))
with_them do
it_behaves_like 'track and redirect'
@@ -109,7 +110,7 @@ RSpec.describe Groups::EmailCampaignsController do
describe 'series parameter' do
context 'when valid' do
- where(series: (0..Namespaces::InProductMarketingEmailsService::INTERVAL_DAYS.length - 1).to_a)
+ where(series: (0..Namespaces::InProductMarketingEmailsService::TRACKS[:create][:interval_days].length - 1).to_a)
with_them do
it_behaves_like 'track and redirect'
@@ -117,7 +118,7 @@ RSpec.describe Groups::EmailCampaignsController do
end
context 'when invalid' do
- where(series: [-1, nil, Namespaces::InProductMarketingEmailsService::INTERVAL_DAYS.length])
+ where(series: [-1, nil, Namespaces::InProductMarketingEmailsService::TRACKS[:create][:interval_days].length])
with_them do
it_behaves_like 'no track and 404'
diff --git a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
index 3094f574184..2bf02e541f9 100644
--- a/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
+++ b/spec/services/namespaces/in_product_marketing_emails_service_spec.rb
@@ -41,22 +41,23 @@ RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute' do
using RSpec::Parameterized::TableSyntax
where(:track, :interval, :actions_completed) do
- :create | 1 | { created_at: frozen_time - 2.days }
- :create | 5 | { created_at: frozen_time - 6.days }
- :create | 10 | { created_at: frozen_time - 11.days }
- :verify | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days }
- :verify | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days }
- :verify | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days }
- :trial | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days, pipeline_created_at: frozen_time - 2.days }
- :trial | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days, pipeline_created_at: frozen_time - 6.days }
- :trial | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days, pipeline_created_at: frozen_time - 11.days }
- :team | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days, pipeline_created_at: frozen_time - 2.days, trial_started_at: frozen_time - 2.days }
- :team | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days, pipeline_created_at: frozen_time - 6.days, trial_started_at: frozen_time - 6.days }
- :team | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days, pipeline_created_at: frozen_time - 11.days, trial_started_at: frozen_time - 11.days }
+ :create | 1 | { created_at: frozen_time - 2.days }
+ :create | 5 | { created_at: frozen_time - 6.days }
+ :create | 10 | { created_at: frozen_time - 11.days }
+ :verify | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days }
+ :verify | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days }
+ :verify | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days }
+ :trial | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days, pipeline_created_at: frozen_time - 2.days }
+ :trial | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days, pipeline_created_at: frozen_time - 6.days }
+ :trial | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days, pipeline_created_at: frozen_time - 11.days }
+ :team | 1 | { created_at: frozen_time - 2.days, git_write_at: frozen_time - 2.days, pipeline_created_at: frozen_time - 2.days, trial_started_at: frozen_time - 2.days }
+ :team | 5 | { created_at: frozen_time - 6.days, git_write_at: frozen_time - 6.days, pipeline_created_at: frozen_time - 6.days, trial_started_at: frozen_time - 6.days }
+ :team | 10 | { created_at: frozen_time - 11.days, git_write_at: frozen_time - 11.days, pipeline_created_at: frozen_time - 11.days, trial_started_at: frozen_time - 11.days }
+ :experience | 30 | { created_at: frozen_time - 31.days, git_write_at: frozen_time - 31.days }
end
with_them do
- it { is_expected.to send_in_product_marketing_email(user.id, group.id, track, described_class::INTERVAL_DAYS.index(interval)) }
+ it { is_expected.to send_in_product_marketing_email(user.id, group.id, track, described_class::TRACKS[track][:interval_days].index(interval)) }
end
end
@@ -235,7 +236,7 @@ RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute' do
let(:track) { :foo }
before do
- stub_const("#{described_class}::TRACKS", { bar: :git_write })
+ stub_const("#{described_class}::TRACKS", { bar: {} })
end
it { expect { subject }.to raise_error(ArgumentError, 'Track foo not defined') }
diff --git a/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb b/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb
index 2dc4a56368b..76830396104 100644
--- a/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb
+++ b/spec/services/projects/schedule_bulk_repository_shard_moves_service_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::ScheduleBulkRepositoryShardMovesService do
it_behaves_like 'moves repository shard in bulk' do
- let_it_be_with_reload(:container) { create(:project, :repository).tap { |project| project.track_project_repository } }
+ let_it_be_with_reload(:container) { create(:project, :repository) }
let(:move_service_klass) { Projects::RepositoryStorageMove }
let(:bulk_worker_klass) { ::Projects::ScheduleBulkRepositoryShardMovesWorker }
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 8498b752610..3171abfb36f 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -195,8 +195,6 @@ RSpec.describe Projects::TransferService do
end
it 'does not update storage location' do
- create(:project_repository, project: project)
-
attempt_project_transfer
expect(project.project_repository).to have_attributes(
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 8963164ac53..1737670071f 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -301,10 +301,8 @@ RSpec.describe 'gitlab:app namespace rake task', :delete do
shared_examples 'includes repositories in all repository storages' do
specify :aggregate_failures do
project_a = create(:project, :repository)
- project_a.track_project_repository
project_snippet_a = create(:project_snippet, :repository, project: project_a, author: project_a.owner)
project_b = create(:project, :repository, repository_storage: second_storage_name)
- project_b.track_project_repository
project_snippet_b = create(:project_snippet, :repository, project: project_b, author: project_b.owner)
project_snippet_b.snippet_repository.update!(shard: project_b.project_repository.shard)
create(:wiki_page, container: project_a)
diff --git a/spec/workers/project_schedule_bulk_repository_shard_moves_worker_spec.rb b/spec/workers/project_schedule_bulk_repository_shard_moves_worker_spec.rb
index f284e1ab8c6..256f665c0c4 100644
--- a/spec/workers/project_schedule_bulk_repository_shard_moves_worker_spec.rb
+++ b/spec/workers/project_schedule_bulk_repository_shard_moves_worker_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe ProjectScheduleBulkRepositoryShardMovesWorker do
it_behaves_like 'schedules bulk repository shard moves' do
- let_it_be_with_reload(:container) { create(:project, :repository).tap { |project| project.track_project_repository } }
+ let_it_be_with_reload(:container) { create(:project, :repository) }
let(:move_service_klass) { Projects::RepositoryStorageMove }
let(:worker_klass) { Projects::UpdateRepositoryStorageWorker }
diff --git a/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb b/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb
index 24957a35b72..7eff8e4dcd7 100644
--- a/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb
+++ b/spec/workers/projects/schedule_bulk_repository_shard_moves_worker_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Projects::ScheduleBulkRepositoryShardMovesWorker do
it_behaves_like 'schedules bulk repository shard moves' do
- let_it_be_with_reload(:container) { create(:project, :repository).tap { |project| project.track_project_repository } }
+ let_it_be_with_reload(:container) { create(:project, :repository) }
let(:move_service_klass) { Projects::RepositoryStorageMove }
let(:worker_klass) { Projects::UpdateRepositoryStorageWorker }