Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-02-08 15:12:33 +00:00
parent dcc096f219
commit 6225d57e55
39 changed files with 387 additions and 162 deletions

View File

@ -62,11 +62,11 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
def usage_data
respond_to do |format|
format.html do
usage_data_json = Gitlab::Json.pretty_generate(Gitlab::Usage::ServicePingReport.for(mode: :values, cached: true))
usage_data_json = Gitlab::Json.pretty_generate(Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true))
render html: Gitlab::Highlight.highlight('payload.json', usage_data_json, language: 'json')
end
format.json { render json: Gitlab::Usage::ServicePingReport.for(mode: :values, cached: true).to_json }
format.json { render json: Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true).to_json }
end
end

View File

@ -16,7 +16,7 @@ class Admin::InstanceReviewController < Admin::ApplicationController
}
if Gitlab::CurrentSettings.usage_ping_enabled?
data = Gitlab::Usage::ServicePingReport.for(mode: :values, cached: true)
data = Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true)
counts = data[:counts]
result[:instance_review].merge!(

View File

@ -33,6 +33,7 @@ class PersonalAccessToken < ApplicationRecord
scope :preload_users, -> { preload(:user) }
scope :order_expires_at_asc, -> { reorder(expires_at: :asc) }
scope :order_expires_at_desc, -> { reorder(expires_at: :desc) }
scope :project_access_token, -> { includes(:user).where(user: { user_type: :project_bot }) }
validates :scopes, presence: true
validate :validate_scopes
@ -93,6 +94,10 @@ class PersonalAccessToken < ApplicationRecord
"#{self.class.token_prefix}#{token}"
end
def project_access_token?
user&.project_bot?
end
protected
def validate_scopes

View File

@ -22,8 +22,6 @@ module AlertManagement
return result unless result.success?
issue = result.payload[:issue]
return error(object_errors(alert), issue) unless associate_alert_with_issue(issue)
update_title_for(issue)
SystemNoteService.new_alert_issue(alert, issue, user)
@ -47,14 +45,11 @@ module AlertManagement
user,
title: alert_presenter.title,
description: alert_presenter.issue_description,
severity: alert.severity
severity: alert.severity,
alert: alert
).execute
end
def associate_alert_with_issue(issue)
alert.update(issue_id: issue.id)
end
def update_title_for(issue)
return unless issue.title == DEFAULT_ALERT_TITLE
@ -78,9 +73,5 @@ module AlertManagement
alert.present
end
end
def object_errors(object)
object.errors.full_messages.to_sentence
end
end
end

View File

@ -2,15 +2,16 @@
module IncidentManagement
module Incidents
class CreateService < BaseService
class CreateService < ::BaseProjectService
ISSUE_TYPE = 'incident'
def initialize(project, current_user, title:, description:, severity: IssuableSeverity::DEFAULT)
super(project, current_user)
def initialize(project, current_user, title:, description:, severity: IssuableSeverity::DEFAULT, alert: nil)
super(project: project, current_user: current_user)
@title = title
@description = description
@severity = severity
@alert = alert
end
def execute
@ -21,11 +22,16 @@ module IncidentManagement
title: title,
description: description,
issue_type: ISSUE_TYPE,
severity: severity
severity: severity,
alert_management_alert: alert
},
spam_params: nil
).execute
if alert
return error(alert.errors.full_messages.to_sentence, issue) unless alert.valid?
end
return error(issue.errors.full_messages.to_sentence, issue) unless issue.valid?
success(issue)
@ -33,7 +39,7 @@ module IncidentManagement
private
attr_reader :title, :description, :severity
attr_reader :title, :description, :severity, :alert
def success(issue)
ServiceResponse.success(payload: { issue: issue })

View File

