Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-15 21:09:01 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-15 21:09:01 +0300
commit74804f8c31491045b62a4b9fed9f819531462ea2 (patch)
tree87c58fb3a34d871e37ed0320a124c5b64f815334 /app
parent10130901f1128c91596c4cbfe14b1e5c9f15032f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/design_management/components/list/item.vue3
-rw-r--r--app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue50
-rw-r--r--app/assets/javascripts/integrations/edit/components/jira_upgrade_cta.vue51
-rw-r--r--app/assets/javascripts/projects/commit/components/form_modal.vue7
-rw-r--r--app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js1
-rw-r--r--app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue23
-rw-r--r--app/controllers/projects/commit_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/controllers/search_controller.rb6
-rw-r--r--app/helpers/sidebars_helper.rb3
-rw-r--r--app/helpers/workhorse_helper.rb12
-rw-r--r--app/models/ci/build.rb4
-rw-r--r--app/models/concerns/milestoneish.rb2
-rw-r--r--app/models/deployment.rb4
-rw-r--r--app/models/environment.rb4
-rw-r--r--app/models/merge_request.rb4
-rw-r--r--app/models/sidebars/projects/menus/learn_gitlab/menu.rb41
-rw-r--r--app/models/sidebars/projects/panel.rb1
-rw-r--r--app/models/user.rb2
-rw-r--r--app/serializers/environment_serializer.rb54
-rw-r--r--app/services/ci/abort_pipelines_service.rb2
-rw-r--r--app/services/ci/drop_pipeline_service.rb37
-rw-r--r--app/views/admin/runners/show.html.haml18
-rw-r--r--app/views/groups/runners/edit.html.haml9
-rw-r--r--app/views/layouts/nav/sidebar/_project_menus.html.haml8
-rw-r--r--app/views/projects/runners/_runner.html.haml66
-rw-r--r--app/views/projects/runners/edit.html.haml11
-rw-r--r--app/views/shared/runners/_runner_type_alert.html.haml20
-rw-r--r--app/views/shared/runners/_runner_type_badge.html.haml10
-rw-r--r--app/views/shared/runners/show.html.haml15
-rw-r--r--app/workers/all_queues.yml8
-rw-r--r--app/workers/ci/drop_pipeline_worker.rb16
33 files changed, 345 insertions, 152 deletions
diff --git a/app/assets/javascripts/design_management/components/list/item.vue b/app/assets/javascripts/design_management/components/list/item.vue
index 2169c9111d2..b6163491abc 100644
--- a/app/assets/javascripts/design_management/components/list/item.vue
+++ b/app/assets/javascripts/design_management/components/list/item.vue
@@ -137,8 +137,7 @@ export default {
<span :title="icon.tooltip" :aria-label="icon.tooltip">
<gl-icon
:name="icon.name"
- :size="18"
- use-deprecated-sizes
+ :size="16"
:class="icon.classes"
data-qa-selector="design_status_icon"
:data-qa-status="icon.name"
diff --git a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
index e6bd0f53672..aea4a8b1c0b 100644
--- a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
+++ b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
@@ -1,15 +1,8 @@
<script>
-import {
- GlFormGroup,
- GlFormCheckbox,
- GlFormInput,
- GlSprintf,
- GlLink,
- GlButton,
- GlCard,
-} from '@gitlab/ui';
+import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
+import JiraUpgradeCta from './jira_upgrade_cta.vue';
export default {
name: 'JiraIssuesFields',
@@ -19,8 +12,7 @@ export default {
GlFormInput,
GlSprintf,
GlLink,
- GlButton,
- GlCard,
+ JiraUpgradeCta,
JiraIssueCreationVulnerabilities: () =>
import('ee_component/integrations/edit/components/jira_issue_creation_vulnerabilities.vue'),
},
@@ -84,11 +76,13 @@ export default {
return !this.enableJiraIssues || Boolean(this.projectKey) || !this.validated;
},
showJiraVulnerabilitiesOptions() {
- return (
- this.enableJiraIssues &&
- this.showJiraVulnerabilitiesIntegration &&
- this.glFeatures.jiraForVulnerabilities
- );
+ return this.showJiraVulnerabilitiesIntegration && this.glFeatures.jiraForVulnerabilities;
+ },
+ showUltimateUpgrade() {
+ return this.showJiraIssuesIntegration && !this.showJiraVulnerabilitiesIntegration;
+ },
+ showPremiumUpgrade() {
+ return !this.showJiraIssuesIntegration;
},
},
created() {
@@ -135,27 +129,23 @@ export default {
</template>
</gl-form-checkbox>
<jira-issue-creation-vulnerabilities
- v-if="showJiraVulnerabilitiesOptions"
+ v-if="enableJiraIssues"
:project-key="projectKey"
:initial-is-enabled="initialEnableJiraVulnerabilities"
:initial-issue-type-id="initialVulnerabilitiesIssuetype"
+ :show-full-feature="showJiraVulnerabilitiesOptions"
data-testid="jira-for-vulnerabilities"
@request-get-issue-types="getJiraIssueTypes"
/>
</template>
- <gl-card v-else class="gl-mt-7">
- <strong>{{ __('This is a Premium feature') }}</strong>
- <p>{{ __('Upgrade your plan to enable this feature of the Jira Integration.') }}</p>
- <gl-button
- v-if="upgradePlanPath"
- category="primary"
- variant="info"
- :href="upgradePlanPath"
- target="_blank"
- >
- {{ __('Upgrade your plan') }}
- </gl-button>
- </gl-card>
+ <jira-upgrade-cta
+ v-if="showUltimateUpgrade || showPremiumUpgrade"
+ class="gl-mt-2"
+ :class="{ 'gl-ml-6': showUltimateUpgrade }"
+ :upgrade-plan-path="upgradePlanPath"
+ :show-ultimate-message="showUltimateUpgrade"
+ :show-premium-message="showPremiumUpgrade"
+ />
</div>
</gl-form-group>
<template v-if="showJiraIssuesIntegration">
diff --git a/app/assets/javascripts/integrations/edit/components/jira_upgrade_cta.vue b/app/assets/javascripts/integrations/edit/components/jira_upgrade_cta.vue
new file mode 100644
index 00000000000..9164e484440
--- /dev/null
+++ b/app/assets/javascripts/integrations/edit/components/jira_upgrade_cta.vue
@@ -0,0 +1,51 @@
+<script>
+import { GlButton, GlCard } from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+
+export default {
+ components: {
+ GlButton,
+ GlCard,
+ },
+ props: {
+ upgradePlanPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ showPremiumMessage: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ showUltimateMessage: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ computed: {
+ title() {
+ return this.showUltimateMessage
+ ? this.$options.i18n.titleUltimate
+ : this.$options.i18n.titlePremium;
+ },
+ },
+ i18n: {
+ titleUltimate: s__('JiraService|This is an Ultimate feature'),
+ titlePremium: s__('JiraService|This is a Premium feature'),
+ content: s__('JiraService|Upgrade your plan to enable this feature of the Jira Integration.'),
+ upgrade: __('Upgrade your plan'),
+ },
+};
+</script>
+
+<template>
+ <gl-card>
+ <strong>{{ title }}</strong>
+ <p>{{ $options.i18n.content }}</p>
+ <gl-button v-if="upgradePlanPath" category="primary" variant="info" :href="upgradePlanPath">
+ {{ $options.i18n.upgrade }}
+ </gl-button>
+ </gl-card>
+</template>
diff --git a/app/assets/javascripts/projects/commit/components/form_modal.vue b/app/assets/javascripts/projects/commit/components/form_modal.vue
index a5f26416828..6eefa5f55e4 100644
--- a/app/assets/javascripts/projects/commit/components/form_modal.vue
+++ b/app/assets/javascripts/projects/commit/components/form_modal.vue
@@ -37,6 +37,11 @@ export default {
type: String,
required: true,
},
+ isCherryPick: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
data() {
return {
@@ -111,7 +116,7 @@ export default {
<input type="hidden" name="authenticity_token" :value="$options.csrf.token" />
<gl-form-group
- v-if="glFeatures.pickIntoProject"
+ v-if="glFeatures.pickIntoProject && isCherryPick"
:label="i18n.projectLabel"
label-for="start_project"
data-testid="dropdown-group"
diff --git a/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js b/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js
index ad31ad14b2a..47ee8237fea 100644
--- a/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js
+++ b/app/assets/javascripts/projects/commit/init_cherry_pick_commit_modal.js
@@ -51,6 +51,7 @@ export default function initInviteMembersModal() {
i18n: { ...I18N_CHERRY_PICK_MODAL, ...I18N_MODAL },
openModal: OPEN_CHERRY_PICK_MODAL,
modalId: CHERRY_PICK_MODAL_ID,
+ isCherryPick: true,
},
}),
});
diff --git a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue b/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
index 654508f0736..cfefdf82d85 100644
--- a/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
+++ b/app/assets/javascripts/reports/codequality_report/grouped_codequality_reports_app.vue
@@ -62,7 +62,7 @@ export default {
helpPath: this.codequalityHelpPath,
});
- this.fetchReports(this.glFeatures.codequalityBackendComparison);
+ this.fetchReports();
},
methods: {
...mapActions(['fetchReports', 'setPaths']),
diff --git a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
index 7182079860a..11f484b2cdf 100644
--- a/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
+++ b/app/assets/javascripts/vue_shared/components/user_popover/user_popover.vue
@@ -1,11 +1,6 @@
<script>
/* eslint-disable vue/no-v-html */
-import {
- GlPopover,
- GlLink,
- GlDeprecatedSkeletonLoading as GlSkeletonLoading,
- GlIcon,
-} from '@gitlab/ui';
+import { GlPopover, GlLink, GlSkeletonLoader, GlIcon } from '@gitlab/ui';
import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue';
import { glEmojiTag } from '../../../emoji';
import UserAvatarImage from '../user_avatar/user_avatar_image.vue';
@@ -19,7 +14,7 @@ export default {
GlIcon,
GlLink,
GlPopover,
- GlSkeletonLoading,
+ GlSkeletonLoader,
UserAvatarImage,
UserNameWithStatus,
},
@@ -65,15 +60,13 @@ export default {
<div class="gl-p-2 flex-shrink-1">
<user-avatar-image :img-src="user.avatarUrl" :size="60" css-classes="gl-mr-3!" />
</div>
- <div class="gl-p-2 gl-w-full">
+ <div class="gl-p-2 gl-w-full gl-min-w-0">
<template v-if="userIsLoading">
- <!-- `gl-skeleton-loading` does not support equal length lines -->
- <!-- This can be migrated to `gl-skeleton-loader` when https://gitlab.com/gitlab-org/gitlab-ui/-/issues/872 is completed -->
- <gl-skeleton-loading
- v-for="n in $options.maxSkeletonLines"
- :key="n"
- :lines="1"
- class="animation-container-small gl-mb-2"
+ <gl-skeleton-loader
+ :lines="$options.maxSkeletonLines"
+ preserve-aspect-ratio="none"
+ equal-width-lines
+ :height="52"
/>
</template>
<template v-else>
diff --git a/app/controllers/projects/commit_controller.rb b/app/controllers/projects/commit_controller.rb
index 1e65974a3cd..3853797e0bf 100644
--- a/app/controllers/projects/commit_controller.rb
+++ b/app/controllers/projects/commit_controller.rb
@@ -20,7 +20,7 @@ class Projects::CommitController < Projects::ApplicationController
before_action :define_note_vars, only: [:show, :diff_for_path, :diff_files]
before_action :authorize_edit_tree!, only: [:revert, :cherry_pick]
before_action do
- push_frontend_feature_flag(:pick_into_project)
+ push_frontend_feature_flag(:pick_into_project, @project, default_enabled: :yaml)
end
BRANCH_SEARCH_LIMIT = 1000
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 9081c9f7c57..4d612cd45d0 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -37,7 +37,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:default_merge_ref_for_diffs, @project, default_enabled: :yaml)
push_frontend_feature_flag(:core_security_mr_widget_counts, @project)
push_frontend_feature_flag(:diffs_gradual_load, @project, default_enabled: true)
- push_frontend_feature_flag(:codequality_backend_comparison, @project, default_enabled: :yaml)
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml)
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 45c1c35a655..3b218822395 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -47,7 +47,11 @@ class SearchController < ApplicationController
params.require([:search, :scope])
scope = search_service.scope
- count = search_service.search_results.formatted_count(scope)
+
+ count = 0
+ ApplicationRecord.with_fast_read_statement_timeout do
+ count = search_service.search_results.formatted_count(scope)
+ end
# Users switching tabs will keep fetching the same tab counts so it's a
# good idea to cache in their browser just for a short time. They can still
diff --git a/app/helpers/sidebars_helper.rb b/app/helpers/sidebars_helper.rb
index efb0fd8a6e3..b0fffe93c25 100644
--- a/app/helpers/sidebars_helper.rb
+++ b/app/helpers/sidebars_helper.rb
@@ -35,7 +35,8 @@ module SidebarsHelper
def project_sidebar_context_data(project, user)
{
current_user: user,
- container: project
+ container: project,
+ learn_gitlab_experiment_enabled: learn_gitlab_experiment_enabled?(project)
}
end
end
diff --git a/app/helpers/workhorse_helper.rb b/app/helpers/workhorse_helper.rb
index 28dd1b00292..8785c4cdcbb 100644
--- a/app/helpers/workhorse_helper.rb
+++ b/app/helpers/workhorse_helper.rb
@@ -7,7 +7,7 @@ module WorkhorseHelper
def send_git_blob(repository, blob, inline: true)
headers.store(*Gitlab::Workhorse.send_git_blob(repository, blob))
- headers['Content-Disposition'] = inline ? 'inline' : content_disposition_attachment(repository.project, blob.name)
+ headers['Content-Disposition'] = content_disposition_for_blob(blob, inline)
# If enabled, this will override the values set above
workhorse_set_content_type!
@@ -49,11 +49,9 @@ module WorkhorseHelper
headers[Gitlab::Workhorse::DETECT_HEADER] = "true"
end
- def content_disposition_attachment(project, filename)
- if Feature.enabled?(:attachment_with_filename, project, default_enabled: :yaml)
- ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: filename)
- else
- 'attachment'
- end
+ def content_disposition_for_blob(blob, inline)
+ return 'inline' if inline
+
+ ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: blob.name)
end
end
diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb
index 57f5f66891e..3d8e9f4c126 100644
--- a/app/models/ci/build.rb
+++ b/app/models/ci/build.rb
@@ -377,11 +377,11 @@ module Ci
end
def other_manual_actions
- pipeline.manual_actions.where.not(name: name)
+ pipeline.manual_actions.reject { |action| action.name == self.name }
end
def other_scheduled_actions
- pipeline.scheduled_actions.where.not(name: name)
+ pipeline.scheduled_actions.reject { |action| action.name == self.name }
end
def pages_generator?
diff --git a/app/models/concerns/milestoneish.rb b/app/models/concerns/milestoneish.rb
index 8f7e6041d4b..eaf64f2541d 100644
--- a/app/models/concerns/milestoneish.rb
+++ b/app/models/concerns/milestoneish.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
module Milestoneish
- DISPLAY_ISSUES_LIMIT = 3000
+ DISPLAY_ISSUES_LIMIT = 500
def total_issues_count
@total_issues_count ||= Milestones::IssuesCountService.new(self).count
diff --git a/app/models/deployment.rb b/app/models/deployment.rb
index 0bfe6172154..d3280403bfd 100644
--- a/app/models/deployment.rb
+++ b/app/models/deployment.rb
@@ -171,7 +171,7 @@ class Deployment < ApplicationRecord
end
def commit
- project.commit(sha)
+ @commit ||= project.commit(sha)
end
def commit_title
@@ -250,7 +250,7 @@ class Deployment < ApplicationRecord
return unless on_stop.present?
return unless manual_actions
- @stop_action ||= manual_actions.find_by(name: on_stop)
+ @stop_action ||= manual_actions.find { |action| action.name == self.on_stop }
end
def finished_at
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 4cc65f4e295..4ee93b0ba4a 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -24,13 +24,13 @@ class Environment < ApplicationRecord
has_many :self_managed_prometheus_alert_events, inverse_of: :environment
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :environment
- has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment'
+ has_one :last_deployment, -> { success.order('deployments.id DESC') }, class_name: 'Deployment', inverse_of: :environment
has_one :last_deployable, through: :last_deployment, source: 'deployable', source_type: 'CommitStatus'
has_one :last_pipeline, through: :last_deployable, source: 'pipeline'
has_one :last_visible_deployment, -> { visible.distinct_on_environment }, inverse_of: :environment, class_name: 'Deployment'
has_one :last_visible_deployable, through: :last_visible_deployment, source: 'deployable', source_type: 'CommitStatus'
has_one :last_visible_pipeline, through: :last_visible_deployable, source: 'pipeline'
- has_one :upcoming_deployment, -> { running.order('deployments.id DESC') }, class_name: 'Deployment'
+ has_one :upcoming_deployment, -> { running.order('deployments.id DESC') }, class_name: 'Deployment', inverse_of: :environment
has_one :latest_opened_most_severe_alert, -> { order_severity_with_open_prometheus_alert }, class_name: 'AlertManagement::Alert', inverse_of: :environment
before_validation :nullify_external_url
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 8f2ec2d6b88..e7f3762b9a3 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -37,7 +37,7 @@ class MergeRequest < ApplicationRecord
SORTING_PREFERENCE_FIELD = :merge_requests_sort
ALLOWED_TO_USE_MERGE_BASE_PIPELINE_FOR_COMPARISON = {
- 'Ci::CompareCodequalityReportsService' => ->(project) { ::Gitlab::Ci::Features.display_codequality_backend_comparison?(project) }
+ 'Ci::CompareCodequalityReportsService' => ->(project) { true }
}.freeze
belongs_to :target_project, class_name: "Project"
@@ -1564,8 +1564,6 @@ class MergeRequest < ApplicationRecord
end
def has_codequality_reports?
- return false unless ::Gitlab::Ci::Features.display_codequality_backend_comparison?(project)
-
actual_head_pipeline&.has_reports?(Ci::JobArtifact.codequality_reports)
end
diff --git a/app/models/sidebars/projects/menus/learn_gitlab/menu.rb b/app/models/sidebars/projects/menus/learn_gitlab/menu.rb
new file mode 100644
index 00000000000..4b572846d1a
--- /dev/null
+++ b/app/models/sidebars/projects/menus/learn_gitlab/menu.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+module Sidebars
+ module Projects
+ module Menus
+ module LearnGitlab
+ class Menu < ::Sidebars::Menu
+ override :link
+ def link
+ project_learn_gitlab_path(context.project)
+ end
+
+ override :active_routes
+ def active_routes
+ { controller: :learn_gitlab }
+ end
+
+ override :title
+ def title
+ _('Learn GitLab')
+ end
+
+ override :extra_container_html_options
+ def nav_link_html_options
+ { class: 'home' }
+ end
+
+ override :sprite_icon
+ def sprite_icon
+ 'home'
+ end
+
+ override :render?
+ def render?
+ context.learn_gitlab_experiment_enabled
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/app/models/sidebars/projects/panel.rb b/app/models/sidebars/projects/panel.rb
index 5f4c7f32164..60cb804f5e8 100644
--- a/app/models/sidebars/projects/panel.rb
+++ b/app/models/sidebars/projects/panel.rb
@@ -8,6 +8,7 @@ module Sidebars
set_scope_menu(Sidebars::Projects::Menus::Scope::Menu.new(context))
add_menu(Sidebars::Projects::Menus::ProjectOverview::Menu.new(context))
+ add_menu(Sidebars::Projects::Menus::LearnGitlab::Menu.new(context))
end
override :render_raw_menus_partial
diff --git a/app/models/user.rb b/app/models/user.rb
index 426309762ca..507e8cc2cf5 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -354,7 +354,7 @@ class User < ApplicationRecord
# this state transition object in order to do a rollback.
# For this reason the tradeoff is to disable this cop.
after_transition any => :blocked do |user|
- Ci::AbortPipelinesService.new.execute(user.pipelines, :user_blocked)
+ Ci::DropPipelineService.new.execute_async_for_all(user.pipelines, :user_blocked, user)
Ci::DisableUserPipelineSchedulesService.new.execute(user)
end
# rubocop: enable CodeReuse/ServiceClass
diff --git a/app/serializers/environment_serializer.rb b/app/serializers/environment_serializer.rb
index 598ce5f9e4f..2bb9a7e7254 100644
--- a/app/serializers/environment_serializer.rb
+++ b/app/serializers/environment_serializer.rb
@@ -23,7 +23,7 @@ class EnvironmentSerializer < BaseSerializer
latest: super(item.latest, opts) }
end
else
- super(resource, opts)
+ super(batch_load(resource), opts)
end
end
@@ -41,11 +41,59 @@ class EnvironmentSerializer < BaseSerializer
# immediately.
items = @paginator.paginate(items) if paginated?
- environments = resource.where(id: items.map(&:last_id)).index_by(&:id)
+ environments = batch_load(resource.where(id: items.map(&:last_id)))
+ environments_by_id = environments.index_by(&:id)
items.map do |item|
- Item.new(item.folder, item.size, environments[item.last_id])
+ Item.new(item.folder, item.size, environments_by_id[item.last_id])
end
end
+
+ def batch_load(resource)
+ resource = resource.preload(environment_associations)
+
+ resource.all.tap do |environments|
+ environments.each do |environment|
+ # Batch loading the commits of the deployments
+ environment.last_deployment&.commit&.try(:lazy_author)
+ environment.upcoming_deployment&.commit&.try(:lazy_author)
+ end
+ end
+ end
+
+ def environment_associations
+ {
+ last_deployment: deployment_associations,
+ upcoming_deployment: deployment_associations,
+ project: project_associations
+ }
+ end
+
+ def deployment_associations
+ {
+ user: [],
+ cluster: [],
+ project: [],
+ deployable: {
+ user: [],
+ metadata: [],
+ pipeline: {
+ manual_actions: [],
+ scheduled_actions: []
+ },
+ project: project_associations
+ }
+ }
+ end
+
+ def project_associations
+ {
+ project_feature: [],
+ route: [],
+ namespace: :route
+ }
+ end
# rubocop: enable CodeReuse/ActiveRecord
end
+
+EnvironmentSerializer.prepend_if_ee('EE::EnvironmentSerializer')
diff --git a/app/services/ci/abort_pipelines_service.rb b/app/services/ci/abort_pipelines_service.rb
index ad619dbdc41..43734c4dd39 100644
--- a/app/services/ci/abort_pipelines_service.rb
+++ b/app/services/ci/abort_pipelines_service.rb
@@ -3,7 +3,7 @@
module Ci
class AbortPipelinesService
# NOTE: This call fails pipelines in bulk without running callbacks.
- # Only for pipeline abandonment scenarios (examples: project delete, user block)
+ # Only for pipeline abandonment scenarios (examples: project delete)
def execute(pipelines, failure_reason)
pipelines.cancelable.each_batch(of: 100) do |pipeline_batch|
now = Time.current
diff --git a/app/services/ci/drop_pipeline_service.rb b/app/services/ci/drop_pipeline_service.rb
new file mode 100644
index 00000000000..f510943251b
--- /dev/null
+++ b/app/services/ci/drop_pipeline_service.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Ci
+ class DropPipelineService
+ # execute service asynchronously for each cancelable pipeline
+ def execute_async_for_all(pipelines, failure_reason, context_user)
+ pipelines.cancelable.select(:id).find_in_batches do |pipelines_batch|
+ Ci::DropPipelineWorker.bulk_perform_async_with_contexts(
+ pipelines_batch,
+ arguments_proc: -> (pipeline) { [pipeline.id, failure_reason] },
+ context_proc: -> (_) { { user: context_user } }
+ )
+ end
+ end
+
+ def execute(pipeline, failure_reason, retries: 3)
+ Gitlab::OptimisticLocking.retry_lock(pipeline.cancelable_statuses, retries, name: 'ci_pipeline_drop_running') do |cancelables|
+ cancelables.find_in_batches do |batch|
+ preload_associations_for_drop(batch)
+
+ batch.each do |job|
+ job.drop(failure_reason)
+ end
+ end
+ end
+ end
+
+ private
+
+ def preload_associations_for_drop(builds_batch)
+ ActiveRecord::Associations::Preloader.new.preload( # rubocop: disable CodeReuse/ActiveRecord
+ builds_batch,
+ [:project, :pipeline, :metadata, :deployment, :taggings]
+ )
+ end
+ end
+end
diff --git a/app/views/admin/runners/show.html.haml b/app/views/admin/runners/show.html.haml
index b5940fb41bc..705716c09b7 100644
--- a/app/views/admin/runners/show.html.haml
+++ b/app/views/admin/runners/show.html.haml
@@ -8,22 +8,10 @@
#js-runner-detail{ data: {runner_id: @runner.id} }
- else
%h2.page-title
- = sprintf(s_('Runners|Runner #%{runner_id}'), {runner_id: @runner.id})
+ = s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
+ = render 'shared/runners/runner_type_badge', runner: @runner
-- if @runner.instance_type?
- .bs-callout.bs-callout-success
- %h4= _('This runner processes jobs for all unassigned projects.')
- %p
- = _('If you want a runner to build only specific projects, restrict the project in the table below. After you restrict a runner to a project, you cannot change it back to a shared runner.')
-- elsif @runner.group_type?
- .bs-callout.bs-callout-success
- %h4= _('This runner processes jobs for all projects in its group and subgroups.')
-- else
- .bs-callout.bs-callout-info
- %h4= _('This runner processes jobs for assigned projects only.')
- %p
- = _('You cannot make this a shared runner.')
-%hr
+= render 'shared/runners/runner_type_alert', runner: @runner
.gl-mb-6
= render 'shared/runners/form', runner: @runner, runner_form_url: admin_runner_path(@runner), in_gitlab_com_admin_context: Gitlab.com?
diff --git a/app/views/groups/runners/edit.html.haml b/app/views/groups/runners/edit.html.haml
index c332009def4..3794c345aa6 100644
--- a/app/views/groups/runners/edit.html.haml
+++ b/app/views/groups/runners/edit.html.haml
@@ -1,6 +1,9 @@
- page_title _('Edit'), "#{@runner.description} ##{@runner.id}", _('Runners')
-%h4 Runner ##{@runner.id}
+%h2.page-title
+ = s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
+ = render 'shared/runners/runner_type_badge', runner: @runner
-%hr
- = render 'shared/runners/form', runner: @runner, runner_form_url: group_runner_path(@group, @runner)
+= render 'shared/runners/runner_type_alert', runner: @runner
+
+= render 'shared/runners/form', runner: @runner, runner_form_url: group_runner_path(@group, @runner)
diff --git a/app/views/layouts/nav/sidebar/_project_menus.html.haml b/app/views/layouts/nav/sidebar/_project_menus.html.haml
index aee506ead6c..8f2da398164 100644
--- a/app/views/layouts/nav/sidebar/_project_menus.html.haml
+++ b/app/views/layouts/nav/sidebar/_project_menus.html.haml
@@ -1,11 +1,3 @@
-- if project_nav_tab? :learn_gitlab
- = nav_link(controller: :learn_gitlab, html_options: { class: 'home' }) do
- = link_to project_learn_gitlab_path(@project) do
- .nav-icon-container
- = sprite_icon('home')
- %span.nav-item-name
- = _('Learn GitLab')
-
- if project_nav_tab? :files
= nav_link(controller: sidebar_repository_paths, unless: -> { current_path?('projects/graphs#charts') }) do
= link_to project_tree_path(@project), class: 'shortcuts-tree', data: { qa_selector: "repository_link" } do
diff --git a/app/views/projects/runners/_runner.html.haml b/app/views/projects/runners/_runner.html.haml
index bc043a5f394..bf2e746b4a4 100644
--- a/app/views/projects/runners/_runner.html.haml
+++ b/app/views/projects/runners/_runner.html.haml
@@ -1,44 +1,40 @@
-%li.runner{ id: dom_id(runner) }
- %h4.gl-font-weight-normal
- = runner_status_icon(runner, size: 16, icon_class: "gl-vertical-align-middle!")
-
- - if @project_runners.include?(runner)
- = link_to _("%{token}...") % { token: runner.short_sha }, project_runner_path(@project, runner), class: 'commit-sha has-tooltip', title: _("Partial token for reference only")
-
+%li{ id: dom_id(runner) }
+ .gl-display-flex.gl-justify-content-space-between
+ %div
+ = runner_status_icon(runner, size: 16)
+ - if @project_runners.include?(runner)
+ = link_to "##{runner.id} (#{runner.short_sha})", project_runner_path(@project, runner)
+ - else
+ %span
+ = "##{runner.id} (#{runner.short_sha})"
- if runner.locked?
%span.has-tooltip{ title: _('Locked to current projects') }
= sprite_icon('lock')
-
- = link_to edit_project_runner_path(@project, runner), class: 'btn gl-button btn-sm btn-icon', data: { testid: 'edit-runner-link' } do
- = sprite_icon('pencil')
-
- - else
- %span.commit-sha
- = runner.short_sha
-
- .float-right
- - if @project_runners.include?(runner)
- - if runner.active?
- = link_to _('Pause'), pause_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-sm btn-danger', data: { confirm: _("Are you sure?") }
- - else
- = link_to _('Resume'), resume_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-confirm btn-sm'
- - if runner.belongs_to_one_project?
- = link_to _('Remove runner'), project_runner_path(@project, runner), data: { confirm: _("Are you sure?") }, method: :delete, class: 'btn gl-button btn-danger btn-sm'
- - else
- - runner_project = @project.runner_projects.find_by(runner_id: runner) # rubocop: disable CodeReuse/ActiveRecord
- = link_to _('Disable for this project'), project_runner_project_path(@project, runner_project), data: { confirm: _("Are you sure?") }, method: :delete, class: 'btn gl-button btn-danger btn-sm'
- - elsif runner.project_type?
- = form_for [@project, @project.runner_projects.new] do |f|
- = f.hidden_field :runner_id, value: runner.id
- = f.submit _('Enable for this project'), class: 'btn gl-button btn-sm'
- .float-right
- %small.light
- \##{runner.id}
+ .gl-ml-2
+ .btn-group.btn-group-sm
+ - if @project_runners.include?(runner)
+ = link_to edit_project_runner_path(@project, runner), class: 'btn gl-button btn-icon', title: _('Edit'), aria: { label: _('Edit') }, data: { testid: 'edit-runner-link', toggle: 'tooltip', placement: 'top', container: 'body' } do
+ = sprite_icon('pencil')
+ - if runner.active?
+ = link_to pause_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: _('Pause'), aria: { label: _('Pause') }, data: { toggle: 'tooltip', placement: 'top', container: 'body', confirm: _("Are you sure?") } do
+ = sprite_icon('pause')
+ - else
+ = link_to resume_project_runner_path(@project, runner), method: :post, class: 'btn gl-button btn-icon', title: _('Resume'), aria: { label: _('Resume') }, data: { toggle: 'tooltip', placement: 'top', container: 'body' } do
+ = sprite_icon('play')
+ - if runner.belongs_to_one_project?
+ = link_to _('Remove runner'), project_runner_path(@project, runner), data: { confirm: _("Are you sure?") }, method: :delete, class: 'btn gl-button btn-danger'
+ - else
+ - runner_project = @project.runner_projects.find_by(runner_id: runner) # rubocop: disable CodeReuse/ActiveRecord
+ = link_to _('Disable for this project'), project_runner_project_path(@project, runner_project), data: { confirm: _("Are you sure?") }, method: :delete, class: 'btn gl-button btn-danger'
+ - elsif runner.project_type?
+ = form_for [@project, @project.runner_projects.new] do |f|
+ = f.hidden_field :runner_id, value: runner.id
+ = f.submit _('Enable for this project'), class: 'btn gl-button'
- if runner.description.present?
- %p.runner-description
+ %p.gl-my-2
= runner.description
- if runner.tags.present?
- %p
+ .gl-my-2
- runner.tags.map(&:name).sort.each do |tag|
%span.badge.gl-badge.sm.badge-pill.badge-primary
= tag
diff --git a/app/views/projects/runners/edit.html.haml b/app/views/projects/runners/edit.html.haml
index f93cd23c83e..77150715158 100644
--- a/app/views/projects/runners/edit.html.haml
+++ b/app/views/projects/runners/edit.html.haml
@@ -1,6 +1,9 @@
-- page_title _('Edit'), "#{@runner.description} ##{@runner.id}", _('runners')
+- page_title _('Edit'), "#{@runner.description} ##{@runner.id}", _('Runners')
-%h4 Runner ##{@runner.id}
+%h2.page-title
+ = s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
+ = render 'shared/runners/runner_type_badge', runner: @runner
-%hr
- = render 'shared/runners/form', runner: @runner, runner_form_url: project_runner_path(@project, @runner)
+= render 'shared/runners/runner_type_alert', runner: @runner
+
+= render 'shared/runners/form', runner: @runner, runner_form_url: project_runner_path(@project, @runner)
diff --git a/app/views/shared/runners/_runner_type_alert.html.haml b/app/views/shared/runners/_runner_type_alert.html.haml
new file mode 100644
index 00000000000..b83def8b802
--- /dev/null
+++ b/app/views/shared/runners/_runner_type_alert.html.haml
@@ -0,0 +1,20 @@
+.gl-alert.gl-alert-info.gl-my-5
+ = sprite_icon('information-o', css_class: 'gl-alert-icon')
+ - if runner.instance_type?
+ %h4.gl-alert-title
+ = s_('Runners|This runner is available to all groups and projects in your GitLab instance.')
+ .gl-alert-body
+ = s_('Runners|Shared runners are available to every project in a GitLab instance. If you want a runner to build only specific projects, restrict the project in the table below. After you restrict a runner to a project, you cannot change it back to a shared runner.')
+ = link_to _('Learn more.'), help_page_path('ci/runners/README', anchor: 'shared-runners'), target: '_blank', rel: 'noopener noreferrer'
+ - elsif runner.group_type?
+ %h4.gl-alert-title
+ = s_('Runners|This runner is available to all projects and subgroups in a group.')
+ .gl-alert-body
+ = s_('Runners|Use Group runners when you want all projects in a group to have access to a set of runners.')
+ = link_to _('Learn more.'), help_page_path('ci/runners/README', anchor: 'group-runners'), target: '_blank', rel: 'noopener noreferrer'
+ - else
+ %h4.gl-alert-title
+ = s_('Runners|This runner is associated with specific projects.')
+ .gl-alert-body
+ = s_('Runners|You can set up a specific runner to be used by multiple projects but you cannot make this a shared runner.')
+ = link_to _('Learn more.'), help_page_path('ci/runners/README', anchor: 'specific-runners'), target: '_blank', rel: 'noopener noreferrer'
diff --git a/app/views/shared/runners/_runner_type_badge.html.haml b/app/views/shared/runners/_runner_type_badge.html.haml
new file mode 100644
index 00000000000..e0318006f09
--- /dev/null
+++ b/app/views/shared/runners/_runner_type_badge.html.haml
@@ -0,0 +1,10 @@
+
+- if runner.instance_type?
+ %span.badge.badge-pill.gl-badge.badge-success
+ = s_('Runners|shared')
+- elsif runner.group_type?
+ %span.badge.badge-pill.gl-badge.badge-success
+ = s_('Runners|group')
+- else
+ %span.badge.badge-pill.gl-badge.badge-info
+ = s_('Runners|specific')
diff --git a/app/views/shared/runners/show.html.haml b/app/views/shared/runners/show.html.haml
index 1af04b808bf..757ec870f79 100644
--- a/app/views/shared/runners/show.html.haml
+++ b/app/views/shared/runners/show.html.haml
@@ -1,17 +1,8 @@
- page_title "#{@runner.description} ##{@runner.id}", _("Runners")
-%h3.page-title
- = s_('Runners|Runner #%{id}' % { id: @runner.id })
- .float-right
- - if @runner.instance_type?
- %span.runner-state.runner-state-shared
- = s_('Runners|Shared')
- - elsif @runner.group_type?
- %span.runner-state.runner-state-shared
- = s_('Runners|Group')
- - else
- %span.runner-state.runner-state-specific
- = s_('Runners|Specific')
+%h2.page-title
+ = s_('Runners|Runner #%{runner_id}' % { runner_id: @runner.id })
+ = render 'shared/runners/runner_type_badge', runner: @runner
.table-holder
%table.table
diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml
index f14497509e1..692adcb6434 100644
--- a/app/workers/all_queues.yml
+++ b/app/workers/all_queues.yml
@@ -1251,6 +1251,14 @@
:weight: 3
:idempotent:
:tags: []
+- :name: pipeline_default:ci_drop_pipeline
+ :feature_category: :continuous_integration
+ :has_external_dependencies:
+ :urgency: :low
+ :resource_boundary: :unknown
+ :weight: 3
+ :idempotent: true
+ :tags: []
- :name: pipeline_default:ci_merge_requests_add_todo_when_build_fails
:feature_category: :continuous_integration
:has_external_dependencies:
diff --git a/app/workers/ci/drop_pipeline_worker.rb b/app/workers/ci/drop_pipeline_worker.rb
new file mode 100644
index 00000000000..d19157a47e8
--- /dev/null
+++ b/app/workers/ci/drop_pipeline_worker.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module Ci
+ class DropPipelineWorker
+ include ApplicationWorker
+ include PipelineQueue
+
+ idempotent!
+
+ def perform(pipeline_id, failure_reason)
+ Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline|
+ Ci::DropPipelineService.new.execute(pipeline, failure_reason.to_sym)
+ end
+ end
+ end
+end