Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-11-10 15:13:21 +00:00
parent 419966e5d3
commit 26881dd926
63 changed files with 184 additions and 275 deletions

View File

@ -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:

View File

@ -1 +1 @@
8d7e242576249154697fed7876cd9fe2a31ffdc3
9de3dd28a5c8248903160ea35d9f718899f51c89

View File

@ -1,4 +1,4 @@
mutation cancelAutoStop($environment: Environment) {
mutation cancelAutoStop($environment: LocalEnvironment) {
cancelAutoStop(environment: $environment) @client {
errors
}

View File

@ -1,4 +1,4 @@
mutation deleteEnvironment($environment: Environment) {
mutation deleteEnvironment($environment: LocalEnvironment) {
deleteEnvironment(environment: $environment) @client {
errors
}

View File

@ -1,4 +1,4 @@
mutation rollbackEnvironment($environment: Environment) {
mutation rollbackEnvironment($environment: LocalEnvironment) {
rollbackEnvironment(environment: $environment) @client {
errors
}

View File

@ -1,4 +1,4 @@
mutation stopEnvironment($environment: Environment) {
mutation stopEnvironment($environment: LocalEnvironment) {
stopEnvironment(environment: $environment) @client {
errors
}

View File

@ -1,4 +1,4 @@
query getEnvironmentFolder($environment: NestedEnvironment) {
query getEnvironmentFolder($environment: NestedLocalEnvironment) {
folder(environment: $environment) @client {
availableCount
environments

View File

@ -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',
}));
},
},

View File

@ -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!
}

View File

@ -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 : '');

View File

@ -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>

View File

@ -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>

View File

@ -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 = [

View File

@ -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) &&

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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|

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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?

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
2ed9198926eb0579fccd4a8b1866f10ba4f42683d676e0664db3fadefe0bed39

View File

@ -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);

View File

@ -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

View File

@ -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 ""

View File

@ -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

View File

@ -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',
};

View File

@ -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', () => {

View File

@ -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);
});
});
});
});

View File

@ -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();

View File

@ -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',

View File

@ -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', () => {

View File

@ -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)