diff options
79 files changed, 829 insertions, 481 deletions
diff --git a/.gitlab/ci/rules.gitlab-ci.yml b/.gitlab/ci/rules.gitlab-ci.yml index ab5c56214be..82bd941f409 100644 --- a/.gitlab/ci/rules.gitlab-ci.yml +++ b/.gitlab/ci/rules.gitlab-ci.yml @@ -871,8 +871,6 @@ .build-images:rules:build-assets-image-as-if-foss: rules: - - <<: *if-not-canonical-namespace - when: never - <<: *if-not-ee when: never - <<: *if-merge-request-labels-pipeline-expedite @@ -1371,6 +1369,11 @@ - <<: *if-merge-request-labels-pipeline-expedite when: never - <<: *if-dot-com-gitlab-org-and-security-merge-request + changes: *ci-build-images-patterns + when: manual + allow_failure: true + - <<: *if-dot-com-gitlab-org-and-security-merge-request + changes: *code-qa-patterns when: manual allow_failure: true diff --git a/.rubocop_todo/lint/ambiguous_range.yml b/.rubocop_todo/lint/ambiguous_range.yml index 3d6f49a4846..155c1a36128 100644 --- a/.rubocop_todo/lint/ambiguous_range.yml +++ b/.rubocop_todo/lint/ambiguous_range.yml @@ -4,7 +4,7 @@ Lint/AmbiguousRange: Details: grace period Exclude: - 'app/models/ci/runner.rb' - - 'app/models/ci/runner_machine.rb' + - 'app/models/ci/runner_manager.rb' - 'app/services/clusters/agent_tokens/track_usage_service.rb' - 'lib/gitlab/seeders/ci/runner/runner_fleet_pipeline_seeder.rb' - 'spec/lib/gitlab/database/reindexing/reindex_concurrently_spec.rb' @@ -451,23 +451,23 @@ end group :test do gem 'fuubar', '~> 2.2.0' - gem 'rspec-retry', '~> 0.6.1' + gem 'rspec-retry', '~> 0.6.2' gem 'rspec_profiling', '~> 0.0.6' gem 'rspec-benchmark', '~> 0.6.0' gem 'rspec-parameterized', '~> 1.0', require: false gem 'capybara', '~> 3.39' - gem 'capybara-screenshot', '~> 1.0.22' - gem 'selenium-webdriver', '~> 3.142' + gem 'capybara-screenshot', '~> 1.0.26' + gem 'selenium-webdriver', '~> 3.142', '>= 3.142.7' gem 'graphlyte', '~> 1.0.0' gem 'shoulda-matchers', '~> 5.1.0', require: false gem 'email_spec', '~> 2.2.0' - gem 'webmock', '~> 3.9.1' + gem 'webmock', '~> 3.18.1' gem 'rails-controller-testing' gem 'concurrent-ruby', '~> 1.1' - gem 'test-prof', '~> 1.0.7' + gem 'test-prof', '~> 1.2.1' gem 'rspec_junit_formatter' gem 'guard-rspec' gem 'axe-core-rspec' diff --git a/Gemfile.checksum b/Gemfile.checksum index f3399786244..ae0ba670fcf 100644 --- a/Gemfile.checksum +++ b/Gemfile.checksum @@ -68,7 +68,7 @@ {"name":"bundler-audit","version":"0.7.0.1","platform":"ruby","checksum":"12d853cb0b92fa8868abbb539414d7a33da9e48b792e2ff28271d36c8ace8912"}, {"name":"byebug","version":"11.1.3","platform":"ruby","checksum":"2485944d2bb21283c593d562f9ae1019bf80002143cc3a255aaffd4e9cf4a35b"}, {"name":"capybara","version":"3.39.0","platform":"ruby","checksum":"a30994beb4b4f318e39e3dc81e73203bd1edf1f9ef237d82b708eb1c21b56419"}, -{"name":"capybara-screenshot","version":"1.0.22","platform":"ruby","checksum":"f86040349a0df7f723123460d9456023f7d693068338991529f10f670fa420f5"}, +{"name":"capybara-screenshot","version":"1.0.26","platform":"ruby","checksum":"816b9370a07752097c82a05f568aaf5d3b7f45c3db5d3aab2014071e1b3c0c77"}, {"name":"carrierwave","version":"1.3.3","platform":"ruby","checksum":"0f0244de2ece54c80745b755993bd26cf47d4650823e5f89c115dbc9d73a13f1"}, {"name":"cbor","version":"0.5.9.6","platform":"ruby","checksum":"434a147658dd1df24ec9e7b3297c1fd4f8a691c97d0e688b3049df8e728b2114"}, {"name":"character_set","version":"1.4.1","platform":"java","checksum":"38b632136b40e02fecba2898497b07ac640cc121f17ac536eaf19873d50053d0"}, @@ -521,7 +521,7 @@ {"name":"rspec-parameterized-core","version":"1.0.0","platform":"ruby","checksum":"287b494985e79821160af63aba4f91db8dbfa9a21cb200db34ba38f40e16ccc1"}, {"name":"rspec-parameterized-table_syntax","version":"1.0.0","platform":"ruby","checksum":"d7df951eff9c5dd367ca7d5f9ae4853bb7ab7941f9d5b35bba361d112704988c"}, {"name":"rspec-rails","version":"6.0.1","platform":"ruby","checksum":"016c8ebd5b38ce5cbce949de2f5b28f2bde7bb78d4de26940516713597b26e34"}, -{"name":"rspec-retry","version":"0.6.1","platform":"ruby","checksum":"86b7e8513c5b0c713c2e28854f4d996deb8efa6304eef50f0ad68ee6c563d8da"}, +{"name":"rspec-retry","version":"0.6.2","platform":"ruby","checksum":"6101ba23a38809811ae3484acde4ab481c54d846ac66d5037ccb40131a60d858"}, {"name":"rspec-support","version":"3.12.0","platform":"ruby","checksum":"dd4d44b247ff679b95b5607ac5641d197a5f9b1d33f916123cb98fc5f917c58b"}, {"name":"rspec_junit_formatter","version":"0.6.0","platform":"ruby","checksum":"40dde674e6ae4e6cc0ff560da25497677e34fefd2338cc467a8972f602b62b15"}, {"name":"rspec_profiling","version":"0.0.6","platform":"ruby","checksum":"7a45697f79dcec9a174a0e26703465f6bd52ee78e8d798741240bfcef38f6e6e"}, @@ -616,7 +616,7 @@ {"name":"term-ansicolor","version":"1.7.1","platform":"ruby","checksum":"92339ffec77c4bddc786a29385c91601dd52fc68feda23609bba0491229b05f7"}, {"name":"terminal-table","version":"3.0.2","platform":"ruby","checksum":"f951b6af5f3e00203fb290a669e0a85c5dd5b051b3b023392ccfd67ba5abae91"}, {"name":"terser","version":"1.0.2","platform":"ruby","checksum":"80c2e0bc7e2db4e12e8529658f9e0820e13d685ae67d745bf981f269743bb28e"}, -{"name":"test-prof","version":"1.0.7","platform":"ruby","checksum":"7df2ece7acf4f14c52788abdfdefae689b4d1cd84530b2fe7cacadf89cfce0ed"}, +{"name":"test-prof","version":"1.2.1","platform":"ruby","checksum":"ea8ac9b75cecc0be469457f9b4681d6f70e3005ff1313907d8553dd7e5c1f026"}, {"name":"test_file_finder","version":"0.1.4","platform":"ruby","checksum":"bc36d8339eac4fb9dc36514a7c5f4d389ac2fb6d010716fc715c5c8fbb98eacd"}, {"name":"text","version":"1.3.1","platform":"ruby","checksum":"2fbbbc82c1ce79c4195b13018a87cbb00d762bda39241bb3cdc32792759dd3f4"}, {"name":"thor","version":"1.2.1","platform":"ruby","checksum":"b1752153dc9c6b8d3fcaa665e9e1a00a3e73f28da5e238b81c404502e539d446"}, @@ -670,7 +670,7 @@ {"name":"warning","version":"1.3.0","platform":"ruby","checksum":"23695a5d8e50bd5c46068931b529bee0b28e4982cbcefbe77d867800dde8069e"}, {"name":"webauthn","version":"3.0.0","platform":"ruby","checksum":"3f77d422c2a8a4b31e56cf42f83414bd066e0506e9896936e1730262dc4a20e6"}, {"name":"webfinger","version":"1.2.0","platform":"ruby","checksum":"7814ef1c85da47514f65c6e5ca14205fa9ce41ea2a70785e0c872842162852a2"}, -{"name":"webmock","version":"3.9.1","platform":"ruby","checksum":"bcf6822456b234fb1bed2b0a89bff31fe0641214b44f6ba4ced2b824cf31337d"}, +{"name":"webmock","version":"3.18.1","platform":"ruby","checksum":"54c955df4ae4bec6181dd266eeec632a1808288c633f9551d81bafb53921d2d7"}, {"name":"webrick","version":"1.8.1","platform":"ruby","checksum":"19411ec6912911fd3df13559110127ea2badd0c035f7762873f58afc803e158f"}, {"name":"websocket-driver","version":"0.7.5","platform":"java","checksum":"fffa83aa188e9ac90e32a385832ec9d26acdf019538e1c7d703f2c8a323b39c8"}, {"name":"websocket-driver","version":"0.7.5","platform":"ruby","checksum":"a280c3f44dcbb0323d58bc78dc49350c05d589ab7d13267fcff08d9d5ae76b28"}, diff --git a/Gemfile.lock b/Gemfile.lock index d953709bde7..89c80be71d0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -283,7 +283,7 @@ GEM rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - capybara-screenshot (1.0.22) + capybara-screenshot (1.0.26) capybara (>= 1.0, < 4) launchy carrierwave (1.3.3) @@ -1319,7 +1319,7 @@ GEM rspec-expectations (~> 3.11) rspec-mocks (~> 3.11) rspec-support (~> 3.11) - rspec-retry (0.6.1) + rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.12.0) rspec_junit_formatter (0.6.0) @@ -1516,7 +1516,7 @@ GEM unicode-display_width (>= 1.1.1, < 3) terser (1.0.2) execjs (>= 0.3.0, < 3) - test-prof (1.0.7) + test-prof (1.2.1) test_file_finder (0.1.4) faraday (~> 1.0) text (1.3.1) @@ -1624,8 +1624,8 @@ GEM webfinger (1.2.0) activesupport httpclient (>= 2.4) - webmock (3.9.1) - addressable (>= 2.3.6) + webmock (3.18.1) + addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) webrick (1.8.1) @@ -1687,7 +1687,7 @@ DEPENDENCIES bundler-audit (~> 0.7.0.1) bundler-checksum (~> 0.1.0)! capybara (~> 3.39) - capybara-screenshot (~> 1.0.22) + capybara-screenshot (~> 1.0.26) carrierwave (~> 1.3) charlock_holmes (~> 0.7.7) cloud_profiler_agent (~> 0.0.0)! @@ -1891,7 +1891,7 @@ DEPENDENCIES rspec-benchmark (~> 0.6.0) rspec-parameterized (~> 1.0) rspec-rails (~> 6.0.1) - rspec-retry (~> 0.6.1) + rspec-retry (~> 0.6.2) rspec_junit_formatter rspec_profiling (~> 0.0.6) rubocop @@ -1907,7 +1907,7 @@ DEPENDENCIES sassc-rails (~> 2.1.0) sd_notify (~> 0.1.0) seed-fu (~> 2.3.7) - selenium-webdriver (~> 3.142) + selenium-webdriver (~> 3.142, >= 3.142.7) sentry-rails (~> 5.8.0) sentry-raven (~> 3.1) sentry-ruby (~> 5.8.0) @@ -1936,7 +1936,7 @@ DEPENDENCIES tanuki_emoji (~> 0.6) telesignenterprise (~> 2.2) terser (= 1.0.2) - test-prof (~> 1.0.7) + test-prof (~> 1.2.1) test_file_finder (~> 0.1.3) thrift (>= 0.16.0) timfel-krb5-auth (~> 0.8) @@ -1954,7 +1954,7 @@ DEPENDENCIES vmstat (~> 2.3.0) warning (~> 1.3.0) webauthn (~> 3.0) - webmock (~> 3.9.1) + webmock (~> 3.18.1) webrick (~> 1.8.1) wikicloth (= 0.8.1) yajl-ruby (~> 1.4.3) 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 diff --git a/config/events/20230407142541_Gitlab__GithubGistsImport__ImportGistWorker_create.yml b/config/events/20230407142541_Gitlab__GithubGistsImport__ImportGistWorker_create.yml new file mode 100644 index 00000000000..efc1c443e5d --- /dev/null +++ b/config/events/20230407142541_Gitlab__GithubGistsImport__ImportGistWorker_create.yml @@ -0,0 +1,27 @@ +--- +description: State of imported gist from GitHub +category: Gitlab::GithubGistsImport::ImportGistWorker +action: create +label_description: github_gist_import +property_description: +value_description: +extra_properties: + status: + type: string + description: Import status +identifiers: +- user +product_section: dev +product_stage: manage +product_group: import +product_category: importers +milestone: "15.11" +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/117057 +distributions: +- ce +- ee +tiers: +- free +- premium +- ultimate + diff --git a/config/initializers/postgres_partitioning.rb b/config/initializers/postgres_partitioning.rb index 572c8439ec1..ac29396aee1 100644 --- a/config/initializers/postgres_partitioning.rb +++ b/config/initializers/postgres_partitioning.rb @@ -6,7 +6,7 @@ Gitlab::Database::Partitioning.register_models( WebHookLog, LooseForeignKeys::DeletedRecord, Gitlab::Database::BackgroundMigration::BatchedJobTransitionLog, - Ci::RunnerMachineBuild + Ci::RunnerManagerBuild ]) if Gitlab.ee? diff --git a/db/docs/ci_runner_machines.yml b/db/docs/ci_runner_machines.yml index 17cb700d96b..c7395907814 100644 --- a/db/docs/ci_runner_machines.yml +++ b/db/docs/ci_runner_machines.yml @@ -1,10 +1,10 @@ --- table_name: ci_runner_machines classes: -- Ci::RunnerMachine +- Ci::RunnerManager feature_categories: - runner_fleet -description: Information about host machines associated to Ci::Runner models +description: Information about runner managers associated to Ci::Runner models introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/107801 milestone: '15.8' gitlab_schema: gitlab_ci diff --git a/db/docs/p_ci_runner_machine_builds.yml b/db/docs/p_ci_runner_machine_builds.yml index 8ffac67fb94..55d09963acc 100644 --- a/db/docs/p_ci_runner_machine_builds.yml +++ b/db/docs/p_ci_runner_machine_builds.yml @@ -1,9 +1,9 @@ table_name: p_ci_runner_machine_builds classes: -- Ci::RunnerMachineBuild +- Ci::RunnerManagerBuild feature_categories: - runner_fleet -description: Relationships between builds and runner machines +description: Relationships between builds and runner managers introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/111476 milestone: '15.9' gitlab_schema: gitlab_ci diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index f030f6169dd..18162ad8d87 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -7500,29 +7500,29 @@ The edge type for [`CiRunner`](#cirunner). | <a id="cirunneredgenode"></a>`node` | [`CiRunner`](#cirunner) | The item at the end of the edge. | | <a id="cirunneredgeweburl"></a>`webUrl` | [`String`](#string) | Web URL of the runner. The value depends on where you put this field in the query. You can use it for projects or groups. | -#### `CiRunnerMachineConnection` +#### `CiRunnerManagerConnection` -The connection type for [`CiRunnerMachine`](#cirunnermachine). +The connection type for [`CiRunnerManager`](#cirunnermanager). ##### Fields | Name | Type | Description | | ---- | ---- | ----------- | -| <a id="cirunnermachineconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. | -| <a id="cirunnermachineconnectionedges"></a>`edges` | [`[CiRunnerMachineEdge]`](#cirunnermachineedge) | A list of edges. | -| <a id="cirunnermachineconnectionnodes"></a>`nodes` | [`[CiRunnerMachine]`](#cirunnermachine) | A list of nodes. | -| <a id="cirunnermachineconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. | +| <a id="cirunnermanagerconnectioncount"></a>`count` | [`Int!`](#int) | Total count of collection. | +| <a id="cirunnermanagerconnectionedges"></a>`edges` | [`[CiRunnerManagerEdge]`](#cirunnermanageredge) | A list of edges. | +| <a id="cirunnermanagerconnectionnodes"></a>`nodes` | [`[CiRunnerManager]`](#cirunnermanager) | A list of nodes. | +| <a id="cirunnermanagerconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. | -#### `CiRunnerMachineEdge` +#### `CiRunnerManagerEdge` -The edge type for [`CiRunnerMachine`](#cirunnermachine). +The edge type for [`CiRunnerManager`](#cirunnermanager). ##### Fields | Name | Type | Description | | ---- | ---- | ----------- | -| <a id="cirunnermachineedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. | -| <a id="cirunnermachineedgenode"></a>`node` | [`CiRunnerMachine`](#cirunnermachine) | The item at the end of the edge. | +| <a id="cirunnermanageredgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. | +| <a id="cirunnermanageredgenode"></a>`node` | [`CiRunnerManager`](#cirunnermanager) | The item at the end of the edge. | #### `CiSecureFileRegistryConnection` @@ -11950,7 +11950,7 @@ CI/CD variables for a GitLab instance. | <a id="cijobrefpath"></a>`refPath` | [`String`](#string) | Path to the ref. | | <a id="cijobretried"></a>`retried` | [`Boolean`](#boolean) | Indicates that the job has been retried. | | <a id="cijobretryable"></a>`retryable` | [`Boolean!`](#boolean) | Indicates the job can be retried. | -| <a id="cijobrunnermachine"></a>`runnerMachine` **{warning-solid}** | [`CiRunnerMachine`](#cirunnermachine) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. Runner machine assigned to the job. | +| <a id="cijobrunnermanager"></a>`runnerManager` **{warning-solid}** | [`CiRunnerManager`](#cirunnermanager) | **Introduced** in 15.11. This feature is in Alpha. It can be changed or removed at any time. Runner manager assigned to the job. | | <a id="cijobscheduled"></a>`scheduled` | [`Boolean!`](#boolean) | Indicates the job is scheduled. | | <a id="cijobscheduledat"></a>`scheduledAt` | [`Time`](#time) | Schedule for the build. | | <a id="cijobschedulingtype"></a>`schedulingType` | [`String`](#string) | Type of job scheduling. Value is `dag` if the job uses the `needs` keyword, and `stage` otherwise. | @@ -12081,7 +12081,7 @@ CI/CD variables for a project. | <a id="cirunnercreatedby"></a>`createdBy` | [`UserCore`](#usercore) | User that created this runner. | | <a id="cirunnerdescription"></a>`description` | [`String`](#string) | Description of the runner. | | <a id="cirunnereditadminurl"></a>`editAdminUrl` | [`String`](#string) | Admin form URL of the runner. Only available for administrators. | -| <a id="cirunnerephemeralauthenticationtoken"></a>`ephemeralAuthenticationToken` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is in Alpha. It can be changed or removed at any time. Ephemeral authentication token used for runner machine registration. Only available for the creator of the runner for a limited time during registration. | +| <a id="cirunnerephemeralauthenticationtoken"></a>`ephemeralAuthenticationToken` **{warning-solid}** | [`String`](#string) | **Introduced** in 15.9. This feature is in Alpha. It can be changed or removed at any time. Ephemeral authentication token used for runner manager registration. Only available for the creator of the runner for a limited time during registration. | | <a id="cirunnerexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. | | <a id="cirunnergroups"></a>`groups` | [`GroupConnection`](#groupconnection) | Groups the runner is associated with. For group runners only. (see [Connections](#connections)) | | <a id="cirunnerid"></a>`id` | [`CiRunnerID!`](#cirunnerid) | ID of the runner. | @@ -12089,9 +12089,9 @@ CI/CD variables for a project. | <a id="cirunnerjobcount"></a>`jobCount` | [`Int`](#int) | Number of jobs processed by the runner (limited to 1000, plus one to indicate that more items exist). | | <a id="cirunnerjobexecutionstatus"></a>`jobExecutionStatus` **{warning-solid}** | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | **Introduced** in 15.7. This feature is in Alpha. It can be changed or removed at any time. Job execution status of the runner. | | <a id="cirunnerlocked"></a>`locked` | [`Boolean`](#boolean) | Indicates the runner is locked. | -| <a id="cirunnermachines"></a>`machines` **{warning-solid}** | [`CiRunnerMachineConnection`](#cirunnermachineconnection) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Machines associated with the runner configuration. | | <a id="cirunnermaintenancenote"></a>`maintenanceNote` | [`String`](#string) | Runner's maintenance notes. | | <a id="cirunnermaintenancenotehtml"></a>`maintenanceNoteHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `maintenance_note`. | +| <a id="cirunnermanagers"></a>`managers` **{warning-solid}** | [`CiRunnerManagerConnection`](#cirunnermanagerconnection) | **Introduced** in 15.10. This feature is in Alpha. It can be changed or removed at any time. Machines associated with the runner configuration. | | <a id="cirunnermaximumtimeout"></a>`maximumTimeout` | [`Int`](#int) | Maximum timeout (in seconds) for jobs processed by the runner. | | <a id="cirunnerownerproject"></a>`ownerProject` | [`Project`](#project) | Project that owns the runner. For project runners only. | | <a id="cirunnerpaused"></a>`paused` | [`Boolean!`](#boolean) | Indicates the runner is paused and not available to run jobs. | @@ -12160,24 +12160,24 @@ Returns [`CiRunnerStatus!`](#cirunnerstatus). | ---- | ---- | ----------- | | <a id="cirunnerstatuslegacymode"></a>`legacyMode` **{warning-solid}** | [`String`](#string) | **Deprecated** in 15.0. Will be removed in 17.0. In GitLab 16.0 and later, the field will act as if `legacyMode` is null. | -### `CiRunnerMachine` +### `CiRunnerManager` #### Fields | Name | Type | Description | | ---- | ---- | ----------- | -| <a id="cirunnermachinearchitecturename"></a>`architectureName` | [`String`](#string) | Architecture provided by the runner machine. | -| <a id="cirunnermachinecontactedat"></a>`contactedAt` | [`Time`](#time) | Timestamp of last contact from the runner machine. | -| <a id="cirunnermachinecreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of creation of the runner machine. | -| <a id="cirunnermachineexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. | -| <a id="cirunnermachineid"></a>`id` | [`CiRunnerMachineID!`](#cirunnermachineid) | ID of the runner machine. | -| <a id="cirunnermachineipaddress"></a>`ipAddress` | [`String`](#string) | IP address of the runner machine. | -| <a id="cirunnermachineplatformname"></a>`platformName` | [`String`](#string) | Platform provided by the runner machine. | -| <a id="cirunnermachinerevision"></a>`revision` | [`String`](#string) | Revision of the runner. | -| <a id="cirunnermachinerunner"></a>`runner` | [`CiRunner`](#cirunner) | Runner configuration for the runner machine. | -| <a id="cirunnermachinestatus"></a>`status` | [`CiRunnerStatus!`](#cirunnerstatus) | Status of the runner machine. | -| <a id="cirunnermachinesystemid"></a>`systemId` | [`String!`](#string) | System ID associated with the runner machine. | -| <a id="cirunnermachineversion"></a>`version` | [`String`](#string) | Version of the runner. | +| <a id="cirunnermanagerarchitecturename"></a>`architectureName` | [`String`](#string) | Architecture provided by the runner manager. | +| <a id="cirunnermanagercontactedat"></a>`contactedAt` | [`Time`](#time) | Timestamp of last contact from the runner manager. | +| <a id="cirunnermanagercreatedat"></a>`createdAt` | [`Time`](#time) | Timestamp of creation of the runner manager. | +| <a id="cirunnermanagerexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. | +| <a id="cirunnermanagerid"></a>`id` | [`CiRunnerManagerID!`](#cirunnermanagerid) | ID of the runner manager. | +| <a id="cirunnermanageripaddress"></a>`ipAddress` | [`String`](#string) | IP address of the runner manager. | +| <a id="cirunnermanagerplatformname"></a>`platformName` | [`String`](#string) | Platform provided by the runner manager. | +| <a id="cirunnermanagerrevision"></a>`revision` | [`String`](#string) | Revision of the runner. | +| <a id="cirunnermanagerrunner"></a>`runner` | [`CiRunner`](#cirunner) | Runner configuration for the runner manager. | +| <a id="cirunnermanagerstatus"></a>`status` | [`CiRunnerStatus!`](#cirunnerstatus) | Status of the runner manager. | +| <a id="cirunnermanagersystemid"></a>`systemId` | [`String!`](#string) | System ID associated with the runner manager. | +| <a id="cirunnermanagerversion"></a>`version` | [`String`](#string) | Version of the runner. | ### `CiSecureFileRegistry` @@ -25159,11 +25159,11 @@ A `CiRunnerID` is a global ID. It is encoded as a string. An example `CiRunnerID` is: `"gid://gitlab/Ci::Runner/1"`. -### `CiRunnerMachineID` +### `CiRunnerManagerID` -A `CiRunnerMachineID` is a global ID. It is encoded as a string. +A `CiRunnerManagerID` is a global ID. It is encoded as a string. -An example `CiRunnerMachineID` is: `"gid://gitlab/Ci::RunnerMachine/1"`. +An example `CiRunnerManagerID` is: `"gid://gitlab/Ci::RunnerManager/1"`. ### `ClustersAgentID` diff --git a/lib/api/ci/helpers/runner.rb b/lib/api/ci/helpers/runner.rb index 738c5bb3789..055b259d43b 100644 --- a/lib/api/ci/helpers/runner.rb +++ b/lib/api/ci/helpers/runner.rb @@ -18,7 +18,7 @@ module API runner_details = get_runner_details_from_request current_runner.heartbeat(runner_details, update_contacted_at: update_contacted_at) - current_runner_machine&.heartbeat(runner_details, update_contacted_at: update_contacted_at) + current_runner_manager&.heartbeat(runner_details, update_contacted_at: update_contacted_at) end def get_runner_details_from_request @@ -52,12 +52,12 @@ module API end end - def current_runner_machine + def current_runner_manager return if Feature.disabled?(:create_runner_machine) - strong_memoize(:current_runner_machine) do + strong_memoize(:current_runner_manager) do system_xid = params.fetch(:system_id, LEGACY_SYSTEM_XID) - current_runner&.ensure_machine(system_xid) { |m| m.contacted_at = Time.current } + current_runner&.ensure_manager(system_xid) { |m| m.contacted_at = Time.current } end end @@ -96,7 +96,7 @@ module API # the heartbeat should be triggered. if heartbeat_runner job.runner&.heartbeat(get_runner_ip) - job.runner_machine&.heartbeat(get_runner_ip) if Feature.enabled?(:runner_machine_heartbeat) + job.runner_manager&.heartbeat(get_runner_ip) if Feature.enabled?(:runner_machine_heartbeat) end job diff --git a/lib/api/ci/runner.rb b/lib/api/ci/runner.rb index 0e67fb762a9..1ecd498c6a8 100644 --- a/lib/api/ci/runner.rb +++ b/lib/api/ci/runner.rb @@ -174,7 +174,7 @@ module API end new_update = current_runner.ensure_runner_queue_value - result = ::Ci::RegisterJobService.new(current_runner, current_runner_machine).execute(runner_params) + result = ::Ci::RegisterJobService.new(current_runner, current_runner_manager).execute(runner_params) if result.valid? if result.build_json diff --git a/locale/gitlab.pot b/locale/gitlab.pot index deb688382e2..13dc05c0d16 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -26322,6 +26322,9 @@ msgstr "" msgid "MD5" msgstr "" +msgid "MLExperimentTracking|Delete experiment?" +msgstr "" + msgid "MR widget|Back to the merge request" msgstr "" @@ -28184,6 +28187,12 @@ msgstr "" msgid "MlExperimentTracking|Created at" msgstr "" +msgid "MlExperimentTracking|Delete experiment" +msgstr "" + +msgid "MlExperimentTracking|Deleting this experiment will also delete its candidates and their associated metadata." +msgstr "" + msgid "MlExperimentTracking|Details" msgstr "" @@ -28714,7 +28723,7 @@ msgstr "" msgid "Navigation|Retrieving search results" msgstr "" -msgid "Navigation|Search for projects or groups" +msgid "Navigation|Search your projects or groups" msgstr "" msgid "Navigation|Secure" @@ -28732,10 +28741,10 @@ msgstr "" msgid "Navigation|Unpin item" msgstr "" -msgid "Navigation|View all groups" +msgid "Navigation|View all your groups" msgstr "" -msgid "Navigation|View all projects" +msgid "Navigation|View all your projects" msgstr "" msgid "Navigation|Your pinned items appear here." @@ -36382,6 +36391,9 @@ msgstr "" msgid "Related" msgstr "" +msgid "Related branches" +msgstr "" + msgid "Related feature flags" msgstr "" diff --git a/package.json b/package.json index c676ae7e661..440b621d7c2 100644 --- a/package.json +++ b/package.json @@ -216,7 +216,7 @@ "yaml": "^2.0.0-10" }, "devDependencies": { - "@gitlab/eslint-plugin": "18.3.0", + "@gitlab/eslint-plugin": "18.3.2", "@gitlab/stylelint-config": "4.1.0", "@graphql-eslint/eslint-plugin": "3.18.0", "@testing-library/dom": "^7.16.2", diff --git a/qa/Gemfile b/qa/Gemfile index eba5fbc63d2..1f63be4234b 100644 --- a/qa/Gemfile +++ b/qa/Gemfile @@ -38,7 +38,7 @@ gem 'chemlab', '~> 0.10' gem 'chemlab-library-www-gitlab-com', '~> 0.1', '>= 0.1.1' # dependencies for jenkins client -gem 'nokogiri', '~> 1.14', '>= 1.14.2' +gem 'nokogiri', '~> 1.14', '>= 1.14.3' gem 'deprecation_toolkit', '~> 2.0.3', require: false diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index 9df37db90c6..3d4ab76ef8c 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -181,7 +181,7 @@ GEM multi_json (1.15.0) multi_xml (0.6.0) netrc (0.11.0) - nokogiri (1.14.2) + nokogiri (1.14.3) mini_portile2 (~> 2.8.0) racc (~> 1.4) octokit (6.1.1) @@ -321,7 +321,7 @@ DEPENDENCIES gitlab-qa (~> 9, >= 9.1.2) influxdb-client (~> 2.9) knapsack (~> 4.0) - nokogiri (~> 1.14, >= 1.14.2) + nokogiri (~> 1.14, >= 1.14.3) octokit (~> 6.1.1) parallel (~> 1.22, >= 1.22.1) parallel_tests (~> 4.2) @@ -343,4 +343,4 @@ DEPENDENCIES zeitwerk (~> 2.6, >= 2.6.7) BUNDLED WITH - 2.4.10 + 2.4.11 diff --git a/spec/factories/ci/runner_machine_builds.rb b/spec/factories/ci/runner_machine_builds.rb index 0181def26ba..34238760112 100644 --- a/spec/factories/ci/runner_machine_builds.rb +++ b/spec/factories/ci/runner_machine_builds.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true FactoryBot.define do - factory :ci_runner_machine_build, class: 'Ci::RunnerMachineBuild' do + factory :ci_runner_machine_build, class: 'Ci::RunnerManagerBuild' do build factory: :ci_build, scheduling_type: :dag - runner_machine factory: :ci_runner_machine + runner_manager factory: :ci_runner_machine end end diff --git a/spec/factories/ci/runner_machines.rb b/spec/factories/ci/runner_managers.rb index 9d601caa634..7a2b0c37215 100644 --- a/spec/factories/ci/runner_machines.rb +++ b/spec/factories/ci/runner_managers.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true FactoryBot.define do - factory :ci_runner_machine, class: 'Ci::RunnerMachine' do + factory :ci_runner_machine, class: 'Ci::RunnerManager' do runner factory: :ci_runner system_xid { "r_#{SecureRandom.hex.slice(0, 10)}" } trait :stale do created_at { 1.year.ago } - contacted_at { Ci::RunnerMachine::STALE_TIMEOUT.ago } + contacted_at { Ci::RunnerManager::STALE_TIMEOUT.ago } end end end diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb index a9a637b4284..f001cecd28e 100644 --- a/spec/factories/ci/runners.rb +++ b/spec/factories/ci/runners.rb @@ -66,9 +66,9 @@ FactoryBot.define do end end - trait :with_runner_machine do + trait :with_runner_manager do after(:build) do |runner, evaluator| - runner.runner_machines << build(:ci_runner_machine, runner: runner) + runner.runner_managers << build(:ci_runner_machine, runner: runner) end end diff --git a/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js b/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js new file mode 100644 index 00000000000..b8b2aadf2c6 --- /dev/null +++ b/spec/frontend/ml/experiment_tracking/components/delete_button_spec.js @@ -0,0 +1,68 @@ +import { GlModal, GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue'; + +const csrfToken = 'mock-csrf-token'; +jest.mock('~/lib/utils/csrf', () => ({ token: csrfToken })); + +const MODAL_BODY = 'MODAL_BODY'; +const MODAL_TITLE = 'MODAL_TITLE'; + +describe('DeleteButton', () => { + let wrapper; + + const findModal = () => wrapper.findComponent(GlModal); + const findDropdown = () => wrapper.findComponent(GlDropdown); + const findDeleteButton = () => wrapper.findComponent(GlDropdownItem); + const findForm = () => wrapper.find('form'); + const findModalText = () => wrapper.findByText(MODAL_BODY); + + beforeEach(() => { + wrapper = shallowMountExtended(DeleteButton, { + propsData: { + deletePath: '/delete', + deleteConfirmationText: MODAL_BODY, + actionPrimaryText: 'Delete!', + modalTitle: MODAL_TITLE, + }, + }); + }); + + it('mounts the modal', () => { + expect(findModal().exists()).toBe(true); + }); + + it('mounts the dropdown', () => { + expect(findDropdown().exists()).toBe(true); + }); + + it('mounts the button', () => { + expect(findDeleteButton().exists()).toBe(true); + }); + + describe('when modal is opened', () => { + it('displays modal title', () => { + expect(findModal().props('title')).toBe(MODAL_TITLE); + }); + + it('displays modal body', () => { + expect(findModalText().exists()).toBe(true); + }); + + it('submits the form when primary action is clicked', async () => { + const submitSpy = jest.spyOn(findForm().element, 'submit'); + + findModal().vm.$emit('primary'); + + expect(submitSpy).toHaveBeenCalled(); + }); + + it('displays form with correct action and inputs', () => { + const form = findForm(); + + expect(form.attributes('action')).toBe('/delete'); + expect(form.find('input[name="_method"]').attributes('value')).toBe('delete'); + expect(form.find('input[name="authenticity_token"]').attributes('value')).toBe(csrfToken); + }); + }); +}); diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js index 97a5049ea88..21e1fba95f9 100644 --- a/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js +++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/ml_experiments_show_spec.js @@ -4,8 +4,9 @@ import MlExperimentsShow from '~/ml/experiment_tracking/routes/experiments/show/ import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue'; import Pagination from '~/vue_shared/components/incubation/pagination.vue'; import setWindowLocation from 'helpers/set_window_location_helper'; +import DeleteButton from '~/ml/experiment_tracking/components/delete_button.vue'; import * as urlHelpers from '~/lib/utils/url_utility'; -import { MOCK_START_CURSOR, MOCK_PAGE_INFO, MOCK_CANDIDATES } from './mock_data'; +import { MOCK_START_CURSOR, MOCK_PAGE_INFO, MOCK_CANDIDATES, MOCK_EXPERIMENT } from './mock_data'; describe('MlExperimentsShow', () => { let wrapper; @@ -15,9 +16,10 @@ describe('MlExperimentsShow', () => { metricNames = [], paramNames = [], pageInfo = MOCK_PAGE_INFO, + experiment = MOCK_EXPERIMENT, ) => { wrapper = mountExtended(MlExperimentsShow, { - propsData: { candidates, metricNames, paramNames, pageInfo }, + propsData: { experiment, candidates, metricNames, paramNames, pageInfo }, }); }; @@ -34,6 +36,8 @@ describe('MlExperimentsShow', () => { const findTableRows = () => findTable().findAll('tbody > tr'); const findNthTableRow = (idx) => findTableRows().at(idx); const findColumnInRow = (row, col) => findNthTableRow(row).findAll('td').at(col); + const findDeleteButton = () => wrapper.findComponent(DeleteButton); + const hrefInRowAndColumn = (row, col) => findColumnInRow(row, col).findComponent(GlLink).attributes().href; @@ -56,6 +60,10 @@ describe('MlExperimentsShow', () => { expect(findPagination().exists()).toBe(false); }); + it('shows delete button', () => { + expect(findDeleteButton().exists()).toBe(true); + }); + it('does not show table', () => { expect(findTable().exists()).toBe(false); }); diff --git a/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js b/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js index 66378cd3f0d..adfb3dbf773 100644 --- a/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js +++ b/spec/frontend/ml/experiment_tracking/routes/experiments/show/mock_data.js @@ -7,6 +7,8 @@ export const MOCK_PAGE_INFO = { hasPreviousPage: true, }; +export const MOCK_EXPERIMENT = { name: 'experiment', path: '/path/to/experiment' }; + export const MOCK_CANDIDATES = [ { rmse: 1, diff --git a/spec/frontend/super_sidebar/components/context_switcher_spec.js b/spec/frontend/super_sidebar/components/context_switcher_spec.js index 365f7a09acf..434f7263eb9 100644 --- a/spec/frontend/super_sidebar/components/context_switcher_spec.js +++ b/spec/frontend/super_sidebar/components/context_switcher_spec.js @@ -100,7 +100,7 @@ describe('ContextSwitcher component', () => { it('passes the placeholder to the search box', () => { expect(findSearchBox().props('placeholder')).toBe( - s__('Navigation|Search for projects or groups'), + s__('Navigation|Search your projects or groups'), ); }); diff --git a/spec/frontend/super_sidebar/components/groups_list_spec.js b/spec/frontend/super_sidebar/components/groups_list_spec.js index 6aee895f611..66397153d71 100644 --- a/spec/frontend/super_sidebar/components/groups_list_spec.js +++ b/spec/frontend/super_sidebar/components/groups_list_spec.js @@ -22,7 +22,7 @@ describe('GroupsList component', () => { expect(findViewAllLink().props('item')).toEqual({ icon: 'group', link: viewAllLink, - title: s__('Navigation|View all groups'), + title: s__('Navigation|View all your groups'), }); }); }; diff --git a/spec/frontend/super_sidebar/components/projects_list_spec.js b/spec/frontend/super_sidebar/components/projects_list_spec.js index cdc003b14e0..3500e0acd6c 100644 --- a/spec/frontend/super_sidebar/components/projects_list_spec.js +++ b/spec/frontend/super_sidebar/components/projects_list_spec.js @@ -22,7 +22,7 @@ describe('ProjectsList component', () => { expect(findViewAllLink().props('item')).toEqual({ icon: 'project', link: viewAllLink, - title: s__('Navigation|View all projects'), + title: s__('Navigation|View all your projects'), }); }); }; diff --git a/spec/frontend_integration/snippets/snippets_notes_spec.js b/spec/frontend_integration/snippets/snippets_notes_spec.js index 5e9eaa1aada..bfda86a48a2 100644 --- a/spec/frontend_integration/snippets/snippets_notes_spec.js +++ b/spec/frontend_integration/snippets/snippets_notes_spec.js @@ -1,12 +1,13 @@ import $ from 'jquery'; +import htmlSnippetsShow from 'test_fixtures/snippets/show.html'; import axios from '~/lib/utils/axios_utils'; import initGFMInput from '~/behaviors/markdown/gfm_auto_complete'; import initDeprecatedNotes from '~/init_deprecated_notes'; -import { loadHTMLFixture } from 'helpers/fixtures'; +import { setHTMLFixture } from 'helpers/fixtures'; describe('Integration Snippets notes', () => { beforeEach(async () => { - loadHTMLFixture('snippets/show.html'); + setHTMLFixture(htmlSnippetsShow); // Check if we have to Load GFM Input const $gfmInputs = $('.js-gfm-input:not(.js-gfm-input-initialized)'); diff --git a/spec/graphql/types/ci/job_type_spec.rb b/spec/graphql/types/ci/job_type_spec.rb index a761a256899..4eb18574969 100644 --- a/spec/graphql/types/ci/job_type_spec.rb +++ b/spec/graphql/types/ci/job_type_spec.rb @@ -40,7 +40,7 @@ RSpec.describe Types::Ci::JobType, feature_category: :continuous_integration do refPath retryable retried - runnerMachine + runnerManager scheduledAt schedulingType shortSha diff --git a/spec/graphql/types/ci/runner_machine_type_spec.rb b/spec/graphql/types/ci/runner_manager_type_spec.rb index 289cc52e27b..240e1edbf78 100644 --- a/spec/graphql/types/ci/runner_machine_type_spec.rb +++ b/spec/graphql/types/ci/runner_manager_type_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' -RSpec.describe GitlabSchema.types['CiRunnerMachine'], feature_category: :runner_fleet do - specify { expect(described_class.graphql_name).to eq('CiRunnerMachine') } +RSpec.describe GitlabSchema.types['CiRunnerManager'], feature_category: :runner_fleet do + specify { expect(described_class.graphql_name).to eq('CiRunnerManager') } - specify { expect(described_class).to require_graphql_authorizations(:read_runner_machine) } + specify { expect(described_class).to require_graphql_authorizations(:read_runner_manager) } - it 'contains attributes related to a runner machine' do + it 'contains attributes related to a runner manager' do expected_fields = %w[ architecture_name contacted_at created_at executor_name id ip_address platform_name revision runner status system_id version diff --git a/spec/graphql/types/ci/runner_type_spec.rb b/spec/graphql/types/ci/runner_type_spec.rb index 9e360f44a4f..58a30e5c226 100644 --- a/spec/graphql/types/ci/runner_type_spec.rb +++ b/spec/graphql/types/ci/runner_type_spec.rb @@ -9,7 +9,7 @@ RSpec.describe GitlabSchema.types['CiRunner'], feature_category: :runner do it 'contains attributes related to a runner' do expected_fields = %w[ - id description created_by created_at contacted_at machines maximum_timeout access_level active paused status + id description created_by created_at contacted_at managers maximum_timeout access_level active paused status version short_sha revision locked run_untagged ip_address runner_type tag_list project_count job_count admin_url edit_admin_url register_admin_url user_permissions executor_name architecture_name platform_name maintenance_note maintenance_note_html groups projects jobs token_expires_at diff --git a/spec/helpers/projects/ml/experiments_helper_spec.rb b/spec/helpers/projects/ml/experiments_helper_spec.rb index 0354ce5d9c4..004c89e5ca7 100644 --- a/spec/helpers/projects/ml/experiments_helper_spec.rb +++ b/spec/helpers/projects/ml/experiments_helper_spec.rb @@ -78,6 +78,16 @@ RSpec.describe Projects::Ml::ExperimentsHelper, feature_category: :mlops do end end + describe '#experiment_as_data' do + subject { Gitlab::Json.parse(helper.experiment_as_data(experiment)) } + + it do + is_expected.to eq( + { 'name' => experiment.name, 'path' => "/#{project.full_path}/-/ml/experiments/#{experiment.iid}" } + ) + end + end + describe '#show_candidate_view_model' do let(:candidate) { candidate0 } diff --git a/spec/lib/api/ci/helpers/runner_spec.rb b/spec/lib/api/ci/helpers/runner_spec.rb index 8264db8344d..7efce9ca2bc 100644 --- a/spec/lib/api/ci/helpers/runner_spec.rb +++ b/spec/lib/api/ci/helpers/runner_spec.rb @@ -67,49 +67,49 @@ RSpec.describe API::Ci::Helpers::Runner do end end - describe '#current_runner_machine', :freeze_time, feature_category: :runner_fleet do + describe '#current_runner_manager', :freeze_time, feature_category: :runner_fleet do let(:runner) { create(:ci_runner, token: 'foo') } - let(:runner_machine) { create(:ci_runner_machine, runner: runner, system_xid: 'bar', contacted_at: 1.hour.ago) } + let(:runner_manager) { create(:ci_runner_machine, runner: runner, system_xid: 'bar', contacted_at: 1.hour.ago) } - subject(:current_runner_machine) { helper.current_runner_machine } + subject(:current_runner_manager) { helper.current_runner_manager } context 'with create_runner_machine FF enabled' do before do stub_feature_flags(create_runner_machine: true) end - context 'when runner machine already exists' do + context 'when runner manager already exists' do before do - allow(helper).to receive(:params).and_return(token: runner.token, system_id: runner_machine.system_xid) + allow(helper).to receive(:params).and_return(token: runner.token, system_id: runner_manager.system_xid) end - it { is_expected.to eq(runner_machine) } + it { is_expected.to eq(runner_manager) } it 'does not update the contacted_at field' do - expect(current_runner_machine.contacted_at).to eq 1.hour.ago + expect(current_runner_manager.contacted_at).to eq 1.hour.ago end end - context 'when runner machine cannot be found' do - it 'creates a new runner machine', :aggregate_failures do + context 'when runner manager cannot be found' do + it 'creates a new runner manager', :aggregate_failures do allow(helper).to receive(:params).and_return(token: runner.token, system_id: 'new_system_id') - expect { current_runner_machine }.to change { Ci::RunnerMachine.count }.by(1) + expect { current_runner_manager }.to change { Ci::RunnerManager.count }.by(1) - expect(current_runner_machine).not_to be_nil - expect(current_runner_machine.system_xid).to eq('new_system_id') - expect(current_runner_machine.contacted_at).to eq(Time.current) - expect(current_runner_machine.runner).to eq(runner) + expect(current_runner_manager).not_to be_nil + expect(current_runner_manager.system_xid).to eq('new_system_id') + expect(current_runner_manager.contacted_at).to eq(Time.current) + expect(current_runner_manager.runner).to eq(runner) end - it 'creates a new <legacy> runner machine if system_id is not specified', :aggregate_failures do + it 'creates a new <legacy> runner manager if system_id is not specified', :aggregate_failures do allow(helper).to receive(:params).and_return(token: runner.token) - expect { current_runner_machine }.to change { Ci::RunnerMachine.count }.by(1) + expect { current_runner_manager }.to change { Ci::RunnerManager.count }.by(1) - expect(current_runner_machine).not_to be_nil - expect(current_runner_machine.system_xid).to eq(::API::Ci::Helpers::Runner::LEGACY_SYSTEM_XID) - expect(current_runner_machine.runner).to eq(runner) + expect(current_runner_manager).not_to be_nil + expect(current_runner_manager.system_xid).to eq(::API::Ci::Helpers::Runner::LEGACY_SYSTEM_XID) + expect(current_runner_manager.runner).to eq(runner) end end end @@ -119,21 +119,21 @@ RSpec.describe API::Ci::Helpers::Runner do stub_feature_flags(create_runner_machine: false) end - it 'does not return runner machine if no system_id specified' do + it 'does not return runner manager if no system_id specified' do allow(helper).to receive(:params).and_return(token: runner.token) is_expected.to be_nil end - context 'when runner machine can not be found' do + context 'when runner manager can not be found' do before do allow(helper).to receive(:params).and_return(token: runner.token, system_id: 'new_system_id') end - it 'does not create a new runner machine', :aggregate_failures do - expect { current_runner_machine }.not_to change { Ci::RunnerMachine.count } + it 'does not create a new runner manager', :aggregate_failures do + expect { current_runner_manager }.not_to change { Ci::RunnerManager.count } - expect(current_runner_machine).to be_nil + expect(current_runner_manager).to be_nil end end end diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 4a300cc45b5..43105c9afea 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -400,8 +400,8 @@ builds: - job_artifacts_cluster_image_scanning - job_artifacts_cyclonedx - job_artifacts_requirements_v2 -- runner_machine -- runner_machine_build +- runner_manager +- runner_manager_build - runner_session - trace_metadata - terraform_state_versions diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 9f39b16bd70..f2c713c22a7 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -39,7 +39,7 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def it { is_expected.to have_many(:pages_deployments).with_foreign_key(:ci_build_id) } it { is_expected.to have_one(:deployment) } - it { is_expected.to have_one(:runner_machine).through(:runner_machine_build) } + it { is_expected.to have_one(:runner_manager).through(:runner_manager_build) } it { is_expected.to have_one(:runner_session).with_foreign_key(:build_id) } it { is_expected.to have_one(:trace_metadata).with_foreign_key(:build_id) } it { is_expected.to have_one(:runtime_metadata).with_foreign_key(:build_id) } @@ -2036,14 +2036,14 @@ RSpec.describe Ci::Build, feature_category: :continuous_integration, factory_def end end - describe '#runner_machine' do + describe '#runner_manager' do let_it_be(:runner) { create(:ci_runner) } - let_it_be(:runner_machine) { create(:ci_runner_machine, runner: runner) } - let_it_be(:build) { create(:ci_build, runner_machine: runner_machine) } + let_it_be(:runner_manager) { create(:ci_runner_machine, runner: runner) } + let_it_be(:build) { create(:ci_build, runner_manager: runner_manager) } - subject(:build_runner_machine) { described_class.find(build.id).runner_machine } + subject(:build_runner_manager) { described_class.find(build.id).runner_manager } - it { is_expected.to eq(runner_machine) } + it { is_expected.to eq(runner_manager) } end describe '#tag_list' do diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb index d30fc45a804..34a56162dd9 100644 --- a/spec/models/ci/processable_spec.rb +++ b/spec/models/ci/processable_spec.rb @@ -85,7 +85,7 @@ RSpec.describe Ci::Processable, feature_category: :continuous_integration do runner_id tag_taggings taggings tags trigger_request_id user_id auto_canceled_by_id retried failure_reason sourced_pipelines sourced_pipeline artifacts_file_store artifacts_metadata_store - metadata runner_machine_build runner_machine runner_session trace_chunks upstream_pipeline_id + metadata runner_manager_build runner_manager runner_session trace_chunks upstream_pipeline_id artifacts_file artifacts_metadata artifacts_size commands resource resource_group_id processed security_scans author pipeline_id report_results pending_state pages_deployments diff --git a/spec/models/ci/runner_machine_build_spec.rb b/spec/models/ci/runner_manager_build_spec.rb index b43ff535477..3a381313b76 100644 --- a/spec/models/ci/runner_machine_build_spec.rb +++ b/spec/models/ci/runner_manager_build_spec.rb @@ -2,40 +2,40 @@ require 'spec_helper' -RSpec.describe Ci::RunnerMachineBuild, model: true, feature_category: :runner_fleet do +RSpec.describe Ci::RunnerManagerBuild, model: true, feature_category: :runner_fleet do let_it_be(:runner) { create(:ci_runner) } - let_it_be(:runner_machine) { create(:ci_runner_machine, runner: runner) } - let_it_be(:build) { create(:ci_build, runner_machine: runner_machine) } + let_it_be(:runner_manager) { create(:ci_runner_machine, runner: runner) } + let_it_be(:build) { create(:ci_build, runner_manager: runner_manager) } it { is_expected.to belong_to(:build) } - it { is_expected.to belong_to(:runner_machine) } + it { is_expected.to belong_to(:runner_manager) } describe 'partitioning' do context 'with build' do let(:build) { FactoryBot.build(:ci_build, partition_id: ci_testing_partition_id) } - let(:runner_machine_build) { FactoryBot.build(:ci_runner_machine_build, build: build) } + let(:runner_manager_build) { FactoryBot.build(:ci_runner_machine_build, build: build) } it 'sets partition_id to the current partition value' do - expect { runner_machine_build.valid? }.to change { runner_machine_build.partition_id } + expect { runner_manager_build.valid? }.to change { runner_manager_build.partition_id } .to(ci_testing_partition_id) end context 'when it is already set' do - let(:runner_machine_build) { FactoryBot.build(:ci_runner_machine_build, partition_id: 125) } + let(:runner_manager_build) { FactoryBot.build(:ci_runner_machine_build, partition_id: 125) } it 'does not change the partition_id value' do - expect { runner_machine_build.valid? }.not_to change { runner_machine_build.partition_id } + expect { runner_manager_build.valid? }.not_to change { runner_manager_build.partition_id } end end end context 'without build' do - let(:runner_machine_build) { FactoryBot.build(:ci_runner_machine_build, build: nil) } + let(:runner_manager_build) { FactoryBot.build(:ci_runner_machine_build, build: nil) } it { is_expected.to validate_presence_of(:partition_id) } it 'does not change the partition_id value' do - expect { runner_machine_build.valid? }.not_to change { runner_machine_build.partition_id } + expect { runner_manager_build.valid? }.not_to change { runner_manager_build.partition_id } end end end @@ -52,10 +52,10 @@ RSpec.describe Ci::RunnerMachineBuild, model: true, feature_category: :runner_fl it { expect(partitioning_strategy.active_partition).to be_present } end - context 'loose foreign key on p_ci_runner_machine_builds.runner_machine_id' do # rubocop:disable RSpec/ContextWording + context 'loose foreign key on p_ci_runner_manager_builds.runner_manager_id' do # rubocop:disable RSpec/ContextWording it_behaves_like 'cleanup by a loose foreign key' do let!(:parent) { create(:ci_runner_machine) } - let!(:model) { create(:ci_runner_machine_build, runner_machine: parent) } + let!(:model) { create(:ci_runner_machine_build, runner_manager: parent) } end end @@ -69,7 +69,7 @@ RSpec.describe Ci::RunnerMachineBuild, model: true, feature_category: :runner_fl end context 'with valid build_ids' do - let(:build2) { create(:ci_build, runner_machine: runner_machine) } + let(:build2) { create(:ci_build, runner_manager: runner_manager) } let(:build_id) { [build, build2] } it { is_expected.to eq(described_class.where(build_id: build_id)) } @@ -82,13 +82,13 @@ RSpec.describe Ci::RunnerMachineBuild, model: true, feature_category: :runner_fl end end - describe '.pluck_runner_machine_id_and_build_id' do - subject { scope.pluck_build_id_and_runner_machine_id } + describe '.pluck_runner_manager_id_and_build_id' do + subject { scope.pluck_build_id_and_runner_manager_id } context 'with default scope' do let(:scope) { described_class } - it { is_expected.to eq({ build.id => runner_machine.id }) } + it { is_expected.to eq({ build.id => runner_manager.id }) } end context 'with scope excluding build' do diff --git a/spec/models/ci/runner_machine_spec.rb b/spec/models/ci/runner_manager_spec.rb index 0989477cd21..d69c9ef845e 100644 --- a/spec/models/ci/runner_machine_spec.rb +++ b/spec/models/ci/runner_manager_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model do +RSpec.describe Ci::RunnerManager, feature_category: :runner_fleet, type: :model do it_behaves_like 'having unique enum values' it_behaves_like 'it has loose foreign keys' do @@ -11,8 +11,8 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model it { is_expected.to belong_to(:runner) } it { is_expected.to belong_to(:runner_version).with_foreign_key(:version) } - it { is_expected.to have_many(:runner_machine_builds) } - it { is_expected.to have_many(:builds).through(:runner_machine_builds) } + it { is_expected.to have_many(:runner_manager_builds) } + it { is_expected.to have_many(:builds).through(:runner_manager_builds) } describe 'validation' do it { is_expected.to validate_presence_of(:runner) } @@ -26,17 +26,17 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model context 'when runner has config' do it 'is valid' do - runner_machine = build(:ci_runner_machine, config: { gpus: "all" }) + runner_manager = build(:ci_runner_machine, config: { gpus: "all" }) - expect(runner_machine).to be_valid + expect(runner_manager).to be_valid end end context 'when runner has an invalid config' do it 'is invalid' do - runner_machine = build(:ci_runner_machine, config: { test: 1 }) + runner_manager = build(:ci_runner_machine, config: { test: 1 }) - expect(runner_machine).not_to be_valid + expect(runner_manager).not_to be_valid end end end @@ -44,16 +44,16 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model describe '.stale', :freeze_time do subject { described_class.stale.ids } - let!(:runner_machine1) { create(:ci_runner_machine, :stale) } - let!(:runner_machine2) { create(:ci_runner_machine, :stale, contacted_at: nil) } - let!(:runner_machine3) { create(:ci_runner_machine, created_at: 6.months.ago, contacted_at: Time.current) } - let!(:runner_machine4) { create(:ci_runner_machine, created_at: 5.days.ago) } - let!(:runner_machine5) do + let!(:runner_manager1) { create(:ci_runner_machine, :stale) } + let!(:runner_manager2) { create(:ci_runner_machine, :stale, contacted_at: nil) } + let!(:runner_manager3) { create(:ci_runner_machine, created_at: 6.months.ago, contacted_at: Time.current) } + let!(:runner_manager4) { create(:ci_runner_machine, created_at: 5.days.ago) } + let!(:runner_manager5) do create(:ci_runner_machine, created_at: (7.days - 1.second).ago, contacted_at: (7.days - 1.second).ago) end - it 'returns stale runner machines' do - is_expected.to match_array([runner_machine1.id, runner_machine2.id]) + it 'returns stale runner managers' do + is_expected.to match_array([runner_manager1.id, runner_manager2.id]) end end @@ -70,20 +70,20 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end describe '#status', :freeze_time do - let(:runner_machine) { build(:ci_runner_machine, created_at: 8.days.ago) } + let(:runner_manager) { build(:ci_runner_machine, created_at: 8.days.ago) } - subject { runner_machine.status } + subject { runner_manager.status } context 'if never connected' do before do - runner_machine.contacted_at = nil + runner_manager.contacted_at = nil end it { is_expected.to eq(:stale) } context 'if created recently' do before do - runner_machine.created_at = 1.day.ago + runner_manager.created_at = 1.day.ago end it { is_expected.to eq(:never_contacted) } @@ -92,7 +92,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model context 'if contacted 1s ago' do before do - runner_machine.contacted_at = 1.second.ago + runner_manager.contacted_at = 1.second.ago end it { is_expected.to eq(:online) } @@ -100,7 +100,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model context 'if contacted recently' do before do - runner_machine.contacted_at = 2.hours.ago + runner_manager.contacted_at = 2.hours.ago end it { is_expected.to eq(:offline) } @@ -108,7 +108,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model context 'if contacted long time ago' do before do - runner_machine.contacted_at = 7.days.ago + runner_manager.contacted_at = 7.days.ago end it { is_expected.to eq(:stale) } @@ -116,7 +116,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end describe '#heartbeat', :freeze_time do - let(:runner_machine) { create(:ci_runner_machine, version: '15.0.0') } + let(:runner_manager) { create(:ci_runner_machine, version: '15.0.0') } let(:executor) { 'shell' } let(:values) do { @@ -129,12 +129,12 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end subject(:heartbeat) do - runner_machine.heartbeat(values) + runner_manager.heartbeat(values) end context 'when database was updated recently' do before do - runner_machine.contacted_at = Time.current + runner_manager.contacted_at = Time.current end context 'when version is changed' do @@ -155,7 +155,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model heartbeat - expect(runner_machine.runner_version).to be_nil + expect(runner_manager.runner_version).to be_nil end context 'when fetching runner releases is disabled' do @@ -186,11 +186,11 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model let(:version) { '15.0.1' } before do - runner_machine.cache_attributes(version: version) + runner_manager.cache_attributes(version: version) end it 'does not lose cached version value' do - expect { heartbeat }.not_to change { runner_machine.version }.from(version) + expect { heartbeat }.not_to change { runner_manager.version }.from(version) end end end @@ -198,7 +198,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model context 'when database was not updated recently' do before do - runner_machine.contacted_at = 2.hours.ago + runner_manager.contacted_at = 2.hours.ago allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).with(version) end @@ -206,13 +206,13 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model context 'when version is changed' do let(:version) { '15.0.1' } - context 'with invalid runner_machine' do + context 'with invalid runner_manager' do before do - runner_machine.runner = nil + runner_manager.runner = nil end it 'still updates redis cache and database' do - expect(runner_machine).to be_invalid + expect(runner_manager).to be_invalid expect_redis_update does_db_update @@ -231,8 +231,8 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model end end - context 'with unchanged runner_machine version' do - let(:version) { runner_machine.version } + context 'with unchanged runner_manager version' do + let(:version) { runner_manager.version } it 'does not schedule ci_runner_versions update' do heartbeat @@ -249,7 +249,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model heartbeat - expect(runner_machine.reload.read_attribute(:executor_type)).to eq(expected_executor_type) + expect(runner_manager.reload.read_attribute(:executor_type)).to eq(expected_executor_type) end def expected_executor_type @@ -266,7 +266,7 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model heartbeat - expect(runner_machine.reload.read_attribute(:executor_type)).to eq('unknown') + expect(runner_manager.reload.read_attribute(:executor_type)).to eq('unknown') end end end @@ -276,16 +276,16 @@ RSpec.describe Ci::RunnerMachine, feature_category: :runner_fleet, type: :model values_json = values == anything ? anything : Gitlab::Json.dump(values) Gitlab::Redis::Cache.with do |redis| - redis_key = runner_machine.send(:cache_attribute_key) + redis_key = runner_manager.send(:cache_attribute_key) expect(redis).to receive(:set).with(redis_key, values_json, any_args).and_call_original end end def does_db_update - expect { heartbeat }.to change { runner_machine.reload.read_attribute(:contacted_at) } - .and change { runner_machine.reload.read_attribute(:architecture) } - .and change { runner_machine.reload.read_attribute(:config) } - .and change { runner_machine.reload.read_attribute(:executor_type) } + expect { heartbeat }.to change { runner_manager.reload.read_attribute(:contacted_at) } + .and change { runner_manager.reload.read_attribute(:architecture) } + .and change { runner_manager.reload.read_attribute(:config) } + .and change { runner_manager.reload.read_attribute(:executor_type) } end end end diff --git a/spec/models/ci/runner_version_spec.rb b/spec/models/ci/runner_version_spec.rb index 511d120ab7f..bce1f2a6c39 100644 --- a/spec/models/ci/runner_version_spec.rb +++ b/spec/models/ci/runner_version_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Ci::RunnerVersion, feature_category: :runner_fleet do create(:ci_runner_version, version: 'abc123', status: :unavailable) end - it { is_expected.to have_many(:runner_machines).with_foreign_key(:version) } + it { is_expected.to have_many(:runner_managers).with_foreign_key(:version) } it_behaves_like 'having unique enum values' diff --git a/spec/models/preloaders/runner_machine_policy_preloader_spec.rb b/spec/models/preloaders/runner_machine_policy_preloader_spec.rb deleted file mode 100644 index 26fc101d8dc..00000000000 --- a/spec/models/preloaders/runner_machine_policy_preloader_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Preloaders::RunnerMachinePolicyPreloader, feature_category: :runner_fleet do - let_it_be(:user) { create(:user) } - let_it_be(:runner1) { create(:ci_runner) } - let_it_be(:runner2) { create(:ci_runner) } - let_it_be(:runner_machine1) { create(:ci_runner_machine, runner: runner1) } - let_it_be(:runner_machine2) { create(:ci_runner_machine, runner: runner2) } - - let(:base_runner_machines) do - Project.where(id: [runner_machine1, runner_machine2]) - end - - it 'avoids N+1 queries when authorizing a list of runner machines', :request_store do - preload_runner_machines_for_policy(user) - control = ActiveRecord::QueryRecorder.new { authorize_all_runner_machines(user) } - - new_runner1 = create(:ci_runner) - new_runner2 = create(:ci_runner) - new_runner_machine1 = create(:ci_runner_machine, runner: new_runner1) - new_runner_machine2 = create(:ci_runner_machine, runner: new_runner2) - - pristine_runner_machines = Project.where(id: base_runner_machines + [new_runner_machine1, new_runner_machine2]) - - preload_runner_machines_for_policy(user, pristine_runner_machines) - expect { authorize_all_runner_machines(user, pristine_runner_machines) }.not_to exceed_query_limit(control) - end - - def authorize_all_runner_machines(current_user, runner_machine_list = base_runner_machines) - runner_machine_list.each { |runner_machine| current_user.can?(:read_runner_machine, runner_machine) } - end - - def preload_runner_machines_for_policy(current_user, runner_machine_list = base_runner_machines) - described_class.new(runner_machine_list, current_user).execute - end -end diff --git a/spec/models/preloaders/runner_manager_policy_preloader_spec.rb b/spec/models/preloaders/runner_manager_policy_preloader_spec.rb new file mode 100644 index 00000000000..1977e2c5787 --- /dev/null +++ b/spec/models/preloaders/runner_manager_policy_preloader_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Preloaders::RunnerManagerPolicyPreloader, feature_category: :runner_fleet do + let_it_be(:user) { create(:user) } + let_it_be(:runner1) { create(:ci_runner) } + let_it_be(:runner2) { create(:ci_runner) } + let_it_be(:runner_manager1) { create(:ci_runner_machine, runner: runner1) } + let_it_be(:runner_manager2) { create(:ci_runner_machine, runner: runner2) } + + let(:base_runner_managers) do + Project.where(id: [runner_manager1, runner_manager2]) + end + + it 'avoids N+1 queries when authorizing a list of runner managers', :request_store do + preload_runner_managers_for_policy(user) + control = ActiveRecord::QueryRecorder.new { authorize_all_runner_managers(user) } + + new_runner1 = create(:ci_runner) + new_runner2 = create(:ci_runner) + new_runner_manager1 = create(:ci_runner_machine, runner: new_runner1) + new_runner_manager2 = create(:ci_runner_machine, runner: new_runner2) + + pristine_runner_managers = Project.where(id: base_runner_managers + [new_runner_manager1, new_runner_manager2]) + + preload_runner_managers_for_policy(user, pristine_runner_managers) + expect { authorize_all_runner_managers(user, pristine_runner_managers) }.not_to exceed_query_limit(control) + end + + def authorize_all_runner_managers(current_user, runner_manager_list = base_runner_managers) + runner_manager_list.each { |runner_manager| current_user.can?(:read_runner_manager, runner_manager) } + end + + def preload_runner_managers_for_policy(current_user, runner_manager_list = base_runner_managers) + described_class.new(runner_manager_list, current_user).execute + end +end diff --git a/spec/policies/ci/runner_machine_policy_spec.rb b/spec/policies/ci/runner_manager_policy_spec.rb index 8b95f2d7526..d7004033ceb 100644 --- a/spec/policies/ci/runner_machine_policy_spec.rb +++ b/spec/policies/ci/runner_manager_policy_spec.rb @@ -2,10 +2,10 @@ require 'spec_helper' -RSpec.describe Ci::RunnerMachinePolicy, feature_category: :runner_fleet do +RSpec.describe Ci::RunnerManagerPolicy, feature_category: :runner_fleet do let_it_be(:owner) { create(:user) } - describe 'ability :read_runner_machine' do + describe 'ability :read_runner_manager' do let_it_be(:guest) { create(:user) } let_it_be(:developer) { create(:user) } let_it_be(:maintainer) { create(:user) } @@ -14,13 +14,13 @@ RSpec.describe Ci::RunnerMachinePolicy, feature_category: :runner_fleet do let_it_be_with_reload(:subgroup) { create(:group, name: 'subgroup', path: 'subgroup', parent: group) } let_it_be_with_reload(:project) { create(:project, group: subgroup) } - let_it_be(:instance_runner) { create(:ci_runner, :instance, :with_runner_machine) } - let_it_be(:group_runner) { create(:ci_runner, :group, :with_runner_machine, groups: [group]) } - let_it_be(:project_runner) { create(:ci_runner, :project, :with_runner_machine, projects: [project]) } + let_it_be(:instance_runner) { create(:ci_runner, :instance, :with_runner_manager) } + let_it_be(:group_runner) { create(:ci_runner, :group, :with_runner_manager, groups: [group]) } + let_it_be(:project_runner) { create(:ci_runner, :project, :with_runner_manager, projects: [project]) } - let(:runner_machine) { runner.runner_machines.first } + let(:runner_manager) { runner.runner_managers.first } - subject(:policy) { described_class.new(user, runner_machine) } + subject(:policy) { described_class.new(user, runner_manager) } before_all do group.add_guest(guest) @@ -29,18 +29,18 @@ RSpec.describe Ci::RunnerMachinePolicy, feature_category: :runner_fleet do group.add_owner(owner) end - shared_examples 'a policy allowing reading instance runner machine depending on runner sharing' do + shared_examples 'a policy allowing reading instance runner manager depending on runner sharing' do context 'with instance runner' do let(:runner) { instance_runner } - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } context 'with shared runners disabled on projects' do before do project.update!(shared_runners_enabled: false) end - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } end context 'with shared runners disabled for groups and projects' do @@ -49,32 +49,32 @@ RSpec.describe Ci::RunnerMachinePolicy, feature_category: :runner_fleet do project.update!(shared_runners_enabled: false) end - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } end end end - shared_examples 'a policy allowing reading group runner machine depending on runner sharing' do + shared_examples 'a policy allowing reading group runner manager depending on runner sharing' do context 'with group runner' do let(:runner) { group_runner } - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } context 'with sharing of group runners disabled' do before do project.update!(group_runners_enabled: false) end - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } end end end - shared_examples 'does not allow reading runners machines on any scope' do + shared_examples 'does not allow reading runners managers on any scope' do context 'with instance runner' do let(:runner) { instance_runner } - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } context 'with shared runners disabled for groups and projects' do before do @@ -82,94 +82,94 @@ RSpec.describe Ci::RunnerMachinePolicy, feature_category: :runner_fleet do project.update!(shared_runners_enabled: false) end - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } end end context 'with group runner' do let(:runner) { group_runner } - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } context 'with sharing of group runners disabled' do before do project.update!(group_runners_enabled: false) end - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } end end context 'with project runner' do let(:runner) { project_runner } - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } end end context 'without access' do let_it_be(:user) { create(:user) } - it_behaves_like 'does not allow reading runners machines on any scope' + it_behaves_like 'does not allow reading runners managers on any scope' end context 'with guest access' do let(:user) { guest } - it_behaves_like 'does not allow reading runners machines on any scope' + it_behaves_like 'does not allow reading runners managers on any scope' end context 'with developer access' do let(:user) { developer } - it_behaves_like 'a policy allowing reading instance runner machine depending on runner sharing' + it_behaves_like 'a policy allowing reading instance runner manager depending on runner sharing' - it_behaves_like 'a policy allowing reading group runner machine depending on runner sharing' + it_behaves_like 'a policy allowing reading group runner manager depending on runner sharing' context 'with project runner' do let(:runner) { project_runner } - it { expect_disallowed :read_runner_machine } + it { expect_disallowed :read_runner_manager } end end context 'with maintainer access' do let(:user) { maintainer } - it_behaves_like 'a policy allowing reading instance runner machine depending on runner sharing' + it_behaves_like 'a policy allowing reading instance runner manager depending on runner sharing' - it_behaves_like 'a policy allowing reading group runner machine depending on runner sharing' + it_behaves_like 'a policy allowing reading group runner manager depending on runner sharing' context 'with project runner' do let(:runner) { project_runner } - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } end end context 'with owner access' do let(:user) { owner } - it_behaves_like 'a policy allowing reading instance runner machine depending on runner sharing' + it_behaves_like 'a policy allowing reading instance runner manager depending on runner sharing' context 'with group runner' do let(:runner) { group_runner } - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } context 'with sharing of group runners disabled' do before do project.update!(group_runners_enabled: false) end - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } end end context 'with project runner' do let(:runner) { project_runner } - it { expect_allowed :read_runner_machine } + it { expect_allowed :read_runner_manager } end end end diff --git a/spec/requests/api/ci/runner/jobs_put_spec.rb b/spec/requests/api/ci/runner/jobs_put_spec.rb index bf28b25e0a6..088bbd338d5 100644 --- a/spec/requests/api/ci/runner/jobs_put_spec.rb +++ b/spec/requests/api/ci/runner/jobs_put_spec.rb @@ -21,13 +21,13 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego let_it_be(:project) { create(:project, namespace: group, shared_runners_enabled: false) } let_it_be(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') } let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) } - let_it_be(:runner_machine) { create(:ci_runner_machine, runner: runner) } + let_it_be(:runner_manager) { create(:ci_runner_machine, runner: runner) } let_it_be(:user) { create(:user) } describe 'PUT /api/v4/jobs/:id' do let_it_be_with_reload(:job) do create(:ci_build, :pending, :trace_live, pipeline: pipeline, project: project, user: user, - runner_id: runner.id, runner_machine: runner_machine) + runner_id: runner.id, runner_manager: runner_manager) end before do @@ -40,7 +40,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego it 'updates runner info' do expect { update_job(state: 'success') }.to change { runner.reload.contacted_at } - .and change { runner_machine.reload.contacted_at } + .and change { runner_manager.reload.contacted_at } end context 'when runner_machine_heartbeat is disabled' do @@ -48,7 +48,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego stub_feature_flags(runner_machine_heartbeat: false) end - it 'does not load runner machine' do + it 'does not load runner manager' do queries = ActiveRecord::QueryRecorder.new { update_job(state: 'success') } expect(queries.log).not_to include(/ci_runner_machines/) end diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb index 28dbc4fd168..545aea6a179 100644 --- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb +++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb @@ -131,29 +131,29 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego let(:args) { { system_id: 's_some_system_id' } } it 'creates respective ci_runner_machines record', :freeze_time do - expect { request }.to change { runner.runner_machines.reload.count }.from(0).to(1) + expect { request }.to change { runner.runner_managers.reload.count }.from(0).to(1) - machine = runner.runner_machines.last - expect(machine.system_xid).to eq args[:system_id] - expect(machine.runner).to eq runner - expect(machine.contacted_at).to eq Time.current + runner_manager = runner.runner_managers.last + expect(runner_manager.system_xid).to eq args[:system_id] + expect(runner_manager.runner).to eq runner + expect(runner_manager.contacted_at).to eq Time.current end end context 'when ci_runner_machines with same system_xid already exists', :freeze_time do let(:args) { { system_id: 's_existing_system_id' } } - let!(:runner_machine) do + let!(:runner_manager) do create(:ci_runner_machine, runner: runner, system_xid: args[:system_id], contacted_at: 1.hour.ago) end it 'does not create new ci_runner_machines record' do - expect { request }.not_to change { Ci::RunnerMachine.count } + expect { request }.not_to change { Ci::RunnerManager.count } end it 'updates the contacted_at field' do request - expect(runner_machine.reload.contacted_at).to eq Time.current + expect(runner_manager.reload.contacted_at).to eq Time.current end end end @@ -167,10 +167,10 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego let(:args) { { system_id: 's_some_system_id' } } it 'does not create respective ci_runner_machines record', :freeze_time, :aggregate_failures do - expect { request }.not_to change { runner.runner_machines.reload.count } + expect { request }.not_to change { runner.runner_managers.reload.count } expect(response).to have_gitlab_http_status(:created) - expect(runner.runner_machines).to be_empty + expect(runner.runner_managers).to be_empty end end end diff --git a/spec/requests/api/ci/runner/runners_verify_post_spec.rb b/spec/requests/api/ci/runner/runners_verify_post_spec.rb index 1b7dfe7706c..940219fecd3 100644 --- a/spec/requests/api/ci/runner/runners_verify_post_spec.rb +++ b/spec/requests/api/ci/runner/runners_verify_post_spec.rb @@ -113,8 +113,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego context 'when system_id is provided' do let(:params) { { token: runner.token, system_id: 's_some_system_id' } } - it 'creates a runner_machine' do - expect { verify }.to change { Ci::RunnerMachine.count }.by(1) + it 'creates a runner_manager' do + expect { verify }.to change { Ci::RunnerManager.count }.by(1) end end end @@ -138,8 +138,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego context 'when system_id is provided' do let(:params) { { token: runner.token, system_id: 's_some_system_id' } } - it 'does not create a runner_machine', :aggregate_failures do - expect { verify }.not_to change { Ci::RunnerMachine.count } + it 'does not create a runner_manager', :aggregate_failures do + expect { verify }.not_to change { Ci::RunnerManager.count } expect(response).to have_gitlab_http_status(:ok) end diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb index d50e9a316bf..ea44be2ec7f 100644 --- a/spec/requests/api/graphql/ci/jobs_spec.rb +++ b/spec/requests/api/graphql/ci/jobs_spec.rb @@ -338,12 +338,12 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati end end - describe '.jobs.runnerMachine' do + describe '.jobs.runnerManager' do let_it_be(:admin) { create(:admin) } - let_it_be(:runner_machine) { create(:ci_runner_machine, created_at: Time.current, contacted_at: Time.current) } + let_it_be(:runner_manager) { create(:ci_runner_machine, created_at: Time.current, contacted_at: Time.current) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } let_it_be(:build) do - create(:ci_build, pipeline: pipeline, name: 'my test job', runner_machine: runner_machine) + create(:ci_build, pipeline: pipeline, name: 'my test job', runner_manager: runner_manager) end let(:query) do @@ -355,8 +355,8 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati nodes { id name - runnerMachine { - #{all_graphql_fields_for('CiRunnerMachine', excluded: [:runner], max_depth: 1)} + runnerManager { + #{all_graphql_fields_for('CiRunnerManager', excluded: [:runner], max_depth: 1)} } } } @@ -368,19 +368,19 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati let(:jobs_graphql_data) { graphql_data_at(:project, :pipeline, :jobs, :nodes) } - it 'returns the runner machine in each job of a pipeline' do + it 'returns the runner manager in each job of a pipeline' do post_graphql(query, current_user: admin) expect(jobs_graphql_data).to contain_exactly( a_graphql_entity_for( build, name: build.name, - runner_machine: a_graphql_entity_for( - runner_machine, - system_id: runner_machine.system_xid, - created_at: runner_machine.created_at.iso8601, - contacted_at: runner_machine.contacted_at.iso8601, - status: runner_machine.status.to_s.upcase + runner_manager: a_graphql_entity_for( + runner_manager, + system_id: runner_manager.system_xid, + created_at: runner_manager.created_at.iso8601, + contacted_at: runner_manager.contacted_at.iso8601, + status: runner_manager.status.to_s.upcase ) ) ) @@ -393,8 +393,8 @@ RSpec.describe 'Query.project.pipeline', feature_category: :continuous_integrati post_graphql(query, current_user: admin) end - runner_machine2 = create(:ci_runner_machine) - create(:ci_build, pipeline: pipeline, name: 'my test job2', runner_machine: runner_machine2) + runner_manager2 = create(:ci_runner_machine) + create(:ci_build, pipeline: pipeline, name: 'my test job2', runner_manager: runner_manager2) expect { post_graphql(query, current_user: admin2) }.not_to exceed_all_query_limit(control) end diff --git a/spec/requests/api/graphql/ci/runner_spec.rb b/spec/requests/api/graphql/ci/runner_spec.rb index 6a177f7fe75..37839c0854c 100644 --- a/spec/requests/api/graphql/ci/runner_spec.rb +++ b/spec/requests/api/graphql/ci/runner_spec.rb @@ -10,7 +10,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do let_it_be(:group) { create(:group) } let_it_be(:active_instance_runner) do - create(:ci_runner, :instance, :with_runner_machine, + create(:ci_runner, :instance, :with_runner_manager, description: 'Runner 1', creator: user, contacted_at: 2.hours.ago, @@ -59,7 +59,7 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do let_it_be(:project1) { create(:project) } let_it_be(:active_project_runner) do - create(:ci_runner, :project, :with_runner_machine, projects: [project1]) + create(:ci_runner, :project, :with_runner_manager, projects: [project1]) end shared_examples 'runner details fetch' do @@ -121,8 +121,8 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do 'deleteRunner' => true, 'assignRunner' => true }, - machines: a_hash_including( - "count" => runner.runner_machines.count, + managers: a_hash_including( + "count" => runner.runner_managers.count, "nodes" => an_instance_of(Array), "pageInfo" => anything ) @@ -625,12 +625,12 @@ RSpec.describe 'Query.runner(id)', feature_category: :runner_fleet do context 'with runner created in last hour' do let(:created_at) { (Ci::Runner::REGISTRATION_AVAILABILITY_TIME - 1.second).ago } - context 'with no runner machine registed yet' do + context 'with no runner manager registered yet' do it_behaves_like 'an ephemeral_authentication_token' end - context 'with first runner machine already registed' do - let!(:runner_machine) { create(:ci_runner_machine, runner: runner) } + context 'with first runner manager already registered' do + let!(:runner_manager) { create(:ci_runner_machine, runner: runner) } it_behaves_like 'a protected ephemeral_authentication_token' end diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 18cb016f94a..6fb61bb3ec5 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -14,9 +14,9 @@ module Ci let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } describe '#execute' do - subject(:execute) { described_class.new(runner, runner_machine).execute } + subject(:execute) { described_class.new(runner, runner_manager).execute } - let(:runner_machine) { nil } + let(:runner_manager) { nil } context 'checks database loadbalancing stickiness' do let(:runner) { shared_runner } @@ -28,7 +28,7 @@ module Ci it 'result is valid if replica did caught-up', :aggregate_failures do expect(ApplicationRecord.sticking).to receive(:all_caught_up?).with(:runner, runner.id) { true } - expect { execute }.not_to change { Ci::RunnerMachineBuild.count }.from(0) + expect { execute }.not_to change { Ci::RunnerManagerBuild.count }.from(0) expect(execute).to be_valid expect(execute.build).to be_nil expect(execute.build_json).to be_nil @@ -46,9 +46,9 @@ module Ci shared_examples 'handles runner assignment' do context 'runner follows tag list' do - subject(:build) { build_on(project_runner, runner_machine: project_runner_machine) } + subject(:build) { build_on(project_runner, runner_manager: project_runner_manager) } - let(:project_runner_machine) { nil } + let(:project_runner_manager) { nil } context 'when job has tag' do before do @@ -62,19 +62,19 @@ module Ci project_runner.update!(tag_list: ["linux"]) end - context 'with no runner machine specified' do + context 'with no runner manager specified' do it 'picks build' do expect(build).to eq(pending_job) - expect(pending_job.runner_machine).to be_nil + expect(pending_job.runner_manager).to be_nil end end - context 'with runner machine specified' do - let(:project_runner_machine) { create(:ci_runner_machine, runner: project_runner) } + context 'with runner manager specified' do + let(:project_runner_manager) { create(:ci_runner_machine, runner: project_runner) } - it 'picks build and assigns runner machine' do + it 'picks build and assigns runner manager' do expect(build).to eq(pending_job) - expect(pending_job.runner_machine).to eq(project_runner_machine) + expect(pending_job.runner_manager).to eq(project_runner_manager) end end end @@ -123,27 +123,27 @@ module Ci end context 'for project runner' do - subject(:build) { build_on(project_runner, runner_machine: project_runner_machine) } + subject(:build) { build_on(project_runner, runner_manager: project_runner_manager) } - let(:project_runner_machine) { nil } + let(:project_runner_manager) { nil } - context 'with no runner machine specified' do + context 'with no runner manager specified' do it 'does not pick a build' do expect(build).to be_nil expect(pending_job.reload).to be_failed expect(pending_job.queuing_entry).to be_nil - expect(Ci::RunnerMachineBuild.all).to be_empty + expect(Ci::RunnerManagerBuild.all).to be_empty end end - context 'with runner machine specified' do - let(:project_runner_machine) { create(:ci_runner_machine, runner: project_runner) } + context 'with runner manager specified' do + let(:project_runner_manager) { create(:ci_runner_machine, runner: project_runner) } it 'does not pick a build' do expect(build).to be_nil expect(pending_job.reload).to be_failed expect(pending_job.queuing_entry).to be_nil - expect(Ci::RunnerMachineBuild.all).to be_empty + expect(Ci::RunnerManagerBuild.all).to be_empty end end end @@ -164,7 +164,7 @@ module Ci pending_job.update!(user: user) end - context 'with no runner machine specified' do + context 'with no runner manager specified' do it 'does not pick the build and drops the build' do expect(build_on(shared_runner)).to be_falsey @@ -172,13 +172,13 @@ module Ci end end - context 'with runner machine specified' do - let(:runner_machine) { create(:ci_runner_machine, runner: runner) } + context 'with runner manager specified' do + let(:runner_manager) { create(:ci_runner_machine, runner: runner) } it 'does not pick the build and does not create join record' do - expect(build_on(shared_runner, runner_machine: runner_machine)).to be_falsey + expect(build_on(shared_runner, runner_manager: runner_manager)).to be_falsey - expect(Ci::RunnerMachineBuild.all).to be_empty + expect(Ci::RunnerManagerBuild.all).to be_empty end end end @@ -1037,8 +1037,8 @@ module Ci end end - def build_on(runner, runner_machine: nil, params: {}) - described_class.new(runner, runner_machine).execute(params).build + def build_on(runner, runner_manager: nil, params: {}) + described_class.new(runner, runner_manager).execute(params).build end end end diff --git a/spec/services/ci/runners/stale_machines_cleanup_service_spec.rb b/spec/services/ci/runners/stale_managers_cleanup_service_spec.rb index 456dbcebb84..a78506ca5f7 100644 --- a/spec/services/ci/runners/stale_machines_cleanup_service_spec.rb +++ b/spec/services/ci/runners/stale_managers_cleanup_service_spec.rb @@ -2,22 +2,22 @@ require 'spec_helper' -RSpec.describe Ci::Runners::StaleMachinesCleanupService, feature_category: :runner_fleet do +RSpec.describe Ci::Runners::StaleManagersCleanupService, feature_category: :runner_fleet do let(:service) { described_class.new } - let!(:runner_machine3) { create(:ci_runner_machine, created_at: 6.months.ago, contacted_at: Time.current) } + let!(:runner_manager3) { create(:ci_runner_machine, created_at: 6.months.ago, contacted_at: Time.current) } subject(:response) { service.execute } - context 'with no stale runner machines' do - it 'does not clean any runner machines and returns :success status' do + context 'with no stale runner managers' do + it 'does not clean any runner managers and returns :success status' do expect do expect(response).to be_success - expect(response.payload).to match({ deleted_machines: false }) - end.not_to change { Ci::RunnerMachine.count }.from(1) + expect(response.payload).to match({ deleted_managers: false }) + end.not_to change { Ci::RunnerManager.count }.from(1) end end - context 'with some stale runner machines' do + context 'with some stale runner managers' do before do create(:ci_runner_machine, :stale) create(:ci_runner_machine, :stale, contacted_at: nil) @@ -25,8 +25,8 @@ RSpec.describe Ci::Runners::StaleMachinesCleanupService, feature_category: :runn it 'only leaves non-stale runners' do expect(response).to be_success - expect(response.payload).to match({ deleted_machines: true }) - expect(Ci::RunnerMachine.all).to contain_exactly(runner_machine3) + expect(response.payload).to match({ deleted_managers: true }) + expect(Ci::RunnerManager.all).to contain_exactly(runner_manager3) end context 'with more stale runners than MAX_DELETIONS' do @@ -37,8 +37,8 @@ RSpec.describe Ci::Runners::StaleMachinesCleanupService, feature_category: :runn it 'only leaves non-stale runners' do expect do expect(response).to be_success - expect(response.payload).to match({ deleted_machines: true }) - end.to change { Ci::RunnerMachine.count }.by(-Ci::Runners::StaleMachinesCleanupService::MAX_DELETIONS) + expect(response.payload).to match({ deleted_managers: true }) + end.to change { Ci::RunnerManager.count }.by(-Ci::Runners::StaleManagersCleanupService::MAX_DELETIONS) end end end diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index eba5771e062..51880a7e81d 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -91,13 +91,13 @@ module CycleAnalyticsHelpers wait_for_requests end - def create_value_stream_group_aggregation(group) - aggregation = Analytics::CycleAnalytics::Aggregation.safe_create_for_namespace(group) + def create_value_stream_aggregation(group_or_project_namespace) + aggregation = Analytics::CycleAnalytics::Aggregation.safe_create_for_namespace(group_or_project_namespace) Analytics::CycleAnalytics::AggregatorService.new(aggregation: aggregation).execute end def select_group_and_custom_value_stream(group, custom_value_stream_name) - create_value_stream_group_aggregation(group) + create_value_stream_aggregation(group) select_group(group) select_value_stream(custom_value_stream_name) diff --git a/spec/workers/ci/runners/stale_machines_cleanup_cron_worker_spec.rb b/spec/workers/ci/runners/stale_machines_cleanup_cron_worker_spec.rb index d8f620bc024..619012eaa6e 100644 --- a/spec/workers/ci/runners/stale_machines_cleanup_cron_worker_spec.rb +++ b/spec/workers/ci/runners/stale_machines_cleanup_cron_worker_spec.rb @@ -8,16 +8,16 @@ RSpec.describe Ci::Runners::StaleMachinesCleanupCronWorker, feature_category: :r describe '#perform', :freeze_time do subject(:perform) { worker.perform } - let!(:runner_machine1) do + let!(:runner_manager1) do create(:ci_runner_machine, created_at: 7.days.ago, contacted_at: 7.days.ago) end - let!(:runner_machine2) { create(:ci_runner_machine) } - let!(:runner_machine3) { create(:ci_runner_machine, created_at: 6.days.ago) } + let!(:runner_manager2) { create(:ci_runner_machine) } + let!(:runner_manager3) { create(:ci_runner_machine, created_at: 6.days.ago) } it_behaves_like 'an idempotent worker' do it 'delegates to Ci::Runners::StaleMachinesCleanupService' do - expect_next_instance_of(Ci::Runners::StaleMachinesCleanupService) do |service| + expect_next_instance_of(Ci::Runners::StaleManagersCleanupService) do |service| expect(service) .to receive(:execute).and_call_original end @@ -26,16 +26,16 @@ RSpec.describe Ci::Runners::StaleMachinesCleanupCronWorker, feature_category: :r expect(worker.logging_extras).to eq({ "extra.ci_runners_stale_machines_cleanup_cron_worker.status" => :success, - "extra.ci_runners_stale_machines_cleanup_cron_worker.deleted_machines" => true + "extra.ci_runners_stale_machines_cleanup_cron_worker.deleted_managers" => true }) end - it 'cleans up stale runner machines', :aggregate_failures do - expect(Ci::RunnerMachine.stale.count).to eq 1 + it 'cleans up stale runner managers', :aggregate_failures do + expect(Ci::RunnerManager.stale.count).to eq 1 - expect { perform }.to change { Ci::RunnerMachine.count }.from(3).to(2) + expect { perform }.to change { Ci::RunnerManager.count }.from(3).to(2) - expect(Ci::RunnerMachine.all).to match_array [runner_machine2, runner_machine3] + expect(Ci::RunnerManager.all).to match_array [runner_manager2, runner_manager3] end end end diff --git a/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb b/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb index 1c24cdcccae..fcbe1b2cf99 100644 --- a/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb +++ b/spec/workers/gitlab/github_gists_import/import_gist_worker_spec.rb @@ -74,20 +74,68 @@ RSpec.describe Gitlab::GithubGistsImport::ImportGistWorker, feature_category: :i .with(log_attributes.merge('message' => 'importer finished')) subject.perform(user.id, gist_hash, 'some_key') + + expect_snowplow_event( + category: 'Gitlab::GithubGistsImport::ImportGistWorker', + label: 'github_gist_import', + action: 'create', + user: user, + status: 'success' + ) end end - context 'when importer raised an error' do - it 'raises an error' do - exception = StandardError.new('_some_error_') + context 'when failure' do + context 'when importer raised an error' do + it 'raises an error' do + exception = StandardError.new('_some_error_') - expect(importer).to receive(:execute).and_raise(exception) - expect(Gitlab::GithubImport::Logger) - .to receive(:error) - .with(log_attributes.merge('message' => 'importer failed', 'error.message' => '_some_error_')) - expect(Gitlab::ErrorTracking).to receive(:track_exception) + expect(importer).to receive(:execute).and_raise(exception) + expect(Gitlab::GithubImport::Logger) + .to receive(:error) + .with(log_attributes.merge('message' => 'importer failed', 'error.message' => '_some_error_')) + expect(Gitlab::ErrorTracking).to receive(:track_exception) + + expect { subject.perform(user.id, gist_hash, 'some_key') }.to raise_error(StandardError) + end + end + + context 'when importer returns error' do + let(:importer_result) { instance_double('ServiceResponse', errors: 'error_message', success?: false) } + + it 'tracks and logs error' do + expect(importer).to receive(:execute).and_return(importer_result) + expect(Gitlab::GithubImport::Logger) + .to receive(:error) + .with(log_attributes.merge('message' => 'importer failed', 'error.message' => 'error_message')) + expect(Gitlab::JobWaiter).to receive(:notify).with('some_key', subject.jid) + + subject.perform(user.id, gist_hash, 'some_key') + + expect_snowplow_event( + category: 'Gitlab::GithubGistsImport::ImportGistWorker', + label: 'github_gist_import', + action: 'create', + user: user, + status: 'failed' + ) + end + end + end + + describe '.sidekiq_retries_exhausted' do + it 'sends snowplow event' do + job = { 'args' => [user.id, 'some_key', '1'], 'jid' => '123' } + + described_class.sidekiq_retries_exhausted_block.call(job) - expect { subject.perform(user.id, gist_hash, 'some_key') }.to raise_error(StandardError) + expect_snowplow_event( + category: 'Gitlab::GithubGistsImport::ImportGistWorker', + label: 'github_gist_import', + action: 'create', + user: user, + status: 'failed' + ) end end end diff --git a/yarn.lock b/yarn.lock index dce72892ba9..fe863eb165a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1085,10 +1085,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e" integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg== -"@gitlab/eslint-plugin@18.3.0": - version "18.3.0" - resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-18.3.0.tgz#1bb7bdfc39ccd4a6b2826608cede2d348cc76c48" - integrity sha512-cPWPDty+7KPyBeYaJZ/EJ9oAWQVj4onea7mHPdZnGtqtL3NcPU8VT0kIXPCk2bcYG2KhA58J+t6nF7NJ/MVPfg== +"@gitlab/eslint-plugin@18.3.2": + version "18.3.2" + resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-18.3.2.tgz#dc4d5b487e26a1473106c1a3e34ae3ea219d4dd1" + integrity sha512-Lz0RnEW5isZ/jkeHcr2k6NqaHISwgKeWN/vkWUU5J4Ax7oYPR0CgA2KO/dEnOvIPmGfbnUKowsekBmmy5SUQHA== dependencies: "@babel/core" "^7.17.0" "@babel/eslint-parser" "^7.17.0" @@ -1097,7 +1097,7 @@ eslint-config-prettier "^6.10.0" eslint-plugin-babel "^5.3.0" eslint-plugin-import "^2.26.0" - eslint-plugin-jest "^27.0.4" + eslint-plugin-jest "^27.2.1" eslint-plugin-promise "^6.0.1" eslint-plugin-unicorn "^40.1.0" eslint-plugin-vue "^9.3.0" @@ -5590,10 +5590,10 @@ eslint-plugin-import@^2.26.0, eslint-plugin-import@^2.27.5: semver "^6.3.0" tsconfig-paths "^3.14.1" -eslint-plugin-jest@^27.0.4: - version "27.0.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.0.4.tgz#ab9c7b3f48bfade4762c24c415a5d9bbc0174a61" - integrity sha512-BuvY78pHMpMJ6Cio7sKg6jrqEcnRYPUc4Nlihku4vKx3FjlmMINSX4vcYokZIe+8TKcyr1aI5Kq7vYwgJNdQSA== +eslint-plugin-jest@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz#b85b4adf41c682ea29f1f01c8b11ccc39b5c672c" + integrity sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg== dependencies: "@typescript-eslint/utils" "^5.10.0" |