@ -6,30 +6,34 @@ module Projects
return unless source_project && source_project.namespace_id == @project.namespace_id
start_time = ::Gitlab::Metrics::System.monotonic_time
original_source_name = source_project.name
original_source_path = source_project.path
tmp_source_name, tmp_source_path = tmp_source_project_name(source_project)
Project.transaction do
move_before_destroy_relationships(source_project)
# Reset is required in order to get the proper
# uncached fork network method calls value.
::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.allow_cross_database_modification_within_transaction(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/340256') do
destroy_old_project(source_project.reset)
end
rename_project(source_project.name, source_project.path)
move_relationships_between(source_project, @project)
@project
end
# Projects::DestroyService can raise Exceptions, but we don't want
# to pass that kind of exception to the caller. Instead, we change it
# for a StandardError exception
rescue Exception => e # rubocop:disable Lint/RescueException
attempt_restore_repositories(source_project)
source_project_rename = rename_project(source_project, tmp_source_name, tmp_source_path)
if e.instance_of?(Exception)
raise StandardError, e.message
else
raise
if source_project_rename[:status] == :error
raise 'Source project rename failed during project overwrite'
end
new_project_rename = rename_project(@project, original_source_name, original_source_path)
if new_project_rename[:status] == :error
rename_project(source_project, original_source_name, original_source_path)
raise 'New project rename failed during project overwrite'
end
schedule_source_project_deletion(source_project)
@project
rescue StandardError => e
move_relationships_between(@project, source_project)
remove_source_project_from_fork_network(source_project)
raise e
ensure
track_service(start_time, source_project, e)
end
@ -48,45 +52,63 @@ module Projects
error: exception.class.name)
end
def move_before_destroy_relationships(source_project)
def move_relationships_between(source_project, target_project)
options = { remove_remaining_elements: false }
::Projects::MoveUsersStarProjectsService.new(@project, @current_user).execute(source_project, **options)
::Projects::MoveAccessService.new(@project, @current_user).execute(source_project, **options)
::Projects::MoveDeployKeysProjectsService.new(@project, @current_user).execute(source_project, **options)
::Projects::MoveNotificationSettingsService.new(@project, @current_user).execute(source_project, **options)
::Projects::MoveForksService.new(@project, @current_user).execute(source_project, **options)
::Projects::MoveLfsObjectsProjectsService.new(@project, @current_user).execute(source_project, **options)
add_source_project_to_fork_network(source_project)
Project.transaction do
::Projects::MoveUsersStarProjectsService.new(target_project, @current_user).execute(source_project, **options)
::Projects::MoveAccessService.new(target_project, @current_user).execute(source_project, **options)
::Projects::MoveDeployKeysProjectsService.new(target_project, @current_user).execute(source_project, **options)
::Projects::MoveNotificationSettingsService.new(target_project, @current_user).execute(source_project, **options)
::Projects::MoveForksService.new(target_project, @current_user).execute(source_project, **options)
::Projects::MoveLfsObjectsProjectsService.new(target_project, @current_user).execute(source_project, **options)
add_source_project_to_fork_network(source_project)
end
end
def destroy_old_project(source_project)
# Delete previous project (synchronously) and unlink relations
::Projects::DestroyService.new(source_project, @current_user).execute
def schedule_source_project_deletion(source_project)
::Projects::DestroyService.new(source_project, @current_user).async_execute
end
def rename_project(name, path)
# Update de project's name and path to the original name/path
::Projects::UpdateService.new(@project,
@current_user,
{ name: name, path: path })
.execute
end
def attempt_restore_repositories(project)
::Projects::DestroyRollbackService.new(project, @current_user).execute
def rename_project(target_project, name, path)
::Projects::UpdateService.new(target_project, @current_user, { name: name, path: path }).execute
end
def add_source_project_to_fork_network(source_project)
return unless @project.fork_network
return if source_project == @project
return unless fork_network
# Because they have moved all references in the fork network from the source_project
# we won't be able to query the database (only through its cached data),
# for its former relationships. That's why we're adding it to the network
# as a fork of the target project
ForkNetworkMember.create!(fork_network: @project.fork_network,
ForkNetworkMember.create!(fork_network: fork_network,
project: source_project,
forked_from_project: @project)
end
def remove_source_project_from_fork_network(source_project)
return unless fork_network
fork_member = ForkNetworkMember.find_by( # rubocop: disable CodeReuse/ActiveRecord
fork_network: fork_network,
project: source_project,
forked_from_project: @project)
fork_member&.destroy
end
def tmp_source_project_name(source_project)
random_string = SecureRandom.hex
tmp_name = "#{source_project.name}-old-#{random_string}"
tmp_path = "#{source_project.path}-old-#{random_string}"
[tmp_name, tmp_path]
end
def fork_network
@project.fork_network_member&.fork_network
end
end
end

View File

@ -19,7 +19,7 @@ module ServicePing
end
def raw_payload
@raw_payload ||= ::Gitlab::Usage::ServicePingReport.for(mode: :values)
@raw_payload ||= ::Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
end
end
end

View File

@ -33,7 +33,7 @@ module ServicePing
}
submit_payload({ error: error_payload }, url: error_url)
usage_data = Gitlab::Usage::ServicePingReport.for(mode: :values)
usage_data = Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
response = submit_usage_data_payload(usage_data)
end

View File

@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338267
milestone: '14.2'
type: development
group: group::optimize
default_enabled: false
default_enabled: true

