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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
commit9dc93a4519d9d5d7be48ff274127136236a3adb3 (patch)
tree70467ae3692a0e35e5ea56bcb803eb512a10bedb /.gitlab/issue_templates
parent4b0f34b6d759d6299322b3a54453e930c6121ff0 (diff)
Add latest changes from gitlab-org/gitlab@13-11-stable-eev13.11.0-rc43
Diffstat (limited to '.gitlab/issue_templates')
-rw-r--r--.gitlab/issue_templates/Experiment Successful Cleanup.md1
-rw-r--r--.gitlab/issue_templates/Experimentation.md2
-rw-r--r--.gitlab/issue_templates/Feature Flag Roll Out.md98
-rw-r--r--.gitlab/issue_templates/Feature proposal.md2
-rw-r--r--.gitlab/issue_templates/Geo: Replicate a new Git repository type.md756
-rw-r--r--.gitlab/issue_templates/Geo: Replicate a new blob type.md722
-rw-r--r--.gitlab/issue_templates/Implementation.md19
-rw-r--r--.gitlab/issue_templates/Lean Feature Proposal.md3
-rw-r--r--.gitlab/issue_templates/OSS_Partner.md (renamed from .gitlab/issue_templates/Migrations.md)13
-rw-r--r--.gitlab/issue_templates/Productivity Improvement.md2
-rw-r--r--.gitlab/issue_templates/Query Performance Investigation.md11
-rw-r--r--.gitlab/issue_templates/Security developer workflow.md5
-rw-r--r--.gitlab/issue_templates/experiment_tracking_template.md3
13 files changed, 1597 insertions, 40 deletions
diff --git a/.gitlab/issue_templates/Experiment Successful Cleanup.md b/.gitlab/issue_templates/Experiment Successful Cleanup.md
index afe4793cdfc..42f26342342 100644
--- a/.gitlab/issue_templates/Experiment Successful Cleanup.md
+++ b/.gitlab/issue_templates/Experiment Successful Cleanup.md
@@ -15,5 +15,6 @@ The changes need to become an official part of the product.
- [ ] Optional: Migrate experiment to a default enabled [feature flag](https://docs.gitlab.com/ee/development/feature_flags) for one milestone and add a changelog. Converting to a feature flag can be skipped at the ICs discretion if risk is deemed low with consideration to both SaaS and (if applicable) self managed
- [ ] In the next milestone, [remove the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) if applicable
- [ ] After the flag removal is deployed, [clean up the feature/experiment feature flags](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
+- [ ] Ensure the corresponding [Experiment Tracking](https://gitlab.com/groups/gitlab-org/-/boards/1352542?label_name[]=devops%3A%3Agrowth&label_name[]=growth%20experiment&label_name[]=experiment%20tracking) issue is updated
/label ~"feature" ~"feature::maintenance" ~"workflow::scheduling" ~"growth experiment" ~"feature flag"
diff --git a/.gitlab/issue_templates/Experimentation.md b/.gitlab/issue_templates/Experimentation.md
index f84c4305c2c..ba7839fb941 100644
--- a/.gitlab/issue_templates/Experimentation.md
+++ b/.gitlab/issue_templates/Experimentation.md
@@ -18,7 +18,7 @@
# Tracking Details
- [json schema](https://gitlab.com/gitlab-org/iglu/-/blob/master/public/schemas/com.gitlab/gitlab_experiment/jsonschema/0-3-0) used in `gitlab-experiment` tracking.
-- see [taxonomy](https://docs.gitlab.com/ee/development/snowplow.html#structured-event-taxonomy) for a guide.
+- see [taxonomy](https://docs.gitlab.com/ee/development/snowplow/index.html#structured-event-taxonomy) for a guide.
| activity | category | action | label | context | property | value |
| -------- | -------- | ------ | ----- | ------- | -------- | ----- |
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md
index fe263b932ae..a67d0f4e31a 100644
--- a/.gitlab/issue_templates/Feature Flag Roll Out.md
+++ b/.gitlab/issue_templates/Feature Flag Roll Out.md
@@ -1,48 +1,107 @@
<!-- Title suggestion: [Feature flag] Enable description of feature -->
-## What
+## Feature
-Remove the `:feature_name` feature flag ...
+This feature uses the `:feature_name` feature flag!
+
+<!-- Short description of what the feature is about and link to relevant other issues. -->
+- [Issue Name](ISSUE LINK)
## Owners
- Team: NAME_OF_TEAM
- Most appropriate slack channel to reach out to: `#g_TEAM_NAME`
- Best individual to reach out to: NAME
+- PM: NAME
-## Expectations
+## Stakeholders
-### What are we expecting to happen?
-
-### What might happen if this goes wrong?
+<!--
+Are there any other stages or teams involved that need to be kept in the loop?
-### What can we monitor to detect problems with this?
+- Name of a PM
+- The Support Team
+- The Delivery Team
+-->
-<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can also be useful to review -->
+## The Rollout Plan
+- Partial Rollout on GitLab.com with beta groups
+- Rollout on GitLab.com for a certain period (How long)
+- Percentage Rollout on GitLab.com
+- Rollout Feature for everyone as soon as it's ready
-## Beta groups/projects
+<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can also be useful to review -->
-If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example.
+**Beta Groups/Projects:**
+<!-- If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example. -->
- `gitlab-org/gitlab` project
- `gitlab-org`/`gitlab-com` groups
- ...
-## Roll Out Steps
+## Expectations
+
+### What are we expecting to happen?
+
+<!-- Describe the expected outcome when rolling out this feature -->
+
+### What might happen if this goes wrong?
+
+<!-- Should the feature flag be turned off? Any MRs that need to be rolled back? Communication that needs to happen? What are some things you can think of that could go wrong - data loss or broken pages? -->
+
+### What can we monitor to detect problems with this?
+
+<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? -->
+
+## Rollout Timeline
+
+<!-- Please check which steps are needed and remove those which don't apply -->
+
+**Initial Rollout**
+
+*Preparation Phase*
- [ ] Enable on staging (`/chatops run feature set feature_name true --staging`)
+
- [ ] Test on staging
-- [ ] Ensure that documentation has been updated
-- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`)
-- [ ] Coordinate a time to enable the flag with the SRE oncall and release managers
- - In `#production` mention `@sre-oncall` and `@release-managers`. Once an SRE on call and Release Manager on call confirm, you can proceed with the rollout
+
+- [ ] Ensure that documentation has been updated ([More info](https://docs.gitlab.com/ee/development/documentation/feature_flags.html#features-that-became-enabled-by-default))
+
- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com
-- [ ] Enable on GitLab.com by running chatops command in `#production` (`/chatops run feature set feature_name true`)
-- [ ] Cross post chatops Slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel
+
+*Partial Rollout Phase*
+- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`)
+
+- [ ] Verify behaviour (See Beta Groups) and add details with screenshots as a comment on this issue
+
+- [ ] If it is possible to perform an incremental rollout, this should be preferred. Proposed increments are: `10%`, `50%`, `100%`. Proposed minimum time between increments is 15 minutes.
+ - When setting percentages, make sure that the feature works correctly between feature checks. See https://gitlab.com/gitlab-org/gitlab/-/issues/327117 for more information
+ - For actor-based rollout: `/chatops run feature set feature_name 10 --actors`
+ - For time-based rollout: `/chatops run feature set feature_name 10`
+
+- [ ] Make the feature flag enabled by default i.e. Change `default_enabled` to `true`
+
+- [ ] Cross post chatops slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel
+
+
+**Cleanup**
+
+This is an __important__ phase, that should be either done in the next Milestone or as soon as possible. For the cleanup phase, please follow our documentation on how to [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up).
+
+<!-- The checklist here is to keep track of it's status for stakeholders -->
- [ ] Announce on the issue that the flag has been enabled
-- [ ] Remove feature flag and add changelog entry. Ensure that the feature flag definition YAML file has been removed in the **same MR** that is removing the feature flag from the code
-- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
+
+- [ ] Remove `:feature_name` feature flag
+ - [ ] Remove all references to the feature flag from the codebase
+ - [ ] Remove the YAML definitions for the feature from the repository
+ - [ ] Create a Changelog Entry
+
+- [ ] Clean up the feature flag from all environments by running this chatops command in `#production` channel `/chatops run feature delete some_feature`.
+
+**Final Step**
+
+- [ ] Close this rollout issue for the feature flag after the feature flag is removed from the codebase.
## Rollback Steps
@@ -53,3 +112,4 @@ If applicable, any groups/projects that are happy to have this feature turned on
```
/label ~"feature flag"
+/assign DRI
diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md
index 2cdf2341c88..72ee11e6f96 100644
--- a/.gitlab/issue_templates/Feature proposal.md
+++ b/.gitlab/issue_templates/Feature proposal.md
@@ -113,3 +113,5 @@ Use the following resources to find the appropriate labels:
/label ~devops:: ~group: ~Category:
/label ~"GitLab Core"/~"GitLab Premium"/~"GitLab Ultimate"
/label ~feature
+/label ~documentation
+/label ~direction
diff --git a/.gitlab/issue_templates/Geo: Replicate a new Git repository type.md b/.gitlab/issue_templates/Geo: Replicate a new Git repository type.md
new file mode 100644
index 00000000000..6b2d732f246
--- /dev/null
+++ b/.gitlab/issue_templates/Geo: Replicate a new Git repository type.md
@@ -0,0 +1,756 @@
+<!--
+
+This template is based on a model named `CoolWidget`.
+
+To adapt this template, find and replace the following tokens:
+
+- `CoolWidget`
+- `Cool Widget`
+- `cool_widget`
+- `coolWidget`
+
+If your Model's pluralized form is non-standard, i.e. it doesn't just end in `s`, then find and replace the following tokens *first*:
+
+- `CoolWidgets`
+- `Cool Widgets`
+- `cool_widgets`
+- `coolWidgets`
+
+-->
+
+## Replicate Cool Widgets
+
+This issue is for implementing Geo replication and verification of Cool Widgets.
+
+For more background, see [Geo self-service framework](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/geo/framework.md).
+
+In order to implement and test this feature, you need to first [set up Geo locally](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/geo.md).
+
+There are three main sections below. It is a good idea to structure your merge requests this way as well:
+
+1. Modify database schemas to prepare to add Geo support for Cool Widgets
+1. Implement Geo support of Cool Widgets behind a feature flag
+1. Release Geo support of Cool Widgets
+
+It is also a good idea to first open a proof-of-concept merge request. It can be helpful for working out kinks and getting initial support and feedback from the Geo team. As an example, see the [Proof of Concept to replicate Pipeline Artifacts](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56423).
+
+### Modify database schemas to prepare to add Geo support for Cool Widgets
+
+You might do this section in its own merge request, but it is not required.
+
+#### Add the registry table to track replication and verification state
+
+Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/geo.md#tracking-database) independent of the main database. It is used to track the replication and verification state of all replicables. Every Model has a corresponding "registry" table in the Geo tracking database.
+
+- [ ] Create the migration file in `ee/db/geo/migrate`:
+
+ ```shell
+ bin/rails generate geo_migration CreateCoolWidgetRegistry
+ ```
+
+- [ ] Replace the contents of the migration file with the following. Note that we cannot add a foreign key constraint on `cool_widget_id` because the `cool_widgets` table is in a different database. The application code must handle logic such as propagating deletions.
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class CreateCoolWidgetRegistry < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:cool_widget_registry)
+ ActiveRecord::Base.transaction do
+ create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
+ t.bigint :cool_widget_id, null: false
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :last_synced_at
+ t.datetime_with_timezone :retry_at
+ t.datetime_with_timezone :verified_at
+ t.datetime_with_timezone :verification_started_at
+ t.datetime_with_timezone :verification_retry_at
+ t.integer :state, default: 0, null: false, limit: 2
+ t.integer :verification_state, default: 0, null: false, limit: 2
+ t.integer :retry_count, default: 0, limit: 2, null: false
+ t.integer :verification_retry_count, default: 0, limit: 2, null: false
+ t.boolean :checksum_mismatch, default: false, null: false
+ t.boolean :force_to_redownload, default: false, null: false
+ t.boolean :missing_on_primary, default: false, null: false
+ t.binary :verification_checksum
+ t.binary :verification_checksum_mismatched
+ t.string :verification_failure, limit: 255 # rubocop:disable Migration/PreventStrings see https://gitlab.com/gitlab-org/gitlab/-/issues/323806
+ t.string :last_sync_failure, limit: 255 # rubocop:disable Migration/PreventStrings see https://gitlab.com/gitlab-org/gitlab/-/issues/323806
+
+ t.index :cool_widget_id, name: :index_cool_widget_registry_on_cool_widget_id, unique: true
+ t.index :retry_at
+ t.index :state
+ # To optimize performance of CoolWidgetRegistry.verification_failed_batch
+ t.index :verification_retry_at, name: :cool_widget_registry_failed_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 3))"
+ # To optimize performance of CoolWidgetRegistry.needs_verification_count
+ t.index :verification_state, name: :cool_widget_registry_needs_verification, where: "((state = 2) AND (verification_state = ANY (ARRAY[0, 3])))"
+ # To optimize performance of CoolWidgetRegistry.verification_pending_batch
+ t.index :verified_at, name: :cool_widget_registry_pending_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 0))"
+ end
+ end
+ end
+ end
+
+ def down
+ drop_table :cool_widget_registry
+ end
+ end
+ ```
+
+- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
+- [ ] Run Geo tracking database migrations:
+
+ ```shell
+ bin/rake geo:db:migrate
+ ```
+
+- [ ] Be sure to commit the relevant changes in `ee/db/geo/schema.rb`
+
+### Add verification state fields on the Geo primary site
+
+The Geo primary site needs to checksum every replicable in order for secondaries to verify their own checksums. To do this, Geo requires fields on the Model. There are two ways to add the necessary verification state fields. If the table is large and wide, then it may be a good idea to add verification state fields to a separate table (Option 2). Consult a database expert if needed.
+
+#### Add verification state fields to the model table (Option 1)
+
+- [ ] Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration AddVerificationStateToCoolWidgets
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationStateToCoolWidgets < ActiveRecord::Migration[6.0]
+ def change
+ change_table(:cool_widgets) do |t|
+ t.integer :verification_state, default: 0, limit: 2, null: false
+ t.column :verification_started_at, :datetime_with_timezone
+ t.integer :verification_retry_count, limit: 2, null: false
+ t.column :verification_retry_at, :datetime_with_timezone
+ t.column :verified_at, :datetime_with_timezone
+ t.binary :verification_checksum, using: 'verification_checksum::bytea'
+
+ t.text :verification_failure # rubocop:disable Migration/AddLimitToTextColumns
+ end
+ end
+ end
+ ```
+
+- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
+- [ ] If `cool_widgets` is a high-traffic table, follow [the database documentation to use `with_lock_retries`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/migration_style_guide.md#when-to-use-the-helper-method)
+- [ ] Adding a `text` column also [requires](../database/strings_and_the_text_data_type.md#add-a-text-column-to-an-existing-table) setting a limit. Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration AddVerificationFailureLimitToCoolWidgets
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationFailureLimitToCoolWidgets < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'cool_widget_verification_failure_text_limit'
+
+ def up
+ add_text_limit :cool_widget, :verification_failure, 255, constraint_name: CONSTRAINT_NAME
+ end
+
+ def down
+ remove_check_constraint(:cool_widget, CONSTRAINT_NAME)
+ end
+ end
+ ```
+
+- [ ] Add indexes on verification fields to ensure verification can be performed efficiently. Some or all of these indexes can be omitted if the table is guaranteed to be small. Ask a database expert if you are considering omitting indexes. Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration AddVerificationIndexesToCoolWidgets
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationIndexesToCoolWidgets < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ VERIFICATION_STATE_INDEX_NAME = "index_cool_widgets_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_cool_widgets_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_cool_widgets_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_cool_widgets_needs_verification"
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :cool_widgets, :verification_state, name: VERIFICATION_STATE_INDEX_NAME
+ add_concurrent_index :cool_widgets, :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
+ add_concurrent_index :cool_widgets, :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
+ add_concurrent_index :cool_widgets, :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :cool_widgets, VERIFICATION_STATE_INDEX_NAME
+ remove_concurrent_index_by_name :cool_widgets, PENDING_VERIFICATION_INDEX_NAME
+ remove_concurrent_index_by_name :cool_widgets, FAILED_VERIFICATION_INDEX_NAME
+ remove_concurrent_index_by_name :cool_widgets, NEEDS_VERIFICATION_INDEX_NAME
+ end
+ end
+ ```
+
+- [ ] Run database migrations:
+
+ ```shell
+ bin/rake db:migrate
+ ```
+
+- [ ] Be sure to commit the relevant changes in `db/structure.sql`
+
+#### Add verification state fields to a separate table (Option 2)
+
+- [ ] Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration CreateCoolWidgetStates
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class CreateCoolWidgetStates < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ VERIFICATION_STATE_INDEX_NAME = "index_cool_widget_states_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_cool_widget_states_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_cool_widget_states_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_cool_widget_states_needs_verification"
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:cool_widget_states)
+ with_lock_retries do
+ create_table :cool_widget_states, id: false do |t|
+ t.references :cool_widget, primary_key: true, null: false, foreign_key: { on_delete: :cascade }
+ t.integer :verification_state, default: 0, limit: 2, null: false
+ t.column :verification_started_at, :datetime_with_timezone
+ t.datetime_with_timezone :verification_retry_at
+ t.datetime_with_timezone :verified_at
+ t.integer :verification_retry_count, limit: 2
+ t.binary :verification_checksum, using: 'verification_checksum::bytea'
+ t.text :verification_failure
+
+ t.index :verification_state, name: VERIFICATION_STATE_INDEX_NAME
+ t.index :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
+ t.index :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
+ t.index :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ end
+ end
+ end
+
+ add_text_limit :cool_widget_states, :verification_failure, 255
+ end
+
+ def down
+ drop_table :cool_widget_states
+ end
+ end
+ ```
+
+- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
+- [ ] Run database migrations:
+
+ ```shell
+ bin/rake db:migrate
+ ```
+
+- [ ] Be sure to commit the relevant changes in `db/structure.sql`
+
+That's all of the required database changes.
+
+### Implement Geo support of Cool Widgets behind a feature flag
+
+#### Step 1. Implement replication and verification
+
+- [ ] Include `Gitlab::Geo::ReplicableModel` in the `CoolWidget` class, and specify the Replicator class `with_replicator Geo::CoolWidgetReplicator`.
+
+ Pay some attention to method `pool_repository`. Not every repository type uses repository pooling. As Geo prefers to use repository snapshotting, it can lead to data loss. Make sure to overwrite `pool_repository` so it returns nil for repositories that do not have pools.
+
+ At this point the `CoolWidget` class should look like this:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class CoolWidget < ApplicationRecord
+ include ::Gitlab::Geo::ReplicableModel
+ include ::Gitlab::Geo::VerificationState
+
+ with_replicator Geo::CoolWidgetReplicator
+
+ mount_uploader :file, CoolWidgetUploader
+
+ # Override the `all` default if not all records can be replicated. For an
+ # example of an existing Model that needs to do this, see
+ # `EE::MergeRequestDiff`.
+ # scope :available_replicables, -> { all }
+
+ # @param primary_key_in [Range, CoolWidget] arg to pass to primary_key_in scope
+ # @return [ActiveRecord::Relation<CoolWidget>] everything that should be synced to this node, restricted by primary key
+ def self.replicables_for_current_secondary(primary_key_in)
+ # This issue template does not help you write this method.
+ #
+ # This method is called only on Geo secondary sites. It is called when
+ # we want to know which records to replicate. This is not easy to automate
+ # because for example:
+ #
+ # * The "selective sync" feature allows admins to choose which namespaces # to replicate, per secondary site. Most Models are scoped to a
+ # namespace, but the nature of the relationship to a namespace varies
+ # between Models.
+ # * The "selective sync" feature allows admins to choose which shards to
+ # replicate, per secondary site. Repositories are associated with
+ # shards. Most blob types are not, but Project Uploads are.
+ # * Remote stored replicables are not replicated, by default. But the
+ # setting `sync_object_storage` enables replication of remote stored
+ # replicables.
+ #
+ # Search the codebase for examples, and consult a Geo expert if needed.
+ end
+
+ # Geo checks this method in FrameworkRepositorySyncService to avoid
+ # snapshotting repositories using object pools
+ def pool_repository
+ nil
+ end
+
+ ...
+ end
+ ```
+
+- [ ] Implement `CoolWidget.replicables_for_current_secondary` above.
+- [ ] Ensure `CoolWidget.replicables_for_current_secondary` is well-tested. Search the codebase for `replicables_for_current_secondary` to find examples of parameterized table specs. You may need to add more `FactoryBot` traits.
+- [ ] If you are using a separate table `cool_widget_states` to track verification state on the Geo primary site, then:
+ - [ ] Do not include `::Gitlab::Geo::VerificationState` on the `CoolWidget` class.
+ - [ ] Add the following lines to the `cool_widget_state.rb` model:
+
+ ```ruby
+ class CoolWidgetState < ApplicationRecord
+ ...
+ self.primary_key = :cool_widget_id
+
+ include ::Gitlab::Geo::VerificationState
+
+ belongs_to :cool_widget, inverse_of: :cool_widget_state
+ ...
+ end
+ ```
+
+ - [ ] Add the following lines to the `cool_widget` model:
+
+ ```ruby
+ class CoolWidget < ApplicationRecord
+ ...
+ has_one :cool_widget_state, inverse_of: :cool_widget
+
+ delegate :verification_retry_at, :verification_retry_at=,
+ :verified_at, :verified_at=,
+ :verification_checksum, :verification_checksum=,
+ :verification_failure, :verification_failure=,
+ :verification_retry_count, :verification_retry_count=,
+ to: :cool_widget_state
+ ...
+ end
+ ```
+
+- [ ] Create `ee/app/replicators/geo/cool_widget_replicator.rb`. Implement the `#repository` method which should return a `<Repository>` instance, and implement the class method `.model` to return the `CoolWidget` class:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Geo
+ class CoolWidgetReplicator < Gitlab::Geo::Replicator
+ include ::Geo::RepositoryReplicatorStrategy
+
+ def self.model
+ ::CoolWidget
+ end
+
+ def repository
+ model_record.repository
+ end
+
+ def self.git_access_class
+ ::Gitlab::GitAccessCoolWidget
+ end
+
+ # The feature flag follows the format `geo_#{replicable_name}_replication`,
+ # so here it would be `geo_cool_widget_replication`
+ def self.replication_enabled_by_default?
+ false
+ end
+
+ override :verification_feature_flag_enabled?
+ def self.verification_feature_flag_enabled?
+ # We are adding verification at the same time as replication, so we
+ # don't need to toggle verification separately from replication. When
+ # the replication feature flag is off, then verification is also off
+ # (see `VerifiableReplicator.verification_enabled?`)
+ true
+ end
+
+ end
+ end
+ ```
+
+- [ ] Make sure Geo push events are created. Usually it needs some change in the `app/workers/post_receive.rb` file. Example:
+
+ ```ruby
+ def replicate_cool_widget_changes(cool_widget)
+ if ::Gitlab::Geo.primary?
+ cool_widget.replicator.handle_after_update if cool_widget
+ end
+ end
+ ```
+
+ See `app/workers/post_receive.rb` for more examples.
+
+- [ ] Make sure the repository removal is also handled. You may need to add something like the following in the destroy service of the repository:
+
+ ```ruby
+ cool_widget.replicator.handle_after_destroy if cool_widget.repository
+ ```
+
+- [ ] Make sure a Geo secondary site can request and download Cool Widgets on the Geo primary site. You may need to make some changes to `Gitlab::GitAccessCoolWidget`. For example, see [this change for Group-level Wikis](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54914/diffs?commit_id=0f2b36f66697b4addbc69bd377ee2818f648dd33).
+- [ ] Generate the feature flag definition file by running the feature flag command and following the command prompts:
+
+ ```shell
+ bin/feature-flag --ee geo_cool_widget_replication --type development --group 'group::geo'
+ ```
+
+- [ ] Add this replicator class to the method `replicator_classes` in
+ `ee/lib/gitlab/geo.rb`:
+
+ ```ruby
+ REPLICATOR_CLASSES = [
+ ::Geo::PackageFileReplicator,
+ ::Geo::CoolWidgetReplicator
+ ]
+ end
+ ```
+
+- [ ] Create `ee/spec/replicators/geo/cool_widget_replicator_spec.rb` and perform the necessary setup to define the `model_record` variable for the shared examples:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Geo::CoolWidgetReplicator do
+ let(:model_record) { build(:cool_widget) }
+
+ include_examples 'a repository replicator'
+ include_examples 'a verifiable replicator'
+ end
+ ```
+
+- [ ] Create `ee/app/models/geo/cool_widget_registry.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class Geo::CoolWidgetRegistry < Geo::BaseRegistry
+ include ::Geo::ReplicableRegistry
+ include ::Geo::VerifiableRegistry
+
+ MODEL_CLASS = ::CoolWidget
+ MODEL_FOREIGN_KEY = :cool_widget_id
+
+ belongs_to :cool_widget, class_name: 'CoolWidget'
+ end
+ ```
+
+- [ ] Update `REGISTRY_CLASSES` in `ee/app/workers/geo/secondary/registry_consistency_worker.rb`.
+- [ ] Update `def model_class_factory_name` in `ee/spec/services/geo/registry_consistency_service_spec.rb`.
+- [ ] Update `it 'creates missing registries for each registry class'` in `ee/spec/workers/geo/secondary/registry_consistency_worker_spec.rb`.
+- [ ] Add `cool_widget_registry` to `ActiveSupport::Inflector.inflections` in `config/initializers_before_autoloader/000_inflections.rb`.
+- [ ] Create `ee/spec/factories/geo/cool_widget_registry.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ FactoryBot.define do
+ factory :geo_cool_widget_registry, class: 'Geo::CoolWidgetRegistry' do
+ cool_widget
+ state { Geo::CoolWidgetRegistry.state_value(:pending) }
+
+ trait :synced do
+ state { Geo::CoolWidgetRegistry.state_value(:synced) }
+ last_synced_at { 5.days.ago }
+ end
+
+ trait :failed do
+ state { Geo::CoolWidgetRegistry.state_value(:failed) }
+ last_synced_at { 1.day.ago }
+ retry_count { 2 }
+ last_sync_failure { 'Random error' }
+ end
+
+ trait :started do
+ state { Geo::CoolWidgetRegistry.state_value(:started) }
+ last_synced_at { 1.day.ago }
+ retry_count { 0 }
+ end
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/models/geo/cool_widget_registry_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Geo::CoolWidgetRegistry, :geo, type: :model do
+ let_it_be(:registry) { create(:geo_cool_widget_registry) }
+
+ specify 'factory is valid' do
+ expect(registry).to be_valid
+ end
+
+ include_examples 'a Geo framework registry'
+ include_examples 'a Geo verifiable registry'
+ end
+ ```
+
+#### Step 2. Implement metrics gathering
+
+Metrics are gathered by `Geo::MetricsUpdateWorker`, persisted in `GeoNodeStatus` for display in the UI, and sent to Prometheus:
+
+- [ ] Add the following fields to Geo Node Status example responses in `doc/api/geo_nodes.md`:
+ - `cool_widgets_count`
+ - `cool_widgets_checksum_total_count`
+ - `cool_widgets_checksummed_count`
+ - `cool_widgets_checksum_failed_count`
+ - `cool_widgets_synced_count`
+ - `cool_widgets_failed_count`
+ - `cool_widgets_registry_count`
+ - `cool_widgets_verification_total_count`
+ - `cool_widgets_verified_count`
+ - `cool_widgets_verification_failed_count`
+ - `cool_widgets_synced_in_percentage`
+ - `cool_widgets_verified_in_percentage`
+- [ ] Add the same fields to `GET /geo_nodes/status` example response in
+ `ee/spec/fixtures/api/schemas/public_api/v4/geo_node_status.json`.
+- [ ] Add the following fields to the `Sidekiq metrics` table in `doc/administration/monitoring/prometheus/gitlab_metrics.md`:
+ - `geo_cool_widgets`
+ - `geo_cool_widgets_checksum_total`
+ - `geo_cool_widgets_checksummed`
+ - `geo_cool_widgets_checksum_failed`
+ - `geo_cool_widgets_synced`
+ - `geo_cool_widgets_failed`
+ - `geo_cool_widgets_registry`
+ - `geo_cool_widgets_verification_total`
+ - `geo_cool_widgets_verified`
+ - `geo_cool_widgets_verification_failed`
+- [ ] Add the following to the parameterized table in the `context 'Replicator stats' do` block in `ee/spec/models/geo_node_status_spec.rb`:
+
+ ```ruby
+ Geo::CoolWidgetReplicator | :cool_widget | :geo_cool_widget_registry
+ ```
+
+- [ ] Add the following to `spec/factories/cool_widgets.rb`:
+
+ ```ruby
+ trait(:verification_succeeded) do
+ with_file
+ verification_checksum { 'abc' }
+ verification_state { CoolWidget.verification_state_value(:verification_succeeded) }
+ end
+
+ trait(:verification_failed) do
+ with_file
+ verification_failure { 'Could not calculate the checksum' }
+ verification_state { CoolWidget.verification_state_value(:verification_failed) }
+ end
+ ```
+
+- [ ] Make sure the factory also allows setting a `project` attribute. If the model does not have a direct relation to a project, you can use a `transient` attribute. Check out `spec/factories/merge_request_diffs.rb` for an example.
+
+Cool Widget replication and verification metrics should now be available in the API, the `Admin > Geo > Nodes` view, and Prometheus.
+
+#### Step 3. Implement the GraphQL API
+
+The GraphQL API is used by `Admin > Geo > Replication Details` views, and is directly queryable by administrators.
+
+- [ ] Add a new field to `GeoNodeType` in `ee/app/graphql/types/geo/geo_node_type.rb`:
+
+ ```ruby
+ field :cool_widget_registries, ::Types::Geo::CoolWidgetRegistryType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Geo::CoolWidgetRegistriesResolver,
+ description: 'Find Cool Widget registries on this Geo node',
+ feature_flag: :geo_cool_widget_replication
+ ```
+
+- [ ] Add the new `cool_widget_registries` field name to the `expected_fields` array in `ee/spec/graphql/types/geo/geo_node_type_spec.rb`.
+- [ ] Create `ee/app/graphql/resolvers/geo/cool_widget_registries_resolver.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Resolvers
+ module Geo
+ class CoolWidgetRegistriesResolver < BaseResolver
+ type ::Types::Geo::GeoNodeType.connection_type, null: true
+
+ include RegistriesResolver
+ end
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/graphql/resolvers/geo/cool_widget_registries_resolver_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Resolvers::Geo::CoolWidgetRegistriesResolver do
+ it_behaves_like 'a Geo registries resolver', :geo_cool_widget_registry
+ end
+ ```
+
+- [ ] Create `ee/app/finders/geo/cool_widget_registry_finder.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Geo
+ class CoolWidgetRegistryFinder
+ include FrameworkRegistryFinder
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/finders/geo/cool_widget_registry_finder_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Geo::CoolWidgetRegistryFinder do
+ it_behaves_like 'a framework registry finder', :geo_cool_widget_registry
+ end
+ ```
+
+- [ ] Create `ee/app/graphql/types/geo/cool_widget_registry_type.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Types
+ module Geo
+ # rubocop:disable Graphql/AuthorizeTypes because it is included
+ class CoolWidgetRegistryType < BaseObject
+ include ::Types::Geo::RegistryType
+
+ graphql_name 'CoolWidgetRegistry'
+ description 'Represents the Geo replication and verification state of a cool_widget'
+
+ field :cool_widget_id, GraphQL::ID_TYPE, null: false, description: 'ID of the Cool Widget'
+ end
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/graphql/types/geo/cool_widget_registry_type_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe GitlabSchema.types['CoolWidgetRegistry'] do
+ it_behaves_like 'a Geo registry type'
+
+ it 'has the expected fields (other than those included in RegistryType)' do
+ expected_fields = %i[cool_widget_id]
+
+ expect(described_class).to have_graphql_fields(*expected_fields).at_least
+ end
+ end
+ ```
+
+- [ ] Add integration tests for providing CoolWidget registry data to the frontend via the GraphQL API, by duplicating and modifying the following shared examples in `ee/spec/requests/api/graphql/geo/registries_spec.rb`:
+
+ ```ruby
+ it_behaves_like 'gets registries for', {
+ field_name: 'coolWidgetRegistries',
+ registry_class_name: 'CoolWidgetRegistry',
+ registry_factory: :geo_cool_widget_registry,
+ registry_foreign_key_field_name: 'coolWidgetId'
+ }
+ ```
+
+- [ ] Update the GraphQL reference documentation:
+
+ ```shell
+ bundle exec rake gitlab:graphql:compile_docs
+ ```
+
+Individual Cool Widget replication and verification data should now be available via the GraphQL API.
+
+### Release Geo support of Cool Widgets
+
+- [ ] In the rollout issue you created when creating the feature flag, modify the Roll Out Steps:
+ - [ ] Cross out any steps related to testing on production GitLab.com, because Geo is not running on production GitLab.com at the moment.
+ - [ ] Add a step to `Test replication and verification of Cool Widgets on a non-GDK-deployment. For example, using GitLab Environment Toolkit`.
+ - [ ] Add a step to `Ping the Geo PM and EM to coordinate testing`. For example, you might add steps to generate Cool Widgets, and then a Geo engineer may take it from there.
+- [ ] In `ee/config/feature_flags/development/geo_cool_widget_replication.yml`, set `default_enabled: true`
+
+- [ ] In `ee/app/replicators/geo/cool_widget_replicator.rb`, delete the `self.replication_enabled_by_default?` method:
+
+ ```ruby
+ module Geo
+ class CoolWidgetReplicator < Gitlab::Geo::Replicator
+ ...
+
+ # REMOVE THIS METHOD
+ def self.replication_enabled_by_default?
+ false
+ end
+ # REMOVE THIS METHOD
+
+ ...
+ end
+ end
+ ```
+
+- [ ] In `ee/app/graphql/types/geo/geo_node_type.rb`, remove the `feature_flag` option for the released type:
+
+ ```ruby
+ field :cool_widget_registries, ::Types::Geo::CoolWidgetRegistryType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Geo::CoolWidgetRegistriesResolver,
+ description: 'Find Cool Widget registries on this Geo node',
+ feature_flag: :geo_cool_widget_replication # REMOVE THIS LINE
+ ```
+
+- [ ] Add a row for Cool Widgets to the `Data types` table in [Geo data types support](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/geo/replication/datatypes.md#data-types)
+- [ ] Add a row for Cool Widgets to the `Limitations on replication/verification` table in [Geo data types support](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/geo/replication/datatypes.md#limitations-on-replicationverification). If the row already exists, then update it to show that Replication and Verification is released in the current version.
diff --git a/.gitlab/issue_templates/Geo: Replicate a new blob type.md b/.gitlab/issue_templates/Geo: Replicate a new blob type.md
new file mode 100644
index 00000000000..12fe6a6f5bb
--- /dev/null
+++ b/.gitlab/issue_templates/Geo: Replicate a new blob type.md
@@ -0,0 +1,722 @@
+<!--
+
+This template is based on a model named `CoolWidget`.
+
+To adapt this template, find and replace the following tokens:
+
+- `CoolWidget`
+- `Cool Widget`
+- `cool_widget`
+- `coolWidget`
+
+If your Model's pluralized form is non-standard, i.e. it doesn't just end in `s`, find and replace the following tokens *first*:
+
+- `CoolWidgets`
+- `Cool Widgets`
+- `cool_widgets`
+- `coolWidgets`
+
+-->
+
+## Replicate Cool Widgets
+
+This issue is for implementing Geo replication and verification of Cool Widgets.
+
+For more background, see [Geo self-service framework](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/geo/framework.md).
+
+In order to implement and test this feature, you need to first [set up Geo locally](https://gitlab.com/gitlab-org/gitlab-development-kit/blob/master/doc/howto/geo.md).
+
+There are three main sections below. It is a good idea to structure your merge requests this way as well:
+
+1. Modify database schemas to prepare to add Geo support for Cool Widgets
+1. Implement Geo support of Cool Widgets behind a feature flag
+1. Release Geo support of Cool Widgets
+
+It is also a good idea to first open a proof-of-concept merge request. It can be helpful for working out kinks and getting initial support and feedback from the Geo team. As an example, see the [Proof of Concept to replicate Pipeline Artifacts](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56423).
+
+### Modify database schemas to prepare to add Geo support for Cool Widgets
+
+You might do this section in its own merge request, but it is not required.
+
+#### Add the registry table to track replication and verification state
+
+Geo secondary sites have a [Geo tracking database](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/geo.md#tracking-database) independent of the main database. It is used to track the replication and verification state of all replicables. Every Model has a corresponding "registry" table in the Geo tracking database.
+
+- [ ] Create the migration file in `ee/db/geo/migrate`:
+
+ ```shell
+ bin/rails generate geo_migration CreateCoolWidgetRegistry
+ ```
+
+- [ ] Replace the contents of the migration file with the following. Note that we cannot add a foreign key constraint on `cool_widget_id` because the `cool_widgets` table is in a different database. The application code must handle logic such as propagating deletions.
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class CreateCoolWidgetRegistry < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:cool_widget_registry)
+ ActiveRecord::Base.transaction do
+ create_table :cool_widget_registry, id: :bigserial, force: :cascade do |t|
+ t.bigint :cool_widget_id, null: false
+ t.datetime_with_timezone :created_at, null: false
+ t.datetime_with_timezone :last_synced_at
+ t.datetime_with_timezone :retry_at
+ t.datetime_with_timezone :verified_at
+ t.datetime_with_timezone :verification_started_at
+ t.datetime_with_timezone :verification_retry_at
+ t.integer :state, default: 0, null: false, limit: 2
+ t.integer :verification_state, default: 0, null: false, limit: 2
+ t.integer :retry_count, default: 0, limit: 2, null: false
+ t.integer :verification_retry_count, default: 0, limit: 2, null: false
+ t.boolean :checksum_mismatch, default: false, null: false
+ t.binary :verification_checksum
+ t.binary :verification_checksum_mismatched
+ t.string :verification_failure, limit: 255 # rubocop:disable Migration/PreventStrings see https://gitlab.com/gitlab-org/gitlab/-/issues/323806
+ t.string :last_sync_failure, limit: 255 # rubocop:disable Migration/PreventStrings see https://gitlab.com/gitlab-org/gitlab/-/issues/323806
+
+ t.index :cool_widget_id, name: :index_cool_widget_registry_on_cool_widget_id, unique: true
+ t.index :retry_at
+ t.index :state
+ # To optimize performance of CoolWidgetRegistry.verification_failed_batch
+ t.index :verification_retry_at, name: :cool_widget_registry_failed_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 3))"
+ # To optimize performance of CoolWidgetRegistry.needs_verification_count
+ t.index :verification_state, name: :cool_widget_registry_needs_verification, where: "((state = 2) AND (verification_state = ANY (ARRAY[0, 3])))"
+ # To optimize performance of CoolWidgetRegistry.verification_pending_batch
+ t.index :verified_at, name: :cool_widget_registry_pending_verification, order: "NULLS FIRST", where: "((state = 2) AND (verification_state = 0))"
+ end
+ end
+ end
+ end
+
+ def down
+ drop_table :cool_widget_registry
+ end
+ end
+ ```
+
+- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
+- [ ] Run Geo tracking database migrations:
+
+ ```shell
+ bin/rake geo:db:migrate
+ ```
+
+- [ ] Be sure to commit the relevant changes in `ee/db/geo/schema.rb`
+
+### Add verification state fields on the Geo primary site
+
+The Geo primary site needs to checksum every replicable in order for secondaries to verify their own checksums. To do this, Geo requires fields on the Model. There are two ways to add the necessary verification state fields. If the table is large and wide, then it may be a good idea to add verification state fields to a separate table (Option 2). Consult a database expert if needed.
+
+#### Add verification state fields to the model table (Option 1)
+
+- [ ] Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration AddVerificationStateToCoolWidgets
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationStateToCoolWidgets < ActiveRecord::Migration[6.0]
+ def change
+ change_table(:cool_widgets) do |t|
+ t.integer :verification_state, default: 0, limit: 2, null: false
+ t.column :verification_started_at, :datetime_with_timezone
+ t.integer :verification_retry_count, limit: 2, null: false
+ t.column :verification_retry_at, :datetime_with_timezone
+ t.column :verified_at, :datetime_with_timezone
+ t.binary :verification_checksum, using: 'verification_checksum::bytea'
+
+ t.text :verification_failure # rubocop:disable Migration/AddLimitToTextColumns
+ end
+ end
+ end
+ ```
+
+- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
+- [ ] If `cool_widgets` is a high-traffic table, follow [the database documentation to use `with_lock_retries`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/migration_style_guide.md#when-to-use-the-helper-method)
+- [ ] Adding a `text` column also [requires](../database/strings_and_the_text_data_type.md#add-a-text-column-to-an-existing-table) setting a limit. Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration AddVerificationFailureLimitToCoolWidgets
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationFailureLimitToCoolWidgets < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ disable_ddl_transaction!
+
+ CONSTRAINT_NAME = 'cool_widget_verification_failure_text_limit'
+
+ def up
+ add_text_limit :cool_widget, :verification_failure, 255, constraint_name: CONSTRAINT_NAME
+ end
+
+ def down
+ remove_check_constraint(:cool_widget, CONSTRAINT_NAME)
+ end
+ end
+ ```
+
+- [ ] Add indexes on verification fields to ensure verification can be performed efficiently. Some or all of these indexes can be omitted if the table is guaranteed to be small. Ask a database expert if you are considering omitting indexes. Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration AddVerificationIndexesToCoolWidgets
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationIndexesToCoolWidgets < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ VERIFICATION_STATE_INDEX_NAME = "index_cool_widgets_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_cool_widgets_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_cool_widgets_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_cool_widgets_needs_verification"
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :cool_widgets, :verification_state, name: VERIFICATION_STATE_INDEX_NAME
+ add_concurrent_index :cool_widgets, :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
+ add_concurrent_index :cool_widgets, :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
+ add_concurrent_index :cool_widgets, :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ end
+
+ def down
+ remove_concurrent_index_by_name :cool_widgets, VERIFICATION_STATE_INDEX_NAME
+ remove_concurrent_index_by_name :cool_widgets, PENDING_VERIFICATION_INDEX_NAME
+ remove_concurrent_index_by_name :cool_widgets, FAILED_VERIFICATION_INDEX_NAME
+ remove_concurrent_index_by_name :cool_widgets, NEEDS_VERIFICATION_INDEX_NAME
+ end
+ end
+ ```
+
+- [ ] Run database migrations:
+
+ ```shell
+ bin/rake db:migrate
+ ```
+
+- [ ] Be sure to commit the relevant changes in `db/structure.sql`
+
+#### Add verification state fields to a separate table (Option 2)
+
+- [ ] Create the migration file in `db/migrate`:
+
+ ```shell
+ bin/rails generate migration CreateCoolWidgetStates
+ ```
+
+- [ ] Replace the contents of the migration file with:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class CreateCoolWidgetStates < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ VERIFICATION_STATE_INDEX_NAME = "index_cool_widget_states_on_verification_state"
+ PENDING_VERIFICATION_INDEX_NAME = "index_cool_widget_states_pending_verification"
+ FAILED_VERIFICATION_INDEX_NAME = "index_cool_widget_states_failed_verification"
+ NEEDS_VERIFICATION_INDEX_NAME = "index_cool_widget_states_needs_verification"
+
+ disable_ddl_transaction!
+
+ def up
+ unless table_exists?(:cool_widget_states)
+ with_lock_retries do
+ create_table :cool_widget_states, id: false do |t|
+ t.references :cool_widget, primary_key: true, null: false, foreign_key: { on_delete: :cascade }
+ t.integer :verification_state, default: 0, limit: 2, null: false
+ t.column :verification_started_at, :datetime_with_timezone
+ t.datetime_with_timezone :verification_retry_at
+ t.datetime_with_timezone :verified_at
+ t.integer :verification_retry_count, limit: 2
+ t.binary :verification_checksum, using: 'verification_checksum::bytea'
+ t.text :verification_failure
+
+ t.index :verification_state, name: VERIFICATION_STATE_INDEX_NAME
+ t.index :verified_at, where: "(verification_state = 0)", order: { verified_at: 'ASC NULLS FIRST' }, name: PENDING_VERIFICATION_INDEX_NAME
+ t.index :verification_retry_at, where: "(verification_state = 3)", order: { verification_retry_at: 'ASC NULLS FIRST' }, name: FAILED_VERIFICATION_INDEX_NAME
+ t.index :verification_state, where: "(verification_state = 0 OR verification_state = 3)", name: NEEDS_VERIFICATION_INDEX_NAME
+ end
+ end
+ end
+
+ add_text_limit :cool_widget_states, :verification_failure, 255
+ end
+
+ def down
+ drop_table :cool_widget_states
+ end
+ end
+ ```
+
+- [ ] If deviating from the above example, then be sure to order columns according to [our guidelines](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/development/ordering_table_columns.md).
+- [ ] Run database migrations:
+
+ ```shell
+ bin/rake db:migrate
+ ```
+
+- [ ] Be sure to commit the relevant changes in `db/structure.sql`
+
+That's all of the required database changes.
+
+### Implement Geo support of Cool Widgets behind a feature flag
+
+#### Step 1. Implement replication and verification
+
+- [ ] Include `Gitlab::Geo::ReplicableModel` in the `CoolWidget` class, and specify the Replicator class `with_replicator Geo::CoolWidgetReplicator`.
+
+ At this point the `CoolWidget` class should look like this:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class CoolWidget < ApplicationRecord
+ include ::Gitlab::Geo::ReplicableModel
+ include ::Gitlab::Geo::VerificationState
+
+ with_replicator Geo::CoolWidgetReplicator
+
+ mount_uploader :file, CoolWidgetUploader
+
+ # Override the `all` default if not all records can be replicated. For an
+ # example of an existing Model that needs to do this, see
+ # `EE::MergeRequestDiff`.
+ # scope :available_replicables, -> { all }
+
+ # @param primary_key_in [Range, CoolWidget] arg to pass to primary_key_in scope
+ # @return [ActiveRecord::Relation<CoolWidget>] everything that should be synced to this node, restricted by primary key
+ def self.replicables_for_current_secondary(primary_key_in)
+ # This issue template does not help you write this method.
+ #
+ # This method is called only on Geo secondary sites. It is called when
+ # we want to know which records to replicate. This is not easy to automate
+ # because for example:
+ #
+ # * The "selective sync" feature allows admins to choose which namespaces # to replicate, per secondary site. Most Models are scoped to a
+ # namespace, but the nature of the relationship to a namespace varies
+ # between Models.
+ # * The "selective sync" feature allows admins to choose which shards to
+ # replicate, per secondary site. Repositories are associated with
+ # shards. Most blob types are not, but Project Uploads are.
+ # * Remote stored replicables are not replicated, by default. But the
+ # setting `sync_object_storage` enables replication of remote stored
+ # replicables.
+ #
+ # Search the codebase for examples, and consult a Geo expert if needed.
+ end
+ ...
+ end
+ ```
+
+- [ ] Implement `CoolWidget.replicables_for_current_secondary` above.
+- [ ] Ensure `CoolWidget.replicables_for_current_secondary` is well-tested. Search the codebase for `replicables_for_current_secondary` to find examples of parameterized table specs. You may need to add more `FactoryBot` traits.
+- [ ] If you are using a separate table `cool_widget_states` to track verification state on the Geo primary site, then:
+ - [ ] Do not include `::Gitlab::Geo::VerificationState` on the `CoolWidget` class.
+ - [ ] Add the following lines to the `cool_widget_state.rb` model:
+
+ ```ruby
+ class CoolWidgetState < ApplicationRecord
+ ...
+ self.primary_key = :cool_widget_id
+
+ include ::Gitlab::Geo::VerificationState
+
+ belongs_to :cool_widget, inverse_of: :cool_widget_state
+ ...
+ end
+ ```
+
+ - [ ] Add the following lines to the `cool_widget` model:
+
+ ```ruby
+ class CoolWidget < ApplicationRecord
+ ...
+ has_one :cool_widget_state, inverse_of: :cool_widget
+
+ delegate :verification_retry_at, :verification_retry_at=,
+ :verified_at, :verified_at=,
+ :verification_checksum, :verification_checksum=,
+ :verification_failure, :verification_failure=,
+ :verification_retry_count, :verification_retry_count=,
+ to: :cool_widget_state
+ ...
+ end
+ ```
+
+- [ ] Create `ee/app/replicators/geo/cool_widget_replicator.rb`. Implement the `#carrierwave_uploader` method which should return a `CarrierWave::Uploader`, and implement the class method `.model` to return the `CoolWidget` class:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Geo
+ class CoolWidgetReplicator < Gitlab::Geo::Replicator
+ include ::Geo::BlobReplicatorStrategy
+
+ def self.model
+ ::CoolWidget
+ end
+
+ def carrierwave_uploader
+ model_record.file
+ end
+
+ # The feature flag follows the format `geo_#{replicable_name}_replication`,
+ # so here it would be `geo_cool_widget_replication`
+ def self.replication_enabled_by_default?
+ false
+ end
+
+ override :verification_feature_flag_enabled?
+ def self.verification_feature_flag_enabled?
+ # We are adding verification at the same time as replication, so we
+ # don't need to toggle verification separately from replication. When
+ # the replication feature flag is off, then verification is also off
+ # (see `VerifiableReplicator.verification_enabled?`)
+ true
+ end
+
+ end
+ end
+ ```
+
+- [ ] Generate the feature flag definition file by running the feature flag command and following the command prompts:
+
+ ```shell
+ bin/feature-flag --ee geo_cool_widget_replication --type development --group 'group::geo'
+ ```
+
+- [ ] Add this replicator class to the method `replicator_classes` in
+ `ee/lib/gitlab/geo.rb`:
+
+ ```ruby
+ REPLICATOR_CLASSES = [
+ ::Geo::PackageFileReplicator,
+ ::Geo::CoolWidgetReplicator
+ ]
+ end
+ ```
+
+- [ ] Create `ee/spec/replicators/geo/cool_widget_replicator_spec.rb` and perform the necessary setup to define the `model_record` variable for the shared examples:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Geo::CoolWidgetReplicator do
+ let(:model_record) { build(:cool_widget) }
+
+ include_examples 'a blob replicator'
+ include_examples 'a verifiable replicator'
+ end
+ ```
+
+- [ ] Create `ee/app/models/geo/cool_widget_registry.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class Geo::CoolWidgetRegistry < Geo::BaseRegistry
+ include ::Geo::ReplicableRegistry
+ include ::Geo::VerifiableRegistry
+
+ MODEL_CLASS = ::CoolWidget
+ MODEL_FOREIGN_KEY = :cool_widget_id
+
+ belongs_to :cool_widget, class_name: 'CoolWidget'
+ end
+ ```
+
+- [ ] Update `REGISTRY_CLASSES` in `ee/app/workers/geo/secondary/registry_consistency_worker.rb`.
+- [ ] Update `def model_class_factory_name` in `ee/spec/services/geo/registry_consistency_service_spec.rb`.
+- [ ] Update `it 'creates missing registries for each registry class'` in `ee/spec/workers/geo/secondary/registry_consistency_worker_spec.rb`.
+- [ ] Add `cool_widget_registry` to `ActiveSupport::Inflector.inflections` in `config/initializers_before_autoloader/000_inflections.rb`.
+- [ ] Create `ee/spec/factories/geo/cool_widget_registry.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ FactoryBot.define do
+ factory :geo_cool_widget_registry, class: 'Geo::CoolWidgetRegistry' do
+ cool_widget
+ state { Geo::CoolWidgetRegistry.state_value(:pending) }
+
+ trait :synced do
+ state { Geo::CoolWidgetRegistry.state_value(:synced) }
+ last_synced_at { 5.days.ago }
+ end
+
+ trait :failed do
+ state { Geo::CoolWidgetRegistry.state_value(:failed) }
+ last_synced_at { 1.day.ago }
+ retry_count { 2 }
+ last_sync_failure { 'Random error' }
+ end
+
+ trait :started do
+ state { Geo::CoolWidgetRegistry.state_value(:started) }
+ last_synced_at { 1.day.ago }
+ retry_count { 0 }
+ end
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/models/geo/cool_widget_registry_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Geo::CoolWidgetRegistry, :geo, type: :model do
+ let_it_be(:registry) { create(:geo_cool_widget_registry) }
+
+ specify 'factory is valid' do
+ expect(registry).to be_valid
+ end
+
+ include_examples 'a Geo framework registry'
+ include_examples 'a Geo verifiable registry'
+ end
+ ```
+
+#### Step 2. Implement metrics gathering
+
+Metrics are gathered by `Geo::MetricsUpdateWorker`, persisted in `GeoNodeStatus` for display in the UI, and sent to Prometheus:
+
+- [ ] Add the following fields to Geo Node Status example responses in `doc/api/geo_nodes.md`:
+ - `cool_widgets_count`
+ - `cool_widgets_checksum_total_count`
+ - `cool_widgets_checksummed_count`
+ - `cool_widgets_checksum_failed_count`
+ - `cool_widgets_synced_count`
+ - `cool_widgets_failed_count`
+ - `cool_widgets_registry_count`
+ - `cool_widgets_verification_total_count`
+ - `cool_widgets_verified_count`
+ - `cool_widgets_verification_failed_count`
+ - `cool_widgets_synced_in_percentage`
+ - `cool_widgets_verified_in_percentage`
+- [ ] Add the same fields to `GET /geo_nodes/status` example response in
+ `ee/spec/fixtures/api/schemas/public_api/v4/geo_node_status.json`.
+- [ ] Add the following fields to the `Sidekiq metrics` table in `doc/administration/monitoring/prometheus/gitlab_metrics.md`:
+ - `geo_cool_widgets`
+ - `geo_cool_widgets_checksum_total`
+ - `geo_cool_widgets_checksummed`
+ - `geo_cool_widgets_checksum_failed`
+ - `geo_cool_widgets_synced`
+ - `geo_cool_widgets_failed`
+ - `geo_cool_widgets_registry`
+ - `geo_cool_widgets_verification_total`
+ - `geo_cool_widgets_verified`
+ - `geo_cool_widgets_verification_failed`
+- [ ] Add the following to the parameterized table in the `context 'Replicator stats' do` block in `ee/spec/models/geo_node_status_spec.rb`:
+
+ ```ruby
+ Geo::CoolWidgetReplicator | :cool_widget | :geo_cool_widget_registry
+ ```
+
+- [ ] Add the following to `spec/factories/cool_widgets.rb`:
+
+ ```ruby
+ trait(:verification_succeeded) do
+ with_file
+ verification_checksum { 'abc' }
+ verification_state { CoolWidget.verification_state_value(:verification_succeeded) }
+ end
+
+ trait(:verification_failed) do
+ with_file
+ verification_failure { 'Could not calculate the checksum' }
+ verification_state { CoolWidget.verification_state_value(:verification_failed) }
+ end
+ ```
+
+- [ ] Make sure the factory also allows setting a `project` attribute. If the model does not have a direct relation to a project, you can use a `transient` attribute. Check out `spec/factories/merge_request_diffs.rb` for an example.
+
+Cool Widget replication and verification metrics should now be available in the API, the `Admin > Geo > Nodes` view, and Prometheus.
+
+#### Step 3. Implement the GraphQL API
+
+The GraphQL API is used by `Admin > Geo > Replication Details` views, and is directly queryable by administrators.
+
+- [ ] Add a new field to `GeoNodeType` in `ee/app/graphql/types/geo/geo_node_type.rb`:
+
+ ```ruby
+ field :cool_widget_registries, ::Types::Geo::CoolWidgetRegistryType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Geo::CoolWidgetRegistriesResolver,
+ description: 'Find Cool Widget registries on this Geo node',
+ feature_flag: :geo_cool_widget_replication
+ ```
+
+- [ ] Add the new `cool_widget_registries` field name to the `expected_fields` array in `ee/spec/graphql/types/geo/geo_node_type_spec.rb`.
+- [ ] Create `ee/app/graphql/resolvers/geo/cool_widget_registries_resolver.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Resolvers
+ module Geo
+ class CoolWidgetRegistriesResolver < BaseResolver
+ type ::Types::Geo::GeoNodeType.connection_type, null: true
+
+ include RegistriesResolver
+ end
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/graphql/resolvers/geo/cool_widget_registries_resolver_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Resolvers::Geo::CoolWidgetRegistriesResolver do
+ it_behaves_like 'a Geo registries resolver', :geo_cool_widget_registry
+ end
+ ```
+
+- [ ] Create `ee/app/finders/geo/cool_widget_registry_finder.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Geo
+ class CoolWidgetRegistryFinder
+ include FrameworkRegistryFinder
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/finders/geo/cool_widget_registry_finder_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe Geo::CoolWidgetRegistryFinder do
+ it_behaves_like 'a framework registry finder', :geo_cool_widget_registry
+ end
+ ```
+
+- [ ] Create `ee/app/graphql/types/geo/cool_widget_registry_type.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Types
+ module Geo
+ # rubocop:disable Graphql/AuthorizeTypes because it is included
+ class CoolWidgetRegistryType < BaseObject
+ include ::Types::Geo::RegistryType
+
+ graphql_name 'CoolWidgetRegistry'
+ description 'Represents the Geo replication and verification state of a cool_widget'
+
+ field :cool_widget_id, GraphQL::ID_TYPE, null: false, description: 'ID of the Cool Widget'
+ end
+ end
+ end
+ ```
+
+- [ ] Create `ee/spec/graphql/types/geo/cool_widget_registry_type_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ RSpec.describe GitlabSchema.types['CoolWidgetRegistry'] do
+ it_behaves_like 'a Geo registry type'
+
+ it 'has the expected fields (other than those included in RegistryType)' do
+ expected_fields = %i[cool_widget_id]
+
+ expect(described_class).to have_graphql_fields(*expected_fields).at_least
+ end
+ end
+ ```
+
+- [ ] Add integration tests for providing CoolWidget registry data to the frontend via the GraphQL API, by duplicating and modifying the following shared examples in `ee/spec/requests/api/graphql/geo/registries_spec.rb`:
+
+ ```ruby
+ it_behaves_like 'gets registries for', {
+ field_name: 'coolWidgetRegistries',
+ registry_class_name: 'CoolWidgetRegistry',
+ registry_factory: :geo_cool_widget_registry,
+ registry_foreign_key_field_name: 'coolWidgetId'
+ }
+ ```
+
+- [ ] Update the GraphQL reference documentation:
+
+ ```shell
+ bundle exec rake gitlab:graphql:compile_docs
+ ```
+
+Individual Cool Widget replication and verification data should now be available via the GraphQL API.
+
+### Release Geo support of Cool Widgets
+
+- [ ] In the rollout issue you created when creating the feature flag, modify the Roll Out Steps:
+ - [ ] Cross out any steps related to testing on production GitLab.com, because Geo is not running on production GitLab.com at the moment.
+ - [ ] Add a step to `Test replication and verification of Cool Widgets on a non-GDK-deployment. For example, using GitLab Environment Toolkit`.
+ - [ ] Add a step to `Ping the Geo PM and EM to coordinate testing`. For example, you might add steps to generate Cool Widgets, and then a Geo engineer may take it from there.
+- [ ] In `ee/config/feature_flags/development/geo_cool_widget_replication.yml`, set `default_enabled: true`
+
+- [ ] In `ee/app/replicators/geo/cool_widget_replicator.rb`, delete the `self.replication_enabled_by_default?` method:
+
+ ```ruby
+ module Geo
+ class CoolWidgetReplicator < Gitlab::Geo::Replicator
+ ...
+
+ # REMOVE THIS METHOD
+ def self.replication_enabled_by_default?
+ false
+ end
+ # REMOVE THIS METHOD
+
+ ...
+ end
+ end
+ ```
+
+- [ ] In `ee/app/graphql/types/geo/geo_node_type.rb`, remove the `feature_flag` option for the released type:
+
+ ```ruby
+ field :cool_widget_registries, ::Types::Geo::CoolWidgetRegistryType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Geo::CoolWidgetRegistriesResolver,
+ description: 'Find Cool Widget registries on this Geo node',
+ feature_flag: :geo_cool_widget_replication # REMOVE THIS LINE
+ ```
+
+- [ ] Add a row for Cool Widgets to the `Data types` table in [Geo data types support](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/geo/replication/datatypes.md#data-types)
+- [ ] Add a row for Cool Widgets to the `Limitations on replication/verification` table in [Geo data types support](https://gitlab.com/gitlab-org/gitlab/blob/master/doc/administration/geo/replication/datatypes.md#limitations-on-replicationverification). If the row already exists, then update it to show that Replication and Verification is released in the current version.
diff --git a/.gitlab/issue_templates/Implementation.md b/.gitlab/issue_templates/Implementation.md
index 888c993766a..058834264b0 100644
--- a/.gitlab/issue_templates/Implementation.md
+++ b/.gitlab/issue_templates/Implementation.md
@@ -39,24 +39,25 @@ Add details for required items and delete others.
<!--
Steps and the parts of the code that will need to get updated. The plan can also
call-out responsibilities for other team members or teams.
--->
+
+e.g.:
- [ ] ~frontend Step 1
- [ ] `@person` Step 1a
- [ ] ~frontend Step 2
+-->
+
<!--
Workflow and other relevant labels
-~"group::" ~"Category:" ~"GitLab Ultimate"
--->
-/label ~"workflow::refinement"
-
-<!--
+# ~"group::" ~"Category:" ~"GitLab Ultimate"
Other settings you might want to include when creating the issue.
-/milestone %"Next 1-3 releases"
-/assign @
-/epic &
+# /assign @
+# /epic &
-->
+
+/label ~"workflow::refinement"
+/milestone %Backlog
diff --git a/.gitlab/issue_templates/Lean Feature Proposal.md b/.gitlab/issue_templates/Lean Feature Proposal.md
index fb9ac306f31..828d5161269 100644
--- a/.gitlab/issue_templates/Lean Feature Proposal.md
+++ b/.gitlab/issue_templates/Lean Feature Proposal.md
@@ -101,3 +101,6 @@ In which enterprise tier should this feature go? See https://about.gitlab.com/ha
### Is this a cross-stage feature?
Communicate if this change will affect multiple Stage Groups or product areas. We recommend always start with the assumption that a feature request will have an impact into another Group. Loop in the most relevant PM and Product Designer from that Group to provide strategic support to help align the Group's broader plan and vision, as well as to avoid UX and technical debt. https://about.gitlab.com/handbook/product/#cross-stage-features -->
+
+/label ~documentation
+/label ~direction
diff --git a/.gitlab/issue_templates/Migrations.md b/.gitlab/issue_templates/OSS_Partner.md
index 822722a0f71..d9c05026e7c 100644
--- a/.gitlab/issue_templates/Migrations.md
+++ b/.gitlab/issue_templates/OSS_Partner.md
@@ -1,10 +1,9 @@
-# Project Name | Migration Tracker
-<!-- Please edit this header with your project / organization's name. -->
+<!-- Please title your issue with the following format: "Project Name | Issue Tracker". -->
## Background
<!--
-Please add information here about why you're planning on migrating. Include any initial announcements that have been made about the decision or status.
+Please add information here about why your project is considering a migration to GitLab, or why it decided to do so. Include any initial announcements that have been / were made about the decision or status.
-->
### Goals
@@ -16,7 +15,7 @@ Please add information here about why you're planning on migrating. Include any
<!-- Please complete as many items in this list as possible. If you're not sure yet, add "TBD" (To be Decided) or "Unknown" -->
* **Timeline.** -
- * **Product.** - GitLab Gold/Ultimate or Community Edition
+ * **Product.** - SaaS-Ultimate/Self-Managed-Ultimate or Community Edition
* **Project's License.** What kind of OSI-approved license does your project use?
## Current Tooling and Replacements
@@ -31,6 +30,8 @@ Please fill in the table to give an overview of your current tooling. Here's a d
Here's an example of a replacements overview from one of the projects which migrated to GitLab: https://gitlab.com/gitlab-org/gitlab/-/issues/25657#gitlab-replacements
+Consider deleting the table below if you are unable to expand upon your current tooling.
+
-->
| Tool | Feature | GitLab feature | GitLab edition |
@@ -63,5 +64,5 @@ Here is an example of what this list might look like once populated: https://git
------
-/label ~"Open Source" ~movingtogitlab
-/cc @nuritzi
+/label ~"Open Source Partners"
+/cc @nuritzi @greg
diff --git a/.gitlab/issue_templates/Productivity Improvement.md b/.gitlab/issue_templates/Productivity Improvement.md
index 974f11f6da3..06692d3ede8 100644
--- a/.gitlab/issue_templates/Productivity Improvement.md
+++ b/.gitlab/issue_templates/Productivity Improvement.md
@@ -34,6 +34,6 @@ after the implementation is merged/deployed/released.
- [ ] The solution improved the situation.
- If yes, check this box and close the issue. Well done! :tada:
- - Otherwise, create a new "Productivity Improvement" issue. You can re-use the description from this issue, but obviously another solution should be chosen this time.
+ - Otherwise, create a new "Productivity Improvement" issue. You can re-use the description from this issue, but another solution should be chosen this time.
/label ~"Engineering Productivity" ~meta
diff --git a/.gitlab/issue_templates/Query Performance Investigation.md b/.gitlab/issue_templates/Query Performance Investigation.md
index ddd361e4f2f..354cdb1bfe1 100644
--- a/.gitlab/issue_templates/Query Performance Investigation.md
+++ b/.gitlab/issue_templates/Query Performance Investigation.md
@@ -10,6 +10,16 @@ As the name implies, the purpose of the template is to detail underperforming qu
- [ ] Provide [priority and severity labels](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#availability)
- [ ] If this requires immediate attention cc `@gitlab-org/database-team` and reach out in the #g_database slack channel
+### SQL Statement
+
+```sql
+
+```
+
+### Data from Elastic
+
+Instructions on collecting data from [PostgreSQL slow logs stored in Elasticsearch](https://gitlab.com/gitlab-com/runbooks/-/merge_requests/3361/diffs)
+
### Requested Data points
Please provide as many of these fields as possible when submitting a query performance report.
@@ -20,7 +30,6 @@ Please provide as many of these fields as possible when submitting a query perfo
- Database time relative to total database time
- Source of calls (Sidekiq, WebAPI, etc)
- Query ID
-- SQL Statement
- Query Plan
- Query Example
- Total number of calls (relative)
diff --git a/.gitlab/issue_templates/Security developer workflow.md b/.gitlab/issue_templates/Security developer workflow.md
index beb066cdfc4..25825fc8888 100644
--- a/.gitlab/issue_templates/Security developer workflow.md
+++ b/.gitlab/issue_templates/Security developer workflow.md
@@ -10,9 +10,10 @@ Set the title to: `Description of the original issue`
- [ ] Read the [security process for developers] if you are not familiar with it.
- Verify if the issue you're working on `gitlab-org/gitlab` is confidential, if it's public fix should be placed on GitLab canonical and no backports are required.
-- [ ] Mark this [issue as related] to the Security Release Tracking Issue. You can find it on the topic of the `#releases` Slack channel.
+- [ ] Mark this [issue as linked] to the Security Release Tracking Issue. You can find it on the topic of the `#releases` Slack channel.
- Fill out the [Links section](#links):
- [ ] Next to **Issue on GitLab**, add a link to the `gitlab-org/gitlab` issue that describes the security vulnerability.
+- [ ] Add one of the `~severity::x` labels to the issue and all associated merge requests.
## Development
@@ -64,6 +65,6 @@ After your merge request has been approved according to our [approval guidelines
[secpick documentation]: https://gitlab.com/gitlab-org/release/docs/-/blob/master/general/security/utilities/secpick_script.md
[security Release merge request template]: https://gitlab.com/gitlab-org/security/gitlab/blob/master/.gitlab/merge_request_templates/Security%20Release.md
[approval guidelines]: https://docs.gitlab.com/ee/development/code_review.html#approval-guidelines
-[issue as related]: https://docs.gitlab.com/ee/user/project/issues/related_issues.html#adding-a-related-issue
+[issue as linked]: https://docs.gitlab.com/ee/user/project/issues/related_issues.html#add-a-linked-issue
/label ~security
diff --git a/.gitlab/issue_templates/experiment_tracking_template.md b/.gitlab/issue_templates/experiment_tracking_template.md
index 432ae57e594..c653a3a2d40 100644
--- a/.gitlab/issue_templates/experiment_tracking_template.md
+++ b/.gitlab/issue_templates/experiment_tracking_template.md
@@ -27,7 +27,7 @@ As well as defining the experiment rollout and cleanup, this issue incorporates
### What might happen if this goes wrong?
### What can we monitor to detect problems with this?
-<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can alse be useful to review -->
+<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can also be useful to review -->
### Tracked data
<!-- brief description or link to issue or Sisense dashboard -->
@@ -81,6 +81,7 @@ If applicable, any groups/projects that are happy to have this feature turned on
- [ ] Announce on the issue that the flag has been enabled
- [ ] Remove experiment code and feature flag and add changelog entry - a separate [cleanup issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Experiment%20Successful%20Cleanup) might be required
- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
+- [ ] Assign to the product manager to update the [knowledge base](https://about.gitlab.com/direction/growth/#growth-insights-knowledge-base) (if applicable)
## Rollback Steps