diff options
63 files changed, 184 insertions, 275 deletions
diff --git a/.gitlab/ci/review-apps/qa.gitlab-ci.yml b/.gitlab/ci/review-apps/qa.gitlab-ci.yml index 6dd0997b3bb..4a6db715f76 100644 --- a/.gitlab/ci/review-apps/qa.gitlab-ci.yml +++ b/.gitlab/ci/review-apps/qa.gitlab-ci.yml @@ -34,7 +34,7 @@ .allure-report-base: image: - name: ${GITLAB_DEPENDENCY_PROXY}andrcuns/allure-report-publisher:0.3.6 + name: ${GITLAB_DEPENDENCY_PROXY}andrcuns/allure-report-publisher:0.4.1 entrypoint: [""] stage: post-qa variables: diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 42d8be2ef60..87da2143dd2 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -8d7e242576249154697fed7876cd9fe2a31ffdc3 +9de3dd28a5c8248903160ea35d9f718899f51c89 diff --git a/app/assets/javascripts/environments/graphql/mutations/cancel_auto_stop.mutation.graphql b/app/assets/javascripts/environments/graphql/mutations/cancel_auto_stop.mutation.graphql index e69d4587215..22dfb8a7a89 100644 --- a/app/assets/javascripts/environments/graphql/mutations/cancel_auto_stop.mutation.graphql +++ b/app/assets/javascripts/environments/graphql/mutations/cancel_auto_stop.mutation.graphql @@ -1,4 +1,4 @@ -mutation cancelAutoStop($environment: Environment) { +mutation cancelAutoStop($environment: LocalEnvironment) { cancelAutoStop(environment: $environment) @client { errors } diff --git a/app/assets/javascripts/environments/graphql/mutations/delete_environment.mutation.graphql b/app/assets/javascripts/environments/graphql/mutations/delete_environment.mutation.graphql index 4f43db6f3e1..9bb68857923 100644 --- a/app/assets/javascripts/environments/graphql/mutations/delete_environment.mutation.graphql +++ b/app/assets/javascripts/environments/graphql/mutations/delete_environment.mutation.graphql @@ -1,4 +1,4 @@ -mutation deleteEnvironment($environment: Environment) { +mutation deleteEnvironment($environment: LocalEnvironment) { deleteEnvironment(environment: $environment) @client { errors } diff --git a/app/assets/javascripts/environments/graphql/mutations/rollback_environment.mutation.graphql b/app/assets/javascripts/environments/graphql/mutations/rollback_environment.mutation.graphql index 83bda10d054..3db4dc2b9a5 100644 --- a/app/assets/javascripts/environments/graphql/mutations/rollback_environment.mutation.graphql +++ b/app/assets/javascripts/environments/graphql/mutations/rollback_environment.mutation.graphql @@ -1,4 +1,4 @@ -mutation rollbackEnvironment($environment: Environment) { +mutation rollbackEnvironment($environment: LocalEnvironment) { rollbackEnvironment(environment: $environment) @client { errors } diff --git a/app/assets/javascripts/environments/graphql/mutations/stop_environment.mutation.graphql b/app/assets/javascripts/environments/graphql/mutations/stop_environment.mutation.graphql index 86112d8f3f8..7eae0ef4ce4 100644 --- a/app/assets/javascripts/environments/graphql/mutations/stop_environment.mutation.graphql +++ b/app/assets/javascripts/environments/graphql/mutations/stop_environment.mutation.graphql @@ -1,4 +1,4 @@ -mutation stopEnvironment($environment: Environment) { +mutation stopEnvironment($environment: LocalEnvironment) { stopEnvironment(environment: $environment) @client { errors } diff --git a/app/assets/javascripts/environments/graphql/queries/folder.query.graphql b/app/assets/javascripts/environments/graphql/queries/folder.query.graphql index 0943d1aa800..3292c916b2e 100644 --- a/app/assets/javascripts/environments/graphql/queries/folder.query.graphql +++ b/app/assets/javascripts/environments/graphql/queries/folder.query.graphql @@ -1,4 +1,4 @@ -query getEnvironmentFolder($environment: NestedEnvironment) { +query getEnvironmentFolder($environment: NestedLocalEnvironment) { folder(environment: $environment) @client { availableCount environments diff --git a/app/assets/javascripts/environments/graphql/resolvers.js b/app/assets/javascripts/environments/graphql/resolvers.js index c9eb6ccdcae..8322b806370 100644 --- a/app/assets/javascripts/environments/graphql/resolvers.js +++ b/app/assets/javascripts/environments/graphql/resolvers.js @@ -3,12 +3,11 @@ import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; const mapNestedEnvironment = (env) => ({ ...convertObjectPropsToCamelCase(env, { deep: true }), - __typename: 'NestedEnvironment', + __typename: 'NestedLocalEnvironment', }); const mapEnvironment = (env) => ({ ...convertObjectPropsToCamelCase(env), - // eslint-disable-next-line @gitlab/require-i18n-strings - __typename: 'Environment', + __typename: 'LocalEnvironment', }); export const resolvers = (endpoint) => ({ @@ -22,7 +21,7 @@ export const resolvers = (endpoint) => ({ __typename: 'ReviewApp', }, stoppedCount: res.data.stopped_count, - __typename: 'EnvironmentApp', + __typename: 'LocalEnvironmentApp', })); }, folder(_, { environment: { folderPath } }) { @@ -30,7 +29,7 @@ export const resolvers = (endpoint) => ({ availableCount: res.data.available_count, environments: res.data.environments.map(mapEnvironment), stoppedCount: res.data.stopped_count, - __typename: 'EnvironmentFolder', + __typename: 'LocalEnvironmentFolder', })); }, }, diff --git a/app/assets/javascripts/environments/graphql/typedefs.graphql b/app/assets/javascripts/environments/graphql/typedefs.graphql index 44c985941d4..49ea719449e 100644 --- a/app/assets/javascripts/environments/graphql/typedefs.graphql +++ b/app/assets/javascripts/environments/graphql/typedefs.graphql @@ -1,4 +1,4 @@ -type Environment { +type LocalEnvironment { id: Int! globalId: ID! name: String! @@ -9,14 +9,14 @@ type Environment { autoStopPath: String } -type NestedEnvironment { +type NestedLocalEnvironment { name: String! size: Int! - latest: Environment! + latest: LocalEnvironment! } -type EnvironmentFolder { - environments: [Environment!]! +type LocalEnvironmentFolder { + environments: [LocalEnvironment!]! availableCount: Int! stoppedCount: Int! } @@ -27,9 +27,9 @@ type ReviewApp { reviewSnippet: String } -type EnvironmentApp { +type LocalEnvironmentApp { stoppedCount: Int! availableCount: Int! - environments: [NestedEnvironment!]! + environments: [NestedLocalEnvironment!]! reviewApp: ReviewApp! } diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index 0804d792631..40dd29bea76 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -233,7 +233,7 @@ export function insertMarkdownText({ } } else if (tag.indexOf(textPlaceholder) > -1) { textToInsert = tag.replace(textPlaceholder, () => - selected.replace(/\\n/g, '\n').replace('%br', '\\n'), + selected.replace(/\\n/g, '\n').replace(/%br/g, '\\n'), ); } else { textToInsert = String(startChar) + tag + selected + (wrap ? tag : ''); diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index 0a573cb3d58..68db5d8078f 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -52,6 +52,7 @@ export default { isFetchingCommitSha: false, isNewCiConfigFile: false, lastCommittedContent: '', + shouldSkipStartScreen: false, showFailure: false, showStartScreen: false, showSuccess: false, @@ -60,7 +61,6 @@ export default { successType: null, }; }, - apollo: { initialCiFileContent: { fetchPolicy: fetchPolicies.NETWORK_ONLY, @@ -103,7 +103,11 @@ export default { } if (!hasCIFile) { - this.showStartScreen = true; + if (this.shouldSkipStartScreen) { + this.setNewEmptyCiConfigFile(); + } else { + this.showStartScreen = true; + } } else if (fileContent.length) { // If the file content is > 0, then we make sure to reset the // start screen flag during a refetch @@ -229,6 +233,7 @@ export default { }, mounted() { this.loadTemplateFromURL(); + this.checkShouldSkipStartScreen(); }, methods: { hideFailure() { @@ -293,6 +298,10 @@ export default { this.setNewEmptyCiConfigFile(); } }, + checkShouldSkipStartScreen() { + const params = queryToObject(window.location.search); + this.shouldSkipStartScreen = Boolean(params?.add_new_config_file); + }, }, }; </script> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue index f3673005c45..cd5b7c3110d 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue @@ -4,9 +4,7 @@ import Tracking from '~/tracking'; import DismissibleContainer from '~/vue_shared/components/dismissible_container.vue'; import { SP_TRACK_LABEL, - SP_LINK_TRACK_EVENT, SP_SHOW_TRACK_EVENT, - SP_LINK_TRACK_VALUE, SP_SHOW_TRACK_VALUE, SP_HELP_CONTENT, SP_HELP_URL, @@ -20,9 +18,7 @@ export default { name: 'MRWidgetSuggestPipeline', SP_ICON_NAME, SP_TRACK_LABEL, - SP_LINK_TRACK_EVENT, SP_SHOW_TRACK_EVENT, - SP_LINK_TRACK_VALUE, SP_SHOW_TRACK_VALUE, SP_HELP_CONTENT, SP_HELP_URL, @@ -81,29 +77,14 @@ export default { <div> <gl-sprintf :message=" - s__(`mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd} - %{addPipelineLinkStart}Add the .gitlab-ci.yml file%{addPipelineLinkEnd} - to create one.`) + s__(`mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}`) " > - <template #prefixToLink="{ content }"> + <template #boldHeader="{ content }"> <strong> {{ content }} </strong> </template> - <template #addPipelineLink="{ content }"> - <gl-link - :href="pipelinePath" - class="gl-ml-1" - data-testid="add-pipeline-link" - :data-track-property="humanAccess" - :data-track-value="$options.SP_LINK_TRACK_VALUE" - :data-track-action="$options.SP_LINK_TRACK_EVENT" - :data-track-label="$options.SP_TRACK_LABEL" - > - {{ content }} - </gl-link> - </template> </gl-sprintf> </div> </template> @@ -115,9 +96,6 @@ export default { </div> <div class="col-md-7 order-md-first col-12"> <div class="ml-6 gl-pt-5"> - <strong> - {{ s__('mrWidget|Are you adding technical debt or code vulnerabilities?') }} - </strong> <p class="gl-mt-2"> <gl-sprintf :message="$options.SP_HELP_CONTENT"> <template #link="{ content }"> @@ -142,7 +120,7 @@ export default { :data-track-action="$options.SP_SHOW_TRACK_EVENT" :data-track-label="$options.SP_TRACK_LABEL" > - {{ __('Show me how to add a pipeline') }} + {{ __('Try out GitLab Pipelines') }} </gl-button> </div> </div> diff --git a/app/assets/javascripts/vue_merge_request_widget/constants.js b/app/assets/javascripts/vue_merge_request_widget/constants.js index b88e83ccb0f..d0c6cf12e25 100644 --- a/app/assets/javascripts/vue_merge_request_widget/constants.js +++ b/app/assets/javascripts/vue_merge_request_widget/constants.js @@ -17,14 +17,12 @@ export const AUTO_MERGE_STRATEGIES = [MWPS_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY, // SP - "Suggest Pipelines" export const SP_TRACK_LABEL = 'no_pipeline_noticed'; -export const SP_LINK_TRACK_EVENT = 'click_link'; export const SP_SHOW_TRACK_EVENT = 'click_button'; -export const SP_LINK_TRACK_VALUE = 30; export const SP_SHOW_TRACK_VALUE = 10; export const SP_HELP_CONTENT = s__( - `mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust.`, + `mrWidget|GitLab %{linkStart}CI/CD can automatically build, test, and deploy your application.%{linkEnd} It only takes a few minutes to get started, and we can help you create a pipeline configuration file.`, ); -export const SP_HELP_URL = 'https://about.gitlab.com/blog/2019/07/12/guide-to-ci-cd-pipelines/'; +export const SP_HELP_URL = 'https://docs.gitlab.com/ee/ci/quick_start/'; export const SP_ICON_NAME = 'status_notfound'; export const MERGE_ACTIVE_STATUS_PHRASES = [ diff --git a/app/serializers/merge_request_widget_entity.rb b/app/serializers/merge_request_widget_entity.rb index a633cefc73d..bd60d60c8db 100644 --- a/app/serializers/merge_request_widget_entity.rb +++ b/app/serializers/merge_request_widget_entity.rb @@ -64,14 +64,12 @@ class MergeRequestWidgetEntity < Grape::Entity end expose :merge_request_add_ci_config_path, if: ->(mr, _) { can_add_ci_config_path?(mr) } do |merge_request| - project_new_blob_path( - merge_request.source_project, - merge_request.source_branch, - file_name: '.gitlab-ci.yml', - commit_message: s_("CommitMessage|Add %{file_name}") % { file_name: Gitlab::FileDetector::PATTERNS[:gitlab_ci] }, - mr_path: merge_request_path(merge_request), - suggest_gitlab_ci_yml: true - ) + project = merge_request.source_project + params = { + branch_name: merge_request.source_branch, + add_new_config_file: true + } + project_ci_pipeline_editor_path(project, params) end expose :user_callouts_path do |_merge_request| @@ -177,7 +175,6 @@ class MergeRequestWidgetEntity < Grape::Entity def can_add_ci_config_path?(merge_request) merge_request.open? && merge_request.source_branch_exists? && - merge_request.source_project&.uses_default_ci_config? && !merge_request.source_project.has_ci? && merge_request.commits_count > 0 && can?(current_user, :read_build, merge_request.source_project) && diff --git a/app/workers/authorized_projects_worker.rb b/app/workers/authorized_projects_worker.rb index 46fe6c7f7ce..afe14369d43 100644 --- a/app/workers/authorized_projects_worker.rb +++ b/app/workers/authorized_projects_worker.rb @@ -25,11 +25,9 @@ class AuthorizedProjectsWorker end end - # rubocop: disable CodeReuse/ActiveRecord def perform(user_id) - user = User.find_by(id: user_id) + user = User.find_by_id(user_id) user&.refresh_authorized_projects(source: self.class.name) end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/build_hooks_worker.rb b/app/workers/build_hooks_worker.rb index a0d1d9dca45..78244e0941e 100644 --- a/app/workers/build_hooks_worker.rb +++ b/app/workers/build_hooks_worker.rb @@ -14,7 +14,7 @@ class BuildHooksWorker # rubocop:disable Scalability/IdempotentWorker # rubocop: disable CodeReuse/ActiveRecord def perform(build_id) Ci::Build.includes({ runner: :tags }) - .find_by(id: build_id) + .find_by_id(build_id) .try(:execute_hooks) end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/workers/build_queue_worker.rb b/app/workers/build_queue_worker.rb index 4ab08bbd7fe..af1136de94c 100644 --- a/app/workers/build_queue_worker.rb +++ b/app/workers/build_queue_worker.rb @@ -12,11 +12,9 @@ class BuildQueueWorker # rubocop:disable Scalability/IdempotentWorker worker_resource_boundary :cpu data_consistency :sticky - # rubocop: disable CodeReuse/ActiveRecord def perform(build_id) - Ci::Build.find_by(id: build_id).try do |build| + Ci::Build.find_by_id(build_id).try do |build| Ci::UpdateBuildQueueService.new.tick(build) end end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/build_success_worker.rb b/app/workers/build_success_worker.rb index ce39ac946a9..114bced0b22 100644 --- a/app/workers/build_success_worker.rb +++ b/app/workers/build_success_worker.rb @@ -11,13 +11,11 @@ class BuildSuccessWorker # rubocop:disable Scalability/IdempotentWorker queue_namespace :pipeline_processing urgency :high - # rubocop: disable CodeReuse/ActiveRecord def perform(build_id) - Ci::Build.find_by(id: build_id).try do |build| + Ci::Build.find_by_id(build_id).try do |build| stop_environment(build) if build.stops_environment? end end - # rubocop: enable CodeReuse/ActiveRecord private diff --git a/app/workers/chat_notification_worker.rb b/app/workers/chat_notification_worker.rb index 2a2e94cc6f1..23d8a1ec29d 100644 --- a/app/workers/chat_notification_worker.rb +++ b/app/workers/chat_notification_worker.rb @@ -16,9 +16,8 @@ class ChatNotificationWorker # rubocop:disable Scalability/IdempotentWorker RESCHEDULE_INTERVAL = 2.seconds RESCHEDULE_TIMEOUT = 5.minutes - # rubocop: disable CodeReuse/ActiveRecord def perform(build_id, reschedule_count = 0) - Ci::Build.find_by(id: build_id).try do |build| + Ci::Build.find_by_id(build_id).try do |build| send_response(build) end rescue Gitlab::Chat::Output::MissingBuildSectionError @@ -30,7 +29,6 @@ class ChatNotificationWorker # rubocop:disable Scalability/IdempotentWorker # the job instead of producing an error. self.class.perform_in(RESCHEDULE_INTERVAL, build_id, reschedule_count + 1) end - # rubocop: enable CodeReuse/ActiveRecord def send_response(build) Gitlab::Chat::Responder.responder_for(build).try do |responder| diff --git a/app/workers/ci/archive_trace_worker.rb b/app/workers/ci/archive_trace_worker.rb index 503cfc07c25..5a22a5c74ee 100644 --- a/app/workers/ci/archive_trace_worker.rb +++ b/app/workers/ci/archive_trace_worker.rb @@ -9,12 +9,10 @@ module Ci sidekiq_options retry: 3 include PipelineBackgroundQueue - # rubocop: disable CodeReuse/ActiveRecord def perform(job_id) - Ci::Build.without_archived_trace.find_by(id: job_id).try do |job| + Ci::Build.without_archived_trace.find_by_id(job_id).try do |job| Ci::ArchiveTraceService.new.execute(job, worker_name: self.class.name) end end - # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/workers/ci/build_finished_worker.rb b/app/workers/ci/build_finished_worker.rb index f047ba8fde5..aa12bdb009e 100644 --- a/app/workers/ci/build_finished_worker.rb +++ b/app/workers/ci/build_finished_worker.rb @@ -16,7 +16,7 @@ module Ci ARCHIVE_TRACES_IN = 2.minutes.freeze def perform(build_id) - return unless build = Ci::Build.find_by(id: build_id) # rubocop: disable CodeReuse/ActiveRecord + return unless build = Ci::Build.find_by_id(build_id) return unless build.project return if build.project.pending_delete? diff --git a/app/workers/ci/build_trace_chunk_flush_worker.rb b/app/workers/ci/build_trace_chunk_flush_worker.rb index 79881ec84fd..62fc3efd4f0 100644 --- a/app/workers/ci/build_trace_chunk_flush_worker.rb +++ b/app/workers/ci/build_trace_chunk_flush_worker.rb @@ -13,12 +13,10 @@ module Ci idempotent! - # rubocop: disable CodeReuse/ActiveRecord def perform(id) - ::Ci::BuildTraceChunk.find_by(id: id).try do |chunk| + ::Ci::BuildTraceChunk.find_by_id(id).try do |chunk| chunk.persist_data! end end - # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/workers/cluster_update_app_worker.rb b/app/workers/cluster_update_app_worker.rb index cd2b2e38ea4..97fdec02ba4 100644 --- a/app/workers/cluster_update_app_worker.rb +++ b/app/workers/cluster_update_app_worker.rb @@ -26,16 +26,14 @@ class ClusterUpdateAppWorker # rubocop:disable Scalability/IdempotentWorker private - # rubocop: disable CodeReuse/ActiveRecord def execute(app_name, app_id, project_id, scheduled_time) - project = Project.find_by(id: project_id) + project = Project.find_by_id(project_id) return unless project find_application(app_name, app_id) do |app| update_prometheus(app, scheduled_time, project) end end - # rubocop: enable CodeReuse/ActiveRecord def update_prometheus(app, scheduled_time, project) return unless app.managed_prometheus? diff --git a/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb b/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb index eb1af0869bd..0a43a0fc4d2 100644 --- a/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb +++ b/app/workers/concerns/gitlab/github_import/rescheduling_methods.rb @@ -8,9 +8,8 @@ module Gitlab # project_id - The ID of the GitLab project to import the note into. # hash - A Hash containing the details of the GitHub object to import. # notify_key - The Redis key to notify upon completion, if any. - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, hash, notify_key = nil) - project = Project.find_by(id: project_id) + project = Project.find_by_id(project_id) return notify_waiter(notify_key) unless project @@ -25,7 +24,6 @@ module Gitlab .perform_in(client.rate_limit_resets_in, project.id, hash, notify_key) end end - # rubocop: enable CodeReuse/ActiveRecord def try_import(*args) import(*args) diff --git a/app/workers/concerns/gitlab/github_import/stage_methods.rb b/app/workers/concerns/gitlab/github_import/stage_methods.rb index d7b4578af63..225716f6bf3 100644 --- a/app/workers/concerns/gitlab/github_import/stage_methods.rb +++ b/app/workers/concerns/gitlab/github_import/stage_methods.rb @@ -33,13 +33,13 @@ module Gitlab self.class.perform_in(client.rate_limit_resets_in, project.id) end - # rubocop: disable CodeReuse/ActiveRecord def find_project(id) # If the project has been marked as failed we want to bail out # automatically. - Project.joins_import_state.where(import_state: { status: :started }).find_by(id: id) + # rubocop: disable CodeReuse/ActiveRecord + Project.joins_import_state.where(import_state: { status: :started }).find_by_id(id) + # rubocop: enable CodeReuse/ActiveRecord end - # rubocop: enable CodeReuse/ActiveRecord def abort_on_failure false diff --git a/app/workers/concerns/gitlab/jira_import/import_worker.rb b/app/workers/concerns/gitlab/jira_import/import_worker.rb index 107b6e2e9be..d18b9ff023b 100644 --- a/app/workers/concerns/gitlab/jira_import/import_worker.rb +++ b/app/workers/concerns/gitlab/jira_import/import_worker.rb @@ -14,7 +14,7 @@ module Gitlab end def perform(project_id) - project = Project.find_by(id: project_id) # rubocop: disable CodeReuse/ActiveRecord + project = Project.find_by_id(project_id) return unless can_import?(project) diff --git a/app/workers/concerns/new_issuable.rb b/app/workers/concerns/new_issuable.rb index 482a74f49f7..d761f023cad 100644 --- a/app/workers/concerns/new_issuable.rb +++ b/app/workers/concerns/new_issuable.rb @@ -10,21 +10,17 @@ module NewIssuable user && issuable end - # rubocop: disable CodeReuse/ActiveRecord def set_user(user_id) - @user = User.find_by(id: user_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables + @user = User.find_by_id(user_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables log_error(User, user_id) unless @user # rubocop:disable Gitlab/ModuleWithInstanceVariables end - # rubocop: enable CodeReuse/ActiveRecord - # rubocop: disable CodeReuse/ActiveRecord def set_issuable(issuable_id) - @issuable = issuable_class.find_by(id: issuable_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables + @issuable = issuable_class.find_by_id(issuable_id) # rubocop:disable Gitlab/ModuleWithInstanceVariables log_error(issuable_class, issuable_id) unless @issuable # rubocop:disable Gitlab/ModuleWithInstanceVariables end - # rubocop: enable CodeReuse/ActiveRecord def log_error(record_class, record_id) Gitlab::AppLogger.error("#{self.class}: couldn't find #{record_class} with ID=#{record_id}, skipping job") diff --git a/app/workers/create_commit_signature_worker.rb b/app/workers/create_commit_signature_worker.rb index 01a2e109967..c35d2d3b33b 100644 --- a/app/workers/create_commit_signature_worker.rb +++ b/app/workers/create_commit_signature_worker.rb @@ -12,7 +12,6 @@ class CreateCommitSignatureWorker idempotent! loggable_arguments 0 - # rubocop: disable CodeReuse/ActiveRecord def perform(commit_shas, project_id) # Older versions of Git::BranchPushService may push a single commit ID on # the stack. We need this to be backwards compatible. @@ -20,7 +19,7 @@ class CreateCommitSignatureWorker return if commit_shas.empty? - project = Project.find_by(id: project_id) + project = Project.find_by_id(project_id) return unless project commits = project.commits_by(oids: commit_shas) @@ -44,5 +43,4 @@ class CreateCommitSignatureWorker Gitlab::AppLogger.error("Failed to create signature for commit #{commit.id}. Error: #{e.message}") end end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/delete_container_repository_worker.rb b/app/workers/delete_container_repository_worker.rb index beeca559060..a4d6adc2195 100644 --- a/app/workers/delete_container_repository_worker.rb +++ b/app/workers/delete_container_repository_worker.rb @@ -15,10 +15,9 @@ class DeleteContainerRepositoryWorker # rubocop:disable Scalability/IdempotentWo attr_reader :container_repository - # rubocop: disable CodeReuse/ActiveRecord def perform(current_user_id, container_repository_id) - current_user = User.find_by(id: current_user_id) - @container_repository = ContainerRepository.find_by(id: container_repository_id) + current_user = User.find_by_id(current_user_id) + @container_repository = ContainerRepository.find_by_id(container_repository_id) project = container_repository&.project return unless current_user && container_repository && project @@ -29,7 +28,6 @@ class DeleteContainerRepositoryWorker # rubocop:disable Scalability/IdempotentWo Projects::ContainerRepository::DestroyService.new(project, current_user).execute(container_repository) end end - # rubocop: enable CodeReuse/ActiveRecord # For ExclusiveLeaseGuard concern def lease_key diff --git a/app/workers/detect_repository_languages_worker.rb b/app/workers/detect_repository_languages_worker.rb index 8c7ef6c9e32..702b83a3185 100644 --- a/app/workers/detect_repository_languages_worker.rb +++ b/app/workers/detect_repository_languages_worker.rb @@ -14,16 +14,14 @@ class DetectRepositoryLanguagesWorker # rubocop:disable Scalability/IdempotentWo attr_reader :project - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, user_id = nil) - @project = Project.find_by(id: project_id) + @project = Project.find_by_id(project_id) return unless project try_obtain_lease do ::Projects::DetectRepositoryLanguagesService.new(project).execute end end - # rubocop: enable CodeReuse/ActiveRecord private diff --git a/app/workers/expire_build_instance_artifacts_worker.rb b/app/workers/expire_build_instance_artifacts_worker.rb index 77b8f59e365..948e1a59b07 100644 --- a/app/workers/expire_build_instance_artifacts_worker.rb +++ b/app/workers/expire_build_instance_artifacts_worker.rb @@ -9,17 +9,17 @@ class ExpireBuildInstanceArtifactsWorker # rubocop:disable Scalability/Idempoten feature_category :build_artifacts - # rubocop: disable CodeReuse/ActiveRecord def perform(build_id) + # rubocop: disable CodeReuse/ActiveRecord build = Ci::Build .with_expired_artifacts .reorder(nil) - .find_by(id: build_id) + .find_by_id(build_id) + # rubocop: enable CodeReuse/ActiveRecord return unless build&.project && !build.project.pending_delete Gitlab::AppLogger.info("Removing artifacts for build #{build.id}...") build.erase_erasable_artifacts! end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/expire_job_cache_worker.rb b/app/workers/expire_job_cache_worker.rb index 7374f650546..3c5a7717d70 100644 --- a/app/workers/expire_job_cache_worker.rb +++ b/app/workers/expire_job_cache_worker.rb @@ -14,9 +14,8 @@ class ExpireJobCacheWorker # rubocop:disable Scalability/IdempotentWorker deduplicate :until_executing, including_scheduled: true idempotent! - # rubocop: disable CodeReuse/ActiveRecord def perform(job_id) - job = CommitStatus.preload(:pipeline, :project).find_by(id: job_id) + job = CommitStatus.preload(:pipeline, :project).find_by_id(job_id) # rubocop: disable CodeReuse/ActiveRecord return unless job pipeline = job.pipeline @@ -25,7 +24,6 @@ class ExpireJobCacheWorker # rubocop:disable Scalability/IdempotentWorker Gitlab::EtagCaching::Store.new.touch(project_job_path(project, job)) ExpirePipelineCacheWorker.perform_async(pipeline.id) end - # rubocop: enable CodeReuse/ActiveRecord private diff --git a/app/workers/expire_pipeline_cache_worker.rb b/app/workers/expire_pipeline_cache_worker.rb index 07e6939d1c7..9a0c617da57 100644 --- a/app/workers/expire_pipeline_cache_worker.rb +++ b/app/workers/expire_pipeline_cache_worker.rb @@ -17,13 +17,11 @@ class ExpirePipelineCacheWorker # Uncomment once https://gitlab.com/gitlab-org/gitlab/-/issues/325291 is resolved # idempotent! - # rubocop: disable CodeReuse/ActiveRecord def perform(pipeline_id) - pipeline = Ci::Pipeline.find_by(id: pipeline_id) + pipeline = Ci::Pipeline.find_by_id(pipeline_id) return unless pipeline Ci::ExpirePipelineCacheService.new.execute(pipeline) end - # rubocop: enable CodeReuse/ActiveRecord end # rubocop:enable Scalability/IdempotentWorker diff --git a/app/workers/gitlab/jira_import/stage/start_import_worker.rb b/app/workers/gitlab/jira_import/stage/start_import_worker.rb index e0de3ee169e..3f6ad66e278 100644 --- a/app/workers/gitlab/jira_import/stage/start_import_worker.rb +++ b/app/workers/gitlab/jira_import/stage/start_import_worker.rb @@ -16,7 +16,7 @@ module Gitlab attr_reader :project def perform(project_id) - @project = Project.find_by(id: project_id) # rubocop: disable CodeReuse/ActiveRecord + @project = Project.find_by_id(project_id) return unless start_import diff --git a/app/workers/hashed_storage/project_migrate_worker.rb b/app/workers/hashed_storage/project_migrate_worker.rb index bcc80cc2a70..460aac3f2f2 100644 --- a/app/workers/hashed_storage/project_migrate_worker.rb +++ b/app/workers/hashed_storage/project_migrate_worker.rb @@ -16,12 +16,11 @@ module HashedStorage attr_reader :project_id - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, old_disk_path = nil) @project_id = project_id # we need to set this in order to create the lease_key try_obtain_lease do - project = Project.without_deleted.find_by(id: project_id) + project = Project.without_deleted.find_by_id(project_id) break unless project && project.storage_upgradable? old_disk_path ||= Storage::LegacyProject.new(project).disk_path @@ -29,6 +28,5 @@ module HashedStorage ::Projects::HashedStorage::MigrationService.new(project, old_disk_path, logger: logger).execute end end - # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/workers/hashed_storage/project_rollback_worker.rb b/app/workers/hashed_storage/project_rollback_worker.rb index 07a7ab63718..91ea3dd9189 100644 --- a/app/workers/hashed_storage/project_rollback_worker.rb +++ b/app/workers/hashed_storage/project_rollback_worker.rb @@ -16,12 +16,11 @@ module HashedStorage attr_reader :project_id - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, old_disk_path = nil) @project_id = project_id # we need to set this in order to create the lease_key try_obtain_lease do - project = Project.without_deleted.find_by(id: project_id) + project = Project.without_deleted.find_by_id(project_id) break unless project old_disk_path ||= project.disk_path @@ -29,6 +28,5 @@ module HashedStorage ::Projects::HashedStorage::RollbackService.new(project, old_disk_path, logger: logger).execute end end - # rubocop: enable CodeReuse/ActiveRecord end end diff --git a/app/workers/invalid_gpg_signature_update_worker.rb b/app/workers/invalid_gpg_signature_update_worker.rb index c9567e102d3..7dc1e395597 100644 --- a/app/workers/invalid_gpg_signature_update_worker.rb +++ b/app/workers/invalid_gpg_signature_update_worker.rb @@ -10,13 +10,11 @@ class InvalidGpgSignatureUpdateWorker # rubocop:disable Scalability/IdempotentWo feature_category :source_code_management weight 2 - # rubocop: disable CodeReuse/ActiveRecord def perform(gpg_key_id) - gpg_key = GpgKey.find_by(id: gpg_key_id) + gpg_key = GpgKey.find_by_id(gpg_key_id) return unless gpg_key Gitlab::Gpg::InvalidGpgSignatureUpdater.new(gpg_key).run end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/new_note_worker.rb b/app/workers/new_note_worker.rb index e1120bee30a..ecc78236161 100644 --- a/app/workers/new_note_worker.rb +++ b/app/workers/new_note_worker.rb @@ -14,14 +14,12 @@ class NewNoteWorker # rubocop:disable Scalability/IdempotentWorker # Keep extra parameter to preserve backwards compatibility with # old `NewNoteWorker` jobs (can remove later) - # rubocop: disable CodeReuse/ActiveRecord def perform(note_id, _params = {}) - if note = Note.find_by(id: note_id) + if note = Note.find_by_id(note_id) NotificationService.new.new_note(note) unless note.skip_notification? Notes::PostProcessService.new(note).execute else Gitlab::AppLogger.error("NewNoteWorker: couldn't find note with ID=#{note_id}, skipping job") end end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/pages_domain_verification_worker.rb b/app/workers/pages_domain_verification_worker.rb index 59de00d40d5..1696abd7b70 100644 --- a/app/workers/pages_domain_verification_worker.rb +++ b/app/workers/pages_domain_verification_worker.rb @@ -9,15 +9,13 @@ class PagesDomainVerificationWorker # rubocop:disable Scalability/IdempotentWork feature_category :pages - # rubocop: disable CodeReuse/ActiveRecord def perform(domain_id) return if Gitlab::Database.read_only? - domain = PagesDomain.find_by(id: domain_id) + domain = PagesDomain.find_by_id(domain_id) return unless domain VerifyPagesDomainService.new(domain).execute end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/pages_worker.rb b/app/workers/pages_worker.rb index 5e951ab2c3a..cceafbc7d2d 100644 --- a/app/workers/pages_worker.rb +++ b/app/workers/pages_worker.rb @@ -14,15 +14,13 @@ class PagesWorker # rubocop:disable Scalability/IdempotentWorker send(action, *arg) # rubocop:disable GitlabSecurity/PublicSend end - # rubocop: disable CodeReuse/ActiveRecord def deploy(build_id) - build = Ci::Build.find_by(id: build_id) + build = Ci::Build.find_by_id(build_id) update_contents = Projects::UpdatePagesService.new(build.project, build).execute if update_contents[:status] == :success Projects::UpdatePagesConfigurationService.new(build.project).execute end end - # rubocop: enable CodeReuse/ActiveRecord def remove(namespace_path, project_path) full_path = File.join(Settings.pages.path, namespace_path, project_path) diff --git a/app/workers/pipeline_hooks_worker.rb b/app/workers/pipeline_hooks_worker.rb index c67f3860a50..eb5d0086592 100644 --- a/app/workers/pipeline_hooks_worker.rb +++ b/app/workers/pipeline_hooks_worker.rb @@ -10,12 +10,10 @@ class PipelineHooksWorker # rubocop:disable Scalability/IdempotentWorker worker_resource_boundary :cpu data_consistency :delayed - # rubocop: disable CodeReuse/ActiveRecord def perform(pipeline_id) - pipeline = Ci::Pipeline.find_by(id: pipeline_id) + pipeline = Ci::Pipeline.find_by_id(pipeline_id) return unless pipeline Ci::Pipelines::HookService.new(pipeline).execute end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/pipeline_metrics_worker.rb b/app/workers/pipeline_metrics_worker.rb index c2580c3d48b..4e98c7268ac 100644 --- a/app/workers/pipeline_metrics_worker.rb +++ b/app/workers/pipeline_metrics_worker.rb @@ -10,14 +10,12 @@ class PipelineMetricsWorker # rubocop:disable Scalability/IdempotentWorker urgency :high - # rubocop: disable CodeReuse/ActiveRecord def perform(pipeline_id) - Ci::Pipeline.find_by(id: pipeline_id).try do |pipeline| + Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline| update_metrics_for_active_pipeline(pipeline) if pipeline.active? update_metrics_for_succeeded_pipeline(pipeline) if pipeline.success? end end - # rubocop: enable CodeReuse/ActiveRecord private @@ -29,11 +27,9 @@ class PipelineMetricsWorker # rubocop:disable Scalability/IdempotentWorker metrics(pipeline).update_all(latest_build_started_at: pipeline.started_at, latest_build_finished_at: pipeline.finished_at, pipeline_id: pipeline.id) end - # rubocop: disable CodeReuse/ActiveRecord def metrics(pipeline) - MergeRequest::Metrics.where(merge_request_id: merge_requests(pipeline)) + MergeRequest::Metrics.where(merge_request_id: merge_requests(pipeline)) # rubocop: disable CodeReuse/ActiveRecord end - # rubocop: enable CodeReuse/ActiveRecord def merge_requests(pipeline) pipeline.merge_requests_as_head_pipeline.map(&:id) diff --git a/app/workers/pipeline_process_worker.rb b/app/workers/pipeline_process_worker.rb index 9370b361068..b4712aaeafb 100644 --- a/app/workers/pipeline_process_worker.rb +++ b/app/workers/pipeline_process_worker.rb @@ -16,13 +16,11 @@ class PipelineProcessWorker idempotent! deduplicate :until_executing - # rubocop: disable CodeReuse/ActiveRecord def perform(pipeline_id) - Ci::Pipeline.find_by(id: pipeline_id).try do |pipeline| + Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline| Ci::ProcessPipelineService .new(pipeline) .execute end end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/project_cache_worker.rb b/app/workers/project_cache_worker.rb index 328fdc4717c..0e90b41e28d 100644 --- a/app/workers/project_cache_worker.rb +++ b/app/workers/project_cache_worker.rb @@ -23,9 +23,8 @@ class ProjectCacheWorker # refresh, if empty all columns will be refreshed # refresh_statistics - A boolean that determines whether project statistics should # be updated. - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, files = [], statistics = [], refresh_statistics = true) - project = Project.find_by(id: project_id) + project = Project.find_by_id(project_id) return unless project @@ -37,7 +36,6 @@ class ProjectCacheWorker project.cleanup end - # rubocop: enable CodeReuse/ActiveRecord # NOTE: triggering both an immediate update and one in 15 minutes if we # successfully obtain the lease. That way, we only need to wait for the diff --git a/app/workers/propagate_service_template_worker.rb b/app/workers/propagate_service_template_worker.rb index 6b8382ae433..908f867279f 100644 --- a/app/workers/propagate_service_template_worker.rb +++ b/app/workers/propagate_service_template_worker.rb @@ -13,13 +13,11 @@ class PropagateServiceTemplateWorker # rubocop:disable Scalability/IdempotentWor LEASE_TIMEOUT = 4.hours.to_i - # rubocop: disable CodeReuse/ActiveRecord def perform(template_id) return unless try_obtain_lease_for(template_id) - Admin::PropagateServiceTemplate.propagate(Integration.find_by(id: template_id)) + Admin::PropagateServiceTemplate.propagate(Integration.find_by_id(template_id)) end - # rubocop: enable CodeReuse/ActiveRecord private diff --git a/app/workers/run_pipeline_schedule_worker.rb b/app/workers/run_pipeline_schedule_worker.rb index 12042ebc4f0..f08d8231e43 100644 --- a/app/workers/run_pipeline_schedule_worker.rb +++ b/app/workers/run_pipeline_schedule_worker.rb @@ -11,16 +11,14 @@ class RunPipelineScheduleWorker # rubocop:disable Scalability/IdempotentWorker queue_namespace :pipeline_creation feature_category :continuous_integration - # rubocop: disable CodeReuse/ActiveRecord def perform(schedule_id, user_id) - schedule = Ci::PipelineSchedule.find_by(id: schedule_id) - user = User.find_by(id: user_id) + schedule = Ci::PipelineSchedule.find_by_id(schedule_id) + user = User.find_by_id(user_id) return unless schedule && user run_pipeline_schedule(schedule, user) end - # rubocop: enable CodeReuse/ActiveRecord def run_pipeline_schedule(schedule, user) Ci::CreatePipelineService.new(schedule.project, diff --git a/app/workers/update_highest_role_worker.rb b/app/workers/update_highest_role_worker.rb index d5df46c172b..064b8203d4d 100644 --- a/app/workers/update_highest_role_worker.rb +++ b/app/workers/update_highest_role_worker.rb @@ -13,17 +13,15 @@ class UpdateHighestRoleWorker idempotent! - # rubocop: disable CodeReuse/ActiveRecord def perform(user_id) - user = User.find_by(id: user_id) + user = User.find_by_id(user_id) return unless user.present? if user.active? && user.human? && !user.internal? Users::UpdateHighestMemberRoleService.new(user).execute else - UserHighestRole.where(user_id: user_id).delete_all + UserHighestRole.where(user_id: user_id).delete_all # rubocop: disable CodeReuse/ActiveRecord end end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/update_merge_requests_worker.rb b/app/workers/update_merge_requests_worker.rb index 421a6e47425..5c96257cb63 100644 --- a/app/workers/update_merge_requests_worker.rb +++ b/app/workers/update_merge_requests_worker.rb @@ -13,15 +13,13 @@ class UpdateMergeRequestsWorker # rubocop:disable Scalability/IdempotentWorker weight 3 loggable_arguments 2, 3, 4 - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, user_id, oldrev, newrev, ref) - project = Project.find_by(id: project_id) + project = Project.find_by_id(project_id) return unless project - user = User.find_by(id: user_id) + user = User.find_by_id(user_id) return unless user MergeRequests::RefreshService.new(project: project, current_user: user).execute(oldrev, newrev, ref) end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/app/workers/update_project_statistics_worker.rb b/app/workers/update_project_statistics_worker.rb index 4a32753ac70..45a6cc8f476 100644 --- a/app/workers/update_project_statistics_worker.rb +++ b/app/workers/update_project_statistics_worker.rb @@ -13,11 +13,9 @@ class UpdateProjectStatisticsWorker # rubocop:disable Scalability/IdempotentWork # project_id - The ID of the project for which to flush the cache. # statistics - An Array containing columns from ProjectStatistics to # refresh, if empty all columns will be refreshed - # rubocop: disable CodeReuse/ActiveRecord def perform(project_id, statistics = []) - project = Project.find_by(id: project_id) + project = Project.find_by_id(project_id) Projects::UpdateStatisticsService.new(project, nil, statistics: statistics).execute end - # rubocop: enable CodeReuse/ActiveRecord end diff --git a/config/feature_flags/development/usage_data_instrumentation.yml b/config/feature_flags/development/usage_data_instrumentation.yml index 3708465ab77..e2610cbd39c 100644 --- a/config/feature_flags/development/usage_data_instrumentation.yml +++ b/config/feature_flags/development/usage_data_instrumentation.yml @@ -1,7 +1,7 @@ --- name: usage_data_instrumentation introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68808 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338029 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345252 milestone: '14.5' type: development group: group::product intelligence diff --git a/db/post_migrate/20211103162025_add_index_on_events_using_btree_created_at_id.rb b/db/post_migrate/20211103162025_add_index_on_events_using_btree_created_at_id.rb new file mode 100644 index 00000000000..a8ef8e51e8c --- /dev/null +++ b/db/post_migrate/20211103162025_add_index_on_events_using_btree_created_at_id.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddIndexOnEventsUsingBtreeCreatedAtId < Gitlab::Database::Migration[1.0] + INDEX_NAME = 'index_events_on_created_at_and_id' + TABLE = :events + COLUMNS = %i[created_at id] + CONSTRAINTS = "created_at > '2021-08-27 00:00:00+00'::timestamp with time zone" + disable_ddl_transaction! + + def up + add_concurrent_index TABLE, COLUMNS, name: INDEX_NAME, where: CONSTRAINTS + end + + def down + remove_concurrent_index TABLE, COLUMNS, name: INDEX_NAME, where: CONSTRAINTS + end +end diff --git a/db/schema_migrations/20211103162025 b/db/schema_migrations/20211103162025 new file mode 100644 index 00000000000..e6cb01358d4 --- /dev/null +++ b/db/schema_migrations/20211103162025 @@ -0,0 +1 @@ +2ed9198926eb0579fccd4a8b1866f10ba4f42683d676e0664db3fadefe0bed39
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 619b0cbcf03..a109953a827 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -25853,6 +25853,8 @@ CREATE INDEX index_events_on_author_id_and_created_at_merge_requests ON events U CREATE INDEX index_events_on_author_id_and_project_id ON events USING btree (author_id, project_id); +CREATE INDEX index_events_on_created_at_and_id ON events USING btree (created_at, id) WHERE (created_at > '2021-08-27 00:00:00+00'::timestamp with time zone); + CREATE INDEX index_events_on_group_id_partial ON events USING btree (group_id) WHERE (group_id IS NOT NULL); CREATE INDEX index_events_on_project_id_and_created_at ON events USING btree (project_id, created_at); diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb index 2caaf126512..5fa843f3f1f 100644 --- a/lib/gitlab/usage_data.rb +++ b/lib/gitlab/usage_data.rb @@ -723,7 +723,9 @@ module Gitlab else # rubocop: disable CodeReuse/ActiveRecord # rubocop: disable UsageData/LargeTable - estimate_batch_distinct_count(::Event.where(time_period), :author_id) + start = ::Event.where(time_period).select(:id).order(created_at: :asc).first&.id + finish = ::Event.where(time_period).select(:id).order(created_at: :asc).first&.id + estimate_batch_distinct_count(::Event.where(time_period), :author_id, start: start, finish: finish) # rubocop: enable UsageData/LargeTable # rubocop: enable CodeReuse/ActiveRecord end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 5c8c809b513..bb95f06cec1 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2928,13 +2928,13 @@ msgstr "" msgid "After a successful password update, you will be redirected to the login page where you can log in with your new password." msgstr "" -msgid "After that, you will not be able to use merge approvals or code quality as well as many other features." +msgid "After it expires, you can't use merge approvals, code quality, or many other features." msgstr "" -msgid "After that, you will not be able to use merge approvals or epics as well as many other features." +msgid "After it expires, you can't use merge approvals, epics, or many other features." msgstr "" -msgid "After that, you will not be able to use merge approvals or epics as well as many security features." +msgid "After it expires, you can't use merge approvals, epics, or many security features." msgstr "" msgid "After you've reviewed these contribution guidelines, you'll be all set to" @@ -31838,9 +31838,6 @@ msgstr "" msgid "Show list" msgstr "" -msgid "Show me how to add a pipeline" -msgstr "" - msgid "Show one file at a time" msgstr "" @@ -36525,6 +36522,9 @@ msgstr "" msgid "Try grouping with different labels" msgstr "" +msgid "Try out GitLab Pipelines" +msgstr "" + msgid "Try to fork again" msgstr "" @@ -41105,6 +41105,9 @@ msgstr "" msgid "mrWidget| Please restore it or use a different %{missingBranchName} branch" msgstr "" +msgid "mrWidget|%{boldHeaderStart}Looks like there's no pipeline here.%{boldHeaderEnd}" +msgstr "" + msgid "mrWidget|%{linkStart}Set up now%{linkEnd} to analyze your source code for known security vulnerabilities." msgstr "" @@ -41123,9 +41126,6 @@ msgstr "" msgid "mrWidget|%{metricsLinkStart} Memory %{metricsLinkEnd} usage is %{emphasisStart} unchanged %{emphasisEnd} at %{memoryFrom}MB" msgstr "" -msgid "mrWidget|%{prefixToLinkStart}No pipeline%{prefixToLinkEnd} %{addPipelineLinkStart}Add the .gitlab-ci.yml file%{addPipelineLinkEnd} to create one." -msgstr "" - msgid "mrWidget|A merge train is a queued list of merge requests waiting to be merged into the target branch. The changes in each merge request are combined with the changes in earlier merge requests and tested before merge." msgstr "" @@ -41168,9 +41168,6 @@ msgstr "" msgid "mrWidget|Approved by you and others" msgstr "" -msgid "mrWidget|Are you adding technical debt or code vulnerabilities?" -msgstr "" - msgid "mrWidget|Cancel auto-merge" msgstr "" @@ -41224,6 +41221,9 @@ msgstr "" msgid "mrWidget|Failed to load deployment statistics" msgstr "" +msgid "mrWidget|GitLab %{linkStart}CI/CD can automatically build, test, and deploy your application.%{linkEnd} It only takes a few minutes to get started, and we can help you create a pipeline configuration file." +msgstr "" + msgid "mrWidget|Hide %{widget} details" msgstr "" @@ -41391,9 +41391,6 @@ msgstr "" msgid "mrWidget|To merge, a Jira issue key must be mentioned in the title or description." msgstr "" -msgid "mrWidget|Use %{linkStart}CI pipelines to test your code%{linkEnd} by simply adding a GitLab CI configuration file to your project. It only takes a minute to make your code more secure and robust." -msgstr "" - msgid "mrWidget|What is a merge train?" msgstr "" diff --git a/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb b/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb index 3893a9cdf28..2191849edd9 100644 --- a/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb +++ b/spec/features/merge_request/user_sees_suggest_pipeline_spec.rb @@ -16,7 +16,8 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do end it 'shows the suggest pipeline widget and then allows dismissal correctly' do - expect(page).to have_content('Are you adding technical debt or code vulnerabilities?') + content = 'GitLab CI/CD can automatically build, test, and deploy your application' + expect(page).to have_content(content) page.within '.mr-pipeline-suggest' do find('[data-testid="close"]').click @@ -24,17 +25,16 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do wait_for_requests - expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?') + expect(page).not_to have_content(content) # Reload so we know the user callout was registered visit page.current_url - expect(page).not_to have_content('Are you adding technical debt or code vulnerabilities?') + expect(page).not_to have_content(content) end - it 'runs tour from start to finish ensuring all nudges are executed' do - # nudge 1 - expect(page).to have_content('Are you adding technical debt or code vulnerabilities?') + it 'takes the user to the pipeline editor with a pre-filled CI config file form' do + expect(page).to have_content('GitLab CI/CD can automatically build, test, and deploy your application') page.within '.mr-pipeline-suggest' do find('[data-testid="ok"]').click @@ -42,30 +42,14 @@ RSpec.describe 'Merge request > User sees suggest pipeline', :js do wait_for_requests - # nudge 2 - expect(page).to have_content('Choose Code Quality to add a pipeline that tests the quality of your code.') + # Drawer is open + expect(page).to have_content('This template creates a simple test pipeline. To use it:') - find('.js-gitlab-ci-yml-selector').click + # Editor shows template + expect(page).to have_content('This file is a template, and might need editing before it works on your project.') - wait_for_requests - - within '.gitlab-ci-yml-selector' do - find('.dropdown-input-field').set('Jekyll') - find('.dropdown-content li', text: 'Jekyll').click - end - - wait_for_requests - - expect(page).not_to have_content('Choose Code Quality to add a pipeline that tests the quality of your code.') - # nudge 3 - expect(page).to have_content('The template is ready!') - - find('#commit-changes').click - - wait_for_requests - - # nudge 4 - expect(page).to have_content("That's it, well done!") + # Commit form is shown + expect(page).to have_button('Commit changes') end context 'when feature setting is disabled' do diff --git a/spec/frontend/environments/graphql/mock_data.js b/spec/frontend/environments/graphql/mock_data.js index 7b241fe44db..e56b6448b7d 100644 --- a/spec/frontend/environments/graphql/mock_data.js +++ b/spec/frontend/environments/graphql/mock_data.js @@ -234,7 +234,7 @@ export const resolvedEnvironmentsApp = { canDelete: false, hasOpenedAlert: false, }, - __typename: 'NestedEnvironment', + __typename: 'NestedLocalEnvironment', }, { name: 'production', @@ -368,7 +368,7 @@ export const resolvedEnvironmentsApp = { canDelete: false, hasOpenedAlert: false, }, - __typename: 'NestedEnvironment', + __typename: 'NestedLocalEnvironment', }, { name: 'staging', @@ -398,7 +398,7 @@ export const resolvedEnvironmentsApp = { canDelete: false, hasOpenedAlert: false, }, - __typename: 'NestedEnvironment', + __typename: 'NestedLocalEnvironment', }, ], reviewApp: { @@ -409,7 +409,7 @@ export const resolvedEnvironmentsApp = { __typename: 'ReviewApp', }, stoppedCount: 0, - __typename: 'EnvironmentApp', + __typename: 'LocalEnvironmentApp', }; export const folder = { @@ -496,7 +496,7 @@ export const resolvedFolder = { enableAdvancedLogsQuerying: false, canDelete: false, hasOpenedAlert: false, - __typename: 'Environment', + __typename: 'LocalEnvironment', }, { id: 41, @@ -522,9 +522,9 @@ export const resolvedFolder = { enableAdvancedLogsQuerying: false, canDelete: false, hasOpenedAlert: false, - __typename: 'Environment', + __typename: 'LocalEnvironment', }, ], stoppedCount: 0, - __typename: 'EnvironmentFolder', + __typename: 'LocalEnvironmentFolder', }; diff --git a/spec/frontend/lib/utils/text_markdown_spec.js b/spec/frontend/lib/utils/text_markdown_spec.js index acbf1a975b8..ab81ec47b64 100644 --- a/spec/frontend/lib/utils/text_markdown_spec.js +++ b/spec/frontend/lib/utils/text_markdown_spec.js @@ -100,11 +100,11 @@ describe('init markdown', () => { text: textArea.value, tag: '```suggestion:-0+0\n{text}\n```', blockTag: true, - selected: '# Does not parse the %br currently.', + selected: '# Does not %br parse the %br currently.', wrap: false, }); - expect(textArea.value).toContain('# Does not parse the \\n currently.'); + expect(textArea.value).toContain('# Does not \\n parse the \\n currently.'); }); it('inserts the tag on the same line if the current line only contains spaces', () => { diff --git a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js index 57fa0aa631b..f6afef595c6 100644 --- a/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js +++ b/spec/frontend/pipeline_editor/pipeline_editor_app_spec.js @@ -411,4 +411,37 @@ describe('Pipeline editor app component', () => { expect(findEditorHome().exists()).toBe(true); }); }); + + describe('when add_new_config_file query param is present', () => { + const originalLocation = window.location.href; + + beforeEach(() => { + setWindowLocation('?add_new_config_file=true'); + + mockCiConfigData.mockResolvedValue(mockCiConfigQueryResponse); + }); + + afterEach(() => { + setWindowLocation(originalLocation); + }); + + describe('when CI config file does not exist', () => { + beforeEach(async () => { + mockBlobContentData.mockResolvedValue(mockBlobContentQueryResponseNoCiFile); + mockLatestCommitShaQuery.mockResolvedValue(mockEmptyCommitShaResults); + mockGetTemplate.mockResolvedValue(mockCiTemplateQueryResponse); + + await createComponentWithApollo(); + + jest + .spyOn(wrapper.vm.$apollo.queries.commitSha, 'startPolling') + .mockImplementation(jest.fn()); + }); + + it('skips empty state and shows editor home component', () => { + expect(findEmptyState().exists()).toBe(false); + expect(findEditorHome().exists()).toBe(true); + }); + }); + }); }); diff --git a/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js b/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js index b5afc1ab21a..8e710b6d65f 100644 --- a/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js +++ b/spec/frontend/vue_mr_widget/components/mr_widget_suggest_pipeline_spec.js @@ -1,4 +1,4 @@ -import { GlLink, GlSprintf } from '@gitlab/ui'; +import { GlSprintf } from '@gitlab/ui'; import { mount, shallowMount } from '@vue/test-utils'; import MockAdapter from 'axios-mock-adapter'; import { mockTracking, triggerEvent, unmockTracking } from 'helpers/tracking_helper'; @@ -7,9 +7,7 @@ import MrWidgetIcon from '~/vue_merge_request_widget/components/mr_widget_icon.v import suggestPipelineComponent from '~/vue_merge_request_widget/components/mr_widget_suggest_pipeline.vue'; import { SP_TRACK_LABEL, - SP_LINK_TRACK_EVENT, SP_SHOW_TRACK_EVENT, - SP_LINK_TRACK_VALUE, SP_SHOW_TRACK_VALUE, SP_HELP_URL, } from '~/vue_merge_request_widget/constants'; @@ -52,15 +50,8 @@ describe('MRWidgetSuggestPipeline', () => { mockAxios.restore(); }); - it('renders add pipeline file link', () => { - const link = wrapper.find(GlLink); - - expect(link.exists()).toBe(true); - expect(link.attributes().href).toBe(suggestProps.pipelinePath); - }); - it('renders the expected text', () => { - const messageText = /\s*No pipeline\s*Add the .gitlab-ci.yml file\s*to create one./; + const messageText = /Looks like there's no pipeline here./; expect(wrapper.text()).toMatch(messageText); }); @@ -109,18 +100,6 @@ describe('MRWidgetSuggestPipeline', () => { }); }); - it('send an event when add pipeline link is clicked', () => { - mockTrackingOnWrapper(); - const link = wrapper.find('[data-testid="add-pipeline-link"]'); - triggerEvent(link.element); - - expect(trackingSpy).toHaveBeenCalledWith('_category_', SP_LINK_TRACK_EVENT, { - label: SP_TRACK_LABEL, - property: suggestProps.humanAccess, - value: SP_LINK_TRACK_VALUE.toString(), - }); - }); - it('send an event when ok button is clicked', () => { mockTrackingOnWrapper(); const okBtn = findOkBtn(); diff --git a/spec/frontend/vue_mr_widget/mock_data.js b/spec/frontend/vue_mr_widget/mock_data.js index 34a741cf8f2..f0c1da346a1 100644 --- a/spec/frontend/vue_mr_widget/mock_data.js +++ b/spec/frontend/vue_mr_widget/mock_data.js @@ -51,7 +51,7 @@ export default { target_branch: 'main', target_project_id: 19, target_project_full_path: '/group2/project2', - merge_request_add_ci_config_path: '/group2/project2/new/pipeline', + merge_request_add_ci_config_path: '/root/group2/project2/-/ci/editor', is_dismissed_suggest_pipeline: false, user_callouts_path: 'some/callout/path', suggest_pipeline_feature_id: 'suggest_pipeline', diff --git a/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js b/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js index febcfcd4019..6eb68a1b00d 100644 --- a/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js +++ b/spec/frontend/vue_mr_widget/stores/mr_widget_store_spec.js @@ -129,7 +129,7 @@ describe('MergeRequestStore', () => { it('should set the add ci config path', () => { store.setPaths({ ...mockData }); - expect(store.mergeRequestAddCiConfigPath).toBe('/group2/project2/new/pipeline'); + expect(store.mergeRequestAddCiConfigPath).toBe('/root/group2/project2/-/ci/editor'); }); it('should set humanAccess=Maintainer when user has that role', () => { diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb index fcfdbfc0967..3e0c61a26c0 100644 --- a/spec/serializers/merge_request_widget_entity_spec.rb +++ b/spec/serializers/merge_request_widget_entity_spec.rb @@ -4,6 +4,7 @@ require 'spec_helper' RSpec.describe MergeRequestWidgetEntity do include ProjectForksHelper + include Gitlab::Routing.url_helpers let(:project) { create :project, :repository } let(:resource) { create(:merge_request, source_project: project, target_project: project) } @@ -140,17 +141,15 @@ RSpec.describe MergeRequestWidgetEntity do let(:role) { :developer } it 'has add ci config path' do - expected_path = "/#{resource.project.full_path}/-/new/#{resource.source_branch}" + expected_path = project_ci_pipeline_editor_path(project) expect(subject[:merge_request_add_ci_config_path]).to include(expected_path) end it 'has expected params' do expected_params = { - commit_message: 'Add .gitlab-ci.yml', - file_name: '.gitlab-ci.yml', - suggest_gitlab_ci_yml: 'true', - mr_path: "/#{resource.project.full_path}/-/merge_requests/#{resource.iid}" + branch_name: resource.source_branch, + add_new_config_file: 'true' }.with_indifferent_access uri = Addressable::URI.parse(subject[:merge_request_add_ci_config_path]) @@ -188,30 +187,6 @@ RSpec.describe MergeRequestWidgetEntity do end end - context 'when ci_config_path is customized' do - it 'has no path if ci_config_path is not set to our default setting' do - project.ci_config_path = 'not_default' - - expect(subject[:merge_request_add_ci_config_path]).to be_nil - end - - it 'has a path if ci_config_path unset' do - expect(subject[:merge_request_add_ci_config_path]).not_to be_nil - end - - it 'has a path if ci_config_path is an empty string' do - project.ci_config_path = '' - - expect(subject[:merge_request_add_ci_config_path]).not_to be_nil - end - - it 'has a path if ci_config_path is set to our default file' do - project.ci_config_path = Gitlab::FileDetector::PATTERNS[:gitlab_ci] - - expect(subject[:merge_request_add_ci_config_path]).not_to be_nil - end - end - context 'when build feature is disabled' do before do project.project_feature.update!(builds_access_level: ProjectFeature::DISABLED) |