View File

@ -1,18 +1,14 @@
# frozen_string_literal: true
class AddUniqueIndexToVulnerabilityFindingLinks < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
NAME_URL_INDEX_NAME = 'finding_link_name_url_idx'
URL_INDEX_NAME = 'finding_link_url_idx'
# This migration has been moved to db/post_migrate/20220201193033_add_unique_index_to_vulnerability_finding_links_with_truncate.rb
# Previously, this was causing an bug where there was a conflict between the table cleanup and the index creation.
def up
add_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :name, :url], unique: true, name: NAME_URL_INDEX_NAME
add_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :url], unique: true, where: 'name is null', name: URL_INDEX_NAME
# no op
end
def down
remove_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :name, :url], name: NAME_URL_INDEX_NAME
remove_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :url], name: URL_INDEX_NAME
# no op
end
end

View File

@ -1,21 +1,14 @@
# frozen_string_literal: true
class RemoveVulnerabilityFindingLinks < Gitlab::Database::Migration[1.0]
BATCH_SIZE = 50_000
MIGRATION = 'RemoveVulnerabilityFindingLinks'
disable_ddl_transaction!
# This migration has been moved to a TRUNCATE in db/post_migrate/20220201193033_add_unique_index_to_vulnerability_finding_links_with_truncate.rb
# Previously, this was causing an bug where there was a conflict between the table cleanup and the index creation.
def up
queue_background_migration_jobs_by_range_at_intervals(
define_batchable_model('vulnerability_finding_links'),
MIGRATION,
2.minutes,
batch_size: BATCH_SIZE
)
# no op
end
def down
# no ops
# no op
end
end

View File

@ -1,21 +1,14 @@
# frozen_string_literal: true
class RemoveVulnerabilityFindingLinksAgain < Gitlab::Database::Migration[1.0]
BATCH_SIZE = 50_000
MIGRATION = 'RemoveVulnerabilityFindingLinks'
disable_ddl_transaction!
# This migration has been moved to a TRUNCATE in db/post_migrate/20220201193033_add_unique_index_to_vulnerability_finding_links_with_truncate.rb
# Previously, this was causing an bug where there was a conflict between the table cleanup and the index creation.
def up
queue_background_migration_jobs_by_range_at_intervals(
define_batchable_model('vulnerability_finding_links'),
MIGRATION,
2.minutes,
batch_size: BATCH_SIZE
)
# no op
end
def down
# no ops
# no op
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class AddUniqueIndexToVulnerabilityFindingLinksWithTruncate < Gitlab::Database::Migration[1.0]
disable_ddl_transaction!
NAME_URL_INDEX_NAME = 'finding_link_name_url_idx'
URL_INDEX_NAME = 'finding_link_url_idx'
def up
execute('TRUNCATE TABLE vulnerability_finding_links')
add_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :name, :url], unique: true, name: NAME_URL_INDEX_NAME
add_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :url], unique: true, where: 'name is null', name: URL_INDEX_NAME
end
def down
remove_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :name, :url], name: NAME_URL_INDEX_NAME
remove_concurrent_index :vulnerability_finding_links, [:vulnerability_occurrence_id, :url], name: URL_INDEX_NAME
end
end

View File

@ -0,0 +1 @@
92bbe74c6c3627dd26f709acd2a20f442212eab933f719be815701a3bc429539

View File

@ -1324,7 +1324,7 @@ has more information about Service Ping.
### Generate or get the cached Service Ping
```ruby
Gitlab::Usage::ServicePingReport.for(mode: :values, cached: true)
Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values, cached: true)
```
### Generate a fresh new Service Ping
@ -1332,7 +1332,7 @@ Gitlab::Usage::ServicePingReport.for(mode: :values, cached: true)
This also refreshes the cached Service Ping displayed in the Admin Area
```ruby
Gitlab::Usage::ServicePingReport.for(mode: :values)
Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
```
### Generate and print

View File

