Commit 07f86bcd authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 1f5bbf3f 61decce7
...@@ -23,6 +23,7 @@ query getFiles( ...@@ -23,6 +23,7 @@ query getFiles(
$nextPageCursor: String $nextPageCursor: String
) { ) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
id
__typename __typename
repository { repository {
__typename __typename
......
query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
id
__typename __typename
repository { repository {
__typename __typename
......
query getPermissions($projectPath: ID!) { query getPermissions($projectPath: ID!) {
project(fullPath: $projectPath) { project(fullPath: $projectPath) {
id
__typename __typename
userPermissions { userPermissions {
__typename __typename
......
...@@ -643,7 +643,7 @@ class Note < ApplicationRecord ...@@ -643,7 +643,7 @@ class Note < ApplicationRecord
user_visible_reference_count > 0 && user_visible_reference_count == total_reference_count user_visible_reference_count > 0 && user_visible_reference_count == total_reference_count
else else
refs = all_references(user) refs = all_references(user)
refs.all.any? && refs.stateful_not_visible_counter == 0 refs.all.any? && refs.all_visible?
end end
end end
......
...@@ -5,7 +5,7 @@ module Projects ...@@ -5,7 +5,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super return unless super
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_deploy_keys_projects move_deploy_keys_projects
remove_remaining_deploy_keys_projects if remove_remaining_elements remove_remaining_deploy_keys_projects if remove_remaining_elements
......
...@@ -5,7 +5,7 @@ module Projects ...@@ -5,7 +5,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super && source_project.fork_network return unless super && source_project.fork_network
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_fork_network_members move_fork_network_members
update_root_project update_root_project
refresh_forks_count refresh_forks_count
......
...@@ -5,7 +5,7 @@ module Projects ...@@ -5,7 +5,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super return unless super
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_lfs_objects_projects move_lfs_objects_projects
remove_remaining_lfs_objects_project if remove_remaining_elements remove_remaining_lfs_objects_project if remove_remaining_elements
......
...@@ -5,7 +5,7 @@ module Projects ...@@ -5,7 +5,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super return unless super
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_notification_settings move_notification_settings
remove_remaining_notification_settings if remove_remaining_elements remove_remaining_notification_settings if remove_remaining_elements
......
...@@ -9,7 +9,7 @@ module Projects ...@@ -9,7 +9,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super return unless super
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_project_authorizations move_project_authorizations
remove_remaining_authorizations if remove_remaining_elements remove_remaining_authorizations if remove_remaining_elements
......
...@@ -9,7 +9,7 @@ module Projects ...@@ -9,7 +9,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super return unless super
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_group_links move_group_links
remove_remaining_project_group_links if remove_remaining_elements remove_remaining_project_group_links if remove_remaining_elements
......
...@@ -9,7 +9,7 @@ module Projects ...@@ -9,7 +9,7 @@ module Projects
def execute(source_project, remove_remaining_elements: true) def execute(source_project, remove_remaining_elements: true)
return unless super return unless super
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
move_project_members move_project_members
remove_remaining_members if remove_remaining_elements remove_remaining_members if remove_remaining_elements
......
...@@ -9,7 +9,7 @@ module Projects ...@@ -9,7 +9,7 @@ module Projects
return unless user_stars.any? return unless user_stars.any?
Project.transaction(requires_new: true) do # rubocop:disable Performance/ActiveRecordSubtransactions Project.transaction do
user_stars.update_all(project_id: @project.id) user_stars.update_all(project_id: @project.id)
Project.reset_counters @project.id, :users_star_projects Project.reset_counters @project.id, :users_star_projects
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
}, },
"status": { "status": {
"type": ["string"], "type": ["string"],
"enum": ["data_available", "implemented", "not_used", "deprecated", "removed", "broken"] "enum": ["active", "data_available", "implemented", "deprecated", "removed", "broken"]
}, },
"milestone": { "milestone": {
"type": ["string", "null"], "type": ["string", "null"],
......
...@@ -20,7 +20,7 @@ class ScheduleExtractProjectTopicsIntoSeparateTable < ActiveRecord::Migration[6. ...@@ -20,7 +20,7 @@ class ScheduleExtractProjectTopicsIntoSeparateTable < ActiveRecord::Migration[6.
def up def up
# this index is used in 20210730104800_schedule_extract_project_topics_into_separate_table # this index is used in 20210730104800_schedule_extract_project_topics_into_separate_table
add_concurrent_index :taggings, :id, where: INDEX_CONDITION, name: INDEX_NAME add_concurrent_index :taggings, :id, where: INDEX_CONDITION, name: INDEX_NAME # rubocop:disable Migration/PreventIndexCreation
queue_background_migration_jobs_by_range_at_intervals( queue_background_migration_jobs_by_range_at_intervals(
Tagging.where(taggable_type: 'Project'), Tagging.where(taggable_type: 'Project'),
......
...@@ -220,7 +220,8 @@ You can use a GitLab CI/CD job token to authenticate with specific API endpoints ...@@ -220,7 +220,8 @@ You can use a GitLab CI/CD job token to authenticate with specific API endpoints
Package Registry, you can use [deploy tokens](../user/project/deploy_tokens/index.md). Package Registry, you can use [deploy tokens](../user/project/deploy_tokens/index.md).
- [Container Registry](../user/packages/container_registry/index.md) - [Container Registry](../user/packages/container_registry/index.md)
(the `$CI_REGISTRY_PASSWORD` is `$CI_JOB_TOKEN`). (the `$CI_REGISTRY_PASSWORD` is `$CI_JOB_TOKEN`).
- [Container Registry API](container_registry.md) (scoped to the job's project, when the `ci_job_token_scope` feature flag is enabled) - [Container Registry API](container_registry.md)
(scoped to the job's project, when the `ci_job_token_scope` feature flag is enabled).
- [Get job artifacts](job_artifacts.md#get-job-artifacts). - [Get job artifacts](job_artifacts.md#get-job-artifacts).
- [Get job token's job](jobs.md#get-job-tokens-job). - [Get job token's job](jobs.md#get-job-tokens-job).
- [Pipeline triggers](pipeline_triggers.md), using the `token=` parameter. - [Pipeline triggers](pipeline_triggers.md), using the `token=` parameter.
...@@ -682,7 +683,7 @@ send the payload body: ...@@ -682,7 +683,7 @@ send the payload body:
```shell ```shell
curl --request POST --header "Content-Type: application/json" \ curl --request POST --header "Content-Type: application/json" \
--data '{"name":"<example-name>", "description":"<example-description"}' "https://gitlab/api/v4/projects" --data '{"name":"<example-name>", "description":"<example-description>"}' "https://gitlab/api/v4/projects"
``` ```
URL encoded query strings have a length limitation. Requests that are too large URL encoded query strings have a length limitation. Requests that are too large
......
...@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w ...@@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
## Validate the CI YAML configuration ## Validate the CI YAML configuration
Checks if CI/CD YAML configuration is valid. This endpoint validates basic CI/CD Checks if CI/CD YAML configuration is valid. This endpoint validates basic CI/CD
configuration syntax. It doesn't have any namespace specific context. configuration syntax. It doesn't have any namespace-specific context.
Access to this endpoint does not require authentication when the instance Access to this endpoint does not require authentication when the instance
[allows new sign ups](../user/admin_area/settings/sign_up_restrictions.md#disable-new-sign-ups) [allows new sign ups](../user/admin_area/settings/sign_up_restrictions.md#disable-new-sign-ups)
......
...@@ -37,7 +37,7 @@ Example response: ...@@ -37,7 +37,7 @@ Example response:
product_group: group::global search product_group: group::global search
product_category: global_search product_category: global_search
value_type: number value_type: number
status: data_available status: active
time_frame: 28d time_frame: 28d
data_source: redis_hll data_source: redis_hll
distribution: distribution:
......
...@@ -34,7 +34,7 @@ Each metric is defined in a separate YAML file consisting of a number of fields: ...@@ -34,7 +34,7 @@ Each metric is defined in a separate YAML file consisting of a number of fields:
| `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the metric. | | `product_group` | yes | The [group](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/stages.yml) that owns the metric. |
| `product_category` | no | The [product category](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml) for the metric. | | `product_category` | no | The [product category](https://gitlab.com/gitlab-com/www-gitlab-com/blob/master/data/categories.yml) for the metric. |
| `value_type` | yes | `string`; one of [`string`, `number`, `boolean`, `object`](https://json-schema.org/understanding-json-schema/reference/type.html). | | `value_type` | yes | `string`; one of [`string`, `number`, `boolean`, `object`](https://json-schema.org/understanding-json-schema/reference/type.html). |
| `status` | yes | `string`; [status](#metric-statuses) of the metric, may be set to `data_available`, `implemented`, `not_used`, `deprecated`, `removed`, `broken`. | | `status` | yes | `string`; [status](#metric-statuses) of the metric, may be set to `active`, `deprecated`, `removed`, `broken`. |
| `time_frame` | yes | `string`; may be set to a value like `7d`, `28d`, `all`, `none`. | | `time_frame` | yes | `string`; may be set to a value like `7d`, `28d`, `all`, `none`. |
| `data_source` | yes | `string`; may be set to a value like `database`, `redis`, `redis_hll`, `prometheus`, `system`. | | `data_source` | yes | `string`; may be set to a value like `database`, `redis`, `redis_hll`, `prometheus`, `system`. |
| `data_category` | yes | `string`; [categories](#data-category) of the metric, may be set to `operational`, `optional`, `subscription`, `standard`. The default value is `optional`.| | `data_category` | yes | `string`; [categories](#data-category) of the metric, may be set to `operational`, `optional`, `subscription`, `standard`. The default value is `optional`.|
...@@ -53,11 +53,8 @@ Each metric is defined in a separate YAML file consisting of a number of fields: ...@@ -53,11 +53,8 @@ Each metric is defined in a separate YAML file consisting of a number of fields:
Metric definitions can have one of the following statuses: Metric definitions can have one of the following statuses:
- `data_available`: Metric data is available and used in a Sisense dashboard. - `active`: Metric is used and reports data.
- `implemented`: Metric is implemented but data is not yet available. This is a temporary
status for newly added metrics awaiting inclusion in a new release.
- `broken`: Metric reports broken data (for example, -1 fallback), or does not report data at all. A metric marked as `broken` must also have the `repair_issue_url` attribute. - `broken`: Metric reports broken data (for example, -1 fallback), or does not report data at all. A metric marked as `broken` must also have the `repair_issue_url` attribute.
- `not_used`: Metric is not used in any dashboard.
- `deprecated`: Metric is deprecated and possibly planned to be removed. - `deprecated`: Metric is deprecated and possibly planned to be removed.
- `removed`: Metric was removed, but it may appear in Service Ping payloads sent from instances running on older versions of GitLab. - `removed`: Metric was removed, but it may appear in Service Ping payloads sent from instances running on older versions of GitLab.
...@@ -177,7 +174,7 @@ product_section: growth ...@@ -177,7 +174,7 @@ product_section: growth
product_stage: growth product_stage: growth
product_group: group::product intelligence product_group: group::product intelligence
value_type: string value_type: string
status: data_available status: active
milestone: 9.1 milestone: 9.1
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1521 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1521
time_frame: none time_frame: none
......
...@@ -60,10 +60,7 @@ API calls made with a project access token are associated with the corresponding ...@@ -60,10 +60,7 @@ API calls made with a project access token are associated with the corresponding
These bot users are included in a project's **Project information > Members** list but cannot be modified. Also, a bot These bot users are included in a project's **Project information > Members** list but cannot be modified. Also, a bot
user cannot be added to any other project. user cannot be added to any other project.
- The username is set to `project_{project_id}_bot` for the first access token, such as `project_123_bot`. When the project access token is [revoked](#revoking-a-project-access-token), the bot user is deleted
- The username is set to `project_{project_id}_bot{bot_count}` for further access tokens, such as `project_123_bot1`.
When the project access token is [revoked](#revoking-a-project-access-token) the bot user is deleted
and all records are moved to a system-wide user with the username "Ghost User". For more and all records are moved to a system-wide user with the username "Ghost User". For more
information, see [Associated Records](../../profile/account/delete_account.md#associated-records). information, see [Associated Records](../../profile/account/delete_account.md#associated-records).
......
...@@ -212,9 +212,8 @@ module Banzai ...@@ -212,9 +212,8 @@ module Banzai
def gather_references(nodes, ids_only: false) def gather_references(nodes, ids_only: false)
nodes = nodes_user_can_reference(current_user, nodes) nodes = nodes_user_can_reference(current_user, nodes)
visible = nodes_visible_to_user(current_user, nodes) visible = nodes_visible_to_user(current_user, nodes)
not_visible = nodes - visible
{ visible: referenced_by(visible, ids_only: ids_only), not_visible: not_visible } { visible: referenced_by(visible, ids_only: ids_only), nodes: nodes, visible_nodes: visible }
end end
# Returns a Hash containing the projects for a given list of HTML nodes. # Returns a Hash containing the projects for a given list of HTML nodes.
......
...@@ -6,16 +6,11 @@ module Gitlab ...@@ -6,16 +6,11 @@ module Gitlab
REFERABLES = %i(user issue label milestone mentioned_user mentioned_group mentioned_project REFERABLES = %i(user issue label milestone mentioned_user mentioned_group mentioned_project
merge_request snippet commit commit_range directly_addressed_user epic iteration vulnerability).freeze merge_request snippet commit commit_range directly_addressed_user epic iteration vulnerability).freeze
attr_accessor :project, :current_user, :author attr_accessor :project, :current_user, :author
# This counter is increased by a number of references filtered out by
# banzai reference exctractor. Note that this counter is stateful and
# not idempotent and is increased whenever you call `references`.
attr_reader :stateful_not_visible_counter
def initialize(project, current_user = nil) def initialize(project, current_user = nil)
@project = project @project = project
@current_user = current_user @current_user = current_user
@references = {} @references = {}
@stateful_not_visible_counter = 0
super() super()
end end
...@@ -26,14 +21,19 @@ module Gitlab ...@@ -26,14 +21,19 @@ module Gitlab
def references(type, ids_only: false) def references(type, ids_only: false)
refs = super(type, project, current_user, ids_only: ids_only) refs = super(type, project, current_user, ids_only: ids_only)
@stateful_not_visible_counter += refs[:not_visible].count update_visible_nodes_set(refs[:nodes], refs[:visible_nodes])
refs[:visible] refs[:visible]
end end
# this method is stateful, it tracks if all nodes from `references`
# calls are visible or not
def all_visible?
not_visible_nodes.empty?
end
def reset_memoized_values def reset_memoized_values
@references = {} @references = {}
@stateful_not_visible_counter = 0
super() super()
end end
...@@ -76,5 +76,16 @@ module Gitlab ...@@ -76,5 +76,16 @@ module Gitlab
@pattern = Regexp.union(patterns.compact) @pattern = Regexp.union(patterns.compact)
end end
private
def update_visible_nodes_set(all, visible)
not_visible_nodes.merge(all)
not_visible_nodes.subtract(visible)
end
def not_visible_nodes
@not_visible_nodes ||= Set.new
end
end end
end end
# frozen_string_literal: true
namespace :gitlab do
namespace :product_intelligence do
# @example
# bundle exec rake gitlab:product_intelligence:activate_metrics MILESTONE=14.0
desc 'GitLab | Product Intelligence | Update milestone metrics status to data_available'
task activate_metrics: :environment do
milestone = ENV['MILESTONE']
raise "Please supply the MILESTONE env var".color(:red) unless milestone.present?
Gitlab::Usage::MetricDefinition.definitions.values.each do |metric|
next if metric.attributes[:milestone] != milestone || metric.attributes[:status] != 'implemented'
metric.attributes[:status] = 'data_available'
path = metric.path
File.open(path, "w") { |file| file << metric.to_h.deep_stringify_keys.to_yaml }
end
puts "Task completed successfully"
end
end
end
...@@ -8,7 +8,7 @@ module RuboCop ...@@ -8,7 +8,7 @@ module RuboCop
class PreventIndexCreation < RuboCop::Cop::Cop class PreventIndexCreation < RuboCop::Cop::Cop
include MigrationHelpers include MigrationHelpers
FORBIDDEN_TABLES = %i[ci_builds].freeze FORBIDDEN_TABLES = %i[ci_builds taggings ci_builds_metadata events].freeze
MSG = "Adding new index to #{FORBIDDEN_TABLES.join(", ")} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886" MSG = "Adding new index to #{FORBIDDEN_TABLES.join(", ")} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886"
......
...@@ -247,15 +247,15 @@ RSpec.describe Banzai::ReferenceParser::BaseParser do ...@@ -247,15 +247,15 @@ RSpec.describe Banzai::ReferenceParser::BaseParser do
end end
end end
it 'returns referenceable and visible objects, alongside nodes that are referenceable but not visible' do it 'returns referenceable and visible objects, alongside all and visible nodes' do
expect(subject.gather_references(nodes)).to match( referenceable = nodes.select { |n| n.id.even? }
visible: contain_exactly(6, 8, 10), visible = nodes.select { |n| [6, 8, 10].include?(n.id) }
not_visible: match_array(nodes.select { |n| n.id.even? && n.id <= 5 })
) expect_gathered_references(subject.gather_references(nodes), [6, 8, 10], referenceable, visible)
end end
it 'is always empty if the input is empty' do it 'is always empty if the input is empty' do
expect(subject.gather_references([])) .to match(visible: be_empty, not_visible: be_empty) expect_gathered_references(subject.gather_references([]), [], [], [])
end end
end end
......
...@@ -19,7 +19,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do ...@@ -19,7 +19,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do
it 'returns empty array' do it 'returns empty array' do
link['data-group'] = project.group.id.to_s link['data-group'] = project.group.id.to_s
expect_gathered_references(subject.gather_references([link]), [], 1) expect_gathered_references(subject.gather_references([link]), [], [link], [])
end end
end end
...@@ -30,7 +30,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do ...@@ -30,7 +30,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do
end end
it 'returns groups' do it 'returns groups' do
expect_gathered_references(subject.gather_references([link]), [group], 0) expect_gathered_references(subject.gather_references([link]), [group], [link], [link])
end end
end end
...@@ -38,7 +38,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do ...@@ -38,7 +38,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedGroupParser do
it 'returns an empty Array' do it 'returns an empty Array' do
link['data-group'] = 'test-non-existing' link['data-group'] = 'test-non-existing'
expect_gathered_references(subject.gather_references([link]), [], 1) expect_gathered_references(subject.gather_references([link]), [], [link], [])
end end
end end
end end
......
...@@ -19,7 +19,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do ...@@ -19,7 +19,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do
it 'returns empty Array' do it 'returns empty Array' do
link['data-project'] = project.id.to_s link['data-project'] = project.id.to_s
expect_gathered_references(subject.gather_references([link]), [], 1) expect_gathered_references(subject.gather_references([link]), [], [link], [])
end end
end end
...@@ -30,7 +30,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do ...@@ -30,7 +30,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do
end end
it 'returns an Array of referenced projects' do it 'returns an Array of referenced projects' do
expect_gathered_references(subject.gather_references([link]), [project], 0) expect_gathered_references(subject.gather_references([link]), [project], [link], [link])
end end
end end
...@@ -38,7 +38,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do ...@@ -38,7 +38,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedProjectParser do
it 'returns an empty Array' do it 'returns an empty Array' do
link['data-project'] = 'inexisting-project-id' link['data-project'] = 'inexisting-project-id'
expect_gathered_references(subject.gather_references([link]), [], 1) expect_gathered_references(subject.gather_references([link]), [], [link], [])
end end
end end
end end
......
...@@ -22,7 +22,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedUserParser do ...@@ -22,7 +22,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedUserParser do
end end
it 'returns empty list of users' do it 'returns empty list of users' do
expect_gathered_references(subject.gather_references([link]), [], 0) expect_gathered_references(subject.gather_references([link]), [], [link], [link])
end end
end end
end end
...@@ -35,7 +35,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedUserParser do ...@@ -35,7 +35,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedUserParser do
end end
it 'returns empty list of users' do it 'returns empty list of users' do
expect_gathered_references(subject.gather_references([link]), [], 0) expect_gathered_references(subject.gather_references([link]), [], [link], [link])
end end
end end
end end
...@@ -44,7 +44,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedUserParser do ...@@ -44,7 +44,7 @@ RSpec.describe Banzai::ReferenceParser::MentionedUserParser do
it 'returns an Array of users' do it 'returns an Array of users' do
link['data-user'] = user.id.to_s link['data-user'] = user.id.to_s
expect_gathered_references(subject.gather_references([link]), [user], 0) expect_gathered_references(subject.gather_references([link]), [user], [link], [link])
end end
end end
end end
......
...@@ -17,7 +17,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do ...@@ -17,7 +17,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do
it 'returns an Array of projects' do it 'returns an Array of projects' do
link['data-project'] = project.id.to_s link['data-project'] = project.id.to_s
expect_gathered_references(subject.gather_references([link]), [project], 0) expect_gathered_references(subject.gather_references([link]), [project], [link], [link])
end end
end end
...@@ -25,7 +25,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do ...@@ -25,7 +25,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do
it 'returns an empty Array' do it 'returns an empty Array' do
link['data-project'] = '' link['data-project'] = ''
expect_gathered_references(subject.gather_references([link]), [], 1) expect_gathered_references(subject.gather_references([link]), [], [link], [])
end end
end end
...@@ -35,7 +35,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do ...@@ -35,7 +35,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do
link['data-project'] = private_project.id.to_s link['data-project'] = private_project.id.to_s
expect_gathered_references(subject.gather_references([link]), [], 1) expect_gathered_references(subject.gather_references([link]), [], [link], [])
end end
it 'returns an Array when authorized' do it 'returns an Array when authorized' do
...@@ -43,7 +43,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do ...@@ -43,7 +43,7 @@ RSpec.describe Banzai::ReferenceParser::ProjectParser do
link['data-project'] = private_project.id.to_s link['data-project'] = private_project.id.to_s
expect_gathered_references(subject.gather_references([link]), [private_project], 0) expect_gathered_references(subject.gather_references([link]), [private_project], [link], [link])
end end
end end
end end
......
...@@ -332,14 +332,59 @@ RSpec.describe Gitlab::ReferenceExtractor do ...@@ -332,14 +332,59 @@ RSpec.describe Gitlab::ReferenceExtractor do
it 'returns visible references of given type' do it 'returns visible references of given type' do
expect(subject.references(:issue)).to eq([issue]) expect(subject.references(:issue)).to eq([issue])
end end
end
it 'does not increase stateful_not_visible_counter' do it 'does not return any references' do
expect { subject.references(:issue) }.not_to change { subject.stateful_not_visible_counter } expect(subject.references(:issue)).to be_empty
end end
end
describe '#all_visible?' do
let_it_be(:user) { create(:user) }
let_it_be(:project2) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:issue2) { create(:issue, project: project2) }
let(:text) { "Ref. #{issue.to_reference} and #{issue2.to_reference(project)}" }
subject { described_class.new(project, user) }
before do
subject.analyze(text)
end end
it 'increases stateful_not_visible_counter' do it 'returns true if no references were parsed yet' do
expect { subject.references(:issue) }.to change { subject.stateful_not_visible_counter }.by(1) expect(subject.all_visible?).to be_truthy
end
context 'when references was already called' do
let(:membership) { [] }
before do
membership.each { |p| p.add_developer(user) }
subject.references(:issue)
end
it 'returns false' do
expect(subject.all_visible?).to be_falsey
end
context 'when user can access only some references' do
let(:membership) { [project] }
it 'returns false' do
expect(subject.all_visible?).to be_falsey
end
end
context 'when user can access all references' do
let(:membership) { [project, project2] }
it 'returns true' do
expect(subject.all_visible?).to be_truthy
end
end
end end
end end
end end
...@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do ...@@ -9,7 +9,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
value_type: 'string', value_type: 'string',
product_category: 'collection', product_category: 'collection',
product_stage: 'growth', product_stage: 'growth',
status: 'data_available', status: 'active',
default_generation: 'generation_1', default_generation: 'generation_1',
key_path: 'uuid', key_path: 'uuid',
product_group: 'group::product analytics', product_group: 'group::product analytics',
...@@ -127,9 +127,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do ...@@ -127,9 +127,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
where(:status, :skip_validation?) do where(:status, :skip_validation?) do
'deprecated' | true 'deprecated' | true
'removed' | true 'removed' | true
'data_available' | false 'active' | false
'implemented' | false
'not_used' | false
end end
with_them do with_them do
...@@ -191,7 +189,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do ...@@ -191,7 +189,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
value_type: 'string', value_type: 'string',
product_category: 'collection', product_category: 'collection',
product_stage: 'growth', product_stage: 'growth',
status: 'data_available', status: 'active',
default_generation: 'generation_1', default_generation: 'generation_1',
key_path: 'counter.category.event', key_path: 'counter.category.event',
product_group: 'group::product analytics', product_group: 'group::product analytics',
......
...@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Usage::Metric do ...@@ -15,7 +15,7 @@ RSpec.describe Gitlab::Usage::Metric do
product_group: "group::plan", product_group: "group::plan",
product_category: "issue_tracking", product_category: "issue_tracking",
value_type: "number", value_type: "number",
status: "data_available", status: "active",
time_frame: "all", time_frame: "all",
data_source: "database", data_source: "database",
instrumentation_class: "CountIssuesMetric", instrumentation_class: "CountIssuesMetric",
......
...@@ -500,15 +500,15 @@ RSpec.describe Note do ...@@ -500,15 +500,15 @@ RSpec.describe Note do
let_it_be(:ext_issue) { create(:issue, project: ext_proj) } let_it_be(:ext_issue) { create(:issue, project: ext_proj) }
shared_examples "checks references" do shared_examples "checks references" do
it "returns true" do it "returns false" do
expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_falsy expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_falsy
end end
it "returns false" do it "returns true" do
expect(note.system_note_with_references_visible_for?(private_user)).to be_truthy expect(note.system_note_with_references_visible_for?(private_user)).to be_truthy
end end
it "returns false if user visible reference count set" do it "returns true if user visible reference count set" do
note.user_visible_reference_count = 1 note.user_visible_reference_count = 1
note.total_reference_count = 1 note.total_reference_count = 1
...@@ -516,7 +516,15 @@ RSpec.describe Note do ...@@ -516,7 +516,15 @@ RSpec.describe Note do
expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_truthy expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_truthy
end end
it "returns true if ref count is 0" do it "returns false if user visible reference count set but does not match total reference count" do
note.user_visible_reference_count = 1
note.total_reference_count = 2
expect(note).not_to receive(:reference_mentionables)
expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_falsy
end
it "returns false if ref count is 0" do
note.user_visible_reference_count = 0 note.user_visible_reference_count = 0
expect(note).not_to receive(:reference_mentionables) expect(note).not_to receive(:reference_mentionables)
...@@ -562,13 +570,35 @@ RSpec.describe Note do ...@@ -562,13 +570,35 @@ RSpec.describe Note do
end end
it_behaves_like "checks references" it_behaves_like "checks references"
end
it "returns true if user visible reference count set and there is a private reference" do context "when there is a private issue and user reference" do
note.user_visible_reference_count = 1 let_it_be(:ext_issue2) { create(:issue, project: ext_proj) }
note.total_reference_count = 2
expect(note).not_to receive(:reference_mentionables) let(:note) do
expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_falsy create :note,
noteable: ext_issue2, project: ext_proj,
note: "mentioned in #{private_issue.to_reference(ext_proj)} and pinged user #{private_user.to_reference}",
system: true
end
it_behaves_like "checks references"
end
context "when there is a publicly visible user reference" do
let(:note) do
create :note,
noteable: ext_issue, project: ext_proj,
note: "mentioned in #{ext_proj.owner.to_reference}",
system: true
end
it "returns true for other users" do
expect(note.system_note_with_references_visible_for?(ext_issue.author)).to be_truthy
end
it "returns true for anonymous users" do
expect(note.system_note_with_references_visible_for?(nil)).to be_truthy
end end
end end
end end
......
...@@ -6,28 +6,35 @@ require_relative '../../../../rubocop/cop/migration/prevent_index_creation' ...@@ -6,28 +6,35 @@ require_relative '../../../../rubocop/cop/migration/prevent_index_creation'
RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do RSpec.describe RuboCop::Cop::Migration::PreventIndexCreation do
subject(:cop) { described_class.new } subject(:cop) { described_class.new }
let(:forbidden_tables) { %w(ci_builds taggings ci_builds_metadata events) }
let(:forbidden_tables_list) { forbidden_tables.join(', ') }
context 'when in migration' do context 'when in migration' do
before do before do
allow(cop).to receive(:in_migration?).and_return(true) allow(cop).to receive(:in_migration?).and_return(true)
end end
context 'when adding an index to a forbidden table' do context 'when adding an index to a forbidden table' do
it 'registers an offense when add_index is used' do it "registers an offense when add_index is used", :aggregate_failures do
expect_offense(<<~RUBY) forbidden_tables.each do |table|
def change expect_offense(<<~RUBY)
add_index :ci_builds, :protected def change
^^^^^^^^^ Adding new index to ci_builds is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 add_index :#{table}, :protected
end ^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886
RUBY end
RUBY
end
end end
it 'registers an offense when add_concurrent_index is used' do it "registers an offense when add_concurrent_index is used", :aggregate_failures do
expect_offense(<<~RUBY) forbidden_tables.each do |table|
def change expect_offense(<<~RUBY)
add_concurrent_index :ci_builds, :protected def change
^^^^^^^^^^^^^^^^^^^^ Adding new index to ci_builds is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886 add_concurrent_index :#{table}, :protected
end ^^^^^^^^^^^^^^^^^^^^ Adding new index to #{forbidden_tables_list} is forbidden, see https://gitlab.com/gitlab-org/gitlab/-/issues/332886
RUBY end
RUBY
end
end end
end end
......
...@@ -5,9 +5,10 @@ module ReferenceParserHelpers ...@@ -5,9 +5,10 @@ module ReferenceParserHelpers
Nokogiri::HTML.fragment('<a></a>').children[0] Nokogiri::HTML.fragment('<a></a>').children[0]
end end
def expect_gathered_references(result, visible, not_visible_count) def expect_gathered_references(result, visible, nodes, visible_nodes)
expect(result[:visible]).to eq(visible) expect(result[:visible]).to eq(visible)
expect(result[:not_visible].count).to eq(not_visible_count) expect(result[:nodes]).to eq(nodes)
expect(result[:visible_nodes]).to eq(visible_nodes)
end end
RSpec.shared_examples 'no project N+1 queries' do RSpec.shared_examples 'no project N+1 queries' do
......
# frozen_string_literal: true
require 'rake_helper'
RSpec.describe 'gitlab:product_intelligence:activate_metrics', :silence_stdout do
def fake_metric(key_path, milestone: 'test_milestone', status: 'implemented')
Gitlab::Usage::MetricDefinition.new(key_path, { key_path: key_path, milestone: milestone, status: status })
end
before do
Rake.application.rake_require 'tasks/gitlab/product_intelligence'
stub_warn_user_is_not_gitlab
end
describe 'activate_metrics' do
it 'fails if the MILESTONE env var is not set' do
stub_env('MILESTONE' => nil)
expect { run_rake_task('gitlab:product_intelligence:activate_metrics') }.to raise_error(RuntimeError, 'Please supply the MILESTONE env var')
end
context 'with MILESTONE env var' do
subject do
updated_metrics = []
file = double('file')
allow(file).to receive(:<<) { |contents| updated_metrics << YAML.safe_load(contents) }
allow(File).to receive(:open).and_yield(file)
stub_env('MILESTONE' => 'test_milestone')
run_rake_task('gitlab:product_intelligence:activate_metrics')
updated_metrics
end
let(:metric_definitions) do
{
matching_metric: fake_metric('matching_metric'),
matching_metric2: fake_metric('matching_metric2'),
other_status_metric: fake_metric('other_status_metric', status: 'deprecated'),
other_milestone_metric: fake_metric('other_milestone_metric', milestone: 'other_milestone')
}
end
before do
allow(Gitlab::Usage::MetricDefinition).to receive(:definitions).and_return(metric_definitions)
end
context 'with metric matching status and milestone' do
it 'updates matching_metric yaml file' do
expect(subject).to eq([
{ 'key_path' => 'matching_metric', 'milestone' => 'test_milestone', 'status' => 'data_available' },
{ 'key_path' => 'matching_metric2', 'milestone' => 'test_milestone', 'status' => 'data_available' }
])
end
end
context 'without metrics definitions' do
let(:metric_definitions) { {} }
it 'runs successfully with no updates' do
expect(subject).to eq([])
end
end
context 'without matching metrics' do
let(:metric_definitions) do
{
other_status_metric: fake_metric('other_status_metric', status: 'deprecated'),
other_milestone_metric: fake_metric('other_milestone_metric', milestone: 'other_milestone')
}
end
it 'runs successfully with no updates' do
expect(subject).to eq([])
end
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment