diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-25 15:09:06 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-07-25 15:09:06 +0300 |
commit | cc1e91be1cd930f58baebb89f2ff1893045a2aea (patch) | |
tree | ad35ee30978a657f17d87fcd569f35337b96da12 /app | |
parent | 012ed4e4f69ab58f9d9b58140865a734fa5a9c88 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
19 files changed, 262 insertions, 26 deletions
diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index a632f5ae0ed..45b53b13a7f 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -367,6 +367,7 @@ export default { :img-alt="avatarUrlTitle(assignee)" :img-src="avatarUrl(assignee)" :img-size="24" + img-css-classes="avatar gl-mr-0!" class="js-no-trigger" tooltip-placement="bottom" > diff --git a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js index e4ad0bf8e76..bc3cb163c39 100644 --- a/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js +++ b/app/assets/javascripts/editor/extensions/source_editor_markdown_livepreview_ext.js @@ -1,3 +1,4 @@ +import { KeyMod, KeyCode } from 'monaco-editor'; import { debounce } from 'lodash'; import { BLOB_PREVIEW_ERROR } from '~/blob_edit/constants'; import createFlash from '~/flash'; @@ -158,8 +159,8 @@ export class EditorMarkdownPreviewExtension { if (instance.getAction(EXTENSION_MARKDOWN_PREVIEW_ACTION_ID)) return; const actionBasis = { keybindings: [ - // eslint-disable-next-line no-bitwise,no-undef - monaco.KeyMod.chord(monaco.KeyMod.CtrlCmd | monaco.KeyMod.Shift | monaco.KeyCode.KEY_P), + // eslint-disable-next-line no-bitwise + KeyMod.chord(KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_P), ], contextMenuGroupId: 'navigation', contextMenuOrder: 1.5, diff --git a/app/assets/javascripts/linked_resources/index.js b/app/assets/javascripts/linked_resources/index.js index 802364acff9..6d799d30b4b 100644 --- a/app/assets/javascripts/linked_resources/index.js +++ b/app/assets/javascripts/linked_resources/index.js @@ -27,8 +27,8 @@ export default function initLinkedResources() { render: (createElement) => createElement('resource-links-block', { props: { - issuableId, helpPath, + issuableId: parseInt(issuableId, 10), canAddResourceLinks: parseBoolean(canAddResourceLinks), }, }), diff --git a/app/assets/javascripts/test_utils/index.js b/app/assets/javascripts/test_utils/index.js index 2727485fb95..369cf9714e8 100644 --- a/app/assets/javascripts/test_utils/index.js +++ b/app/assets/javascripts/test_utils/index.js @@ -1,8 +1,10 @@ +import { editor } from 'monaco-editor'; import { Sortable } from 'sortablejs'; import simulateDrag from './simulate_drag'; import simulateInput from './simulate_input'; // Export to global space for rspec to use +window.localMonaco = editor; window.simulateDrag = simulateDrag; window.simulateInput = simulateInput; window.Sortable = Sortable; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/extensions/README.md b/app/assets/javascripts/vue_merge_request_widget/components/extensions/README.md new file mode 100644 index 00000000000..e5bb4e1af4c --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/extensions/README.md @@ -0,0 +1,64 @@ +### Widget Extensions + +#### Telemetry + +Telemetry is enabled by default in all widget extensions. + +However, telemetry events are not reported until they have been marked as a "known event" with a Metric Dictionary. + +If telemetry metrics are desired when adding a widget extension, it is important to also create known events. + +The following steps are needed to generate these known events for a single widget: + +1. Widgets should be named `Widget${CamelName}`. + - For example: a widget for "Test Reports" should be `WidgetTestReports` +1. "Compute" the widget name slug by converting the `${CamelName}` to lower-, snake-case. + - The above example would be `test_reports` +1. Add the new widget name slug to `lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb` in the `WIDGETS` list. +1. Ensure the GDK is running (`gdk start`) +1. Generate known events on the command line with the following command. Replace `test_reports` with your appropriate name slug. + ``` + bundle exec rails generate gitlab:usage_metric_definition \ + counts.code_review.i_merge_request_widget_test_reports_count_view \ + counts.code_review.i_merge_request_widget_test_reports_count_full_report_clicked \ + counts.code_review.i_merge_request_widget_test_reports_count_expand \ + counts.code_review.i_merge_request_widget_test_reports_count_expand_success \ + counts.code_review.i_merge_request_widget_test_reports_count_expand_warning \ + counts.code_review.i_merge_request_widget_test_reports_count_expand_failed \ + --dir=all + ``` +1. Modify each newly generated file so that they match the existing files for MR Widget Extension telemetry. + - You can find existing examples by doing a glob search like so: `metrics/**/*_i_code_review_merge_request_widget_*` + - Roughly-speaking, each file should have these values: + 1. `description` = A plain English description of this value. Please see existing widget extension telemetry files for examples. + 1. `product_section` = `dev` + 1. `product_stage` = `create` + 1. `product_group` = `code_review` + 1. `product_category` = `code_review` + 1. `introduced_by_url` = `'[your MR]'` + 1. `options.events` = (the event in the command from above that generated this file, like `i_code_review_merge_request_widget_test_reports_count_view`) + - This is how the telemetry events are linked to "metrics" so this is probably one of the more important values + 1. `data_source` = `redis` + 1. `data_category` = `optional` +1. Repeat steps 5 and 6 for the HLL metrics. Replace `test_reports` with your appropriate name slug. + ``` + bundle exec rails generate gitlab:usage_metric_definition:redis_hll code_review \ + i_code_review_merge_request_widget_test_reports_view \ + i_code_review_merge_request_widget_test_reports_full_report_clicked \ + i_code_review_merge_request_widget_test_reports_expand \ + i_code_review_merge_request_widget_test_reports_expand_success \ + i_code_review_merge_request_widget_test_reports_expand_warning \ + i_code_review_merge_request_widget_test_reports_expand_failed \ + --class_name=RedisHLLMetric + ``` + - In step 6 for HLL, change the `data_source` to `redis_hll`. +1. Add each of the HLL metrics to `lib/gitlab/usage_data_counters/known_events/code_review_events.yml` + 1. `name` = [the event] + 1. `redis_slot` = `code_review` + 1. `category` = `code_review` + 1. `aggregation` = `weekly` +1. Add each event to the appropriate aggregates in `config/metrics/aggregates/code_review.yml` + +##### New Events + +If you are adding a new event to our known events, it will need to be included in `lib/gitlab/usage_data_counters/merge_request_widget_extension_counter.rb`. Update the list of `KNOWN_EVENTS` with the new event(s). diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index 41265de0ca0..00ae509ad15 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -576,10 +576,10 @@ span.idiff { } } -// *:nth-of-type(1n+5) - makes sure we do not render elements 5+ right away when +// *:nth-of-type(1n+30) - makes sure we do not render elements 30+ right away when // viewing a file. Even though the HTML is injected in the DOM, as long as we do // not render those elements, the browser doesn't need to spend resources // calculating and repainting what's hidden. -.file-holder [data-loading] .file-content *:nth-of-type(1n+5) { +.file-holder [data-loading] .file-content *:nth-of-type(1n+30) { @include gl-display-none; } diff --git a/app/controllers/profiles/personal_access_tokens_controller.rb b/app/controllers/profiles/personal_access_tokens_controller.rb index a8d8e1e38a3..07d786ab060 100644 --- a/app/controllers/profiles/personal_access_tokens_controller.rb +++ b/app/controllers/profiles/personal_access_tokens_controller.rb @@ -58,7 +58,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController end def active_personal_access_tokens - tokens = finder(state: 'active', sort: 'expires_at_asc').execute + tokens = finder(state: 'active', sort: 'expires_at_asc_id_desc').execute if Feature.enabled?('access_token_pagination') tokens = tokens.page(page) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 0c1cc6eb1b0..3a8e68c58a6 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -102,6 +102,7 @@ module Ci has_one :chat_data, class_name: 'Ci::PipelineChatData' has_many :triggered_pipelines, through: :sourced_pipelines, source: :pipeline + # Only includes direct and not nested children has_many :child_pipelines, -> { merge(Ci::Sources::Pipeline.same_project) }, through: :sourced_pipelines, source: :pipeline has_one :triggered_by_pipeline, through: :source_pipeline, source: :source_pipeline has_one :parent_pipeline, -> { merge(Ci::Sources::Pipeline.same_project) }, through: :source_pipeline, source: :source_pipeline @@ -592,26 +593,20 @@ module Ci canceled? && auto_canceled_by_id? end - def cancel_running(retries: 1) - preloaded_relations = [:project, :pipeline, :deployment, :taggings] + # Cancel a pipelines cancelable jobs and optionally it's child pipelines cancelable jobs + # retries - # of times to retry if errors + # cascade_to_children - if true cancels all related child pipelines for parent child pipelines + # auto_canceled_by_pipeline_id - store the pipeline_id of the pipeline that triggered cancellation + # execute_async - if true cancel the children asyncronously + def cancel_running(retries: 1, cascade_to_children: true, auto_canceled_by_pipeline_id: nil, execute_async: true) + update(auto_canceled_by_id: auto_canceled_by_pipeline_id) if auto_canceled_by_pipeline_id - retry_lock(cancelable_statuses, retries, name: 'ci_pipeline_cancel_running') do |cancelables| - cancelables.find_in_batches do |batch| - Preloaders::CommitStatusPreloader.new(batch).execute(preloaded_relations) + cancel_jobs(cancelable_statuses, retries: retries, auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id) - batch.each do |job| - yield(job) if block_given? - job.cancel - end - end - end - end - - def auto_cancel_running(pipeline, retries: 1) - update(auto_canceled_by: pipeline) - - cancel_running(retries: retries) do |job| - job.auto_canceled_by = pipeline + if cascade_to_children && project.cascade_cancel_pipelines_enabled? + # cancel any bridges that could spin up new child pipelines + cancel_jobs(bridges_in_self_and_descendants.cancelable, retries: retries, auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id) + cancel_children(auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id, execute_async: execute_async) end end @@ -953,6 +948,10 @@ module Ci Ci::Build.latest.where(pipeline: self_and_descendants) end + def bridges_in_self_and_descendants + Ci::Bridge.latest.where(pipeline: self_and_descendants) + end + def environments_in_self_and_descendants(deployment_status: nil) # We limit to 100 unique environments for application safety. # See: https://gitlab.com/gitlab-org/gitlab/-/issues/340781#note_699114700 @@ -986,6 +985,11 @@ module Ci object_hierarchy(project_condition: :same).base_and_descendants end + # With only parent-child pipelines + def all_child_pipelines + object_hierarchy(project_condition: :same).descendants + end + def self_and_descendants_complete? self_and_descendants.all?(&:complete?) end @@ -1323,6 +1327,42 @@ module Ci private + def cancel_jobs(jobs, retries: 1, auto_canceled_by_pipeline_id: nil) + retry_lock(jobs, retries, name: 'ci_pipeline_cancel_running') do |statuses| + preloaded_relations = [:project, :pipeline, :deployment, :taggings] + + statuses.find_in_batches do |status_batch| + relation = CommitStatus.where(id: status_batch) + Preloaders::CommitStatusPreloader.new(relation).execute(preloaded_relations) + + relation.each do |job| + job.auto_canceled_by_id = auto_canceled_by_pipeline_id if auto_canceled_by_pipeline_id + job.cancel + end + end + end + end + + # For parent child-pipelines only (not multi-project) + def cancel_children(auto_canceled_by_pipeline_id: nil, execute_async: true) + all_child_pipelines.each do |child_pipeline| + if execute_async + ::Ci::CancelPipelineWorker.perform_async( + child_pipeline.id, + auto_canceled_by_pipeline_id + ) + else + child_pipeline.cancel_running( + # cascade_to_children is false because we iterate through children + # we also cancel bridges prior to prevent more children + cascade_to_children: false, + execute_async: execute_async, + auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id + ) + end + end + end + def add_message(severity, content) messages.build(severity: severity, content: content) end diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb index 68ba3d6eab4..31e5e6f73bf 100644 --- a/app/models/personal_access_token.rb +++ b/app/models/personal_access_token.rb @@ -33,6 +33,7 @@ class PersonalAccessToken < ApplicationRecord scope :preload_users, -> { preload(:user) } scope :order_expires_at_asc, -> { reorder(expires_at: :asc) } scope :order_expires_at_desc, -> { reorder(expires_at: :desc) } + scope :order_expires_at_asc_id_desc, -> { reorder(expires_at: :asc, id: :desc) } scope :project_access_token, -> { includes(:user).where(user: { user_type: :project_bot }) } scope :owner_is_human, -> { includes(:user).where(user: { user_type: :human }) } @@ -77,7 +78,8 @@ class PersonalAccessToken < ApplicationRecord super.merge( { 'expires_at_asc' => -> { order_expires_at_asc }, - 'expires_at_desc' => -> { order_expires_at_desc } + 'expires_at_desc' => -> { order_expires_at_desc }, + 'expires_at_asc_id_desc' => -> { order_expires_at_asc_id_desc } } ) end diff --git a/app/models/project.rb b/app/models/project.rb index c8d7afdd46f..39a7541e5d3 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1041,6 +1041,13 @@ class Project < ApplicationRecord def emails_enabled? !emails_disabled? end + + def cascade_cancel_pipelines_enabled? + strong_memoize(:cascade_cancel_pipelines_enabled) do + Feature.enabled?(:ci_parent_pipeline_cancels_children, self) + end + end + override :lfs_enabled? def lfs_enabled? return namespace.lfs_enabled? if self[:lfs_enabled].nil? diff --git a/app/serializers/group_access_token_entity.rb b/app/serializers/group_access_token_entity.rb new file mode 100644 index 00000000000..e832eef1188 --- /dev/null +++ b/app/serializers/group_access_token_entity.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +# rubocop: disable Gitlab/NamespacedClass +class GroupAccessTokenEntity < API::Entities::PersonalAccessToken + include Gitlab::Routing + + expose :revoke_path do |token, options| + group = options.fetch(:group) + + next unless group + + revoke_group_settings_access_token_path( + id: token, + group_id: group.path) + end + + expose :access_level do |token, options| + group = options.fetch(:group) + + next unless group + next unless token.user + + group.member(token.user)&.access_level + end +end +# rubocop: enable Gitlab/NamespacedClass diff --git a/app/serializers/group_access_token_serializer.rb b/app/serializers/group_access_token_serializer.rb new file mode 100644 index 00000000000..55f6de77844 --- /dev/null +++ b/app/serializers/group_access_token_serializer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# rubocop: disable Gitlab/NamespacedClass +class GroupAccessTokenSerializer < BaseSerializer + entity GroupAccessTokenEntity +end +# rubocop: enable Gitlab/NamespacedClass diff --git a/app/serializers/personal_access_token_entity.rb b/app/serializers/personal_access_token_entity.rb new file mode 100644 index 00000000000..acd06fecd12 --- /dev/null +++ b/app/serializers/personal_access_token_entity.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +# rubocop: disable Gitlab/NamespacedClass +class PersonalAccessTokenEntity < API::Entities::PersonalAccessToken + include Gitlab::Routing + + expose :revoke_path do |token, options| + revoke_profile_personal_access_token_path(token) + end +end +# rubocop: enable Gitlab/NamespacedClass diff --git a/app/serializers/personal_access_token_serializer.rb b/app/serializers/personal_access_token_serializer.rb new file mode 100644 index 00000000000..0a59fa117f9 --- /dev/null +++ b/app/serializers/personal_access_token_serializer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# rubocop: disable Gitlab/NamespacedClass +class PersonalAccessTokenSerializer < BaseSerializer + entity PersonalAccessTokenEntity +end +# rubocop: enable Gitlab/NamespacedClass diff --git a/app/serializers/project_access_token_entity.rb b/app/serializers/project_access_token_entity.rb new file mode 100644 index 00000000000..b317057c952 --- /dev/null +++ b/app/serializers/project_access_token_entity.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +# rubocop: disable Gitlab/NamespacedClass +class ProjectAccessTokenEntity < API::Entities::PersonalAccessToken + include Gitlab::Routing + + expose :revoke_path do |token, options| + project = options.fetch(:project) + + next unless project + + revoke_namespace_project_settings_access_token_path( + id: token, + namespace_id: project.namespace.path, + project_id: project.path) + end + + expose :access_level do |token, options| + project = options.fetch(:project) + + next unless project + next unless token.user + + project.member(token.user)&.access_level + end +end +# rubocop: enable Gitlab/NamespacedClass diff --git a/app/serializers/project_access_token_serializer.rb b/app/serializers/project_access_token_serializer.rb new file mode 100644 index 00000000000..97db088cf64 --- /dev/null +++ b/app/serializers/project_access_token_serializer.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# rubocop: disable Gitlab/NamespacedClass +class ProjectAccessTokenSerializer < BaseSerializer + entity ProjectAccessTokenEntity +end +# rubocop: enable Gitlab/NamespacedClass diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb index d85e52e1312..1c563396162 100644 --- a/app/services/ci/destroy_pipeline_service.rb +++ b/app/services/ci/destroy_pipeline_service.rb @@ -7,7 +7,7 @@ module Ci Ci::ExpirePipelineCacheService.new.execute(pipeline, delete: true) - pipeline.cancel_running if pipeline.cancelable? + pipeline.cancel_running(cascade_to_children: true, execute_async: false) if pipeline.cancelable? # The pipeline, the builds, job and pipeline artifacts all get destroyed here. # Ci::Pipeline#destroy triggers fast destroy on job_artifacts and diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index a1a5248c060..22503531008 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -2109,6 +2109,15 @@ :weight: 2 :idempotent: false :tags: [] +- :name: ci_cancel_pipeline + :worker_name: Ci::CancelPipelineWorker + :feature_category: :continuous_integration + :has_external_dependencies: false + :urgency: :high + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: ci_delete_objects :worker_name: Ci::DeleteObjectsWorker :feature_category: :continuous_integration diff --git a/app/workers/ci/cancel_pipeline_worker.rb b/app/workers/ci/cancel_pipeline_worker.rb new file mode 100644 index 00000000000..147839a0625 --- /dev/null +++ b/app/workers/ci/cancel_pipeline_worker.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Ci + class CancelPipelineWorker + include ApplicationWorker + + # lots of updates to ci_builds + data_consistency :always + feature_category :continuous_integration + idempotent! + deduplicate :until_executed + urgency :high + + def perform(pipeline_id, auto_canceled_by_pipeline_id) + ::Ci::Pipeline.find_by_id(pipeline_id).try do |pipeline| + pipeline.cancel_running( + # cascade_to_children is false because we iterate through children + # we also cancel bridges prior to prevent more children + cascade_to_children: false, + auto_canceled_by_pipeline_id: auto_canceled_by_pipeline_id + ) + end + end + end +end |