diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-12 00:08:18 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-12 00:08:18 +0300 |
commit | d5012fff67191be53070d024a89195a666a581ed (patch) | |
tree | 08d4334c0202f365a5513dd2147d5a411fe05bcb /app | |
parent | 1a2f754734eb189e371e25e685413808f69a7f2c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
28 files changed, 296 insertions, 127 deletions
diff --git a/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue b/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue new file mode 100644 index 00000000000..4c0f99cf62c --- /dev/null +++ b/app/assets/javascripts/ml/experiment_tracking/components/delete_button.vue @@ -0,0 +1,98 @@ +<script> +import { + GlModal, + GlDropdown, + GlTooltipDirective, + GlDropdownItem, + GlModalDirective, +} from '@gitlab/ui'; +import { __ } from '~/locale'; +import csrf from '~/lib/utils/csrf'; + +export default { + components: { + GlModal, + GlDropdown, + GlDropdownItem, + }, + directives: { + GlTooltip: GlTooltipDirective, + GlModalDirective, + }, + props: { + deletePath: { + type: String, + required: true, + }, + deleteConfirmationText: { + type: String, + required: true, + }, + actionPrimaryText: { + type: String, + required: true, + }, + modalTitle: { + type: String, + required: true, + }, + }, + data() { + return { + isDeleteModalVisible: false, + modal: { + id: 'ml-experiments-delete-modal', + deleteConfirmation: this.deleteConfirmationText, + actionPrimary: { + text: this.actionPrimaryText, + attributes: { variant: 'danger' }, + }, + actionCancel: { + text: __('Cancel'), + }, + }, + }; + }, + methods: { + confirmDelete() { + this.$refs.deleteForm.submit(); + }, + }, + csrf, +}; +</script> + +<template> + <gl-dropdown + right + category="tertiary" + :aria-label="__('More actions')" + icon="ellipsis_v" + no-caret + > + <gl-dropdown-item + v-gl-modal-directive="modal.id" + :aria-label="actionPrimaryText" + variant="danger" + > + {{ actionPrimaryText }} + + <form ref="deleteForm" method="post" :action="deletePath"> + <input type="hidden" name="_method" value="delete" /> + <input type="hidden" name="authenticity_token" :value="$options.csrf.token" /> + </form> + + <gl-modal + :modal-id="modal.id" + :title="modalTitle" + :action-primary="modal.actionPrimary" + :action-cancel="modal.actionCancel" + @primary="confirmDelete" + > + <p> + {{ deleteConfirmationText }} + </p> + </gl-modal> + </gl-dropdown-item> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue index ca0a42fda10..40b9e0723e9 100644 --- a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue +++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/ml_experiments_show.vue @@ -12,6 +12,7 @@ import { queryToObject, setUrlParams, visitUrl } from '~/lib/utils/url_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import KeysetPagination from '~/vue_shared/components/incubation/pagination.vue'; import IncubationAlert from '~/vue_shared/components/incubation/incubation_alert.vue'; +import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue'; import { LIST_KEY_CREATED_AT, BASE_SORT_FIELDS, @@ -30,8 +31,13 @@ export default { IncubationAlert, RegistrySearch, KeysetPagination, + DeleteButton, }, props: { + experiment: { + type: Object, + required: true, + }, candidates: { type: Array, required: true, @@ -157,6 +163,21 @@ export default { :link-to-feedback-issue="$options.constants.FEATURE_FEEDBACK_ISSUE" /> + <div class="detail-page-header gl-flex-wrap-wrap"> + <div class="detail-page-header-body"> + <h1 class="page-title gl-font-size-h-display flex-fill"> + {{ experiment.name }} + </h1> + + <delete-button + :delete-path="experiment.path" + :delete-confirmation-text="$options.i18n.DELETE_EXPERIMENT_CONFIRMATION_MESSAGE" + :action-primary-text="$options.i18n.DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL" + :modal-title="$options.i18n.DELETE_EXPERIMENT_MODAL_TITLE" + /> + </div> + </div> + <registry-search :filters="filters" :sorting="sorting" diff --git a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js index 63b0d902b72..5c34a66921d 100644 --- a/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js +++ b/app/assets/javascripts/ml/experiment_tracking/routes/experiments/show/translations.js @@ -14,3 +14,8 @@ export const EMPTY_STATE_DESCRIPTION_LABEL = s__( 'MlExperimentTracking|No candidates logged for the query. Create new candidates using the MLflow client.', ); export const EMPTY_STATE_TITLE_LABEL = s__('MlExperimentTracking|No candidates'); +export const DELETE_EXPERIMENT_CONFIRMATION_MESSAGE = s__( + 'MlExperimentTracking|Deleting this experiment will also delete its candidates and their associated metadata.', +); +export const DELETE_EXPERIMENT_PRIMARY_ACTION_LABEL = s__('MlExperimentTracking|Delete experiment'); +export const DELETE_EXPERIMENT_MODAL_TITLE = s__('MLExperimentTracking|Delete experiment?'); diff --git a/app/assets/javascripts/pages/projects/ml/experiments/show/index.js b/app/assets/javascripts/pages/projects/ml/experiments/show/index.js index a90cabb3c68..f50763151ef 100644 --- a/app/assets/javascripts/pages/projects/ml/experiments/show/index.js +++ b/app/assets/javascripts/pages/projects/ml/experiments/show/index.js @@ -9,6 +9,7 @@ const initShowExperiment = () => { } const props = { + experiment: JSON.parse(element.dataset.experiment), candidates: JSON.parse(element.dataset.candidates), metricNames: JSON.parse(element.dataset.metrics), paramNames: JSON.parse(element.dataset.params), diff --git a/app/assets/javascripts/super_sidebar/components/context_switcher.vue b/app/assets/javascripts/super_sidebar/components/context_switcher.vue index 2f036c7ddcc..5c1cebe0195 100644 --- a/app/assets/javascripts/super_sidebar/components/context_switcher.vue +++ b/app/assets/javascripts/super_sidebar/components/context_switcher.vue @@ -13,7 +13,7 @@ export default { i18n: { contextNavigation: s__('Navigation|Context navigation'), switchTo: s__('Navigation|Switch to...'), - searchPlaceholder: s__('Navigation|Search for projects or groups'), + searchPlaceholder: s__('Navigation|Search your projects or groups'), searchingLabel: s__('Navigation|Retrieving search results'), searchError: s__('Navigation|There was an error fetching search results.'), }, diff --git a/app/assets/javascripts/super_sidebar/components/groups_list.vue b/app/assets/javascripts/super_sidebar/components/groups_list.vue index 78b5ed2d31e..1360d58dc6c 100644 --- a/app/assets/javascripts/super_sidebar/components/groups_list.vue +++ b/app/assets/javascripts/super_sidebar/components/groups_list.vue @@ -39,7 +39,7 @@ export default { viewAllItem() { return { link: this.viewAllLink, - title: s__('Navigation|View all groups'), + title: s__('Navigation|View all your groups'), icon: 'group', }; }, diff --git a/app/assets/javascripts/super_sidebar/components/projects_list.vue b/app/assets/javascripts/super_sidebar/components/projects_list.vue index a545de06bd4..de22f5d9897 100644 --- a/app/assets/javascripts/super_sidebar/components/projects_list.vue +++ b/app/assets/javascripts/super_sidebar/components/projects_list.vue @@ -39,7 +39,7 @@ export default { viewAllItem() { return { link: this.viewAllLink, - title: s__('Navigation|View all projects'), + title: s__('Navigation|View all your projects'), icon: 'project', }; }, diff --git a/app/graphql/types/ci/job_type.rb b/app/graphql/types/ci/job_type.rb index 60c1c2e601d..61f2d0cdb51 100644 --- a/app/graphql/types/ci/job_type.rb +++ b/app/graphql/types/ci/job_type.rb @@ -25,8 +25,8 @@ module Types description: 'References to builds that must complete before the jobs run.' field :pipeline, Types::Ci::PipelineType, null: true, description: 'Pipeline the job belongs to.' - field :runner_machine, ::Types::Ci::RunnerMachineType, null: true, - description: 'Runner machine assigned to the job.', + field :runner_manager, ::Types::Ci::RunnerManagerType, null: true, + description: 'Runner manager assigned to the job.', alpha: { milestone: '15.11' } field :stage, Types::Ci::StageType, null: true, description: 'Stage of the job.' @@ -172,17 +172,16 @@ module Types ::Gitlab::Graphql::Loaders::BatchModelLoader.new(::Ci::Stage, object.stage_id).find end - def runner_machine - BatchLoader::GraphQL.for(object.id).batch(key: :runner_machines) do |build_ids, loader| - plucked_build_to_machine_ids = ::Ci::RunnerMachineBuild.for_build(build_ids).pluck_build_id_and_runner_machine_id - runner_machines = ::Ci::RunnerMachine.id_in(plucked_build_to_machine_ids.values.uniq) - Preloaders::RunnerMachinePolicyPreloader.new(runner_machines, current_user).execute - runner_machines_by_id = runner_machines.index_by(&:id) + def runner_manager + BatchLoader::GraphQL.for(object.id).batch(key: :runner_managers) do |build_ids, loader| + plucked_build_to_runner_manager_ids = + ::Ci::RunnerManagerBuild.for_build(build_ids).pluck_build_id_and_runner_manager_id + runner_managers = ::Ci::RunnerManager.id_in(plucked_build_to_runner_manager_ids.values.uniq) + Preloaders::RunnerManagerPolicyPreloader.new(runner_managers, current_user).execute + runner_managers_by_id = runner_managers.index_by(&:id) build_ids.each do |build_id| - runner_machine_id = plucked_build_to_machine_ids[build_id] - - loader.call(build_id, runner_machines_by_id[runner_machine_id]) + loader.call(build_id, runner_managers_by_id[plucked_build_to_runner_manager_ids[build_id]]) end end end diff --git a/app/graphql/types/ci/runner_machine_type.rb b/app/graphql/types/ci/runner_manager_type.rb index 8e6656288d9..2a5053f8f07 100644 --- a/app/graphql/types/ci/runner_machine_type.rb +++ b/app/graphql/types/ci/runner_manager_type.rb @@ -2,50 +2,48 @@ module Types module Ci - class RunnerMachineType < BaseObject - graphql_name 'CiRunnerMachine' + class RunnerManagerType < BaseObject + graphql_name 'CiRunnerManager' connection_type_class(::Types::CountableConnectionType) - authorize :read_runner_machine + authorize :read_runner_manager - alias_method :runner_machine, :object + alias_method :runner_manager, :object field :architecture_name, GraphQL::Types::String, null: true, - description: 'Architecture provided by the runner machine.', + description: 'Architecture provided by the runner manager.', method: :architecture field :contacted_at, Types::TimeType, null: true, - description: 'Timestamp of last contact from the runner machine.', + description: 'Timestamp of last contact from the runner manager.', method: :contacted_at field :created_at, Types::TimeType, null: true, - description: 'Timestamp of creation of the runner machine.' + description: 'Timestamp of creation of the runner manager.' field :executor_name, GraphQL::Types::String, null: true, description: 'Executor last advertised by the runner.', method: :executor_name - field :id, ::Types::GlobalIDType[::Ci::RunnerMachine], null: false, - description: 'ID of the runner machine.' + field :id, ::Types::GlobalIDType[::Ci::RunnerManager], null: false, + description: 'ID of the runner manager.' field :ip_address, GraphQL::Types::String, null: true, - description: 'IP address of the runner machine.' + description: 'IP address of the runner manager.' field :platform_name, GraphQL::Types::String, null: true, - description: 'Platform provided by the runner machine.', + description: 'Platform provided by the runner manager.', method: :platform field :revision, GraphQL::Types::String, null: true, description: 'Revision of the runner.' - field :runner, RunnerType, null: true, description: 'Runner configuration for the runner machine.' + field :runner, RunnerType, null: true, description: 'Runner configuration for the runner manager.' field :status, Types::Ci::RunnerStatusEnum, null: false, - description: 'Status of the runner machine.' + description: 'Status of the runner manager.' field :system_id, GraphQL::Types::String, null: false, - description: 'System ID associated with the runner machine.', + description: 'System ID associated with the runner manager.', method: :system_xid field :version, GraphQL::Types::String, null: true, description: 'Version of the runner.' def executor_name - ::Ci::Runner::EXECUTOR_TYPE_TO_NAMES[runner_machine.executor_type&.to_sym] + ::Ci::Runner::EXECUTOR_TYPE_TO_NAMES[runner_manager.executor_type&.to_sym] end end end end - -Types::Ci::RunnerType.prepend_mod_with('Types::Ci::RunnerType') diff --git a/app/graphql/types/ci/runner_type.rb b/app/graphql/types/ci/runner_type.rb index 60ea78752ca..8b0a969f7f5 100644 --- a/app/graphql/types/ci/runner_type.rb +++ b/app/graphql/types/ci/runner_type.rb @@ -39,7 +39,7 @@ module Types field :edit_admin_url, GraphQL::Types::String, null: true, description: 'Admin form URL of the runner. Only available for administrators.' field :ephemeral_authentication_token, GraphQL::Types::String, null: true, - description: 'Ephemeral authentication token used for runner machine registration. Only available for the creator of the runner for a limited time during registration.', + description: 'Ephemeral authentication token used for runner manager registration. Only available for the creator of the runner for a limited time during registration.', authorize: :read_ephemeral_token, alpha: { milestone: '15.9' } field :executor_name, GraphQL::Types::String, null: true, @@ -65,12 +65,12 @@ module Types resolver: ::Resolvers::Ci::RunnerJobsResolver field :locked, GraphQL::Types::Boolean, null: true, description: 'Indicates the runner is locked.' - field :machines, ::Types::Ci::RunnerMachineType.connection_type, null: true, - description: 'Machines associated with the runner configuration.', - method: :runner_machines, - alpha: { milestone: '15.10' } field :maintenance_note, GraphQL::Types::String, null: true, description: 'Runner\'s maintenance notes.' + field :managers, ::Types::Ci::RunnerManagerType.connection_type, null: true, + description: 'Machines associated with the runner configuration.', + method: :runner_managers, + alpha: { milestone: '15.10' } field :maximum_timeout, GraphQL::Types::Int, null: true, description: 'Maximum timeout (in seconds) for jobs processed by the runner.' field :owner_project, ::Types::ProjectType, null: true, diff --git a/app/helpers/projects/ml/experiments_helper.rb b/app/helpers/projects/ml/experiments_helper.rb index 55216d412a5..927337da6bb 100644 --- a/app/helpers/projects/ml/experiments_helper.rb +++ b/app/helpers/projects/ml/experiments_helper.rb @@ -24,6 +24,15 @@ module Projects Gitlab::Json.generate(data) end + def experiment_as_data(experiment) + data = { + name: experiment.name, + path: link_to_experiment(experiment.project, experiment) + } + + Gitlab::Json.generate(data) + end + def candidates_table_items(candidates) items = candidates.map do |candidate| { diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 9762106755b..d389c59f16b 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -55,9 +55,9 @@ module Ci has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', foreign_key: :job_id, inverse_of: :job end - has_one :runner_machine_build, class_name: 'Ci::RunnerMachineBuild', foreign_key: :build_id, inverse_of: :build, + has_one :runner_manager_build, class_name: 'Ci::RunnerManagerBuild', foreign_key: :build_id, inverse_of: :build, autosave: true - has_one :runner_machine, through: :runner_machine_build, class_name: 'Ci::RunnerMachine' + has_one :runner_manager, foreign_key: :runner_machine_id, through: :runner_manager_build, class_name: 'Ci::RunnerManager' has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, foreign_key: :build_id, inverse_of: :build has_one :trace_metadata, class_name: 'Ci::BuildTraceMetadata', foreign_key: :build_id, inverse_of: :build diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 1e5108a873e..80a3d8df632 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -70,7 +70,7 @@ module Ci TAG_LIST_MAX_LENGTH = 50 - has_many :runner_machines, inverse_of: :runner + has_many :runner_managers, inverse_of: :runner has_many :builds has_many :runner_projects, inverse_of: :runner, autosave: true, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent has_many :projects, through: :runner_projects, disable_joins: true @@ -496,14 +496,14 @@ module Ci end end - def ensure_machine(system_xid, &blk) - RunnerMachine.safe_find_or_create_by!(runner_id: id, system_xid: system_xid.to_s, &blk) # rubocop: disable Performance/ActiveRecordSubtransactionMethods + def ensure_manager(system_xid, &blk) + RunnerManager.safe_find_or_create_by!(runner_id: id, system_xid: system_xid.to_s, &blk) # rubocop: disable Performance/ActiveRecordSubtransactionMethods end def registration_available? authenticated_user_registration_type? && created_at > REGISTRATION_AVAILABILITY_TIME.ago && - !runner_machines.any? + !runner_managers.any? end private diff --git a/app/models/ci/runner_machine_build.rb b/app/models/ci/runner_machine_build.rb deleted file mode 100644 index d4f2c403337..00000000000 --- a/app/models/ci/runner_machine_build.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -module Ci - class RunnerMachineBuild < Ci::ApplicationRecord - include Ci::Partitionable - - self.table_name = :p_ci_runner_machine_builds - self.primary_key = :build_id - - partitionable scope: :build, partitioned: true - - belongs_to :build, inverse_of: :runner_machine_build, class_name: 'Ci::Build' - belongs_to :runner_machine, inverse_of: :runner_machine_builds, class_name: 'Ci::RunnerMachine' - - validates :build, presence: true - validates :runner_machine, presence: true - - scope :for_build, ->(build_id) { where(build_id: build_id) } - - def self.pluck_build_id_and_runner_machine_id - select(:build_id, :runner_machine_id) - .pluck(:build_id, :runner_machine_id) - .to_h - end - end -end diff --git a/app/models/ci/runner_machine.rb b/app/models/ci/runner_manager.rb index a9c411eb3a2..e36024d9f5b 100644 --- a/app/models/ci/runner_machine.rb +++ b/app/models/ci/runner_manager.rb @@ -1,19 +1,22 @@ # frozen_string_literal: true module Ci - class RunnerMachine < Ci::ApplicationRecord + class RunnerManager < Ci::ApplicationRecord include FromUnion include RedisCacheable include Ci::HasRunnerExecutor + # For legacy reasons, the table name is ci_runner_machines in the database + self.table_name = 'ci_runner_machines' + # The `UPDATE_CONTACT_COLUMN_EVERY` defines how often the Runner Machine DB entry can be updated UPDATE_CONTACT_COLUMN_EVERY = (40.minutes)..(55.minutes) belongs_to :runner - has_many :runner_machine_builds, inverse_of: :runner_machine, class_name: 'Ci::RunnerMachineBuild' - has_many :builds, through: :runner_machine_builds, class_name: 'Ci::Build' - belongs_to :runner_version, inverse_of: :runner_machines, primary_key: :version, foreign_key: :version, + has_many :runner_manager_builds, inverse_of: :runner_manager, class_name: 'Ci::RunnerManagerBuild' + has_many :builds, through: :runner_manager_builds, class_name: 'Ci::Build' + belongs_to :runner_version, inverse_of: :runner_managers, primary_key: :version, foreign_key: :version, class_name: 'Ci::RunnerVersion' validates :runner, presence: true @@ -27,7 +30,7 @@ module Ci cached_attr_reader :version, :revision, :platform, :architecture, :ip_address, :contacted_at, :executor_type - # The `STALE_TIMEOUT` constant defines the how far past the last contact or creation date a runner machine + # The `STALE_TIMEOUT` constant defines the how far past the last contact or creation date a runner manager # will be considered stale STALE_TIMEOUT = 7.days diff --git a/app/models/ci/runner_manager_build.rb b/app/models/ci/runner_manager_build.rb new file mode 100644 index 00000000000..322c5ae3a68 --- /dev/null +++ b/app/models/ci/runner_manager_build.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module Ci + class RunnerManagerBuild < Ci::ApplicationRecord + include Ci::Partitionable + + self.table_name = :p_ci_runner_machine_builds + self.primary_key = :build_id + + partitionable scope: :build, partitioned: true + + alias_attribute :runner_manager_id, :runner_machine_id + + belongs_to :build, inverse_of: :runner_manager_build, class_name: 'Ci::Build' + belongs_to :runner_manager, foreign_key: :runner_machine_id, inverse_of: :runner_manager_builds, + class_name: 'Ci::RunnerManager' + + validates :build, presence: true + validates :runner_manager, presence: true + + scope :for_build, ->(build_id) { where(build_id: build_id) } + + def self.pluck_build_id_and_runner_manager_id + select(:build_id, :runner_manager_id) + .pluck(:build_id, :runner_manager_id) + .to_h + end + end +end diff --git a/app/models/ci/runner_version.rb b/app/models/ci/runner_version.rb index 41e7a2b8e8a..03b50f13989 100644 --- a/app/models/ci/runner_version.rb +++ b/app/models/ci/runner_version.rb @@ -19,7 +19,7 @@ module Ci recommended: 'Upgrade is available and recommended for the runner.' }.freeze - has_many :runner_machines, inverse_of: :runner_version, foreign_key: :version, class_name: 'Ci::RunnerMachine' + has_many :runner_managers, inverse_of: :runner_version, foreign_key: :version, class_name: 'Ci::RunnerManager' # This scope returns all versions that might need recalculating. For instance, once a version is considered # :recommended, it normally doesn't change status even if the instance is upgraded diff --git a/app/models/concerns/ci/partitionable.rb b/app/models/concerns/ci/partitionable.rb index 5268970db00..d8417773dbd 100644 --- a/app/models/concerns/ci/partitionable.rb +++ b/app/models/concerns/ci/partitionable.rb @@ -36,7 +36,7 @@ module Ci Ci::Pipeline Ci::PendingBuild Ci::RunningBuild - Ci::RunnerMachineBuild + Ci::RunnerManagerBuild Ci::PipelineVariable Ci::Sources::Pipeline Ci::Stage diff --git a/app/models/preloaders/runner_machine_policy_preloader.rb b/app/models/preloaders/runner_machine_policy_preloader.rb deleted file mode 100644 index 52864eeba8d..00000000000 --- a/app/models/preloaders/runner_machine_policy_preloader.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -module Preloaders - class RunnerMachinePolicyPreloader - def initialize(runner_machines, current_user) - @runner_machines = runner_machines - @current_user = current_user - end - - def execute - return if runner_machines.is_a?(ActiveRecord::NullRelation) - - ActiveRecord::Associations::Preloader.new( - records: runner_machines, - associations: [:runner] - ).call - end - - private - - attr_reader :runner_machines, :current_user - end -end diff --git a/app/models/preloaders/runner_manager_policy_preloader.rb b/app/models/preloaders/runner_manager_policy_preloader.rb new file mode 100644 index 00000000000..788a3d25a87 --- /dev/null +++ b/app/models/preloaders/runner_manager_policy_preloader.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module Preloaders + class RunnerManagerPolicyPreloader + def initialize(runner_managers, current_user) + @runner_managers = runner_managers + @current_user = current_user + end + + def execute + return if runner_managers.is_a?(ActiveRecord::NullRelation) + + ActiveRecord::Associations::Preloader.new( + records: runner_managers, + associations: [:runner] + ).call + end + + private + + attr_reader :runner_managers, :current_user + end +end diff --git a/app/policies/ci/runner_machine_policy.rb b/app/policies/ci/runner_manager_policy.rb index 9893d7dee14..43e81e373fc 100644 --- a/app/policies/ci/runner_machine_policy.rb +++ b/app/policies/ci/runner_manager_policy.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module Ci - class RunnerMachinePolicy < BasePolicy + class RunnerManagerPolicy < BasePolicy with_options scope: :subject, score: 0 condition(:can_read_runner, scope: :subject) do @@ -12,7 +12,7 @@ module Ci rule { can_read_runner }.policy do enable :read_builds - enable :read_runner_machine + enable :read_runner_manager end end end diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index 228a246f480..4b55ce149e1 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -6,7 +6,7 @@ module Ci class RegisterJobService include ::Gitlab::Ci::Artifacts::Logger - attr_reader :runner, :runner_machine, :metrics + attr_reader :runner, :runner_manager, :metrics TEMPORARY_LOCK_TIMEOUT = 3.seconds @@ -18,9 +18,9 @@ module Ci # affect 5% of the worst case scenarios. MAX_QUEUE_DEPTH = 45 - def initialize(runner, runner_machine) + def initialize(runner, runner_manager) @runner = runner - @runner_machine = runner_machine + @runner_manager = runner_manager @metrics = ::Gitlab::Ci::Queue::Metrics.new(runner) end @@ -255,7 +255,7 @@ module Ci @metrics.increment_queue_operation(:runner_pre_assign_checks_success) build.run! - build.runner_machine = runner_machine if runner_machine + build.runner_manager = runner_manager if runner_manager end !failure_reason diff --git a/app/services/ci/runners/stale_machines_cleanup_service.rb b/app/services/ci/runners/stale_managers_cleanup_service.rb index 3e5706d24a6..b39f7315bc6 100644 --- a/app/services/ci/runners/stale_machines_cleanup_service.rb +++ b/app/services/ci/runners/stale_managers_cleanup_service.rb @@ -2,25 +2,25 @@ module Ci module Runners - class StaleMachinesCleanupService + class StaleManagersCleanupService MAX_DELETIONS = 1000 def execute ServiceResponse.success(payload: { # the `stale` relationship can return duplicates, so we don't try to return a precise count here - deleted_machines: delete_stale_runner_machines > 0 + deleted_managers: delete_stale_runner_managers > 0 }) end private - def delete_stale_runner_machines + def delete_stale_runner_managers total_deleted_count = 0 loop do sub_batch_limit = [100, MAX_DELETIONS].min # delete_all discards part of the `stale` scope query, so we expliclitly wrap it with a SELECT as a workaround - deleted_count = Ci::RunnerMachine.id_in(Ci::RunnerMachine.stale.limit(sub_batch_limit)).delete_all + deleted_count = Ci::RunnerManager.id_in(Ci::RunnerManager.stale.limit(sub_batch_limit)).delete_all total_deleted_count += deleted_count break if deleted_count == 0 || total_deleted_count >= MAX_DELETIONS diff --git a/app/views/projects/issues/_related_branches.html.haml b/app/views/projects/issues/_related_branches.html.haml index 466eca2fdb0..d26b0f96992 100644 --- a/app/views/projects/issues/_related_branches.html.haml +++ b/app/views/projects/issues/_related_branches.html.haml @@ -1,12 +1,24 @@ - if @related_branches.any? - %h2.gl-font-lg - = pluralize(@related_branches.size, 'Related Branch') - %ul.related-merge-requests.gl-pl-0.gl-mb-3 - - @related_branches.each do |branch| - %li.gl-display-flex.gl-align-items-center - - if branch[:pipeline_status].present? - %span.related-branch-ci-status - = render 'ci/status/icon', status: branch[:pipeline_status] - %span.related-branch-info - %strong - = link_to branch[:name], branch[:link], class: "ref-name" + - if @related_branches.any? + = render Pajamas::CardComponent.new(card_options: { class: 'gl-bg-gray-10 gl-mt-5 gl-mb-0' }, header_options: { class: 'gl-bg-white gl-pl-5 gl-pr-4 gl-py-4' } , body_options: { class: 'gl-py-3 gl-px-4' }) do |c| + - c.header do + %h3.card-title.h5.gl-my-0.gl-display-flex.gl-align-items-center.gl-flex-grow-1.gl-relative.gl-line-height-24 + = link_to "", "#related-branches", class: "gl-link anchor position-absolute gl-text-decoration-none", "aria-hidden": true + = _('Related branches') + .gl-display-inline-flex.gl-mx-3.gl-text-gray-500 + .gl-display-inline-flex.gl-align-items-center + = sprite_icon('branch', css_class: "gl-mr-2 gl-text-gray-500 gl-icon") + = @related_branches.size + - c.body do + %ul.related-merge-requests.content-list.gl-p-3! + - @related_branches.each do |branch| + %li.list-item{ class: "gl-py-0! gl-border-0!" } + .item-body.gl-display-flex.align-items-center.gl-px-3.gl-pr-2.gl-mx-n2 + .item-contents.gl-display-flex.gl-align-items-center.gl-flex-wrap.gl-flex-grow-1.gl-min-h-7 + .item-title.gl-display-flex.mb-xl-0.gl-min-w-0 + - if branch[:pipeline_status].present? + %span.related-branch-ci-status + = render 'ci/status/icon', status: branch[:pipeline_status] + %span.related-branch-info + %strong + = link_to branch[:name], branch[:link], class: "ref-name" diff --git a/app/views/projects/ml/experiments/show.html.haml b/app/views/projects/ml/experiments/show.html.haml index 52145eb0964..cfec627d249 100644 --- a/app/views/projects/ml/experiments/show.html.haml +++ b/app/views/projects/ml/experiments/show.html.haml @@ -3,15 +3,14 @@ - page_title @experiment.name - add_page_specific_style 'page_bundles/ml_experiment_tracking' +- experiment = experiment_as_data(@experiment) - items = candidates_table_items(@candidates) - metrics = unique_logged_names(@candidates, &:latest_metrics) - params = unique_logged_names(@candidates, &:params) - page_info = formatted_page_info(@page_info) -.page-title-holder.d-flex.align-items-center - %h1.page-title.gl-font-size-h-display= @experiment.name - #js-show-ml-experiment{ data: { + experiment: experiment, candidates: items, metrics: metrics, params: params, diff --git a/app/views/shared/issue_type/_details_content.html.haml b/app/views/shared/issue_type/_details_content.html.haml index d6a05934cae..fdbe247c6ba 100644 --- a/app/views/shared/issue_type/_details_content.html.haml +++ b/app/views/shared/issue_type/_details_content.html.haml @@ -30,14 +30,14 @@ #js-related-merge-requests{ data: { endpoint: expose_path(api_v4_projects_issues_related_merge_requests_path(id: @project.id, issue_iid: issuable.iid)), project_namespace: @project.namespace.path, project_path: @project.path } } - - if can?(current_user, :admin_feature_flags_issue_links, @project) - = render_if_exists 'projects/issues/related_feature_flags' - - if can?(current_user, :read_code, @project) - add_page_startup_api_call related_branches_path #related-branches{ data: { url: related_branches_path } } -# This element is filled in using JavaScript. + - if can?(current_user, :admin_feature_flags_issue_links, @project) + = render_if_exists 'projects/issues/related_feature_flags' + .js-issue-widgets = render 'projects/issues/discussion' diff --git a/app/workers/ci/runners/stale_machines_cleanup_cron_worker.rb b/app/workers/ci/runners/stale_machines_cleanup_cron_worker.rb index 9a11db33fb6..9407e7c0e0a 100644 --- a/app/workers/ci/runners/stale_machines_cleanup_cron_worker.rb +++ b/app/workers/ci/runners/stale_machines_cleanup_cron_worker.rb @@ -15,7 +15,7 @@ module Ci idempotent! def perform - result = ::Ci::Runners::StaleMachinesCleanupService.new.execute + result = ::Ci::Runners::StaleManagersCleanupService.new.execute log_extra_metadata_on_done(:status, result.status) log_hash_metadata_on_done(result.payload) end diff --git a/app/workers/gitlab/github_gists_import/import_gist_worker.rb b/app/workers/gitlab/github_gists_import/import_gist_worker.rb index fb7fb661f4c..8cbbe35dd30 100644 --- a/app/workers/gitlab/github_gists_import/import_gist_worker.rb +++ b/app/workers/gitlab/github_gists_import/import_gist_worker.rb @@ -14,12 +14,21 @@ module Gitlab sidekiq_options dead: false, retry: 5 + sidekiq_retries_exhausted do |msg, _| + new.track_gist_import('failed', msg['args'][0]) + end + def perform(user_id, gist_hash, notify_key) gist = ::Gitlab::GithubGistsImport::Representation::Gist.from_json_hash(gist_hash) with_logging(user_id, gist.github_identifiers) do result = importer_class.new(gist, user_id).execute - error(user_id, result.errors, gist.github_identifiers) unless result.success? + if result.success? + track_gist_import('success', user_id) + else + error(user_id, result.errors, gist.github_identifiers) + track_gist_import('failed', user_id) + end JobWaiter.notify(notify_key, jid) end @@ -29,6 +38,18 @@ module Gitlab raise end + def track_gist_import(status, user_id) + user = User.find(user_id) + + Gitlab::Tracking.event( + self.class.name, + 'create', + label: 'github_gist_import', + user: user, + status: status + ) + end + private def importer_class |