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-19 18:09:08 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-19 18:09:08 +0300
commit6a3c4476fa8f1c686eadbed05262bce95504ffa7 (patch)
treed6e29b8f855e704d560d40df0726ba52e74aebca
parentc6af94ea4ea649171ff930b6bf94c73a5d03edb9 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.gitlab/ci/global.gitlab-ci.yml2
-rw-r--r--.rubocop_todo.yml5
-rw-r--r--app/controllers/groups/email_campaigns_controller.rb21
-rw-r--r--app/finders/award_emojis_finder.rb3
-rw-r--r--app/finders/branches_finder.rb3
-rw-r--r--app/finders/ci/daily_build_group_report_results_finder.rb6
-rw-r--r--app/finders/ci/variables_finder.rb3
-rw-r--r--app/finders/context_commits_finder.rb18
-rw-r--r--app/finders/deployments_finder.rb4
-rw-r--r--app/finders/environments_finder.rb4
-rw-r--r--app/finders/group_projects_finder.rb3
-rw-r--r--app/finders/issuable_finder.rb4
-rw-r--r--app/finders/issues_finder.rb3
-rw-r--r--app/finders/merge_request/metrics_finder.rb4
-rw-r--r--app/finders/namespaces/projects_finder.rb3
-rw-r--r--app/finders/packages/conan/package_file_finder.rb3
-rw-r--r--app/finders/packages/debian/distributions_finder.rb3
-rw-r--r--app/finders/packages/group_packages_finder.rb3
-rw-r--r--app/finders/packages/package_file_finder.rb4
-rw-r--r--app/finders/packages/packages_finder.rb3
-rw-r--r--app/finders/pending_todos_finder.rb4
-rw-r--r--app/finders/projects/export_job_finder.rb4
-rw-r--r--app/finders/projects/prometheus/alerts_finder.rb4
-rw-r--r--app/finders/projects_finder.rb3
-rw-r--r--app/finders/prometheus_metrics_finder.rb4
-rw-r--r--app/finders/protected_branches_finder.rb4
-rw-r--r--app/finders/releases_finder.rb3
-rw-r--r--app/finders/tags_finder.rb3
-rw-r--r--app/finders/users_star_projects_finder.rb4
-rw-r--r--app/helpers/application_helper.rb4
-rw-r--r--app/helpers/git_helper.rb3
-rw-r--r--app/models/ci/build_dependencies.rb3
-rw-r--r--app/models/project_services/teamcity_service.rb15
-rw-r--r--app/models/users/in_product_marketing_email.rb10
-rw-r--r--app/services/merge_requests/add_context_service.rb4
-rw-r--r--app/services/packages/debian/extract_metadata_service.rb21
-rw-r--r--app/services/packages/debian/process_changes_service.rb101
-rw-r--r--app/services/resource_events/base_synthetic_notes_builder_service.rb4
-rw-r--r--app/workers/irker_worker.rb3
-rw-r--r--changelogs/unreleased/docs-eb-pages-deployment-migration.yml5
-rw-r--r--changelogs/unreleased/pl-rubocop-todo-redundant-assignment.yml5
-rw-r--r--changelogs/unreleased/ui-text-jetbrains-integration.yml5
-rw-r--r--config/bullet.yml44
-rw-r--r--config/initializers/bullet.rb14
-rw-r--r--config/initializers/hangouts_chat_http_override.rb3
-rw-r--r--doc/administration/geo/replication/datatypes.md7
-rw-r--r--doc/administration/geo/replication/docker_registry.md2
-rw-r--r--doc/administration/pages/index.md22
-rw-r--r--doc/development/migration_style_guide.md6
-rw-r--r--doc/integration/jira/dvcs.md2
-rw-r--r--doc/user/group/index.md19
-rw-r--r--lib/api/groups.rb4
-rw-r--r--lib/api/helpers/packages/conan/api_helpers.rb4
-rw-r--r--lib/error_tracking/sentry_client/issue.rb4
-rw-r--r--lib/gitlab/bullet.rb16
-rw-r--r--lib/gitlab/bullet/exclusions.rb37
-rw-r--r--lib/gitlab/ci/config.rb4
-rw-r--r--lib/gitlab/ci/pipeline/chain/validate/external.rb2
-rw-r--r--lib/gitlab/crypto_helper.rb3
-rw-r--r--lib/gitlab/data_builder/build.rb4
-rw-r--r--lib/gitlab/fogbugz_import/importer.rb6
-rw-r--r--lib/gitlab/git/diff_collection.rb3
-rw-r--r--lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb4
-rw-r--r--lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb4
-rw-r--r--lib/gitlab/graphql/queries.rb4
-rw-r--r--lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb8
-rw-r--r--lib/gitlab/slug/environment.rb17
-rw-r--r--locale/gitlab.pot14
-rw-r--r--qa/qa/flow/saml.rb4
-rw-r--r--qa/qa/scenario/test/integration/object_storage.rb13
-rw-r--r--qa/spec/scenario/test/integration/object_storage_spec.rb9
-rw-r--r--scripts/gitaly_test.rb4
-rw-r--r--spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb6
-rw-r--r--spec/lib/gitlab/bullet/exclusions_spec.rb155
-rw-r--r--spec/lib/gitlab/bullet_spec.rb51
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb4
-rw-r--r--spec/migrations/backfill_operations_feature_flags_active_spec.rb4
-rw-r--r--spec/migrations/backfill_operations_feature_flags_iid_spec.rb4
-rw-r--r--spec/migrations/delete_internal_ids_where_feature_flags_usage_spec.rb4
-rw-r--r--spec/migrations/migrate_ops_feature_flags_scopes_target_user_ids_spec.rb4
-rw-r--r--spec/models/project_spec.rb2
-rw-r--r--spec/models/users/in_product_marketing_email_spec.rb77
-rw-r--r--spec/requests/groups/email_campaigns_controller_spec.rb46
-rw-r--r--spec/services/packages/debian/process_changes_service_spec.rb58
-rw-r--r--spec/support/helpers/query_recorder.rb40
-rw-r--r--spec/support_specs/helpers/active_record/query_recorder_spec.rb70
87 files changed, 856 insertions, 276 deletions
diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml
index b083f4f4651..891457afe6e 100644
--- a/.gitlab/ci/global.gitlab-ci.yml
+++ b/.gitlab/ci/global.gitlab-ci.yml
@@ -27,7 +27,7 @@
.rails-cache:
cache:
- key: "rails-v4"
+ key: "rails-v5"
paths:
- vendor/ruby/
- vendor/gitaly-ruby/
diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml
index cfcf990029d..22f261ab347 100644
--- a/.rubocop_todo.yml
+++ b/.rubocop_todo.yml
@@ -864,11 +864,6 @@ Style/RaiseArgs:
Enabled: false
EnforcedStyle: exploded
-# Offense count: 73
-# Cop supports --auto-correct.
-Style/RedundantAssignment:
- Enabled: false
-
# Offense count: 2
# Cop supports --auto-correct.
Style/RedundantBegin:
diff --git a/app/controllers/groups/email_campaigns_controller.rb b/app/controllers/groups/email_campaigns_controller.rb
index e085cefbc24..4ce7d86be3c 100644
--- a/app/controllers/groups/email_campaigns_controller.rb
+++ b/app/controllers/groups/email_campaigns_controller.rb
@@ -17,16 +17,19 @@ class Groups::EmailCampaignsController < Groups::ApplicationController
private
def track_click
- data = {
- namespace_id: group.id,
- track: @track.to_s,
- series: @series,
- subject_line: subject_line(@track, @series)
- }
+ if Gitlab.com?
+ data = {
+ namespace_id: group.id,
+ track: @track.to_s,
+ series: @series,
+ subject_line: subject_line(@track, @series)
+ }
+ context = SnowplowTracker::SelfDescribingJson.new(EMAIL_CAMPAIGNS_SCHEMA_URL, data)
- context = SnowplowTracker::SelfDescribingJson.new(EMAIL_CAMPAIGNS_SCHEMA_URL, data)
-
- ::Gitlab::Tracking.event(self.class.name, 'click', context: [context])
+ ::Gitlab::Tracking.event(self.class.name, 'click', context: [context])
+ else
+ ::Users::InProductMarketingEmail.save_cta_click(current_user, @track, @series)
+ end
end
def redirect_link
diff --git a/app/finders/award_emojis_finder.rb b/app/finders/award_emojis_finder.rb
index 7882beb64bf..9ff64637128 100644
--- a/app/finders/award_emojis_finder.rb
+++ b/app/finders/award_emojis_finder.rb
@@ -13,8 +13,7 @@ class AwardEmojisFinder
def execute
awards = awardable.award_emoji
awards = by_name(awards)
- awards = by_awarded_by(awards)
- awards
+ by_awarded_by(awards)
end
private
diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb
index 2eee90a512a..157c454183a 100644
--- a/app/finders/branches_finder.rb
+++ b/app/finders/branches_finder.rb
@@ -11,8 +11,7 @@ class BranchesFinder < GitRefsFinder
else
branches = repository.branches_sorted_by(sort)
branches = by_search(branches)
- branches = by_names(branches)
- branches
+ by_names(branches)
end
end
diff --git a/app/finders/ci/daily_build_group_report_results_finder.rb b/app/finders/ci/daily_build_group_report_results_finder.rb
index 9e736c70dda..5ac1bbd0670 100644
--- a/app/finders/ci/daily_build_group_report_results_finder.rb
+++ b/app/finders/ci/daily_build_group_report_results_finder.rb
@@ -35,8 +35,7 @@ module Ci
return Ci::DailyBuildGroupReportResult.none unless query_allowed?
collection = Ci::DailyBuildGroupReportResult.by_projects(params[:project])
- collection = filter_report_results(collection)
- collection
+ filter_report_results(collection)
end
private
@@ -51,8 +50,7 @@ module Ci
collection = by_dates(collection)
collection = sort(collection)
- collection = limit_by(collection)
- collection
+ limit_by(collection)
end
def by_coverage(items)
diff --git a/app/finders/ci/variables_finder.rb b/app/finders/ci/variables_finder.rb
index 3e61127ff5b..d1546b27995 100644
--- a/app/finders/ci/variables_finder.rb
+++ b/app/finders/ci/variables_finder.rb
@@ -11,8 +11,7 @@ module Ci
def execute
variables = resource.variables
variables = by_key(variables)
- variables = by_environment_scope(variables)
- variables
+ by_environment_scope(variables)
end
private
diff --git a/app/finders/context_commits_finder.rb b/app/finders/context_commits_finder.rb
index de89a556ee0..d623854ada4 100644
--- a/app/finders/context_commits_finder.rb
+++ b/app/finders/context_commits_finder.rb
@@ -11,9 +11,7 @@ class ContextCommitsFinder
def execute
commits = init_collection
- commits = filter_existing_commits(commits)
-
- commits
+ filter_existing_commits(commits)
end
private
@@ -21,19 +19,15 @@ class ContextCommitsFinder
attr_reader :project, :merge_request, :search, :limit, :offset
def init_collection
- commits =
- if search.present?
- search_commits
- else
- project.repository.commits(merge_request.target_branch, { limit: limit, offset: offset })
- end
-
- commits
+ if search.present?
+ search_commits
+ else
+ project.repository.commits(merge_request.target_branch, { limit: limit, offset: offset })
+ end
end
def filter_existing_commits(commits)
commits.select! { |commit| already_included_ids.exclude?(commit.id) }
-
commits
end
diff --git a/app/finders/deployments_finder.rb b/app/finders/deployments_finder.rb
index 89a28d9dfb8..ae26fc14ad5 100644
--- a/app/finders/deployments_finder.rb
+++ b/app/finders/deployments_finder.rb
@@ -33,9 +33,7 @@ class DeploymentsFinder
items = by_environment(items)
items = by_status(items)
items = preload_associations(items)
- items = sort(items)
-
- items
+ sort(items)
end
private
diff --git a/app/finders/environments_finder.rb b/app/finders/environments_finder.rb
index 3ce5e258cf2..688c241dfb2 100644
--- a/app/finders/environments_finder.rb
+++ b/app/finders/environments_finder.rb
@@ -15,9 +15,7 @@ class EnvironmentsFinder
environments = by_search(environments)
# Raises InvalidStatesError if params[:states] contains invalid states.
- environments = by_states(environments)
-
- environments
+ by_states(environments)
end
private
diff --git a/app/finders/group_projects_finder.rb b/app/finders/group_projects_finder.rb
index 8362e782ad1..dfdf821e3f0 100644
--- a/app/finders/group_projects_finder.rb
+++ b/app/finders/group_projects_finder.rb
@@ -48,8 +48,7 @@ class GroupProjectsFinder < ProjectsFinder
def filter_projects(collection)
projects = super
- projects = by_feature_availability(projects)
- projects
+ by_feature_availability(projects)
end
def limit(collection)
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 2a1dcbaaf1d..40a4e2b4f26 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -119,9 +119,7 @@ class IssuableFinder
# https://www.postgresql.org/docs/current/static/queries-with.html
items = by_search(items)
- items = sort(items)
-
- items
+ sort(items)
end
def filter_items(items)
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index e55c1e937b0..e1a334413f8 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -81,8 +81,7 @@ class IssuesFinder < IssuableFinder
issues = super
issues = by_due_date(issues)
issues = by_confidential(issues)
- issues = by_issue_types(issues)
- issues
+ by_issue_types(issues)
end
def by_confidential(items)
diff --git a/app/finders/merge_request/metrics_finder.rb b/app/finders/merge_request/metrics_finder.rb
index d93e53d1636..1a3732bbdf9 100644
--- a/app/finders/merge_request/metrics_finder.rb
+++ b/app/finders/merge_request/metrics_finder.rb
@@ -14,9 +14,7 @@ class MergeRequest::MetricsFinder
items = init_collection
items = by_target_project(items)
items = by_merged_after(items)
- items = by_merged_before(items)
-
- items
+ by_merged_before(items)
end
private
diff --git a/app/finders/namespaces/projects_finder.rb b/app/finders/namespaces/projects_finder.rb
index a6d98015e9d..bac5328d077 100644
--- a/app/finders/namespaces/projects_finder.rb
+++ b/app/finders/namespaces/projects_finder.rb
@@ -39,8 +39,7 @@ module Namespaces
def filter_projects(collection)
collection = by_ids(collection)
- collection = by_similarity(collection)
- collection
+ by_similarity(collection)
end
def by_ids(items)
diff --git a/app/finders/packages/conan/package_file_finder.rb b/app/finders/packages/conan/package_file_finder.rb
index edf35388a36..a1ebf9f40fa 100644
--- a/app/finders/packages/conan/package_file_finder.rb
+++ b/app/finders/packages/conan/package_file_finder.rb
@@ -8,8 +8,7 @@ module Packages
def package_files
files = super
files = by_conan_file_type(files)
- files = by_conan_package_reference(files)
- files
+ by_conan_package_reference(files)
end
def by_conan_file_type(files)
diff --git a/app/finders/packages/debian/distributions_finder.rb b/app/finders/packages/debian/distributions_finder.rb
index e64b6bdfec1..98afc918fb1 100644
--- a/app/finders/packages/debian/distributions_finder.rb
+++ b/app/finders/packages/debian/distributions_finder.rb
@@ -11,8 +11,7 @@ module Packages
collection = relation.with_container(container)
collection = by_codename(collection)
collection = by_suite(collection)
- collection = by_codename_or_suite(collection)
- collection
+ by_codename_or_suite(collection)
end
private
diff --git a/app/finders/packages/group_packages_finder.rb b/app/finders/packages/group_packages_finder.rb
index db5161d6e16..8771bf90e75 100644
--- a/app/finders/packages/group_packages_finder.rb
+++ b/app/finders/packages/group_packages_finder.rb
@@ -32,8 +32,7 @@ module Packages
packages = filter_with_version(packages)
packages = filter_by_package_type(packages)
packages = filter_by_package_name(packages)
- packages = filter_by_status(packages)
- packages
+ filter_by_status(packages)
end
def group_projects_visible_to_current_user
diff --git a/app/finders/packages/package_file_finder.rb b/app/finders/packages/package_file_finder.rb
index d015f4adfa6..792ffa0591b 100644
--- a/app/finders/packages/package_file_finder.rb
+++ b/app/finders/packages/package_file_finder.rb
@@ -21,9 +21,7 @@ class Packages::PackageFileFinder
def package_files
files = package.package_files
- files = by_file_name(files)
-
- files
+ by_file_name(files)
end
def by_file_name(files)
diff --git a/app/finders/packages/packages_finder.rb b/app/finders/packages/packages_finder.rb
index bd9e62e3f2a..840cbbf7b9d 100644
--- a/app/finders/packages/packages_finder.rb
+++ b/app/finders/packages/packages_finder.rb
@@ -22,8 +22,7 @@ module Packages
packages = filter_by_package_type(packages)
packages = filter_by_package_name(packages)
packages = filter_by_status(packages)
- packages = order_packages(packages)
- packages
+ order_packages(packages)
end
private
diff --git a/app/finders/pending_todos_finder.rb b/app/finders/pending_todos_finder.rb
index bf1eb07f34e..d79a2340379 100644
--- a/app/finders/pending_todos_finder.rb
+++ b/app/finders/pending_todos_finder.rb
@@ -26,9 +26,7 @@ class PendingTodosFinder
todos = by_project(todos)
todos = by_target_id(todos)
todos = by_target_type(todos)
- todos = by_commit_id(todos)
-
- todos
+ by_commit_id(todos)
end
def by_project(todos)
diff --git a/app/finders/projects/export_job_finder.rb b/app/finders/projects/export_job_finder.rb
index c26a7a3f1a6..c270feb23dc 100644
--- a/app/finders/projects/export_job_finder.rb
+++ b/app/finders/projects/export_job_finder.rb
@@ -12,9 +12,7 @@ module Projects
def execute
export_jobs = project.export_jobs
- export_jobs = by_status(export_jobs)
-
- export_jobs
+ by_status(export_jobs)
end
private
diff --git a/app/finders/projects/prometheus/alerts_finder.rb b/app/finders/projects/prometheus/alerts_finder.rb
index 3e3b72647c5..2105516db5f 100644
--- a/app/finders/projects/prometheus/alerts_finder.rb
+++ b/app/finders/projects/prometheus/alerts_finder.rb
@@ -30,9 +30,7 @@ module Projects
relation = by_environment(relation)
relation = by_metric(relation)
relation = by_id(relation)
- relation = ordered(relation)
-
- relation
+ ordered(relation)
end
private
diff --git a/app/finders/projects_finder.rb b/app/finders/projects_finder.rb
index f5b98d3314c..893e89daa3c 100644
--- a/app/finders/projects_finder.rb
+++ b/app/finders/projects_finder.rb
@@ -83,8 +83,7 @@ class ProjectsFinder < UnionFinder
collection = by_deleted_status(collection)
collection = by_last_activity_after(collection)
collection = by_last_activity_before(collection)
- collection = by_repository_storage(collection)
- collection
+ by_repository_storage(collection)
end
def collection_with_user
diff --git a/app/finders/prometheus_metrics_finder.rb b/app/finders/prometheus_metrics_finder.rb
index 84a071abbd5..152ee73ef26 100644
--- a/app/finders/prometheus_metrics_finder.rb
+++ b/app/finders/prometheus_metrics_finder.rb
@@ -36,9 +36,7 @@ class PrometheusMetricsFinder
metrics = by_common(metrics)
metrics = by_ordered(metrics)
metrics = by_identifier(metrics)
- metrics = by_id(metrics)
-
- metrics
+ by_id(metrics)
end
private
diff --git a/app/finders/protected_branches_finder.rb b/app/finders/protected_branches_finder.rb
index 68e8d2a9f54..a452a1f993b 100644
--- a/app/finders/protected_branches_finder.rb
+++ b/app/finders/protected_branches_finder.rb
@@ -20,9 +20,7 @@ class ProtectedBranchesFinder
def execute
protected_branches = project.limited_protected_branches(LIMIT)
- protected_branches = by_name(protected_branches)
-
- protected_branches
+ by_name(protected_branches)
end
private
diff --git a/app/finders/releases_finder.rb b/app/finders/releases_finder.rb
index da72178169e..0cfa4310ab7 100644
--- a/app/finders/releases_finder.rb
+++ b/app/finders/releases_finder.rb
@@ -20,8 +20,7 @@ class ReleasesFinder
releases = get_releases
releases = by_tag(releases)
releases = releases.preloaded if preload
- releases = order_releases(releases)
- releases
+ order_releases(releases)
end
private
diff --git a/app/finders/tags_finder.rb b/app/finders/tags_finder.rb
index fd58f478b45..d9848d027cf 100644
--- a/app/finders/tags_finder.rb
+++ b/app/finders/tags_finder.rb
@@ -7,7 +7,6 @@ class TagsFinder < GitRefsFinder
def execute
tags = repository.tags_sorted_by(sort)
- tags = by_search(tags)
- tags
+ by_search(tags)
end
end
diff --git a/app/finders/users_star_projects_finder.rb b/app/finders/users_star_projects_finder.rb
index 49c4e087b4b..7a7587c8631 100644
--- a/app/finders/users_star_projects_finder.rb
+++ b/app/finders/users_star_projects_finder.rb
@@ -15,9 +15,7 @@ class UsersStarProjectsFinder
stars = UsersStarProject.all
stars = by_project(stars)
stars = by_search(stars)
- stars = filter_visible_profiles(stars)
-
- stars
+ filter_visible_profiles(stars)
end
private
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 6309d5a2d82..a2ef2f1207c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -165,7 +165,7 @@ module ApplicationHelper
css_classes = [short_format ? 'js-short-timeago' : 'js-timeago']
css_classes << html_class unless html_class.blank?
- element = content_tag :time, l(time, format: "%b %d, %Y"),
+ content_tag :time, l(time, format: "%b %d, %Y"),
class: css_classes.join(' '),
title: l(time.to_time.in_time_zone, format: :timeago_tooltip),
datetime: time.to_time.getutc.iso8601,
@@ -174,8 +174,6 @@ module ApplicationHelper
placement: placement,
container: 'body'
}
-
- element
end
def edited_time_ago_with_tooltip(object, placement: 'top', html_class: 'time_ago', exclude_author: false)
diff --git a/app/helpers/git_helper.rb b/app/helpers/git_helper.rb
index 0fb37a69e56..f7c511cdc47 100644
--- a/app/helpers/git_helper.rb
+++ b/app/helpers/git_helper.rb
@@ -4,8 +4,7 @@ module GitHelper
def strip_signature(text)
text = text.gsub(/-----BEGIN PGP SIGNATURE-----(.*)-----END PGP SIGNATURE-----/m, "")
text = text.gsub(/-----BEGIN PGP MESSAGE-----(.*)-----END PGP MESSAGE-----/m, "")
- text = text.gsub(/-----BEGIN SIGNED MESSAGE-----(.*)-----END SIGNED MESSAGE-----/m, "")
- text
+ text.gsub(/-----BEGIN SIGNED MESSAGE-----(.*)-----END SIGNED MESSAGE-----/m, "")
end
def short_sha(text)
diff --git a/app/models/ci/build_dependencies.rb b/app/models/ci/build_dependencies.rb
index b50ecf99439..8ae921f1416 100644
--- a/app/models/ci/build_dependencies.rb
+++ b/app/models/ci/build_dependencies.rb
@@ -21,8 +21,7 @@ module Ci
deps = model_class.where(pipeline_id: processable.pipeline_id).latest
deps = from_previous_stages(deps)
deps = from_needs(deps)
- deps = from_dependencies(deps)
- deps
+ from_dependencies(deps)
end
# Dependencies from the same parent-pipeline hierarchy excluding
diff --git a/app/models/project_services/teamcity_service.rb b/app/models/project_services/teamcity_service.rb
index 60d107d7557..6fc24a4778c 100644
--- a/app/models/project_services/teamcity_service.rb
+++ b/app/models/project_services/teamcity_service.rb
@@ -51,16 +51,15 @@ class TeamcityService < CiService
end
def title
- 'JetBrains TeamCity CI'
+ 'JetBrains TeamCity'
end
def description
- 'A continuous integration and build server'
+ s_('ProjectService|Run CI/CD pipelines with JetBrains TeamCity.')
end
def help
- 'You will want to configure monitoring of all branches so merge '\
- 'requests build, that setting is in the vsc root advanced settings.'
+ s_('To run CI/CD pipelines with JetBrains TeamCity, input the GitLab project details in the TeamCity project Version Control Settings.')
end
def fields
@@ -68,20 +67,20 @@ class TeamcityService < CiService
{
type: 'text',
name: 'teamcity_url',
- title: s_('ProjectService|TeamCity URL'),
- placeholder: 'TeamCity root URL like https://teamcity.example.com',
+ title: s_('ProjectService|TeamCity server URL'),
+ placeholder: 'https://teamcity.example.com',
required: true
},
{
type: 'text',
name: 'build_type',
- placeholder: 'Build configuration ID',
+ help: s_('ProjectService|The build configuration ID of the TeamCity project.'),
required: true
},
{
type: 'text',
name: 'username',
- placeholder: 'A user with permissions to trigger a manual build'
+ help: s_('ProjectService|Must have permission to trigger a manual build in TeamCity.')
},
{
type: 'password',
diff --git a/app/models/users/in_product_marketing_email.rb b/app/models/users/in_product_marketing_email.rb
index b5a08716c7f..195cfe162ac 100644
--- a/app/models/users/in_product_marketing_email.rb
+++ b/app/models/users/in_product_marketing_email.rb
@@ -35,5 +35,15 @@ module Users
.where(in_product_marketing_emails: { id: nil })
.select(Arel.sql("DISTINCT ON(#{users.table_name}.id) #{users.table_name}.*"))
end
+
+ scope :for_user_with_track_and_series, -> (user, track, series) do
+ where(user: user, track: track, series: series)
+ end
+
+ def self.save_cta_click(user, track, series)
+ email = for_user_with_track_and_series(user, track, series).take
+
+ email.update(cta_clicked_at: Time.zone.now) if email && email.cta_clicked_at.blank?
+ end
end
end
diff --git a/app/services/merge_requests/add_context_service.rb b/app/services/merge_requests/add_context_service.rb
index b693f8509a2..77b00f645c9 100644
--- a/app/services/merge_requests/add_context_service.rb
+++ b/app/services/merge_requests/add_context_service.rb
@@ -49,11 +49,9 @@ module MergeRequests
def duplicates
existing_oids = merge_request.merge_request_context_commits.map { |commit| commit.sha.to_s }
- duplicate_oids = existing_oids.select do |existing_oid|
+ existing_oids.select do |existing_oid|
commit_ids.select { |commit_id| existing_oid.start_with?(commit_id) }.count > 0
end
-
- duplicate_oids
end
def build_context_commit_rows(merge_request_id, commits)
diff --git a/app/services/packages/debian/extract_metadata_service.rb b/app/services/packages/debian/extract_metadata_service.rb
index fc5a6db51de..015f472c7c9 100644
--- a/app/services/packages/debian/extract_metadata_service.rb
+++ b/app/services/packages/debian/extract_metadata_service.rb
@@ -58,21 +58,22 @@ module Packages
file_type == :dsc || file_type == :buildinfo || file_type == :changes
end
- def extracted_fields
- if file_type_debian?
- package_file.file.use_file do |file_path|
- ::Packages::Debian::ExtractDebMetadataService.new(file_path).execute
- end
- elsif file_type_meta?
- package_file.file.use_file do |file_path|
- ::Packages::Debian::ParseDebian822Service.new(File.read(file_path)).execute.each_value.first
+ def fields
+ strong_memoize(:fields) do
+ if file_type_debian?
+ package_file.file.use_file do |file_path|
+ ::Packages::Debian::ExtractDebMetadataService.new(file_path).execute
+ end
+ elsif file_type_meta?
+ package_file.file.use_file do |file_path|
+ ::Packages::Debian::ParseDebian822Service.new(File.read(file_path)).execute.each_value.first
+ end
end
end
end
def extract_metadata
- fields = extracted_fields
- architecture = fields.delete('Architecture') if file_type_debian?
+ architecture = fields['Architecture'] if file_type_debian?
{
file_type: file_type,
diff --git a/app/services/packages/debian/process_changes_service.rb b/app/services/packages/debian/process_changes_service.rb
new file mode 100644
index 00000000000..bf42cb78d39
--- /dev/null
+++ b/app/services/packages/debian/process_changes_service.rb
@@ -0,0 +1,101 @@
+# frozen_string_literal: true
+
+module Packages
+ module Debian
+ class ProcessChangesService
+ include ExclusiveLeaseGuard
+ include Gitlab::Utils::StrongMemoize
+
+ # used by ExclusiveLeaseGuard
+ DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze
+
+ def initialize(package_file, creator)
+ @package_file, @creator = package_file, creator
+ end
+
+ def execute
+ try_obtain_lease do
+ # return if changes file has already been processed
+ break if package_file.debian_file_metadatum&.changes?
+
+ validate!
+
+ package_file.transaction do
+ update_files_metadata
+ update_changes_metadata
+ end
+ end
+ end
+
+ private
+
+ attr_reader :package_file, :creator
+
+ def validate!
+ raise ArgumentError, 'invalid package file' unless package_file.debian_file_metadatum
+ raise ArgumentError, 'invalid package file' unless package_file.debian_file_metadatum.unknown?
+ raise ArgumentError, 'invalid package file' unless metadata[:file_type] == :changes
+ end
+
+ def update_files_metadata
+ files.each do |filename, entry|
+ entry.package_file.package = package
+
+ file_metadata = ::Packages::Debian::ExtractMetadataService.new(entry.package_file).execute
+
+ entry.package_file.debian_file_metadatum.update!(
+ file_type: file_metadata[:file_type],
+ component: files[filename].component,
+ architecture: file_metadata[:architecture],
+ fields: file_metadata[:fields]
+ )
+ entry.package_file.save!
+ end
+ end
+
+ def update_changes_metadata
+ package_file.update!(package: package)
+ package_file.debian_file_metadatum.update!(
+ file_type: metadata[:file_type],
+ fields: metadata[:fields]
+ )
+ end
+
+ def metadata
+ strong_memoize(:metadata) do
+ ::Packages::Debian::ExtractChangesMetadataService.new(package_file).execute
+ end
+ end
+
+ def files
+ metadata[:files]
+ end
+
+ def project
+ package_file.package.project
+ end
+
+ def package
+ strong_memoize(:package) do
+ params = {
+ 'name': metadata[:fields]['Source'],
+ 'version': metadata[:fields]['Version'],
+ 'distribution_name': metadata[:fields]['Distribution']
+ }
+ response = Packages::Debian::FindOrCreatePackageService.new(project, creator, params).execute
+ response.payload[:package]
+ end
+ end
+
+ # used by ExclusiveLeaseGuard
+ def lease_key
+ "packages:debian:process_changes_service:package_file:#{package_file.id}"
+ end
+
+ # used by ExclusiveLeaseGuard
+ def lease_timeout
+ DEFAULT_LEASE_TIMEOUT
+ end
+ end
+ end
+end
diff --git a/app/services/resource_events/base_synthetic_notes_builder_service.rb b/app/services/resource_events/base_synthetic_notes_builder_service.rb
index a2d78ec67c3..5939b9d2f9c 100644
--- a/app/services/resource_events/base_synthetic_notes_builder_service.rb
+++ b/app/services/resource_events/base_synthetic_notes_builder_service.rb
@@ -25,9 +25,7 @@ module ResourceEvents
def apply_common_filters(events)
events = apply_last_fetched_at(events)
- events = apply_fetch_until(events)
-
- events
+ apply_fetch_until(events)
end
def apply_last_fetched_at(events)
diff --git a/app/workers/irker_worker.rb b/app/workers/irker_worker.rb
index 687fb1cd02a..c5bdb3e0970 100644
--- a/app/workers/irker_worker.rb
+++ b/app/workers/irker_worker.rb
@@ -147,8 +147,7 @@ class IrkerWorker # rubocop:disable Scalability/IdempotentWorker
def files_count(commit)
diff_size = commit.raw_deltas.size
- files = "#{diff_size} file".pluralize(diff_size)
- files
+ "#{diff_size} file".pluralize(diff_size)
end
def colorize_sha(sha)
diff --git a/changelogs/unreleased/docs-eb-pages-deployment-migration.yml b/changelogs/unreleased/docs-eb-pages-deployment-migration.yml
new file mode 100644
index 00000000000..88e86063efa
--- /dev/null
+++ b/changelogs/unreleased/docs-eb-pages-deployment-migration.yml
@@ -0,0 +1,5 @@
+---
+title: Add documentation about Pages deployment migration
+merge_request: 59475
+author:
+type: added
diff --git a/changelogs/unreleased/pl-rubocop-todo-redundant-assignment.yml b/changelogs/unreleased/pl-rubocop-todo-redundant-assignment.yml
new file mode 100644
index 00000000000..6bd48a33722
--- /dev/null
+++ b/changelogs/unreleased/pl-rubocop-todo-redundant-assignment.yml
@@ -0,0 +1,5 @@
+---
+title: Resolves offenses Style/RedundantAssignment
+merge_request: 58013
+author: Shubham Kumar (@imskr)
+type: fixed
diff --git a/changelogs/unreleased/ui-text-jetbrains-integration.yml b/changelogs/unreleased/ui-text-jetbrains-integration.yml
new file mode 100644
index 00000000000..874e2f4efa0
--- /dev/null
+++ b/changelogs/unreleased/ui-text-jetbrains-integration.yml
@@ -0,0 +1,5 @@
+---
+title: Update UI text for TeamCity integration
+merge_request: 59493
+author:
+type: other
diff --git a/config/bullet.yml b/config/bullet.yml
new file mode 100644
index 00000000000..18eaa778aad
--- /dev/null
+++ b/config/bullet.yml
@@ -0,0 +1,44 @@
+---
+
+exclusions:
+ # See https://github.com/flyerhzm/bullet#configuration for exclusion formats
+ # Example usage:
+ #
+ # paths with method name(recommended use):
+ #
+ # example_path_with_method_exclusion_name:
+ # merge_request: 'some merge request link for context'
+ # exact_file_name: true
+ # exclude:
+ # - 'some_ruby_file_name.rb'
+ # - 'method_name_inside_the_file_above'
+ #
+ # path or pattern only to file(fuzzy, not recommended):
+ #
+ # example_path_with_exact_file_name:
+ # merge_request: 'some merge request link for context'
+ # exact_file_name: true
+ # exclude:
+ # - 'some_ruby_file_name.rb'
+ #
+ # example_path_with_pattern:
+ # merge_request: 'some merge request link for context'
+ # exact_file_name: false
+ # exclude:
+ # - 'file_pattern'
+ #
+ # path with line numbers(extremely fragile, not recommended):
+ #
+ # example_path_with_line_range:
+ # merge_request: 'some merge request link for context'
+ # exact_file_name: true
+ # exclude:
+ # - 'some_ruby_file_name.rb'
+ # - 5..10
+ #
+ group_member_presenter_managing_group:
+ merge_request: 'https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58927'
+ path_with_method: true
+ exclude:
+ - 'ee/app/presenters/ee/group_member_presenter.rb'
+ - 'group_managed_account?'
diff --git a/config/initializers/bullet.rb b/config/initializers/bullet.rb
index 2d21514b121..3ef426aaadc 100644
--- a/config/initializers/bullet.rb
+++ b/config/initializers/bullet.rb
@@ -1,18 +1,18 @@
# frozen_string_literal: true
-def bullet_enabled?
- Gitlab::Utils.to_boolean(ENV['ENABLE_BULLET'].to_s)
-end
-
-if defined?(Bullet) && (bullet_enabled? || Rails.env.development?)
+if Gitlab::Bullet.configure_bullet?
Rails.application.configure do
config.after_initialize do
Bullet.enable = true
- Bullet.bullet_logger = bullet_enabled?
- Bullet.console = bullet_enabled?
+ if Gitlab::Bullet.extra_logging_enabled?
+ Bullet.bullet_logger = true
+ Bullet.console = true
+ end
Bullet.raise = Rails.env.test?
+
+ Bullet.stacktrace_excludes = Gitlab::Bullet::Exclusions.new.execute
end
end
end
diff --git a/config/initializers/hangouts_chat_http_override.rb b/config/initializers/hangouts_chat_http_override.rb
index 4fd886697e4..edb31ed53f1 100644
--- a/config/initializers/hangouts_chat_http_override.rb
+++ b/config/initializers/hangouts_chat_http_override.rb
@@ -17,9 +17,8 @@ module HangoutsChat
headers: { 'Content-Type' => 'application/json' },
parse: nil # disables automatic response parsing
)
- net_http_response = httparty_response.response
+ httparty_response.response
# The rest of the integration expects a Net::HTTP response
- net_http_response
end
end
diff --git a/doc/administration/geo/replication/datatypes.md b/doc/administration/geo/replication/datatypes.md
index 82e94e94cd5..1df2fb4e3ab 100644
--- a/doc/administration/geo/replication/datatypes.md
+++ b/doc/administration/geo/replication/datatypes.md
@@ -33,8 +33,9 @@ verification methods:
| Git | Project wiki repository | Geo with Gitaly | Gitaly Checksum |
| Git | Project designs repository | Geo with Gitaly | Gitaly Checksum |
| Git | Object pools for forked project deduplication | Geo with Gitaly | _Not implemented_ |
-| Git | Project Snippets | Geo with Gitaly | _Not implemented_ |
-| Git | Personal Snippets | Geo with Gitaly | _Not implemented_ |
+| Git | Project Snippets | Geo with Gitaly | Gitaly Checksum |
+| Git | Personal Snippets | Geo with Gitaly | Gitaly Checksum |
+| Git | Group wiki repository | Geo with Gitaly | _Not implemented_ |
| Blobs | User uploads _(file system)_ | Geo with API | _Not implemented_ |
| Blobs | User uploads _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
| Blobs | LFS objects _(file system)_ | Geo with API | _Not implemented_ |
@@ -51,6 +52,8 @@ verification methods:
| Blobs | Versioned Terraform State _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
| Blobs | External Merge Request Diffs _(file system)_ | Geo with API | _Not implemented_ |
| Blobs | External Merge Request Diffs _(object storage)_ | Geo with API/Managed (*2*) | _Not implemented_ |
+| Blobs | Pipeline artifacts _(file system)_ | Geo with API | SHA256 checksum |
+| Blobs | Pipeline artifacts _(object storage)_ | Geo with API/Managed (*2*) | SHA256 checksum |
- (*1*): Redis replication can be used as part of HA with Redis sentinel. It's not used between Geo sites.
- (*2*): Object storage replication can be performed by Geo or by your object storage provider/appliance
diff --git a/doc/administration/geo/replication/docker_registry.md b/doc/administration/geo/replication/docker_registry.md
index 745ed28056f..ea73614511f 100644
--- a/doc/administration/geo/replication/docker_registry.md
+++ b/doc/administration/geo/replication/docker_registry.md
@@ -99,7 +99,7 @@ pair for all the sites. The **secondary** site will use this key to
generate a short-lived JWT that is pull-only-capable to access the
**primary** site Container Registry.
-For each application node on the **secondary** site:
+For each application and Sidekiq node on the **secondary** site:
1. SSH into the node and login as the `root` user:
diff --git a/doc/administration/pages/index.md b/doc/administration/pages/index.md
index 4d2ef141622..d04688dab7a 100644
--- a/doc/administration/pages/index.md
+++ b/doc/administration/pages/index.md
@@ -999,6 +999,28 @@ sudo gitlab-rake gitlab:pages:clean_migrated_zip_storage
This will not remove any data from the legacy disk storage and the GitLab Pages daemon will automatically fallback
to using that.
+### Migrate Pages deployments to object storage
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/325285) in GitLab 13.11
+
+Existing Pages deployments objects (which store [ZIP archives](#zip-storage)) can similarly be
+migrated to [object storage](#using-object-storage), if
+you've been having them stored locally.
+
+Migrate your existing Pages deployments from local storage to object storage:
+
+```shell
+sudo gitlab-rails gitlab:pages:deployments:migrate_to_object_storage
+```
+
+### Rolling Pages deployments back to local storage
+
+After the migration to object storage is performed, you can choose to revert your Pages deployments back to local storage:
+
+```shell
+sudo gitlab-rails gitlab:pages:deployments:migrate_to_local
+```
+
## Backup
GitLab Pages are part of the [regular backup](../../raketasks/backup_restore.md), so there is no separate backup to configure.
diff --git a/doc/development/migration_style_guide.md b/doc/development/migration_style_guide.md
index d4ea5f927d6..40457dbb533 100644
--- a/doc/development/migration_style_guide.md
+++ b/doc/development/migration_style_guide.md
@@ -254,10 +254,10 @@ def up
t.bigint :project_id, null: false
t.bigint :user_id, null: false
t.string :jid, limit: 255
- end
- add_index :imports, :project_id
- add_index :imports, :user_id
+ t.index :project_id
+ t.index :user_id
+ end
end
def down
diff --git a/doc/integration/jira/dvcs.md b/doc/integration/jira/dvcs.md
index ce80d370627..5d315ebd802 100644
--- a/doc/integration/jira/dvcs.md
+++ b/doc/integration/jira/dvcs.md
@@ -87,7 +87,7 @@ it completes, refreshes every 60 minutes:
1. In the **Host URL** field, enter the URI appropriate for your version of GitLab,
replacing `<gitlab.example.com>` with your GitLab instance domain:
- - *For GitLab versions 11.3 and later,* use `https://<gitlab.example.com>/`.
+ - *For GitLab versions 11.3 and later,* use `https://<gitlab.example.com>`.
- *For GitLab versions 11.2 and earlier,* use
`https://<gitlab.example.com>/-/jira`.
diff --git a/doc/user/group/index.md b/doc/user/group/index.md
index 45e9d5bfd20..d070277beed 100644
--- a/doc/user/group/index.md
+++ b/doc/user/group/index.md
@@ -7,22 +7,17 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Groups **(FREE)**
-In GitLab, you can put related projects together in a group.
+In GitLab, you use groups to manage one or more related projects at the same time.
-For example, you might create a group for your company members and a subgroup for each individual team.
-You can name the group `company-team`, and the subgroups `backend-team`, `frontend-team`, and `production-team`.
+You can use groups to manage permissions for your projects. If someone has access to
+the group, they get access to all the projects in the group.
-Then you can:
+You can also view all of the issues and merge requests for the projects in the group,
+and view analytics that show the group's activity.
-- Grant members access to multiple projects at once.
-- Add to-do items for all of the group members at once.
-- View the [issues](../project/issues/index.md) and
- [merge requests](../project/merge_requests/reviewing_and_managing_merge_requests.md#view-merge-requests-for-all-projects-in-a-group)
- for all projects in the group, together in a single list view.
-- [Bulk edit](../group/bulk_editing/index.md) issues, epics, and merge requests.
-- [Create a wiki](../project/wiki/index.md) for the group.
+You can use groups to communicate with all of the members of the group at once.
-You can also create [subgroups](subgroups/index.md).
+For larger organizations, you can also create [subgroups](subgroups/index.md).
## View groups
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index f4ad4cfcd41..912813d5bb7 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -52,9 +52,7 @@ module API
groups = groups.where.not(id: params[:skip_groups]) if params[:skip_groups].present?
order_options = { params[:order_by] => params[:sort] }
order_options["id"] ||= "asc"
- groups = groups.reorder(order_options)
-
- groups
+ groups.reorder(order_options)
end
# rubocop: enable CodeReuse/ActiveRecord
diff --git a/lib/api/helpers/packages/conan/api_helpers.rb b/lib/api/helpers/packages/conan/api_helpers.rb
index 5499b6fe653..b18f52b5be6 100644
--- a/lib/api/helpers/packages/conan/api_helpers.rb
+++ b/lib/api/helpers/packages/conan/api_helpers.rb
@@ -209,10 +209,8 @@ module API
end
def find_personal_access_token
- personal_access_token = find_personal_access_token_from_conan_jwt ||
+ find_personal_access_token_from_conan_jwt ||
find_personal_access_token_from_http_basic_auth
-
- personal_access_token
end
def find_user_from_job_token
diff --git a/lib/error_tracking/sentry_client/issue.rb b/lib/error_tracking/sentry_client/issue.rb
index 513fb3daabe..bdc567bd859 100644
--- a/lib/error_tracking/sentry_client/issue.rb
+++ b/lib/error_tracking/sentry_client/issue.rb
@@ -113,9 +113,7 @@ module ErrorTracking
uri = URI(url)
uri.path.squeeze!('/')
# Remove trailing slash
- uri = uri.to_s.delete_suffix('/')
-
- uri
+ uri.to_s.delete_suffix('/')
end
def map_to_errors(issues)
diff --git a/lib/gitlab/bullet.rb b/lib/gitlab/bullet.rb
new file mode 100644
index 00000000000..f5f8a316855
--- /dev/null
+++ b/lib/gitlab/bullet.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Bullet
+ extend self
+
+ def enabled?
+ Gitlab::Utils.to_boolean(ENV['ENABLE_BULLET'], default: false)
+ end
+ alias_method :extra_logging_enabled?, :enabled?
+
+ def configure_bullet?
+ defined?(::Bullet) && (enabled? || Rails.env.development?)
+ end
+ end
+end
diff --git a/lib/gitlab/bullet/exclusions.rb b/lib/gitlab/bullet/exclusions.rb
new file mode 100644
index 00000000000..f897ff492d9
--- /dev/null
+++ b/lib/gitlab/bullet/exclusions.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Gitlab
+ module Bullet
+ class Exclusions
+ def initialize(config_file = Gitlab.root.join('config/bullet.yml'))
+ @config_file = config_file
+ end
+
+ def execute
+ exclusions.map { |v| v['exclude'] }
+ end
+
+ def validate_paths!
+ exclusions.each do |properties|
+ next unless properties['path_with_method']
+
+ file = properties['exclude'].first
+
+ raise "Bullet: File used by #{config_file} doesn't exist, validate the #{file} exclusion!" unless File.exist?(file)
+ end
+ end
+
+ private
+
+ attr_reader :config_file
+
+ def exclusions
+ @exclusions ||= if File.exist?(config_file)
+ YAML.load_file(config_file)['exclusions']&.values || []
+ else
+ []
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/ci/config.rb b/lib/gitlab/ci/config.rb
index 3f06ab261c2..23b0c93a3ee 100644
--- a/lib/gitlab/ci/config.rb
+++ b/lib/gitlab/ci/config.rb
@@ -96,9 +96,7 @@ module Gitlab
initial_config = Config::External::Processor.new(initial_config, @context).perform
initial_config = Config::Extendable.new(initial_config).to_hash
initial_config = Config::Yaml::Tags::Resolver.new(initial_config).to_hash
- initial_config = Config::EdgeStagesInjector.new(initial_config).to_hash
-
- initial_config
+ Config::EdgeStagesInjector.new(initial_config).to_hash
end
def find_sha(project)
diff --git a/lib/gitlab/ci/pipeline/chain/validate/external.rb b/lib/gitlab/ci/pipeline/chain/validate/external.rb
index 93f4bebd41d..6149d2f04d7 100644
--- a/lib/gitlab/ci/pipeline/chain/validate/external.rb
+++ b/lib/gitlab/ci/pipeline/chain/validate/external.rb
@@ -70,7 +70,7 @@ module Gitlab
def validate_service_request
headers = {
- 'X-Request-ID' => Labkit::Correlation::CorrelationId.current_id,
+ 'X-Gitlab-Correlation-id' => Labkit::Correlation::CorrelationId.current_id,
'X-Gitlab-Token' => validation_service_token
}.compact
diff --git a/lib/gitlab/crypto_helper.rb b/lib/gitlab/crypto_helper.rb
index 56d80a5a5d7..c113cebd72f 100644
--- a/lib/gitlab/crypto_helper.rb
+++ b/lib/gitlab/crypto_helper.rb
@@ -25,8 +25,7 @@ module Gitlab
return unless value
encrypted_token = Base64.decode64(value)
- decrypted_token = Encryptor.decrypt(AES256_GCM_OPTIONS.merge(value: encrypted_token, iv: nonce))
- decrypted_token
+ Encryptor.decrypt(AES256_GCM_OPTIONS.merge(value: encrypted_token, iv: nonce))
end
end
end
diff --git a/lib/gitlab/data_builder/build.rb b/lib/gitlab/data_builder/build.rb
index d5f157de372..0e4fc8efa95 100644
--- a/lib/gitlab/data_builder/build.rb
+++ b/lib/gitlab/data_builder/build.rb
@@ -12,7 +12,7 @@ module Gitlab
author_url = build_author_url(build.commit, commit)
- data = {
+ {
object_kind: 'build',
ref: build.ref,
@@ -67,8 +67,6 @@ module Gitlab
environment: build_environment(build)
}
-
- data
end
private
diff --git a/lib/gitlab/fogbugz_import/importer.rb b/lib/gitlab/fogbugz_import/importer.rb
index bd5d2e53180..612865ed1be 100644
--- a/lib/gitlab/fogbugz_import/importer.rb
+++ b/lib/gitlab/fogbugz_import/importer.rb
@@ -199,8 +199,7 @@ module Gitlab
def linkify_issues(str)
str = str.gsub(/([Ii]ssue) ([0-9]+)/, '\1 #\2')
- str = str.gsub(/([Cc]ase) ([0-9]+)/, '\1 #\2')
- str
+ str.gsub(/([Cc]ase) ([0-9]+)/, '\1 #\2')
end
def escape_for_markdown(str)
@@ -208,8 +207,7 @@ module Gitlab
str = str.gsub(/^-/, "\\-")
str = str.gsub("`", "\\~")
str = str.delete("\r")
- str = str.gsub("\n", " \n")
- str
+ str.gsub("\n", " \n")
end
def format_content(raw_content)
diff --git a/lib/gitlab/git/diff_collection.rb b/lib/gitlab/git/diff_collection.rb
index b7b6343aec0..fb947c80b7e 100644
--- a/lib/gitlab/git/diff_collection.rb
+++ b/lib/gitlab/git/diff_collection.rb
@@ -127,10 +127,9 @@ module Gitlab
end
def decorate!
- collection = each_with_index do |element, i|
+ each_with_index do |element, i|
@array[i] = yield(element)
end
- collection
end
alias_method :to_ary, :to_a
diff --git a/lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb b/lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb
index 3164598b7b9..ec70f5c5a24 100644
--- a/lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb
+++ b/lib/gitlab/graphql/pagination/keyset/conditions/not_null_condition.rb
@@ -30,15 +30,13 @@ module Gitlab
# ex: " OR (relative_position = 23 AND id > 500)"
def second_attribute_condition
- condition = <<~SQL
+ <<~SQL
OR (
#{table_condition(order_list.first, values.first, '=').to_sql}
AND
#{table_condition(order_list[1], values[1], operators[1]).to_sql}
)
SQL
-
- condition
end
# ex: " OR (relative_position IS NULL)"
diff --git a/lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb b/lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb
index fa25181d663..1aae1020e79 100644
--- a/lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb
+++ b/lib/gitlab/graphql/pagination/keyset/conditions/null_condition.rb
@@ -14,15 +14,13 @@ module Gitlab
# ex: "(relative_position IS NULL AND id > 500)"
def first_attribute_condition
- condition = <<~SQL
+ <<~SQL
(
#{table_condition(order_list.first, nil, 'is_null').to_sql}
AND
#{table_condition(order_list[1], values[1], operators[1]).to_sql}
)
SQL
-
- condition
end
# ex: " OR (relative_position IS NOT NULL)"
diff --git a/lib/gitlab/graphql/queries.rb b/lib/gitlab/graphql/queries.rb
index fcf293fb13e..74f55abccbc 100644
--- a/lib/gitlab/graphql/queries.rb
+++ b/lib/gitlab/graphql/queries.rb
@@ -224,11 +224,9 @@ module Gitlab
frag_path = frag_path.gsub(DOTS_RE) do |dots|
rel_dir(dots.split('/').count)
end
- frag_path = frag_path.gsub(IMPLICIT_ROOT) do
+ frag_path.gsub(IMPLICIT_ROOT) do
(Rails.root / 'app').to_s + '/'
end
-
- frag_path
end
def rel_dir(n_steps_up)
diff --git a/lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb b/lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb
index c90c1e3f0bc..55d14d6f94a 100644
--- a/lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb
+++ b/lib/gitlab/metrics/dashboard/stages/grafana_formatter.rb
@@ -104,9 +104,7 @@ module Gitlab
def format_query(metric)
expression = remove_new_lines(metric[:expr])
expression = replace_variables(expression)
- expression = replace_global_variables(expression, metric)
-
- expression
+ replace_global_variables(expression, metric)
end
# Accomodates instance-defined Grafana variables.
@@ -135,9 +133,7 @@ module Gitlab
def replace_global_variables(expression, metric)
expression = expression.gsub('$__interval', metric[:interval]) if metric[:interval]
expression = expression.gsub('$__from', query_params[:from])
- expression = expression.gsub('$__to', query_params[:to])
-
- expression
+ expression.gsub('$__to', query_params[:to])
end
# Removes new lines from expression.
diff --git a/lib/gitlab/slug/environment.rb b/lib/gitlab/slug/environment.rb
index 1b87d3bb626..fd70def8e7c 100644
--- a/lib/gitlab/slug/environment.rb
+++ b/lib/gitlab/slug/environment.rb
@@ -26,16 +26,13 @@ module Gitlab
# Repeated dashes are invalid (OpenShift limitation)
slugified.squeeze!('-')
- slugified =
- if slugified.size > 24 || slugified != name
- # Maximum length: 24 characters (OpenShift limitation)
- shorten_and_add_suffix(slugified)
- else
- # Cannot end with a dash (Kubernetes label limitation)
- slugified.chomp('-')
- end
-
- slugified
+ if slugified.size > 24 || slugified != name
+ # Maximum length: 24 characters (OpenShift limitation)
+ shorten_and_add_suffix(slugified)
+ else
+ # Cannot end with a dash (Kubernetes label limitation)
+ slugified.chomp('-')
+ end
end
private
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index cd3e66e6cea..4ca3bc505db 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -24707,6 +24707,9 @@ msgstr ""
msgid "ProjectService|Mock service URL"
msgstr ""
+msgid "ProjectService|Must have permission to trigger a manual build in TeamCity."
+msgstr ""
+
msgid "ProjectService|New issue URL"
msgstr ""
@@ -24716,7 +24719,13 @@ msgstr ""
msgid "ProjectService|Run CI/CD pipelines with Drone."
msgstr ""
-msgid "ProjectService|TeamCity URL"
+msgid "ProjectService|Run CI/CD pipelines with JetBrains TeamCity."
+msgstr ""
+
+msgid "ProjectService|TeamCity server URL"
+msgstr ""
+
+msgid "ProjectService|The build configuration ID of the TeamCity project."
msgstr ""
msgid "ProjectService|To configure this integration, you should:"
@@ -32827,6 +32836,9 @@ msgstr ""
msgid "To receive alerts from manually configured Prometheus services, add the following URL and Authorization key to your Prometheus webhook config file. Learn more about %{linkStart}configuring Prometheus%{linkEnd} to send alerts to GitLab."
msgstr ""
+msgid "To run CI/CD pipelines with JetBrains TeamCity, input the GitLab project details in the TeamCity project Version Control Settings."
+msgstr ""
+
msgid "To see all the user's personal access tokens you must impersonate them first."
msgstr ""
diff --git a/qa/qa/flow/saml.rb b/qa/qa/flow/saml.rb
index e8007978071..c414d648198 100644
--- a/qa/qa/flow/saml.rb
+++ b/qa/qa/flow/saml.rb
@@ -53,12 +53,10 @@ module QA
end
def run_saml_idp_service(group_name)
- service = Service::DockerRun::SamlIdp.new(Runtime::Scenario.gitlab_address, group_name).tap do |runner|
+ Service::DockerRun::SamlIdp.new(Runtime::Scenario.gitlab_address, group_name).tap do |runner|
runner.pull
runner.register!
end
-
- service
end
def remove_saml_idp_service(saml_idp_service)
diff --git a/qa/qa/scenario/test/integration/object_storage.rb b/qa/qa/scenario/test/integration/object_storage.rb
deleted file mode 100644
index 2e028bbb5c6..00000000000
--- a/qa/qa/scenario/test/integration/object_storage.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-# frozen_string_literal: true
-
-module QA
- module Scenario
- module Test
- module Integration
- class ObjectStorage < Test::Instance::All
- tags :object_storage
- end
- end
- end
- end
-end
diff --git a/qa/spec/scenario/test/integration/object_storage_spec.rb b/qa/spec/scenario/test/integration/object_storage_spec.rb
deleted file mode 100644
index 235dd495687..00000000000
--- a/qa/spec/scenario/test/integration/object_storage_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe QA::Scenario::Test::Integration::ObjectStorage do
- describe '#perform' do
- it_behaves_like 'a QA scenario class' do
- let(:tags) { [:object_storage] }
- end
- end
-end
diff --git a/scripts/gitaly_test.rb b/scripts/gitaly_test.rb
index f970457fea7..b7ea9cd628e 100644
--- a/scripts/gitaly_test.rb
+++ b/scripts/gitaly_test.rb
@@ -43,7 +43,7 @@ module GitalyTest
end
def env
- env_hash = {
+ {
'HOME' => File.expand_path('tmp/tests'),
'GEM_PATH' => Gem.path.join(':'),
'BUNDLE_APP_CONFIG' => File.join(gemfile_dir, '.bundle'),
@@ -54,8 +54,6 @@ module GitalyTest
# Git hooks can't run during tests as the internal API is not running.
'GITALY_TESTING_NO_GIT_HOOKS' => "1"
}
-
- env_hash
end
# rubocop:disable GitlabSecurity/SystemCommandInjection
diff --git a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
index 8e3a15cf61a..17bfe8fc1e2 100644
--- a/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
+++ b/spec/features/projects/services/user_activates_jetbrains_teamcity_ci_spec.rb
@@ -10,16 +10,16 @@ RSpec.describe 'User activates JetBrains TeamCity CI' do
end
it 'activates service', :js do
- visit_project_integration('JetBrains TeamCity CI')
+ visit_project_integration('JetBrains TeamCity')
check('Push')
check('Merge Request')
- fill_in('TeamCity URL', with: 'http://teamcity.example.com')
+ fill_in('TeamCity server URL', with: 'http://teamcity.example.com')
fill_in('Build type', with: 'GitlabTest_Build')
fill_in('Username', with: 'user')
fill_in('Password', with: 'verySecret')
click_test_then_save_integration(expect_test_to_fail: false)
- expect(page).to have_content('JetBrains TeamCity CI settings saved and active.')
+ expect(page).to have_content('JetBrains TeamCity settings saved and active.')
end
end
diff --git a/spec/lib/gitlab/bullet/exclusions_spec.rb b/spec/lib/gitlab/bullet/exclusions_spec.rb
new file mode 100644
index 00000000000..ba42156b0c4
--- /dev/null
+++ b/spec/lib/gitlab/bullet/exclusions_spec.rb
@@ -0,0 +1,155 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+RSpec.describe Gitlab::Bullet::Exclusions do
+ let(:config_file) do
+ file = Tempfile.new('bullet.yml')
+ File.basename(file)
+ end
+
+ let(:exclude) { [] }
+ let(:config) do
+ {
+ exclusions: {
+ abc: {
+ merge_request: '_mr_',
+ path_with_method: true,
+ exclude: exclude
+ }
+ }
+ }
+ end
+
+ before do
+ File.write(config_file, config.deep_stringify_keys.to_yaml)
+ end
+
+ after do
+ FileUtils.rm_f(config_file)
+ end
+
+ describe '#execute' do
+ subject(:executor) { described_class.new(config_file).execute }
+
+ shared_examples_for 'loads exclusion results' do
+ let(:config) { { exclusions: { abc: { exclude: exclude } } } }
+ let(:results) { [exclude] }
+
+ specify do
+ expect(executor).to match(results)
+ end
+ end
+
+ context 'with preferred method of path and method name' do
+ it_behaves_like 'loads exclusion results' do
+ let(:exclude) { %w[_path_ _method_] }
+ end
+ end
+
+ context 'with file pattern' do
+ it_behaves_like 'loads exclusion results' do
+ let(:exclude) { ['_file_pattern_'] }
+ end
+ end
+
+ context 'with file name and line range' do
+ it_behaves_like 'loads exclusion results' do
+ let(:exclude) { ['file_name.rb', 5..10] }
+ end
+ end
+
+ context 'without exclusions' do
+ it_behaves_like 'loads exclusion results' do
+ let(:exclude) { [] }
+ end
+ end
+
+ context 'without exclusions key in config' do
+ it_behaves_like 'loads exclusion results' do
+ let(:config) { {} }
+ let(:results) { [] }
+ end
+ end
+
+ context 'when config file does not exist' do
+ it 'provides an empty array for exclusions' do
+ expect(described_class.new('_some_bogus_file_').execute).to match([])
+ end
+ end
+ end
+
+ describe '#validate_paths!' do
+ context 'when validating scenarios' do
+ let(:source_file) do
+ file = Tempfile.new('bullet_test_source_file.rb')
+ File.basename(file)
+ end
+
+ subject { described_class.new(config_file).validate_paths! }
+
+ before do
+ FileUtils.touch(source_file)
+ end
+
+ after do
+ FileUtils.rm_f(source_file)
+ end
+
+ context 'when using paths with method name' do
+ let(:exclude) { [source_file, '_method_'] }
+
+ context 'when source file for exclusion exists' do
+ specify do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context 'when source file for exclusion does not exist' do
+ let(:exclude) { %w[_bogus_file_ _method_] }
+
+ specify do
+ expect { subject }.to raise_error(RuntimeError)
+ end
+ end
+ end
+
+ context 'when using path only' do
+ let(:exclude) { [source_file] }
+
+ context 'when source file for exclusion exists' do
+ specify do
+ expect { subject }.not_to raise_error
+ end
+ end
+
+ context 'when source file for exclusion does not exist' do
+ let(:exclude) { '_bogus_file_' }
+
+ specify do
+ expect { subject }.to raise_error(RuntimeError)
+ end
+ end
+ end
+
+ context 'when path_with_method is false for a file pattern' do
+ let(:exclude) { ['_file_pattern_'] }
+ let(:config) do
+ {
+ exclusions: {
+ abc: {
+ merge_request: '_mr_',
+ path_with_method: false,
+ exclude: exclude
+ }
+ }
+ }
+ end
+
+ specify do
+ expect { subject }.not_to raise_error
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/bullet_spec.rb b/spec/lib/gitlab/bullet_spec.rb
new file mode 100644
index 00000000000..1262a0b8bde
--- /dev/null
+++ b/spec/lib/gitlab/bullet_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Bullet do
+ describe '#enabled?' do
+ it 'is enabled' do
+ stub_env('ENABLE_BULLET', true)
+
+ expect(described_class.enabled?).to be(true)
+ end
+
+ it 'is not enabled' do
+ stub_env('ENABLE_BULLET', nil)
+
+ expect(described_class.enabled?).to be(false)
+ end
+
+ it 'is correctly aliased for #extra_logging_enabled?' do
+ expect(described_class.method(:extra_logging_enabled?).original_name).to eq(:enabled?)
+ end
+ end
+
+ describe '#configure_bullet?' do
+ context 'with ENABLE_BULLET true' do
+ before do
+ stub_env('ENABLE_BULLET', true)
+ end
+
+ it 'is configurable' do
+ expect(described_class.configure_bullet?).to be(true)
+ end
+ end
+
+ context 'with ENABLE_BULLET falsey' do
+ before do
+ stub_env('ENABLE_BULLET', nil)
+ end
+
+ it 'is not configurable' do
+ expect(described_class.configure_bullet?).to be(false)
+ end
+
+ it 'is configurable in development' do
+ allow(Rails).to receive_message_chain(:env, :development?).and_return(true)
+
+ expect(described_class.configure_bullet?).to be(true)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index 2bf4ee1a9fd..caf3a053c4e 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -88,7 +88,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
expect(::Gitlab::HTTP).to receive(:post) do |_url, params|
expect(params[:body]).to match_schema('/external_validation')
expect(params[:timeout]).to eq(described_class::DEFAULT_VALIDATION_REQUEST_TIMEOUT)
- expect(params[:headers]).to eq({ 'X-Request-ID' => 'correlation-id' })
+ expect(params[:headers]).to eq({ 'X-Gitlab-Correlation-id' => 'correlation-id' })
end
perform!
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 43dc94e8c1b..ac1d89b4225 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -2016,9 +2016,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
- project = projects.create!(namespace_id: namespace.id)
-
- project
+ projects.create!(namespace_id: namespace.id)
end
it 'generates iids properly for models created after the migration' do
diff --git a/spec/migrations/backfill_operations_feature_flags_active_spec.rb b/spec/migrations/backfill_operations_feature_flags_active_spec.rb
index 4ec2a4a2a92..e49b317d850 100644
--- a/spec/migrations/backfill_operations_feature_flags_active_spec.rb
+++ b/spec/migrations/backfill_operations_feature_flags_active_spec.rb
@@ -10,9 +10,7 @@ RSpec.describe BackfillOperationsFeatureFlagsActive do
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
- project = projects.create!(namespace_id: namespace.id)
-
- project
+ projects.create!(namespace_id: namespace.id)
end
it 'executes successfully when there are no flags in the table' do
diff --git a/spec/migrations/backfill_operations_feature_flags_iid_spec.rb b/spec/migrations/backfill_operations_feature_flags_iid_spec.rb
index bafe5830652..1ade08f657e 100644
--- a/spec/migrations/backfill_operations_feature_flags_iid_spec.rb
+++ b/spec/migrations/backfill_operations_feature_flags_iid_spec.rb
@@ -10,9 +10,7 @@ RSpec.describe BackfillOperationsFeatureFlagsIid do
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
- project = projects.create!(namespace_id: namespace.id)
-
- project
+ projects.create!(namespace_id: namespace.id)
end
it 'migrates successfully when there are no flags in the database' do
diff --git a/spec/migrations/delete_internal_ids_where_feature_flags_usage_spec.rb b/spec/migrations/delete_internal_ids_where_feature_flags_usage_spec.rb
index a58121fb708..50b5897220a 100644
--- a/spec/migrations/delete_internal_ids_where_feature_flags_usage_spec.rb
+++ b/spec/migrations/delete_internal_ids_where_feature_flags_usage_spec.rb
@@ -10,9 +10,7 @@ RSpec.describe DeleteInternalIdsWhereFeatureFlagsUsage do
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
- project = projects.create!(namespace_id: namespace.id)
-
- project
+ projects.create!(namespace_id: namespace.id)
end
it 'deletes feature flag rows from the internal_ids table' do
diff --git a/spec/migrations/migrate_ops_feature_flags_scopes_target_user_ids_spec.rb b/spec/migrations/migrate_ops_feature_flags_scopes_target_user_ids_spec.rb
index b2c36db2e1d..f066b9c90cd 100644
--- a/spec/migrations/migrate_ops_feature_flags_scopes_target_user_ids_spec.rb
+++ b/spec/migrations/migrate_ops_feature_flags_scopes_target_user_ids_spec.rb
@@ -12,9 +12,7 @@ RSpec.describe MigrateOpsFeatureFlagsScopesTargetUserIds do
def setup
namespace = namespaces.create!(name: 'foo', path: 'foo')
project = projects.create!(namespace_id: namespace.id)
- flag = flags.create!(project_id: project.id, active: true, name: 'test_flag')
-
- flag
+ flags.create!(project_id: project.id, active: true, name: 'test_flag')
end
it 'migrates successfully when there are no scopes in the database' do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 55d049b9d47..12c17e699e3 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -5816,7 +5816,7 @@ RSpec.describe Project, factory_default: :keep do
services = subject.find_or_initialize_services
expect(services.size).to eq(2)
- expect(services.map(&:title)).to eq(['JetBrains TeamCity CI', 'Pushover'])
+ expect(services.map(&:title)).to eq(['JetBrains TeamCity', 'Pushover'])
end
end
end
diff --git a/spec/models/users/in_product_marketing_email_spec.rb b/spec/models/users/in_product_marketing_email_spec.rb
index e115faa5a7f..772d875d69e 100644
--- a/spec/models/users/in_product_marketing_email_spec.rb
+++ b/spec/models/users/in_product_marketing_email_spec.rb
@@ -3,6 +3,9 @@
require 'spec_helper'
RSpec.describe Users::InProductMarketingEmail, type: :model do
+ let(:track) { :create }
+ let(:series) { 0 }
+
describe 'associations' do
it { is_expected.to belong_to(:user) }
end
@@ -17,9 +20,6 @@ RSpec.describe Users::InProductMarketingEmail, type: :model do
end
describe '.without_track_and_series' do
- let(:track) { :create }
- let(:series) { 0 }
-
let_it_be(:user) { create(:user) }
subject(:without_track_and_series) { User.merge(described_class.without_track_and_series(track, series)) }
@@ -57,4 +57,75 @@ RSpec.describe Users::InProductMarketingEmail, type: :model do
it { expect(without_track_and_series).to eq [@other_user] }
end
end
+
+ describe '.for_user_with_track_and_series' do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:in_product_marketing_email) { create(:in_product_marketing_email, series: 0, track: 0, user: user) }
+
+ subject(:for_user_with_track_and_series) { described_class.for_user_with_track_and_series(user, track, series).first }
+
+ context 'when record for user with given track and series exists' do
+ it { is_expected.to eq(in_product_marketing_email) }
+ end
+
+ context 'when user is different' do
+ let(:user) { build_stubbed(:user) }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when track is different' do
+ let(:track) { 1 }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'when series is different' do
+ let(:series) { 1 }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe '.save_cta_click' do
+ let(:user) { create(:user) }
+
+ subject(:save_cta_click) { described_class.save_cta_click(user, track, series) }
+
+ context 'when there is no record' do
+ it 'does not error' do
+ expect { save_cta_click }.not_to raise_error
+ end
+ end
+
+ context 'when there is no record for the track and series' do
+ it 'does not perform an update' do
+ other_email = create(:in_product_marketing_email, user: user, track: :verify, series: 2, cta_clicked_at: nil)
+
+ expect { save_cta_click }.not_to change { other_email.reload }
+ end
+ end
+
+ context 'when there is a record for the track and series' do
+ it 'saves the cta click date' do
+ email = create(:in_product_marketing_email, user: user, track: track, series: series, cta_clicked_at: nil)
+
+ freeze_time do
+ expect { save_cta_click }.to change { email.reload.cta_clicked_at }.from(nil).to(Time.zone.now)
+ end
+ end
+
+ context 'cta_clicked_at is already set' do
+ it 'does not update' do
+ create(:in_product_marketing_email, user: user, track: track, series: series, cta_clicked_at: Time.zone.now)
+
+ expect_next_found_instance_of(described_class) do |record|
+ expect(record).not_to receive(:update)
+ end
+
+ save_cta_click
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/groups/email_campaigns_controller_spec.rb b/spec/requests/groups/email_campaigns_controller_spec.rb
index 90c182b8827..a77f600ea1e 100644
--- a/spec/requests/groups/email_campaigns_controller_spec.rb
+++ b/spec/requests/groups/email_campaigns_controller_spec.rb
@@ -38,17 +38,43 @@ RSpec.describe Groups::EmailCampaignsController do
expect(subject).to have_gitlab_http_status(:redirect)
end
- it 'emits a snowplow event', :snowplow do
- subject
+ context 'on .com' do
+ before do
+ allow(Gitlab).to receive(:com?).and_return(true)
+ end
+
+ it 'emits a snowplow event', :snowplow do
+ subject
+
+ expect_snowplow_event(
+ category: described_class.name,
+ action: 'click',
+ context: [{
+ schema: described_class::EMAIL_CAMPAIGNS_SCHEMA_URL,
+ data: { namespace_id: group.id, series: series.to_i, subject_line: subject_line_text, track: track.to_s }
+ }]
+ )
+ end
- expect_snowplow_event(
- category: described_class.name,
- action: 'click',
- context: [{
- schema: described_class::EMAIL_CAMPAIGNS_SCHEMA_URL,
- data: { namespace_id: group.id, series: series.to_i, subject_line: subject_line_text, track: track.to_s }
- }]
- )
+ it 'does not save the cta_click' do
+ expect(Users::InProductMarketingEmail).not_to receive(:save_cta_click)
+
+ subject
+ end
+ end
+
+ context 'when not on.com' do
+ it 'saves the cta_click' do
+ expect(Users::InProductMarketingEmail).to receive(:save_cta_click)
+
+ subject
+ end
+
+ it 'does not track snowplow events' do
+ subject
+
+ expect_no_snowplow_event
+ end
end
end
diff --git a/spec/services/packages/debian/process_changes_service_spec.rb b/spec/services/packages/debian/process_changes_service_spec.rb
new file mode 100644
index 00000000000..98b531bde10
--- /dev/null
+++ b/spec/services/packages/debian/process_changes_service_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Debian::ProcessChangesService do
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:distribution) { create(:debian_project_distribution, :with_file, codename: 'unstable') }
+ let_it_be(:incoming) { create(:debian_incoming, project: distribution.project) }
+
+ let(:package_file) { incoming.package_files.last }
+
+ subject { described_class.new(package_file, user) }
+
+ context 'with valid package file' do
+ it 'updates package and package file', :aggregate_failures do
+ expect { subject.execute }
+ .to change { Packages::Package.count }.from(1).to(2)
+ .and not_change { Packages::PackageFile.count }
+ .and change { incoming.package_files.count }.from(7).to(0)
+
+ created_package = Packages::Package.last
+ expect(created_package.name).to eq 'sample'
+ expect(created_package.version).to eq '1.2.3~alpha2'
+ expect(created_package.creator).to eq user
+ end
+ end
+
+ context 'with invalid package file' do
+ let(:package_file) { incoming.package_files.first }
+
+ it 'raise ExtractionError', :aggregate_failures do
+ expect { subject.execute }
+ .to not_change { Packages::Package.count }
+ .and not_change { Packages::PackageFile.count }
+ .and not_change { incoming.package_files.count }
+ .and not_change { distribution.reload.needs_update? }
+ .and raise_error(Packages::Debian::ExtractChangesMetadataService::ExtractionError, 'is not a changes file')
+ end
+ end
+
+ context 'when creating package fails' do
+ before do
+ allow_next_instance_of(::Packages::Debian::FindOrCreatePackageService) do |find_or_create_package_service|
+ expect(find_or_create_package_service).to receive(:execute).and_raise(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
+ end
+ end
+
+ it 'remove the package file', :aggregate_failures do
+ expect { subject.execute }
+ .to not_change { Packages::Package.count }
+ .and not_change { Packages::PackageFile.count }
+ .and not_change { incoming.package_files.count }
+ .and not_change { distribution.reload.needs_update? }
+ .and raise_error(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
+ end
+ end
+ end
+end
diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb
index 61634813a1c..2d880c7a8fe 100644
--- a/spec/support/helpers/query_recorder.rb
+++ b/spec/support/helpers/query_recorder.rb
@@ -3,37 +3,53 @@
module ActiveRecord
class QueryRecorder
attr_reader :log, :skip_cached, :cached, :data
- UNKNOWN = %w(unknown unknown).freeze
- def initialize(skip_cached: true, query_recorder_debug: false, &block)
- @data = Hash.new { |h, k| h[k] = { count: 0, occurrences: [], backtrace: [] } }
+ UNKNOWN = %w[unknown unknown].freeze
+
+ def initialize(skip_cached: true, log_file: nil, query_recorder_debug: false, &block)
+ @data = Hash.new { |h, k| h[k] = { count: 0, occurrences: [], backtrace: [], durations: [] } }
@log = []
@cached = []
@skip_cached = skip_cached
- @query_recorder_debug = query_recorder_debug
+ @query_recorder_debug = ENV['QUERY_RECORDER_DEBUG'] || query_recorder_debug
+ @log_file = log_file
# force replacement of bind parameters to give tests the ability to check for ids
ActiveRecord::Base.connection.unprepared_statement do
ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block)
end
end
- def show_backtrace(values)
- Rails.logger.debug("QueryRecorder SQL: #{values[:sql]}")
+ def show_backtrace(values, duration)
+ values[:sql].lines.each do |line|
+ print_to_log(:SQL, line)
+ end
+ print_to_log(:DURATION, duration)
Gitlab::BacktraceCleaner.clean_backtrace(caller).each do |line|
- Rails.logger.debug("QueryRecorder backtrace: --> #{line}")
+ print_to_log(:backtrace, line)
+ end
+ end
+
+ def print_to_log(label, line)
+ msg = "QueryRecorder #{label}: --> #{line}"
+
+ if @log_file
+ @log_file.puts(msg)
+ else
+ Rails.logger.debug(msg)
end
end
def get_sql_source(sql)
- matches = sql.match(/,line:(?<line>.*):in\s+`(?<method>.*)'\*\//)
+ matches = sql.match(%r{,line:(?<line>.*):in\s+`(?<method>.*)'\*/})
matches ? [matches[:line], matches[:method]] : UNKNOWN
end
- def store_sql_by_source(values: {}, backtrace: nil)
+ def store_sql_by_source(values: {}, duration: nil, backtrace: nil)
full_name = get_sql_source(values[:sql]).join(':')
@data[full_name][:count] += 1
@data[full_name][:occurrences] << values[:sql]
@data[full_name][:backtrace] << backtrace
+ @data[full_name][:durations] << duration
end
def find_query(query_regexp, limit, first_only: false)
@@ -55,14 +71,14 @@ module ActiveRecord
end
def callback(name, start, finish, message_id, values)
- store_backtrace = ENV['QUERY_RECORDER_DEBUG'] || @query_recorder_debug
- backtrace = store_backtrace ? show_backtrace(values) : nil
+ duration = finish - start
if values[:cached] && skip_cached
@cached << values[:sql]
elsif !values[:name]&.include?("SCHEMA")
+ backtrace = @query_recorder_debug ? show_backtrace(values, duration) : nil
@log << values[:sql]
- store_sql_by_source(values: values, backtrace: backtrace)
+ store_sql_by_source(values: values, duration: duration, backtrace: backtrace)
end
end
diff --git a/spec/support_specs/helpers/active_record/query_recorder_spec.rb b/spec/support_specs/helpers/active_record/query_recorder_spec.rb
index f968f511a2a..f1af9ceffb9 100644
--- a/spec/support_specs/helpers/active_record/query_recorder_spec.rb
+++ b/spec/support_specs/helpers/active_record/query_recorder_spec.rb
@@ -11,6 +11,72 @@ RSpec.describe ActiveRecord::QueryRecorder do
end
end
+ describe 'printing to the log' do
+ let(:backtrace) { %r{QueryRecorder backtrace: --> (\w+/)*\w+\.rb:\d+:in `.*'} }
+ let(:duration_line) { %r{QueryRecorder DURATION: --> \d+\.\d+} }
+
+ def expect_section(query, lines)
+ query_lines = lines.take(query.size)
+
+ # the query comes first
+ expect(query_lines).to match(query)
+
+ # followed by the duration
+ expect(lines[query.size]).to match(duration_line)
+
+ # and then one or more lines of backtrace
+ backtrace_lines = lines.drop(query.size + 1).take_while { |line| line.match(backtrace) }
+ expect(backtrace_lines).not_to be_empty
+
+ # Advance to the next section
+ lines.drop(query.size + 1 + backtrace_lines.size)
+ end
+
+ it 'prints SQL, duration and backtrace, all prefixed with QueryRecorder', :aggregate_failures do
+ io = StringIO.new
+
+ control = ActiveRecord::QueryRecorder.new(log_file: io, query_recorder_debug: true) do
+ TestQueries.count
+ TestQueries.first
+ TestQueries.where(<<~FRAGMENT).to_a # tests multi-line SQL
+ version = 'foo'
+ OR
+ version = 'bar'
+ FRAGMENT
+ end
+
+ query_a = start_with(%q[QueryRecorder SQL: --> SELECT COUNT(*) FROM "schema_migrations"])
+
+ query_b = start_with(%q[QueryRecorder SQL: --> SELECT "schema_migrations".* FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC LIMIT 1])
+
+ query_c_a = eq(%q[QueryRecorder SQL: --> SELECT "schema_migrations".* FROM "schema_migrations" WHERE (version = 'foo'])
+ query_c_b = eq(%q(QueryRecorder SQL: --> OR))
+ query_c_c = eq(%q(QueryRecorder SQL: --> version = 'bar'))
+ query_c_d = start_with("QueryRecorder SQL: --> )")
+
+ expect(control.count).to eq(3)
+
+ lines = io.string.lines.map(&:chomp)
+
+ expect(lines).to all(start_with('QueryRecorder'))
+ lines = expect_section([query_a], lines)
+ lines = expect_section([query_b], lines)
+ lines = expect_section([query_c_a, query_c_b, query_c_c, query_c_d], lines)
+
+ expect(lines).to be_empty
+ end
+ end
+
+ it 'includes duration information' do
+ control = ActiveRecord::QueryRecorder.new do
+ TestQueries.count
+ TestQueries.first
+ end
+
+ expect(control.count).to eq(2)
+ expect(control.data.values.flat_map { _1[:durations] }).to match([be > 0, be > 0])
+ end
+
describe 'detecting the right number of calls and their origin' do
it 'detects two separate queries' do
control = ActiveRecord::QueryRecorder.new query_recorder_debug: true do
@@ -23,10 +89,10 @@ RSpec.describe ActiveRecord::QueryRecorder do
.to eq(control.data.keys.size)
# Ensure exactly 2 COUNT queries were detected
expect(control.occurrences_by_line_method.last[1][:occurrences]
- .find_all {|i| i.match(/SELECT COUNT/) }.count).to eq(2)
+ .count { |str| str.start_with?('SELECT COUNT') }).to eq(2)
# Ensure exactly 1 LIMIT 1 (#first)
expect(control.occurrences_by_line_method.first[1][:occurrences]
- .find_all { |i| i.match(/ORDER BY.*#{TestQueries.table_name}.*LIMIT 1/) }.count).to eq(1)
+ .count { |str| str.match(/ORDER BY.*#{TestQueries.table_name}.*LIMIT 1/) }).to eq(1)
# Ensure 3 DB calls overall were executed
expect(control.log.size).to eq(3)