@ -198,8 +198,8 @@ sequenceDiagram
## How Service Ping works
1. The Service Ping [cron job](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/workers/gitlab_service_ping_worker.rb#L24) is set in Sidekiq to run weekly.
1. When the cron job runs, it calls [`Gitlab::Usage::ServicePingReport.for(mode: :values)`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/service_ping/submit_service.rb).
1. `Gitlab::Usage::ServicePingReport.for(mode: :values)` [cascades down](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb) to ~400+ other counter method calls.
1. When the cron job runs, it calls [`Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/service_ping/submit_service.rb).
1. `Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)` [cascades down](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb) to ~400+ other counter method calls.
1. The response of all methods calls are [merged together](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/usage_data.rb#L68) into a single JSON payload.
1. The JSON payload is then [posted to the Versions application](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/services/service_ping/submit_service.rb#L20)
If a firewall exception is needed, the required URL depends on several things. If

View File

@ -30,11 +30,14 @@ Elasticsearch and follows Elasticsearch's [End of Life Policy](https://www.elast
When we change Elasticsearch supported versions in GitLab, we announce them in [deprecation notes](https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations) in monthly release posts
before we remove them.
NOTE:
We do not support
[Amazon's OpenSearch](https://aws.amazon.com/blogs/opensource/opensearch-1-0-launches/)
### Versions not supported
GitLab does not support:
- [Amazon's OpenSearch](https://aws.amazon.com/blogs/opensource/opensearch-1-0-launches/)
(a [fork of Elasticsearch](https://www.elastic.co/what-is/opensearch)).
Follow our progress in [issue #327560](https://gitlab.com/gitlab-org/gitlab/-/issues/327560).
For updates, see [issue #327560](https://gitlab.com/gitlab-org/gitlab/-/issues/327560).
- Elasticsearch 8.0. For updates, see [issue #350600](https://gitlab.com/gitlab-org/gitlab/-/issues/350600).
## System requirements

View File

@ -13,9 +13,14 @@ GitLab administrators are responsible for the overall security of their instance
provides a Credentials inventory to keep track of all the credentials that can be used to access
their self-managed instance.
Using Credentials inventory, you can see all the personal access tokens (PAT), SSH keys, and GPG keys
that exist in your GitLab instance. In addition, you can [revoke](#revoke-a-users-personal-access-token)
and [delete](#delete-a-users-ssh-key) and see:
Use Credentials inventory to see for your GitLab instance all:
- Personal access tokens (PAT).
- Project access tokens (GitLab 14.8 and later).
- SSH keys.
- GPG keys.
You can also [revoke](#revoke-a-users-personal-access-token) and [delete](#delete-a-users-ssh-key) and see:
- Who they belong to.
- Their access scope.
@ -28,10 +33,6 @@ To access the Credentials inventory:
1. On the top bar, select **Menu > Admin**.
1. On the left sidebar, select **Credentials**.
The following is an example of the Credentials inventory page:
![Credentials inventory page](img/credentials_inventory_v13_10.png)
## Revoke a user's personal access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/214811) in GitLab 13.4.
@ -49,6 +50,15 @@ If you see a **Revoke** button, you can revoke that user's PAT. Whether you see
When a PAT is revoked from the credentials inventory, the instance notifies the user by email.
## Revoke a user's project access token
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/243833) in GitLab 14.8.
The **Revoke** button next to a project access token can be selected to revoke that particular project access token. This will both:
- Revoke the token project access token.
- Enqueue a background worker to delete the project bot user.
## Delete a user's SSH key
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/225248) in GitLab 13.5.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@ -117,6 +117,8 @@ module API
# rubocop: disable CodeReuse/ActiveRecord
def find_project(id)
return unless id
projects = Project.without_deleted
if id.is_a?(Integer) || id =~ /^\d+$/

View File

@ -18,7 +18,7 @@ module API
get 'non_sql_metrics' do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/325534')
data = Gitlab::UsageDataNonSqlMetrics.data
data = Gitlab::Usage::ServicePingReport.for(output: :non_sql_metrics_values)
present data
end

View File

@ -18,7 +18,7 @@ module API
get 'queries' do
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/325534')
queries = Gitlab::UsageDataQueries.data
queries = Gitlab::Usage::ServicePingReport.for(output: :metrics_queries)
present queries
end

View File

@ -25,7 +25,7 @@ module Gitlab
read_timeout: 20,
write_timeout: 30
}.freeze
DEFAULT_READ_TOTAL_TIMEOUT = 20.seconds
DEFAULT_READ_TOTAL_TIMEOUT = 30.seconds
include HTTParty # rubocop:disable Gitlab/HTTParty

View File

@ -4,20 +4,32 @@ module Gitlab
module Usage
class ServicePingReport
class << self
def for(mode:, cached: false)
case mode.to_sym
when :values
usage_data(cached)
def for(output:, cached: false)
case output.to_sym
when :all_metrics_values
all_metrics_values(cached)
when :metrics_queries
metrics_queries
when :non_sql_metrics_values
non_sql_metrics_values
end
end
private
def usage_data(cached)
def all_metrics_values(cached)
Rails.cache.fetch('usage_data', force: !cached, expires_in: 2.weeks) do
Gitlab::UsageData.data
end
end
def metrics_queries
Gitlab::UsageDataQueries.data
end
def non_sql_metrics_values
Gitlab::UsageDataNonSqlMetrics.data
end
end
end
end

View File

@ -203,6 +203,13 @@ module Gitlab
rescue Addressable::URI::InvalidURIError, TypeError
end
def add_url_parameters(url, params)
uri = parse_url(url.to_s)
uri.query_values = uri.query_values.to_h.merge(params.to_h.stringify_keys)
uri.query_values = nil if uri.query_values.empty?
uri.to_s
end
def removes_sensitive_data_from_url(uri_string)
uri = parse_url(uri_string)

View File

@ -4,17 +4,17 @@ namespace :gitlab do
namespace :usage_data do
desc 'GitLab | UsageData | Generate raw SQLs for usage ping in YAML'
task dump_sql_in_yaml: :environment do
puts Gitlab::UsageDataQueries.data.to_yaml
puts Gitlab::Usage::ServicePingReport.for(output: :metrics_queries).to_yaml
end
desc 'GitLab | UsageData | Generate raw SQLs for usage ping in JSON'
task dump_sql_in_json: :environment do
puts Gitlab::Json.pretty_generate(Gitlab::UsageDataQueries.data)
puts Gitlab::Json.pretty_generate(Gitlab::Usage::ServicePingReport.for(output: :metrics_queries))
end
desc 'GitLab | UsageData | Generate usage ping in JSON'
task generate: :environment do
puts Gitlab::Json.pretty_generate(Gitlab::Usage::ServicePingReport.for(mode: :values))
puts Gitlab::Json.pretty_generate(Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values))
end
desc 'GitLab | UsageData | Generate usage ping and send it to Versions Application'

View File

@ -4785,6 +4785,9 @@ msgstr ""
msgid "Are you sure you want to revoke this personal access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to revoke this project access token? This action cannot be undone."
msgstr ""
msgid "Are you sure you want to stop this environment?"
msgstr ""
@ -10499,6 +10502,9 @@ msgstr ""
msgid "Creation date"
msgstr ""
msgid "Creator"
msgstr ""
msgid "Credentials"
msgstr ""
@ -10511,6 +10517,9 @@ msgstr ""
msgid "CredentialsInventory|Personal Access Tokens"
msgstr ""
msgid "CredentialsInventory|Project Access Tokens"
msgstr ""
msgid "CredentialsInventory|SSH Keys"
msgstr ""
@ -11010,10 +11019,16 @@ msgstr ""
msgid "DastProfiles|AJAX spider"
msgstr ""
msgid "DastProfiles|API"
msgstr ""
msgid "DastProfiles|API endpoint URL"
msgstr ""
msgid "DastProfiles|Active"
msgstr ""
msgid "DastProfiles|Additional request headers (Optional)"
msgid "DastProfiles|Additional request headers (optional)"
msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
@ -11097,7 +11112,13 @@ msgstr ""
msgid "DastProfiles|Excluded URLs"
msgstr ""
msgid "DastProfiles|Excluded URLs (Optional)"
msgid "DastProfiles|Excluded URLs (optional)"
msgstr ""
msgid "DastProfiles|Excluded paths"
msgstr ""
msgid "DastProfiles|Excluded paths (optional)"
msgstr ""
msgid "DastProfiles|Hide debug messages"
@ -11154,9 +11175,6 @@ msgstr ""
msgid "DastProfiles|Request headers"
msgstr ""
msgid "DastProfiles|Rest API"
msgstr ""
msgid "DastProfiles|Run the AJAX spider, in addition to the traditional spider, to crawl the target site."
msgstr ""

View File

@ -55,7 +55,7 @@
"@babel/preset-env": "^7.10.1",
"@gitlab/at.js": "1.5.7",
"@gitlab/favicon-overlay": "2.0.0",
"@gitlab/svgs": "2.3.0",
"@gitlab/svgs": "2.5.0",
"@gitlab/ui": "35.1.0",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "6.1.4-1",

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Create', only: { subdomain: %i[staging staging-canary] } do
describe 'Git push to canary Gitaly node over HTTP' do
it 'pushes to a project using a canary specific Gitaly repository storage', :smoke, :requires_admin, testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/351116' do
Flow::Login.sign_in_as_admin
project = Resource::Project.fabricate_via_api! do |storage_project|
storage_project.name = 'canary-specific-repository-storage'
storage_project.repository_storage = 'nfs-file-cny01' # TODO: move to ENV var
end
Resource::Repository::Push.fabricate! do |push|
push.repository_http_uri = project.repository_http_location.uri
push.file_name = 'README.md'
push.file_content = "# This is a test project named #{project.name}"
push.commit_message = 'Add README.md'
push.new_branch = true
end
project.visit!
Page::Project::Show.perform do |project_page|
expect(project_page).to have_file('README.md')
expect(project_page).to have_readme_content("This is a test project named #{project.name}")
end
end
end
end
end

View File

@ -23,7 +23,7 @@ RSpec.describe Admin::InstanceReviewController do
stub_application_setting(usage_ping_enabled: true)
stub_usage_data_connections
stub_database_flavor_check
::Gitlab::Usage::ServicePingReport.for(mode: :values)
::Gitlab::Usage::ServicePingReport.for(output: :all_metrics_values)
subject
end

View File

@ -76,6 +76,12 @@ RSpec.describe API::Helpers do
expect(subject.find_project(non_existing_id)).to be_nil
end
end
context 'when project id is not provided' do
it 'returns nil' do
expect(subject.find_project(nil)).to be_nil
end
end
end
context 'when ID is used as an argument' do

View File

@ -5,11 +5,27 @@ require 'spec_helper'
RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_caching do
let(:usage_data) { { uuid: "1111" } }
context 'for mode: :values' do
context 'for output: :all_metrics_values' do
it 'generates the service ping' do
expect(Gitlab::UsageData).to receive(:data)
described_class.for(mode: :values)
described_class.for(output: :all_metrics_values)
end
end
context 'for output: :metrics_queries' do
it 'generates the service ping' do
expect(Gitlab::UsageDataQueries).to receive(:data)
described_class.for(output: :metrics_queries)
end
end
context 'for output: :non_sql_metrics_values' do
it 'generates the service ping' do
expect(Gitlab::UsageDataNonSqlMetrics).to receive(:data)
described_class.for(output: :non_sql_metrics_values)
end
end
@ -20,8 +36,8 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
it 'caches the values' do
allow(Gitlab::UsageData).to receive(:data).and_return(usage_data, new_usage_data)
expect(described_class.for(mode: :values)).to eq(usage_data)
expect(described_class.for(mode: :values, cached: true)).to eq(usage_data)
expect(described_class.for(output: :all_metrics_values)).to eq(usage_data)
expect(described_class.for(output: :all_metrics_values, cached: true)).to eq(usage_data)
expect(Rails.cache.fetch('usage_data')).to eq(usage_data)
end
@ -29,9 +45,9 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
it 'writes to cache and returns fresh data' do
allow(Gitlab::UsageData).to receive(:data).and_return(usage_data, new_usage_data)
expect(described_class.for(mode: :values)).to eq(usage_data)
expect(described_class.for(mode: :values)).to eq(new_usage_data)
expect(described_class.for(mode: :values, cached: true)).to eq(new_usage_data)
expect(described_class.for(output: :all_metrics_values)).to eq(usage_data)
expect(described_class.for(output: :all_metrics_values)).to eq(new_usage_data)
expect(described_class.for(output: :all_metrics_values, cached: true)).to eq(new_usage_data)
expect(Rails.cache.fetch('usage_data')).to eq(new_usage_data)
end
@ -43,8 +59,8 @@ RSpec.describe Gitlab::Usage::ServicePingReport, :use_clean_rails_memory_store_c
it 'returns fresh data' do
allow(Gitlab::UsageData).to receive(:data).and_return(usage_data, new_usage_data)
expect(described_class.for(mode: :values)).to eq(usage_data)
expect(described_class.for(mode: :values)).to eq(new_usage_data)
expect(described_class.for(output: :all_metrics_values)).to eq(usage_data)
expect(described_class.for(output: :all_metrics_values)).to eq(new_usage_data)
expect(Rails.cache.fetch('usage_data')).to eq(new_usage_data)
end

View File

@ -439,6 +439,23 @@ RSpec.describe Gitlab::Utils do
end
end
describe '.add_url_parameters' do
subject { described_class.add_url_parameters(url, params) }
where(:url, :params, :expected_url) do
nil | nil | ''
nil | { b: 3, a: 2 } | '?a=2&b=3'
'https://gitlab.com' | nil | 'https://gitlab.com'
'https://gitlab.com' | { b: 3, a: 2 } | 'https://gitlab.com?a=2&b=3'
'https://gitlab.com?a=1#foo' | { b: 3, 'a': 2 } | 'https://gitlab.com?a=2&b=3#foo'
'https://gitlab.com?a=1#foo' | [[:b, 3], [:a, 2]] | 'https://gitlab.com?a=2&b=3#foo'
end
with_them do
it { is_expected.to eq(expected_url) }
end
end
describe '.removes_sensitive_data_from_url' do
it 'returns string object' do
expect(described_class.removes_sensitive_data_from_url('http://gitlab.com')).to be_instance_of(String)

View File

@ -22,6 +22,16 @@ RSpec.describe PersonalAccessToken do
end
describe 'scopes' do
describe '.project_access_tokens' do
let_it_be(:user) { create(:user, :project_bot) }
let_it_be(:project_member) { create(:project_member, user: user) }
let_it_be(:project_access_token) { create(:personal_access_token, user: user) }
subject { described_class.project_access_token }
it { is_expected.to contain_exactly(project_access_token) }
end
describe '.for_user' do
it 'returns personal access tokens of specified user only' do
user_1 = create(:user)

View File

@ -43,10 +43,10 @@ RSpec.describe AlertManagement::CreateAlertIssueService do
expect(execute).to be_success
end
it 'updates alert.issue_id' do
it 'sets alert.issue_id in the same ActiveRecord query execution' do
execute
expect(alert.reload.issue_id).to eq(created_issue.id)
expect(alert.issue_id).to eq(created_issue.id)
end
it 'creates a system note' do

View File

@ -83,6 +83,25 @@ RSpec.describe IncidentManagement::Incidents::CreateService do
it 'result payload contains an Issue object' do
expect(create_incident.payload[:issue]).to be_kind_of(Issue)
end
context 'with alert' do
let(:alert) { create(:alert_management_alert, project: project) }
subject(:create_incident) { described_class.new(project, user, title: title, description: description, alert: alert).execute }
it 'associates the alert with the incident' do
expect(create_incident[:issue].alert_management_alert).to eq(alert)
end
context 'the alert prevents the issue from saving' do
let(:alert) { create(:alert_management_alert, :with_validation_errors, project: project) }
it 'responds with errors' do
expect(create_incident).to be_error
expect(create_incident.message).to eq('Hosts hosts array is over 255 chars')
end
end
end
end
end
end

View File

@ -81,16 +81,58 @@ RSpec.describe Projects::OverwriteProjectService do
end
end
it 'removes the original project' do
subject.execute(project_from)
it 'schedules original project for deletion' do
expect_next_instance_of(Projects::DestroyService) do |service|
expect(service).to receive(:async_execute)
end
expect { Project.find(project_from.id) }.to raise_error(ActiveRecord::RecordNotFound)
subject.execute(project_from)
end
it 'renames the project' do
original_path = project_from.full_path
subject.execute(project_from)
expect(project_to.full_path).to eq project_from.full_path
expect(project_to.full_path).to eq(original_path)
end
it 'renames source project to temp name' do
allow(SecureRandom).to receive(:hex).and_return('test')
subject.execute(project_from)
expect(project_from.full_path).to include('-old-test')
end
context 'when project rename fails' do
before do
expect(subject).to receive(:move_relationships_between).with(project_from, project_to)
expect(subject).to receive(:move_relationships_between).with(project_to, project_from)
end
context 'source rename' do
it 'moves relations back to source project and raises an exception' do
allow(subject).to receive(:rename_project).and_return(status: :error)
expect { subject.execute(project_from) }.to raise_error(StandardError, 'Source project rename failed during project overwrite')
end
end
context 'new project rename' do
it 'moves relations back, renames source project back to original name and raises' do
name = project_from.name
path = project_from.path
allow(subject).to receive(:rename_project).and_call_original
allow(subject).to receive(:rename_project).with(project_to, name, path).and_return(status: :error)
expect { subject.execute(project_from) }.to raise_error(StandardError, 'New project rename failed during project overwrite')
expect(project_from.name).to eq(name)
expect(project_from.path).to eq(path)
end
end
end
end
@ -121,7 +163,7 @@ RSpec.describe Projects::OverwriteProjectService do
end
end
context 'forks' do
context 'forks', :sidekiq_inline do
context 'when moving a root forked project' do
it 'moves the descendant forks' do
expect(project_from.forks.count).to eq 2
@ -147,6 +189,7 @@ RSpec.describe Projects::OverwriteProjectService do
expect(project_to.fork_network.fork_network_members.map(&:project)).not_to include project_from
end
end
context 'when moving a intermediate forked project' do
let(:project_to) { create(:project, namespace: lvl1_forked_project_1.namespace) }
@ -180,22 +223,26 @@ RSpec.describe Projects::OverwriteProjectService do
end
context 'if an exception is raised' do
before do
allow(subject).to receive(:rename_project).and_raise(StandardError)
end
it 'rollbacks changes' do
updated_at = project_from.updated_at
allow(subject).to receive(:rename_project).and_raise(StandardError)
expect { subject.execute(project_from) }.to raise_error(StandardError)
expect(Project.find(project_from.id)).not_to be_nil
expect(project_from.reload.updated_at.change(usec: 0)).to eq updated_at.change(usec: 0)
end
it 'tries to restore the original project repositories' do
allow(subject).to receive(:rename_project).and_raise(StandardError)
expect(subject).to receive(:attempt_restore_repositories).with(project_from)
it 'removes fork network member' do
expect(ForkNetworkMember).to receive(:create!)
expect(ForkNetworkMember).to receive(:find_by)
expect(subject).to receive(:remove_source_project_from_fork_network).and_call_original
expect { subject.execute(project_from) }.to raise_error(StandardError)
expect(project_from.fork_network_member).to be_nil
end
end
end

View File

@ -118,7 +118,7 @@ RSpec.describe ServicePing::SubmitService do
it 'generates service ping' do
stub_response(body: with_dev_ops_score_params)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_call_original
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_call_original
subject.execute
end
@ -151,7 +151,7 @@ RSpec.describe ServicePing::SubmitService do
it 'forces a refresh of usage data statistics before submitting' do
stub_response(body: with_dev_ops_score_params)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_call_original
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_call_original
subject.execute
end
@ -167,7 +167,7 @@ RSpec.describe ServicePing::SubmitService do
recorded_at = Time.current
usage_data = { uuid: 'uuid', recorded_at: recorded_at }
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return(usage_data)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return(usage_data)
subject.execute
@ -190,7 +190,7 @@ RSpec.describe ServicePing::SubmitService do
recorded_at = Time.current
usage_data = { uuid: 'uuid', recorded_at: recorded_at }
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return(usage_data)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return(usage_data)
subject.execute
@ -235,7 +235,7 @@ RSpec.describe ServicePing::SubmitService do
recorded_at = Time.current
usage_data = { uuid: 'uuid', recorded_at: recorded_at }
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return(usage_data)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return(usage_data)
subject.execute
@ -260,7 +260,7 @@ RSpec.describe ServicePing::SubmitService do
context 'and usage data is empty string' do
before do
allow(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return({})
allow(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return({})
end
it_behaves_like 'does not send a blank usage ping payload'
@ -269,7 +269,7 @@ RSpec.describe ServicePing::SubmitService do
context 'and usage data is nil' do
before do
allow(ServicePing::BuildPayloadService).to receive(:execute).and_return(nil)
allow(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return(nil)
allow(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return(nil)
end
it_behaves_like 'does not send a blank usage ping payload'
@ -285,7 +285,7 @@ RSpec.describe ServicePing::SubmitService do
it 'calls Gitlab::Usage::ServicePingReport .for method' do
usage_data = build_usage_data
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return(usage_data)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return(usage_data)
subject.execute
end
@ -329,7 +329,7 @@ RSpec.describe ServicePing::SubmitService do
it 'calls Gitlab::Usage::ServicePingReport .for method' do
usage_data = build_usage_data
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(mode: :values).and_return(usage_data)
expect(Gitlab::Usage::ServicePingReport).to receive(:for).with(output: :all_metrics_values).and_return(usage_data)
# SubmissionError is raised as a result of 404 in response from HTTP Request
expect { subject.execute }.to raise_error(described_class::SubmissionError)

View File

@ -957,10 +957,10 @@
stylelint-declaration-strict-value "1.8.0"
stylelint-scss "4.1.0"
"@gitlab/svgs@2.3.0":
version "2.3.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.3.0.tgz#2ddb38c1e27a5f1945863c3093107117c0175be4"
integrity sha512-VXryDplnM+sImEleyxDnW4oyDvIwUhSCZ/+hxYmXesysQiK+vm+hEfdc2N+AnlD2xbdbnuMQnegckOL38Ic2/g==
"@gitlab/svgs@2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.5.0.tgz#e0569916fa858462b1801cc90ef8dd9706a12e96"
integrity sha512-cH/EBs//wdkH6kG+kDpvRCIl63/A8JgjAhBJ+ZWucPgtNCDD6x6RDMGdQrxSqhYwcCKDoLStfcxmblBkuiSRXQ==
"@gitlab/ui@35.1.0":
version "35.1.0"