diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-18 18:09:04 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-03-18 18:09:04 +0300 |
commit | dfda8b7e77835fc54d469eda336b13b415365703 (patch) | |
tree | b94d991d464dc1e98f0f365e1e15e94c3ee8c9ca | |
parent | 19d46f60a3699232458357111365e63a8c71f20d (diff) |
Add latest changes from gitlab-org/gitlab@master
147 files changed, 846 insertions, 516 deletions
diff --git a/app/assets/javascripts/blob/file_template_selector.js b/app/assets/javascripts/blob/file_template_selector.js index a5c8050b772..21c23495315 100644 --- a/app/assets/javascripts/blob/file_template_selector.js +++ b/app/assets/javascripts/blob/file_template_selector.js @@ -19,6 +19,17 @@ export default class FileTemplateSelector { this.$dropdownToggleText = this.$wrapper.find('.dropdown-toggle-text'); this.initDropdown(); + this.selectInitialTemplate(); + } + + selectInitialTemplate() { + const template = this.$dropdown.data('selected'); + + if (!template) { + return; + } + + this.mediator.selectTemplateFile(this, template); } show() { diff --git a/app/assets/javascripts/design_management/pages/index.vue b/app/assets/javascripts/design_management/pages/index.vue index 99ac38fc554..3cc22e1519b 100644 --- a/app/assets/javascripts/design_management/pages/index.vue +++ b/app/assets/javascripts/design_management/pages/index.vue @@ -485,9 +485,7 @@ export default { <template #upload-text="{ openFileUpload }"> <gl-sprintf :message="$options.i18n.dropzoneDescriptionText"> <template #link="{ content }"> - <gl-link @click.stop="openFileUpload"> - {{ content }} - </gl-link> + <gl-link @click.stop="openFileUpload">{{ content }}</gl-link> </template> </gl-sprintf> </template> diff --git a/app/assets/javascripts/emoji/index.js b/app/assets/javascripts/emoji/index.js index d3b658a4020..7faf0fe5f08 100644 --- a/app/assets/javascripts/emoji/index.js +++ b/app/assets/javascripts/emoji/index.js @@ -2,7 +2,7 @@ import { escape, minBy } from 'lodash'; import emojiAliases from 'emojis/aliases.json'; import AccessorUtilities from '../lib/utils/accessor'; import axios from '../lib/utils/axios_utils'; -import { CATEGORY_ICON_MAP } from './constants'; +import { CATEGORY_ICON_MAP, FREQUENTLY_USED_KEY } from './constants'; let emojiMap = null; let validEmojiNames = null; @@ -162,6 +162,9 @@ let emojiCategoryMap; export function getEmojiCategoryMap() { if (!emojiCategoryMap) { emojiCategoryMap = CATEGORY_NAMES.reduce((acc, category) => { + if (category === FREQUENTLY_USED_KEY) { + return acc; + } return { ...acc, [category]: [] }; }, {}); Object.keys(emojiMap).forEach((name) => { diff --git a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue index 0b58cb4731d..419e98dad50 100644 --- a/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue +++ b/app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue @@ -482,18 +482,6 @@ export default { /> </project-setting-row> <project-setting-row - ref="pipeline-settings" - :label="s__('ProjectSettings|Pipelines')" - :help-text="s__('ProjectSettings|Build, test, and deploy your changes.')" - > - <project-feature-setting - v-model="buildsAccessLevel" - :options="repoFeatureAccessLevelOptions" - :disabled-input="!repositoryEnabled" - name="project[project_feature_attributes][builds_access_level]" - /> - </project-setting-row> - <project-setting-row v-if="registryAvailable" ref="container-registry-settings" :help-path="registryHelpPath" @@ -567,6 +555,18 @@ export default { </project-setting-row> </div> <project-setting-row + ref="pipeline-settings" + :label="__('CI/CD')" + :help-text="s__('ProjectSettings|Build, test, and deploy your changes.')" + > + <project-feature-setting + v-model="buildsAccessLevel" + :options="repoFeatureAccessLevelOptions" + :disabled-input="!repositoryEnabled" + name="project[project_feature_attributes][builds_access_level]" + /> + </project-setting-row> + <project-setting-row ref="analytics-settings" :label="s__('ProjectSettings|Analytics')" :help-text="s__('ProjectSettings|View project analytics.')" diff --git a/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue b/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue index ff6a354f673..772fe178b24 100644 --- a/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue +++ b/app/assets/javascripts/pipeline_new/components/pipeline_new_form.vue @@ -447,7 +447,7 @@ export default { <gl-button type="submit" category="primary" - variant="success" + variant="confirm" class="js-no-auto-disable" data-qa-selector="run_pipeline_button" data-testid="run_pipeline_button" diff --git a/app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js b/app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js new file mode 100644 index 00000000000..b115b1fb34b --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/lib/utils/props_utils.js @@ -0,0 +1,35 @@ +/** + * Return the union of the given components' props options. Required props take + * precendence over non-required props of the same name. + * + * This makes two assumptions: + * - All given components define their props in verbose object format. + * - The components all agree on the `type` of a common prop. + * + * @param {object[]} components The components to derive the union from. + * @returns {object} The union of the props of the given components. + */ +export const propsUnion = (components) => + components.reduce((acc, component) => { + Object.entries(component.props ?? {}).forEach(([propName, propOptions]) => { + if (process.env.NODE_ENV !== 'production') { + if (typeof propOptions !== 'object' || !('type' in propOptions)) { + throw new Error( + `Cannot create props union: expected verbose prop options for prop "${propName}"`, + ); + } + + if (propName in acc && acc[propName]?.type !== propOptions?.type) { + throw new Error( + `Cannot create props union: incompatible prop types for prop "${propName}"`, + ); + } + } + + if (!(propName in acc) || propOptions.required) { + acc[propName] = propOptions; + } + }); + + return acc; + }, {}); diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb index 1a3f011d9eb..96966001e85 100644 --- a/app/finders/notes_finder.rb +++ b/app/finders/notes_finder.rb @@ -17,6 +17,7 @@ class NotesFinder # target_id: integer # last_fetched_at: time # search: string + # sort: string # def initialize(current_user, params = {}) @project = params[:project] @@ -29,8 +30,7 @@ class NotesFinder notes = init_collection notes = since_fetch_at(notes) notes = notes.with_notes_filter(@params[:notes_filter]) if notes_filter? - - notes.fresh + sort(notes) end def target @@ -173,6 +173,14 @@ class NotesFinder def notes_filter? @params[:notes_filter].present? end + + def sort(notes) + sort = @params[:sort].presence + + return notes.fresh unless sort + + notes.order_by(sort) + end end NotesFinder.prepend_if_ee('EE::NotesFinder') diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb index 9127dab56a6..04af1145769 100644 --- a/app/models/bulk_imports/entity.rb +++ b/app/models/bulk_imports/entity.rb @@ -68,25 +68,6 @@ class BulkImports::Entity < ApplicationRecord end end - def update_tracker_for(relation:, has_next_page:, next_page: nil) - attributes = { - relation: relation, - has_next_page: has_next_page, - next_page: next_page, - bulk_import_entity_id: id - } - - trackers.upsert(attributes, unique_by: %i[bulk_import_entity_id relation]) - end - - def has_next_page?(relation) - trackers.find_by(relation: relation)&.has_next_page - end - - def next_page_for(relation) - trackers.find_by(relation: relation)&.next_page - end - private def validate_parent_is_a_group diff --git a/app/models/bulk_imports/tracker.rb b/app/models/bulk_imports/tracker.rb index 182c0bbaa8a..8d16edccd5b 100644 --- a/app/models/bulk_imports/tracker.rb +++ b/app/models/bulk_imports/tracker.rb @@ -3,6 +3,8 @@ class BulkImports::Tracker < ApplicationRecord self.table_name = 'bulk_import_trackers' + alias_attribute :pipeline_name, :relation + belongs_to :entity, class_name: 'BulkImports::Entity', foreign_key: :bulk_import_entity_id, @@ -28,6 +30,10 @@ class BulkImports::Tracker < ApplicationRecord end event :finish do + # When applying the concurrent model, + # remove the created => finished transaction + # https://gitlab.com/gitlab-org/gitlab/-/issues/323384 + transition created: :finished transition started: :finished transition failed: :failed transition skipped: :skipped diff --git a/app/models/concerns/sortable.rb b/app/models/concerns/sortable.rb index 4fe2a0e1827..9f5e9b2bb57 100644 --- a/app/models/concerns/sortable.rb +++ b/app/models/concerns/sortable.rb @@ -9,6 +9,7 @@ module Sortable included do scope :with_order_id_desc, -> { order(self.arel_table['id'].desc) } + scope :with_order_id_asc, -> { order(self.arel_table['id'].asc) } scope :order_id_desc, -> { reorder(self.arel_table['id'].desc) } scope :order_id_asc, -> { reorder(self.arel_table['id'].asc) } scope :order_created_desc, -> { reorder(self.arel_table['created_at'].desc) } diff --git a/app/models/note.rb b/app/models/note.rb index fb540d692d1..c75d6aa77e6 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -19,6 +19,7 @@ class Note < ApplicationRecord include Gitlab::SQL::Pattern include ThrottledTouch include FromUnion + include Sortable cache_markdown_field :note, pipeline: :note, issuable_state_filter_enabled: true @@ -103,10 +104,9 @@ class Note < ApplicationRecord scope :system, -> { where(system: true) } scope :user, -> { where(system: false) } scope :common, -> { where(noteable_type: ["", nil]) } - scope :fresh, -> { order(created_at: :asc, id: :asc) } + scope :fresh, -> { order_created_asc.with_order_id_asc } scope :updated_after, ->(time) { where('updated_at > ?', time) } scope :with_updated_at, ->(time) { where(updated_at: time) } - scope :by_updated_at, -> { reorder(:updated_at, :id) } scope :inc_author_project, -> { includes(:project, :author) } scope :inc_author, -> { includes(:author) } scope :inc_relations_for_view, -> do @@ -148,6 +148,8 @@ class Note < ApplicationRecord after_commit :notify_after_destroy, on: :destroy class << self + extend Gitlab::Utils::Override + def model_name ActiveModel::Name.new(self, nil, 'note') end @@ -204,6 +206,13 @@ class Note < ApplicationRecord def search(query) fuzzy_search(query, [:note]) end + + # Override the `Sortable` module's `.simple_sorts` to remove name sorting, + # as a `Note` does not have any property that correlates to a "name". + override :simple_sorts + def simple_sorts + super.except('name_asc', 'name_desc') + end end # rubocop: disable CodeReuse/ServiceClass diff --git a/app/models/wiki.rb b/app/models/wiki.rb index df31c54bd0f..3445e7180e6 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -196,10 +196,20 @@ class Wiki def delete_page(page, message = nil) return unless page - wiki.delete_page(page.path, commit_details(:deleted, message, page.title)) - after_wiki_activity + if Feature.enabled?(:gitaly_replace_wiki_delete_page, user, default_enabled: :yaml) + capture_git_error(:deleted) do + repository.delete_file(user, page.path, **multi_commit_options(:deleted, message, page.title)) - true + after_wiki_activity + + true + end + else + wiki.delete_page(page.path, commit_details(:deleted, message, page.title)) + after_wiki_activity + + true + end end def page_title_and_dir(title) @@ -276,8 +286,20 @@ class Wiki private + def multi_commit_options(action, message = nil, title = nil) + commit_message = build_commit_message(action, message, title) + git_user = Gitlab::Git::User.from_gitlab(user) + + { + branch_name: repository.root_ref, + message: commit_message, + author_email: git_user.email, + author_name: git_user.name + } + end + def commit_details(action, message = nil, title = nil) - commit_message = message.presence || default_message(action, title) + commit_message = build_commit_message(action, message, title) git_user = Gitlab::Git::User.from_gitlab(user) Gitlab::Git::Wiki::CommitDetails.new(user.id, @@ -287,9 +309,26 @@ class Wiki commit_message) end + def build_commit_message(action, message, title) + message.presence || default_message(action, title) + end + def default_message(action, title) "#{user.username} #{action} page: #{title}" end + + def capture_git_error(action, &block) + yield block + rescue Gitlab::Git::Index::IndexError, + Gitlab::Git::CommitError, + Gitlab::Git::PreReceiveError, + Gitlab::Git::CommandError, + ArgumentError => error + + Gitlab::ErrorTracking.log_exception(error, action: action, wiki_id: id) + + false + end end Wiki.prepend_if_ee('EE::Wiki') diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index 7f42ec0b750..f6978c76058 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -24,7 +24,7 @@ module Ci def execute(params = {}) @metrics.increment_queue_operation(:queue_attempt) - @metrics.observe_queue_time do + @metrics.observe_queue_time(:process) do process_queue(params) end end @@ -110,7 +110,7 @@ module Ci end if Feature.enabled?(:ci_register_job_service_one_by_one, runner, default_enabled: true) - build_ids = builds.pluck(:id) + build_ids = retrieve_queue(-> { builds.pluck(:id) }) @metrics.observe_queue_size(-> { build_ids.size }) @@ -118,13 +118,21 @@ module Ci yield Ci::Build.find(build_id) end else - @metrics.observe_queue_size(-> { builds.to_a.size }) + builds_array = retrieve_queue(-> { builds.to_a }) - builds.each(&blk) + @metrics.observe_queue_size(-> { builds_array.size }) + + builds_array.each(&blk) end end # rubocop: enable CodeReuse/ActiveRecord + def retrieve_queue(queue_query_proc) + @metrics.observe_queue_time(:retrieve) do + queue_query_proc.call + end + end + def process_build(build, params) unless build.pending? @metrics.increment_queue_operation(:build_not_pending) diff --git a/app/services/concerns/integrations/project_test_data.rb b/app/services/concerns/integrations/project_test_data.rb index 57bcba98b49..5968b90f8fe 100644 --- a/app/services/concerns/integrations/project_test_data.rb +++ b/app/services/concerns/integrations/project_test_data.rb @@ -9,7 +9,7 @@ module Integrations end def note_events_data - note = NotesFinder.new(current_user, project: project, target: project).execute.reorder(nil).last # rubocop: disable CodeReuse/ActiveRecord + note = NotesFinder.new(current_user, project: project, target: project, sort: 'id_desc').execute.first return { error: s_('TestHooks|Ensure the project has notes.') } unless note.present? diff --git a/app/views/projects/blob/_template_selectors.html.haml b/app/views/projects/blob/_template_selectors.html.haml index 717c03ad27d..24a4db010c8 100644 --- a/app/views/projects/blob/_template_selectors.html.haml +++ b/app/views/projects/blob/_template_selectors.html.haml @@ -10,7 +10,7 @@ .metrics-dashboard-selector.js-metrics-dashboard-selector-wrap.js-template-selector-wrap.hidden = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-metrics-dashboard-selector qa-metrics-dashboard-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: metrics_dashboard_ymls(@project) } } ) #gitlab-ci-yml-selector.gitlab-ci-yml-selector.js-gitlab-ci-yml-selector-wrap.js-template-selector-wrap.hidden - = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-gitlab-ci-yml-selector qa-gitlab-ci-yml-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls(@project) } } ) + = dropdown_tag(_("Apply a template"), options: { toggle_class: 'js-gitlab-ci-yml-selector qa-gitlab-ci-yml-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: gitlab_ci_ymls(@project), selected: params[:template] } } ) - if experiment_enabled?(:ci_syntax_templates_b, subject: current_user) && @project.namespace.recent? .gitlab-ci-syntax-yml-selector.js-gitlab-ci-syntax-yml-selector-wrap.js-template-selector-wrap.hidden = dropdown_tag(_("Learn CI/CD syntax"), options: { toggle_class: 'js-gitlab-ci-syntax-yml-selector qa-gitlab-ci-syntax-yml-dropdown', dropdown_class: 'dropdown-menu-selectable', filter: true, placeholder: "Filter", data: { data: gitlab_ci_syntax_ymls(@project) } } ) diff --git a/app/views/projects/jobs/index.html.haml b/app/views/projects/jobs/index.html.haml index a0ec6002db7..0f9cf1c511e 100644 --- a/app/views/projects/jobs/index.html.haml +++ b/app/views/projects/jobs/index.html.haml @@ -5,11 +5,5 @@ - build_path_proc = ->(scope) { project_jobs_path(@project, scope: scope) } = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope - .nav-controls - - if can?(current_user, :update_build, @project) - = link_to project_ci_lint_path(@project), class: 'btn gl-button btn-default' do - %span - = _('CI Lint') - .content-list.builds-content-list = render "table", builds: @builds, project: @project diff --git a/app/views/projects/logs/empty_logs.html.haml b/app/views/projects/logs/empty_logs.html.haml index 5e3db401d79..48403f5e55e 100644 --- a/app/views/projects/logs/empty_logs.html.haml +++ b/app/views/projects/logs/empty_logs.html.haml @@ -11,4 +11,4 @@ %p.state-description.text-center = s_('Logs|To see the logs, deploy your code to an environment.') .text-center - = link_to s_('Environments|Learn about environments'), help_page_path('ci/environments/index.md'), class: 'gl-button btn btn-success' + = link_to s_('Environments|Learn about environments'), help_page_path('ci/environments/index.md'), class: 'gl-button btn btn-confirm' diff --git a/app/views/projects/tracings/_tracing_button.html.haml b/app/views/projects/tracings/_tracing_button.html.haml index b0ab6fa21e1..fe3af1c6a1a 100644 --- a/app/views/projects/tracings/_tracing_button.html.haml +++ b/app/views/projects/tracings/_tracing_button.html.haml @@ -1,2 +1,2 @@ -= link_to project_settings_operations_path(@project), title: _('Configure Tracing'), class: 'gl-button btn btn-success' do += link_to project_settings_operations_path(@project), title: _('Configure Tracing'), class: 'gl-button btn btn-confirm' do = _('Add Jaeger URL') diff --git a/changelogs/unreleased/232887-add-created_at-to-job-webhooks.yml b/changelogs/unreleased/232887-add-created_at-to-job-webhooks.yml new file mode 100644 index 00000000000..4ece4ba2f9b --- /dev/null +++ b/changelogs/unreleased/232887-add-created_at-to-job-webhooks.yml @@ -0,0 +1,5 @@ +--- +title: Add created_at to job webhooks +merge_request: 56835 +author: +type: changed diff --git a/changelogs/unreleased/btn-confirm-logs.yml b/changelogs/unreleased/btn-confirm-logs.yml new file mode 100644 index 00000000000..8da1dddbad2 --- /dev/null +++ b/changelogs/unreleased/btn-confirm-logs.yml @@ -0,0 +1,5 @@ +--- +title: Move from btn-success to btn-confirm in logs directory +merge_request: 56211 +author: Yogi (@yo) +type: changed diff --git a/changelogs/unreleased/btn-confirm-pipeline_new.yml b/changelogs/unreleased/btn-confirm-pipeline_new.yml new file mode 100644 index 00000000000..d38b582ec07 --- /dev/null +++ b/changelogs/unreleased/btn-confirm-pipeline_new.yml @@ -0,0 +1,5 @@ +--- +title: Move to confirm variant from success in pipeline_new directory +merge_request: 56199 +author: Yogi (@yo) +type: changed diff --git a/changelogs/unreleased/btn-confirm-tracing.yml b/changelogs/unreleased/btn-confirm-tracing.yml new file mode 100644 index 00000000000..3b3f84ce73f --- /dev/null +++ b/changelogs/unreleased/btn-confirm-tracing.yml @@ -0,0 +1,5 @@ +--- +title: Move from btn-success to btn-confirm in tracings directory +merge_request: 56209 +author: Yogi (@yo) +type: changed diff --git a/changelogs/unreleased/kassio-bulkimports-track-pipeline-work.yml b/changelogs/unreleased/kassio-bulkimports-track-pipeline-work.yml new file mode 100644 index 00000000000..3665f0c995f --- /dev/null +++ b/changelogs/unreleased/kassio-bulkimports-track-pipeline-work.yml @@ -0,0 +1,5 @@ +--- +title: 'BulkImports: Track pipeline worker with BulkImports::Tracker#status' +merge_request: 56242 +author: +type: changed diff --git a/changelogs/unreleased/lm-deep-stringify-merged-yaml.yml b/changelogs/unreleased/lm-deep-stringify-merged-yaml.yml new file mode 100644 index 00000000000..0640c45060d --- /dev/null +++ b/changelogs/unreleased/lm-deep-stringify-merged-yaml.yml @@ -0,0 +1,5 @@ +--- +title: Returns deep stringified keys for merged_yaml in linting endpoint +merge_request: 54336 +author: +type: changed diff --git a/changelogs/unreleased/nicolasdular-apply-ci-template-via-param.yml b/changelogs/unreleased/nicolasdular-apply-ci-template-via-param.yml new file mode 100644 index 00000000000..72d4384b323 --- /dev/null +++ b/changelogs/unreleased/nicolasdular-apply-ci-template-via-param.yml @@ -0,0 +1,5 @@ +--- +title: Allow selecting a CI template by providing the template name as a URL param gitlab_ci_yml +merge_request: 56861 +author: +type: added diff --git a/changelogs/unreleased/pb-remove-jobs-page-ci-lint-button.yml b/changelogs/unreleased/pb-remove-jobs-page-ci-lint-button.yml new file mode 100644 index 00000000000..42b0e909150 --- /dev/null +++ b/changelogs/unreleased/pb-remove-jobs-page-ci-lint-button.yml @@ -0,0 +1,5 @@ +--- +title: Remove CI lint button from Jobs page nav +merge_request: 56854 +author: +type: removed diff --git a/changelogs/unreleased/pb-ux-ci-cd-toggle-setting.yml b/changelogs/unreleased/pb-ux-ci-cd-toggle-setting.yml new file mode 100644 index 00000000000..1c283abced7 --- /dev/null +++ b/changelogs/unreleased/pb-ux-ci-cd-toggle-setting.yml @@ -0,0 +1,5 @@ +--- +title: Rename pipelines setting to CI/CD and move out from under repository section +merge_request: 56857 +author: +type: changed diff --git a/config/feature_flags/development/ci_runner_builds_queue_on_replicas.yml b/config/feature_flags/development/ci_runner_builds_queue_on_replicas.yml new file mode 100644 index 00000000000..edd16781a14 --- /dev/null +++ b/config/feature_flags/development/ci_runner_builds_queue_on_replicas.yml @@ -0,0 +1,8 @@ +--- +name: ci_runner_builds_queue_on_replicas +introduced_by_url: +rollout_issue_url: +milestone: '13.10' +type: development +group: group::continuous integration +default_enabled: false diff --git a/config/feature_flags/development/gitaly_replace_wiki_delete_page.yml b/config/feature_flags/development/gitaly_replace_wiki_delete_page.yml new file mode 100644 index 00000000000..40100bb2fe6 --- /dev/null +++ b/config/feature_flags/development/gitaly_replace_wiki_delete_page.yml @@ -0,0 +1,8 @@ +--- +name: gitaly_replace_wiki_delete_page +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56495 +rollout_issue_url: +milestone: '13.10' +type: development +group: group::editor +default_enabled: false diff --git a/doc/administration/logs.md b/doc/administration/logs.md index 1950403ce35..289e2cb5362 100644 --- a/doc/administration/logs.md +++ b/doc/administration/logs.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/github_imports.md b/doc/administration/monitoring/github_imports.md index 736ff299a86..cd35b8b3f9e 100644 --- a/doc/administration/monitoring/github_imports.md +++ b/doc/administration/monitoring/github_imports.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md index ca8daf4dc22..8d3c8555660 100644 --- a/doc/administration/monitoring/gitlab_self_monitoring_project/index.md +++ b/doc/administration/monitoring/gitlab_self_monitoring_project/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/index.md b/doc/administration/monitoring/index.md index 4ebe3d420b5..4c49efd6bd5 100644 --- a/doc/administration/monitoring/index.md +++ b/doc/administration/monitoring/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/ip_whitelist.md b/doc/administration/monitoring/ip_whitelist.md index 91f9c5d560f..522267ce362 100644 --- a/doc/administration/monitoring/ip_whitelist.md +++ b/doc/administration/monitoring/ip_whitelist.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/performance/gitlab_configuration.md b/doc/administration/monitoring/performance/gitlab_configuration.md index a0f170e93d9..6e7557854ad 100644 --- a/doc/administration/monitoring/performance/gitlab_configuration.md +++ b/doc/administration/monitoring/performance/gitlab_configuration.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/performance/grafana_configuration.md b/doc/administration/monitoring/performance/grafana_configuration.md index 62d4f3c2625..ac322f3e1ef 100644 --- a/doc/administration/monitoring/performance/grafana_configuration.md +++ b/doc/administration/monitoring/performance/grafana_configuration.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/performance/index.md b/doc/administration/monitoring/performance/index.md index cdf78811092..15c54a36f6c 100644 --- a/doc/administration/monitoring/performance/index.md +++ b/doc/administration/monitoring/performance/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/performance/performance_bar.md b/doc/administration/monitoring/performance/performance_bar.md index 39e5e4f6c00..f6aa60b36a1 100644 --- a/doc/administration/monitoring/performance/performance_bar.md +++ b/doc/administration/monitoring/performance/performance_bar.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/performance/request_profiling.md b/doc/administration/monitoring/performance/request_profiling.md index ee035c6ad7a..15a58456e05 100644 --- a/doc/administration/monitoring/performance/request_profiling.md +++ b/doc/administration/monitoring/performance/request_profiling.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/gitlab_exporter.md b/doc/administration/monitoring/prometheus/gitlab_exporter.md index 589fa799cca..4ba4cad9143 100644 --- a/doc/administration/monitoring/prometheus/gitlab_exporter.md +++ b/doc/administration/monitoring/prometheus/gitlab_exporter.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/gitlab_metrics.md b/doc/administration/monitoring/prometheus/gitlab_metrics.md index 3c6c984cbe3..f56349fc9e6 100644 --- a/doc/administration/monitoring/prometheus/gitlab_metrics.md +++ b/doc/administration/monitoring/prometheus/gitlab_metrics.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/index.md b/doc/administration/monitoring/prometheus/index.md index 23bffae99cf..035c5b3ee7e 100644 --- a/doc/administration/monitoring/prometheus/index.md +++ b/doc/administration/monitoring/prometheus/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/node_exporter.md b/doc/administration/monitoring/prometheus/node_exporter.md index 6efc9d67e8d..68d997d7596 100644 --- a/doc/administration/monitoring/prometheus/node_exporter.md +++ b/doc/administration/monitoring/prometheus/node_exporter.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/pgbouncer_exporter.md b/doc/administration/monitoring/prometheus/pgbouncer_exporter.md index df2aa08efaa..d42c471ac71 100644 --- a/doc/administration/monitoring/prometheus/pgbouncer_exporter.md +++ b/doc/administration/monitoring/prometheus/pgbouncer_exporter.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/postgres_exporter.md b/doc/administration/monitoring/prometheus/postgres_exporter.md index 8b6d3d82018..783030a9220 100644 --- a/doc/administration/monitoring/prometheus/postgres_exporter.md +++ b/doc/administration/monitoring/prometheus/postgres_exporter.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/redis_exporter.md b/doc/administration/monitoring/prometheus/redis_exporter.md index e9d656a6493..6cc262842a1 100644 --- a/doc/administration/monitoring/prometheus/redis_exporter.md +++ b/doc/administration/monitoring/prometheus/redis_exporter.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/administration/monitoring/prometheus/registry_exporter.md b/doc/administration/monitoring/prometheus/registry_exporter.md index d2bd86aa908..87b51aaed08 100644 --- a/doc/administration/monitoring/prometheus/registry_exporter.md +++ b/doc/administration/monitoring/prometheus/registry_exporter.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/api/error_tracking.md b/doc/api/error_tracking.md index c737edbdc44..306383c2de7 100644 --- a/doc/api/error_tracking.md +++ b/doc/api/error_tracking.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/api/metrics_dashboard_annotations.md b/doc/api/metrics_dashboard_annotations.md index 896420ed0fb..b2f1e52f194 100644 --- a/doc/api/metrics_dashboard_annotations.md +++ b/doc/api/metrics_dashboard_annotations.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments type: concepts, howto --- diff --git a/doc/api/metrics_user_starred_dashboards.md b/doc/api/metrics_user_starred_dashboards.md index 9178291181e..6f360cddd61 100644 --- a/doc/api/metrics_user_starred_dashboards.md +++ b/doc/api/metrics_user_starred_dashboards.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments type: concepts, howto --- diff --git a/doc/development/agent/identity.md b/doc/development/agent/identity.md index 49d20d2fd87..83af4318de9 100644 --- a/doc/development/agent/identity.md +++ b/doc/development/agent/identity.md @@ -92,3 +92,15 @@ GitLab provides the following information in its response for a given Agent acce - Agent configuration Git repository. (The agent doesn't support per-folder authorization.) - Agent name. + +## Create an agent + +You can create an agent by following the [user documentation](../../user/clusters/agent/index.md#create-an-agent-record-in-gitlab), or via Rails console: + +```ruby +project = ::Project.find_by_full_path("path-to/your-configuration-project") +# agent-name should be the same as specified above in the config.yaml +agent = ::Clusters::Agent.create(name: "<agent-name>", project: project) +token = ::Clusters::AgentToken.create(agent: agent) +token.token # this will print out the token you need to use on the next step +``` diff --git a/doc/development/distributed_tracing.md b/doc/development/distributed_tracing.md index 17967c5f63c..4f53d6b7385 100644 --- a/doc/development/distributed_tracing.md +++ b/doc/development/distributed_tracing.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index 28f958e2604..b6130335654 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -381,7 +381,7 @@ Use `webpackChunkName` when generating dynamic imports as it provides a deterministic filename for the chunk which can then be cached in the browser across GitLab versions. -More information is available in [webpack's code splitting documentation](https://webpack.js.org/guides/code-splitting/#dynamic-imports). +More information is available in [webpack's code splitting documentation](https://webpack.js.org/guides/code-splitting/#dynamic-imports) and [vue's dynamic component documentation](https://vuejs.org/v2/guide/components-dynamic-async.html). ### Minimizing page size diff --git a/doc/development/i18n/externalization.md b/doc/development/i18n/externalization.md index 90355e1cccb..6d848934a17 100644 --- a/doc/development/i18n/externalization.md +++ b/doc/development/i18n/externalization.md @@ -255,7 +255,44 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s - In Vue: - See the section on [Vue component interpolation](#vue-components-interpolation). + Use the [`GlSprintf`](https://gitlab-org.gitlab.io/gitlab-ui/?path=/docs/utilities-sprintf--sentence-with-link) component if: + - you need to include child components in the translation string. + - you need to include HTML in your translation string. + - you are using `sprintf` and need to pass `false` as the third argument to + prevent it from escaping placeholder values. + + For example: + + ```html + <gl-sprintf :message="s__('ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}')"> + <template #link="{ content }"> + <gl-link :href="somePath">{{ content }}</gl-link> + </template> + </gl-sprintf> + ``` + + In other cases it may be simpler to use `sprintf`, perhaps in a computed + property. For example: + + ```html + <script> + import { __, sprintf } from '~/locale'; + + export default { + ... + computed: { + userWelcome() { + sprintf(__('Hello %{username}'), { username: this.user.name }); + } + } + ... + } + </script> + + <template> + <span>{{ userWelcome }}</span> + </template> + ``` - In JavaScript (when Vue cannot be used): @@ -265,12 +302,10 @@ For example use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make s sprintf(__('Hello %{username}'), { username: 'Joe' }); // => 'Hello Joe' ``` - If you want to use markup within the translation and are using Vue, you - **must** use the [`gl-sprintf`](#vue-components-interpolation) component. If - for some reason you cannot use Vue, use `sprintf` and stop it from escaping - placeholder values by passing `false` as its third argument. You **must** - escape any interpolated dynamic values yourself, for instance using - `escape` from `lodash`. + If you need to use markup within the translation, use `sprintf` and stop it + from escaping placeholder values by passing `false` as its third argument. + You **must** escape any interpolated dynamic values yourself, for instance + using `escape` from `lodash`. ```javascript import { escape } from 'lodash'; @@ -632,7 +667,7 @@ This also applies when using links in between translated sentences, otherwise th {{ sprintf(s__("ClusterIntegration|Learn more about %{link}"), { link: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">zones</a>' - }) + }, false) }} ``` @@ -643,7 +678,7 @@ This also applies when using links in between translated sentences, otherwise th sprintf(s__("ClusterIntegration|Learn more about %{linkStart}zones%{linkEnd}"), { linkStart: '<a href="https://cloud.google.com/compute/docs/regions-zones/regions-zones" target="_blank" rel="noopener noreferrer">', linkEnd: '</a>', - }) + }, false) }} ``` @@ -652,45 +687,6 @@ The reasoning behind this is that in some languages words change depending on co When in doubt, try to follow the best practices described in this [Mozilla Developer documentation](https://developer.mozilla.org/en-US/docs/Mozilla/Localization/Localization_content_best_practices#Splitting). -##### Vue components interpolation - -When translating UI text in Vue components, you might want to include child components inside -the translation string. -You could not use a JavaScript-only solution to render the translation, -because Vue would not be aware of the child components and would render them as plain text. - -For this use case, you should use the `gl-sprintf` component which is maintained -in **GitLab UI**. - -The `gl-sprintf` component accepts a `message` property, which is the translatable string, -and it exposes a named slot for every placeholder in the string, which lets you include Vue -components easily. - -Assume you want to print the translatable string -`Pipeline %{pipelineId} triggered %{timeago} by %{author}`. To replace the `%{timeago}` and -`%{author}` placeholders with Vue components, here's how you would do that with `gl-sprintf`: - -```html -<template> - <div> - <gl-sprintf :message="__('Pipeline %{pipelineId} triggered %{timeago} by %{author}')"> - <template #pipelineId>{{ pipeline.id }}</template> - <template #timeago> - <timeago :time="pipeline.triggerTime" /> - </template> - <template #author> - <gl-avatar-labeled - :src="pipeline.triggeredBy.avatarPath" - :label="pipeline.triggeredBy.name" - /> - </template> - </gl-sprintf> - </div> -</template> -``` - -For more information, see the [`gl-sprintf`](https://gitlab-org.gitlab.io/gitlab-ui/?path=/story/base-sprintf--default) documentation. - ## Updating the PO files with the new content Now that the new content is marked for translation, we need to update diff --git a/doc/development/instrumentation.md b/doc/development/instrumentation.md index 338ad76d414..83e7444bb1f 100644 --- a/doc/development/instrumentation.md +++ b/doc/development/instrumentation.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/development/logging.md b/doc/development/logging.md index 30398eb87a1..88ae3950f1a 100644 --- a/doc/development/logging.md +++ b/doc/development/logging.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/development/prometheus_metrics.md b/doc/development/prometheus_metrics.md index 05a623448bf..51c5c4954e4 100644 --- a/doc/development/prometheus_metrics.md +++ b/doc/development/prometheus_metrics.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md index 60c576a44e5..a6173548042 100644 --- a/doc/operations/error_tracking.md +++ b/doc/operations/error_tracking.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/incident_management/alerts.md b/doc/operations/incident_management/alerts.md index 3c60c737309..276009ac200 100644 --- a/doc/operations/incident_management/alerts.md +++ b/doc/operations/incident_management/alerts.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/incident_management/incidents.md b/doc/operations/incident_management/incidents.md index 317797376fc..e4d9a87e39d 100644 --- a/doc/operations/incident_management/incidents.md +++ b/doc/operations/incident_management/incidents.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/incident_management/index.md b/doc/operations/incident_management/index.md index 6e285300b12..eb931b3eec5 100644 --- a/doc/operations/incident_management/index.md +++ b/doc/operations/incident_management/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/incident_management/integrations.md b/doc/operations/incident_management/integrations.md index 62a50255dd8..bdb16b1f88a 100644 --- a/doc/operations/incident_management/integrations.md +++ b/doc/operations/incident_management/integrations.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/incident_management/paging.md b/doc/operations/incident_management/paging.md index dbd90cf5847..1588cb96218 100644 --- a/doc/operations/incident_management/paging.md +++ b/doc/operations/incident_management/paging.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/incident_management/status_page.md b/doc/operations/incident_management/status_page.md index 46f0a6f278c..1e11a9c62e0 100644 --- a/doc/operations/incident_management/status_page.md +++ b/doc/operations/incident_management/status_page.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/index.md b/doc/operations/index.md index 8d0aaaf7cb2..934634562fc 100644 --- a/doc/operations/index.md +++ b/doc/operations/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/alerts.md b/doc/operations/metrics/alerts.md index 98beb8d6773..472892c77f9 100644 --- a/doc/operations/metrics/alerts.md +++ b/doc/operations/metrics/alerts.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/default.md b/doc/operations/metrics/dashboards/default.md index 3c151586f12..2ba7a4e0d87 100644 --- a/doc/operations/metrics/dashboards/default.md +++ b/doc/operations/metrics/dashboards/default.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/develop.md b/doc/operations/metrics/dashboards/develop.md index 76ad609870c..28a4488014a 100644 --- a/doc/operations/metrics/dashboards/develop.md +++ b/doc/operations/metrics/dashboards/develop.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/index.md b/doc/operations/metrics/dashboards/index.md index a0ac4fe6226..7b056020a99 100644 --- a/doc/operations/metrics/dashboards/index.md +++ b/doc/operations/metrics/dashboards/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/panel_types.md b/doc/operations/metrics/dashboards/panel_types.md index 4b942ffcf4f..dc96e2556ac 100644 --- a/doc/operations/metrics/dashboards/panel_types.md +++ b/doc/operations/metrics/dashboards/panel_types.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/settings.md b/doc/operations/metrics/dashboards/settings.md index 18cfd6c53b8..e998db6b51b 100644 --- a/doc/operations/metrics/dashboards/settings.md +++ b/doc/operations/metrics/dashboards/settings.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/templating_variables.md b/doc/operations/metrics/dashboards/templating_variables.md index 72541f7ced5..20071300dec 100644 --- a/doc/operations/metrics/dashboards/templating_variables.md +++ b/doc/operations/metrics/dashboards/templating_variables.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/variables.md b/doc/operations/metrics/dashboards/variables.md index df2dd0939bb..31782b5c95f 100644 --- a/doc/operations/metrics/dashboards/variables.md +++ b/doc/operations/metrics/dashboards/variables.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/yaml.md b/doc/operations/metrics/dashboards/yaml.md index 138d9b28c76..45803598a40 100644 --- a/doc/operations/metrics/dashboards/yaml.md +++ b/doc/operations/metrics/dashboards/yaml.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/dashboards/yaml_number_format.md b/doc/operations/metrics/dashboards/yaml_number_format.md index dd652a0cc2b..3b6e10e647e 100644 --- a/doc/operations/metrics/dashboards/yaml_number_format.md +++ b/doc/operations/metrics/dashboards/yaml_number_format.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/embed.md b/doc/operations/metrics/embed.md index 87d84bfdfc0..d773d04f1cc 100644 --- a/doc/operations/metrics/embed.md +++ b/doc/operations/metrics/embed.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/embed_grafana.md b/doc/operations/metrics/embed_grafana.md index 2548e81813b..3b509f7c4c6 100644 --- a/doc/operations/metrics/embed_grafana.md +++ b/doc/operations/metrics/embed_grafana.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/metrics/index.md b/doc/operations/metrics/index.md index ca7bce347d3..8ff45ac4015 100644 --- a/doc/operations/metrics/index.md +++ b/doc/operations/metrics/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/operations/tracing.md b/doc/operations/tracing.md index a4aae05c46d..bf9e0d2390e 100644 --- a/doc/operations/tracing.md +++ b/doc/operations/tracing.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/raketasks/generate_sample_prometheus_data.md b/doc/raketasks/generate_sample_prometheus_data.md index 41e31c0b817..f014b82cca1 100644 --- a/doc/raketasks/generate_sample_prometheus_data.md +++ b/doc/raketasks/generate_sample_prometheus_data.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md index 38d95ccd0be..fa0f32a8fb0 100644 --- a/doc/user/clusters/agent/index.md +++ b/doc/user/clusters/agent/index.md @@ -176,23 +176,9 @@ documentation on the [Kubernetes Agent configuration repository](repository.md). ### Create an Agent record in GitLab -Next, create an GitLab Rails Agent record so the Agent can associate itself with +Next, create a GitLab Rails Agent record to associate it with the configuration repository project. Creating this record also creates a Secret needed to configure -the Agent in subsequent steps. You can create an Agent record either: - -- Through the Rails console: - - ```ruby - project = ::Project.find_by_full_path("path-to/your-configuration-project") - # agent-name should be the same as specified above in the config.yaml - agent = ::Clusters::Agent.create(name: "<agent-name>", project: project) - token = ::Clusters::AgentToken.create(agent: agent) - token.token # this will print out the token you need to use on the next step - ``` - - For full details, read [Starting a Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session). - -- Through GraphQL: **(PREMIUM SELF)** +the Agent in subsequent steps. You can create an Agent record with GraphQL: ```graphql mutation createAgent { diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index 1af452d75da..6b144556e05 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/clusters/kubernetes_pod_logs.md b/doc/user/project/clusters/kubernetes_pod_logs.md index 349040e0bf6..bafb7d472c6 100644 --- a/doc/user/project/clusters/kubernetes_pod_logs.md +++ b/doc/user/project/clusters/kubernetes_pod_logs.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md index c307fd8d628..05dd4da88fc 100644 --- a/doc/user/project/integrations/prometheus.md +++ b/doc/user/project/integrations/prometheus.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/cloudwatch.md b/doc/user/project/integrations/prometheus_library/cloudwatch.md index 04abb922175..0eaa9cae7c0 100644 --- a/doc/user/project/integrations/prometheus_library/cloudwatch.md +++ b/doc/user/project/integrations/prometheus_library/cloudwatch.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/haproxy.md b/doc/user/project/integrations/prometheus_library/haproxy.md index 290313ac1af..11b74c35a74 100644 --- a/doc/user/project/integrations/prometheus_library/haproxy.md +++ b/doc/user/project/integrations/prometheus_library/haproxy.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/index.md b/doc/user/project/integrations/prometheus_library/index.md index 998300e255f..584c0898fec 100644 --- a/doc/user/project/integrations/prometheus_library/index.md +++ b/doc/user/project/integrations/prometheus_library/index.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/kubernetes.md b/doc/user/project/integrations/prometheus_library/kubernetes.md index 2a6bc810f71..e14c1c0f6fd 100644 --- a/doc/user/project/integrations/prometheus_library/kubernetes.md +++ b/doc/user/project/integrations/prometheus_library/kubernetes.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/nginx.md b/doc/user/project/integrations/prometheus_library/nginx.md index dcaef1e2ae6..3f888a89b1b 100644 --- a/doc/user/project/integrations/prometheus_library/nginx.md +++ b/doc/user/project/integrations/prometheus_library/nginx.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress.md b/doc/user/project/integrations/prometheus_library/nginx_ingress.md index f7e6b6e76d6..8846aadd420 100644 --- a/doc/user/project/integrations/prometheus_library/nginx_ingress.md +++ b/doc/user/project/integrations/prometheus_library/nginx_ingress.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md index 0c86c4921b3..4752fec976c 100644 --- a/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md +++ b/doc/user/project/integrations/prometheus_library/nginx_ingress_vts.md @@ -1,6 +1,6 @@ --- stage: Monitor -group: Health +group: Monitor info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- diff --git a/doc/user/project/integrations/webhooks.md b/doc/user/project/integrations/webhooks.md index bf289c9707c..dc63a32ed10 100644 --- a/doc/user/project/integrations/webhooks.md +++ b/doc/user/project/integrations/webhooks.md @@ -1297,6 +1297,7 @@ X-Gitlab-Event: Job Hook "build_name": "test", "build_stage": "test", "build_status": "created", + "build_created_at": "2021-02-23T02:41:37.886Z", "build_started_at": null, "build_finished_at": null, "build_duration": null, diff --git a/lib/bulk_imports/groups/graphql/get_labels_query.rb b/lib/bulk_imports/groups/graphql/get_labels_query.rb index 23efbc33581..2d246a217a7 100644 --- a/lib/bulk_imports/groups/graphql/get_labels_query.rb +++ b/lib/bulk_imports/groups/graphql/get_labels_query.rb @@ -31,7 +31,7 @@ module BulkImports def variables(context) { full_path: context.entity.source_full_path, - cursor: context.entity.next_page_for(:labels) + cursor: context.tracker.next_page } end diff --git a/lib/bulk_imports/groups/graphql/get_members_query.rb b/lib/bulk_imports/groups/graphql/get_members_query.rb index e3a78124a47..f3a0d77acc2 100644 --- a/lib/bulk_imports/groups/graphql/get_members_query.rb +++ b/lib/bulk_imports/groups/graphql/get_members_query.rb @@ -34,7 +34,7 @@ module BulkImports def variables(context) { full_path: context.entity.source_full_path, - cursor: context.entity.next_page_for(:group_members) + cursor: context.tracker.next_page } end diff --git a/lib/bulk_imports/groups/graphql/get_milestones_query.rb b/lib/bulk_imports/groups/graphql/get_milestones_query.rb index 2ade87e6fa0..c254b35054a 100644 --- a/lib/bulk_imports/groups/graphql/get_milestones_query.rb +++ b/lib/bulk_imports/groups/graphql/get_milestones_query.rb @@ -33,7 +33,7 @@ module BulkImports def variables(context) { full_path: context.entity.source_full_path, - cursor: context.entity.next_page_for(:milestones) + cursor: context.tracker.next_page } end diff --git a/lib/bulk_imports/groups/pipelines/labels_pipeline.rb b/lib/bulk_imports/groups/pipelines/labels_pipeline.rb index 9f8b8682751..61d3e6c700e 100644 --- a/lib/bulk_imports/groups/pipelines/labels_pipeline.rb +++ b/lib/bulk_imports/groups/pipelines/labels_pipeline.rb @@ -16,8 +16,7 @@ module BulkImports end def after_run(extracted_data) - context.entity.update_tracker_for( - relation: :labels, + tracker.update( has_next_page: extracted_data.has_next_page?, next_page: extracted_data.next_page ) diff --git a/lib/bulk_imports/groups/pipelines/members_pipeline.rb b/lib/bulk_imports/groups/pipelines/members_pipeline.rb index 32fc931e8c3..d29bd74c5ae 100644 --- a/lib/bulk_imports/groups/pipelines/members_pipeline.rb +++ b/lib/bulk_imports/groups/pipelines/members_pipeline.rb @@ -19,8 +19,7 @@ module BulkImports end def after_run(extracted_data) - context.entity.update_tracker_for( - relation: :group_members, + tracker.update( has_next_page: extracted_data.has_next_page?, next_page: extracted_data.next_page ) diff --git a/lib/bulk_imports/groups/pipelines/milestones_pipeline.rb b/lib/bulk_imports/groups/pipelines/milestones_pipeline.rb index 8497162e0e7..eb51424c14a 100644 --- a/lib/bulk_imports/groups/pipelines/milestones_pipeline.rb +++ b/lib/bulk_imports/groups/pipelines/milestones_pipeline.rb @@ -20,8 +20,7 @@ module BulkImports end def after_run(extracted_data) - context.entity.update_tracker_for( - relation: :milestones, + tracker.update( has_next_page: extracted_data.has_next_page?, next_page: extracted_data.next_page ) diff --git a/lib/bulk_imports/importers/group_importer.rb b/lib/bulk_imports/importers/group_importer.rb index f016b552fd4..ccc61ee787d 100644 --- a/lib/bulk_imports/importers/group_importer.rb +++ b/lib/bulk_imports/importers/group_importer.rb @@ -8,9 +8,18 @@ module BulkImports end def execute - context = BulkImports::Pipeline::Context.new(entity) + pipelines.each.with_index do |pipeline, stage| + pipeline_tracker = entity.trackers.create!( + pipeline_name: pipeline, + stage: stage + ) - pipelines.each { |pipeline| pipeline.new(context).run } + context = BulkImports::Pipeline::Context.new(pipeline_tracker) + + pipeline.new(context).run + + pipeline_tracker.finish! + end entity.finish! end diff --git a/lib/bulk_imports/pipeline.rb b/lib/bulk_imports/pipeline.rb index 14445162737..df4f020d6b2 100644 --- a/lib/bulk_imports/pipeline.rb +++ b/lib/bulk_imports/pipeline.rb @@ -15,6 +15,10 @@ module BulkImports @context = context end + def tracker + @tracker ||= context.tracker + end + included do private diff --git a/lib/bulk_imports/pipeline/context.rb b/lib/bulk_imports/pipeline/context.rb index dd121b2dbed..3c69c729f36 100644 --- a/lib/bulk_imports/pipeline/context.rb +++ b/lib/bulk_imports/pipeline/context.rb @@ -3,25 +3,33 @@ module BulkImports module Pipeline class Context - attr_reader :entity, :bulk_import attr_accessor :extra - def initialize(entity, extra = {}) - @entity = entity - @bulk_import = entity.bulk_import + attr_reader :tracker + + def initialize(tracker, extra = {}) + @tracker = tracker @extra = extra end + def entity + @entity ||= tracker.entity + end + def group - entity.group + @group ||= entity.group + end + + def bulk_import + @bulk_import ||= entity.bulk_import end def current_user - bulk_import.user + @current_user ||= bulk_import.user end def configuration - bulk_import.configuration + @configuration ||= bulk_import.configuration end end end diff --git a/lib/bulk_imports/pipeline/extracted_data.rb b/lib/bulk_imports/pipeline/extracted_data.rb index 685a91a4afe..15b5caa1a47 100644 --- a/lib/bulk_imports/pipeline/extracted_data.rb +++ b/lib/bulk_imports/pipeline/extracted_data.rb @@ -11,11 +11,14 @@ module BulkImports end def has_next_page? - @page_info['has_next_page'] + Gitlab::Utils.to_boolean( + @page_info&.dig('has_next_page'), + default: false + ) end def next_page - @page_info['end_cursor'] + @page_info&.dig('end_cursor') end def each(&block) diff --git a/lib/bulk_imports/pipeline/runner.rb b/lib/bulk_imports/pipeline/runner.rb index e3535e585cc..588d2c87209 100644 --- a/lib/bulk_imports/pipeline/runner.rb +++ b/lib/bulk_imports/pipeline/runner.rb @@ -26,7 +26,7 @@ module BulkImports end end - if respond_to?(:after_run) + if extracted_data && respond_to?(:after_run) run_pipeline_step(:after_run) do after_run(extracted_data) end @@ -34,7 +34,7 @@ module BulkImports info(message: 'Pipeline finished') rescue MarkedAsFailedError - log_skip + skip!('Skipping pipeline due to failed entity') end private # rubocop:disable Lint/UselessAccessModifier @@ -46,7 +46,11 @@ module BulkImports yield rescue MarkedAsFailedError - log_skip(step => class_name) + skip!( + 'Skipping pipeline due to failed entity', + pipeline_step: step, + step_class: class_name + ) rescue => e log_import_failure(e, step) @@ -65,10 +69,13 @@ module BulkImports warn(message: 'Pipeline failed') context.entity.fail_op! + tracker.fail_op! end - def log_skip(extra = {}) - info({ message: 'Skipping due to failed pipeline status' }.merge(extra)) + def skip!(message, extra = {}) + warn({ message: message }.merge(extra)) + + tracker.skip! end def log_import_failure(exception, step) diff --git a/lib/gitlab/ci/queue/metrics.rb b/lib/gitlab/ci/queue/metrics.rb index 5398c19e536..b25e715bc00 100644 --- a/lib/gitlab/ci/queue/metrics.rb +++ b/lib/gitlab/ci/queue/metrics.rb @@ -10,7 +10,7 @@ module Gitlab QUEUE_ACTIVE_RUNNERS_BUCKETS = [1, 3, 10, 30, 60, 300, 900, 1800, 3600].freeze QUEUE_DEPTH_TOTAL_BUCKETS = [1, 2, 3, 5, 8, 16, 32, 50, 100, 250, 500, 1000, 2000, 5000].freeze QUEUE_SIZE_TOTAL_BUCKETS = [1, 5, 10, 50, 100, 500, 1000, 2000, 5000].freeze - QUEUE_ITERATION_DURATION_SECONDS_BUCKETS = [0.1, 0.3, 0.5, 1, 5, 10, 30, 60, 180, 300].freeze + QUEUE_PROCESSING_DURATION_SECONDS_BUCKETS = [0.01, 0.05, 0.1, 0.3, 0.5, 1, 5, 10, 30, 60, 180, 300].freeze METRICS_SHARD_TAG_PREFIX = 'metrics_shard::' DEFAULT_METRICS_SHARD = 'default' @@ -100,7 +100,7 @@ module Gitlab self.class.queue_size_total.observe({}, size_proc.call.to_f) end - def observe_queue_time + def observe_queue_time(metric) start_time = ::Gitlab::Metrics::System.monotonic_time result = yield @@ -108,7 +108,15 @@ module Gitlab return result unless Feature.enabled?(:gitlab_ci_builds_queuing_metrics, default_enabled: false) seconds = ::Gitlab::Metrics::System.monotonic_time - start_time - self.class.queue_iteration_duration_seconds.observe({}, seconds.to_f) + + case metric + when :process + self.class.queue_iteration_duration_seconds.observe({}, seconds.to_f) + when :retrieve + self.class.queue_retrieval_duration_seconds.observe({}, seconds.to_f) + else + raise ArgumentError unless Rails.env.production? + end result end @@ -187,7 +195,18 @@ module Gitlab strong_memoize(:queue_iteration_duration_seconds) do name = :gitlab_ci_queue_iteration_duration_seconds comment = 'Time it takes to find a build in CI/CD queue' - buckets = QUEUE_ITERATION_DURATION_SECONDS_BUCKETS + buckets = QUEUE_PROCESSING_DURATION_SECONDS_BUCKETS + labels = {} + + Gitlab::Metrics.histogram(name, comment, labels, buckets) + end + end + + def self.queue_retrieval_duration_seconds + strong_memoize(:queue_retrieval_duration_seconds) do + name = :gitlab_ci_queue_retrieval_duration_seconds + comment = 'Time it takes to execute a SQL query to retrieve builds queue' + buckets = QUEUE_PROCESSING_DURATION_SECONDS_BUCKETS labels = {} Gitlab::Metrics.histogram(name, comment, labels, buckets) diff --git a/lib/gitlab/ci/yaml_processor/result.rb b/lib/gitlab/ci/yaml_processor/result.rb index 3459b69bebc..f2c75227002 100644 --- a/lib/gitlab/ci/yaml_processor/result.rb +++ b/lib/gitlab/ci/yaml_processor/result.rb @@ -101,7 +101,7 @@ module Gitlab end def merged_yaml - @ci_config&.to_hash&.to_yaml + @ci_config&.to_hash&.deep_stringify_keys&.to_yaml end def variables_with_data diff --git a/lib/gitlab/data_builder/build.rb b/lib/gitlab/data_builder/build.rb index c4af5e6608e..8ce71558ab3 100644 --- a/lib/gitlab/data_builder/build.rb +++ b/lib/gitlab/data_builder/build.rb @@ -26,6 +26,7 @@ module Gitlab build_name: build.name, build_stage: build.stage, build_status: build.status, + build_created_at: build.created_at, build_started_at: build.started_at, build_finished_at: build.finished_at, build_duration: build.duration, diff --git a/lib/gitlab/updated_notes_paginator.rb b/lib/gitlab/updated_notes_paginator.rb index 511d6dccf7c..d5c01bde6b3 100644 --- a/lib/gitlab/updated_notes_paginator.rb +++ b/lib/gitlab/updated_notes_paginator.rb @@ -37,7 +37,7 @@ module Gitlab end def fetch_page(relation) - relation = relation.by_updated_at + relation = relation.order_updated_asc.with_order_id_asc notes = relation.limit(LIMIT + 1).to_a return [notes, false] unless notes.size > LIMIT diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 79def8448fb..22f146e0d06 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -24052,9 +24052,6 @@ msgstr "" msgid "ProjectSettings|Pages for project documentation." msgstr "" -msgid "ProjectSettings|Pipelines" -msgstr "" - msgid "ProjectSettings|Pipelines must succeed" msgstr "" diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb index 6dc1cbfb2d7..aad5d319bc4 100644 --- a/spec/features/issues/markdown_toolbar_spec.rb +++ b/spec/features/issues/markdown_toolbar_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' RSpec.describe 'Issue markdown toolbar', :js do - let(:project) { create(:project, :public) } - let(:issue) { create(:issue, project: project) } - let(:user) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:user) { create(:user) } before do sign_in(user) @@ -14,28 +14,22 @@ RSpec.describe 'Issue markdown toolbar', :js do end it "doesn't include first new line when adding bold" do - find('#note-body').native.send_keys('test') - find('#note-body').native.send_key(:enter) - find('#note-body').native.send_keys('bold') + fill_in 'Comment', with: "test\nbold" - find('.js-main-target-form #note-body') - page.evaluate_script('document.querySelectorAll(".js-main-target-form #note-body")[0].setSelectionRange(4, 9)') + page.evaluate_script('document.getElementById("note-body").setSelectionRange(4, 9)') - first('.toolbar-btn').click + click_button 'Add bold text' - expect(find('#note-body')[:value]).to eq("test\n**bold**\n") + expect(find_field('Comment').value).to eq("test\n**bold**\n") end it "doesn't include first new line when adding underline" do - find('#note-body').native.send_keys('test') - find('#note-body').native.send_key(:enter) - find('#note-body').native.send_keys('underline') + fill_in 'Comment', with: "test\nunderline" - find('.js-main-target-form #note-body') - page.evaluate_script('document.querySelectorAll(".js-main-target-form #note-body")[0].setSelectionRange(4, 50)') + page.evaluate_script('document.getElementById("note-body").setSelectionRange(4, 50)') - all('.toolbar-btn')[1].click + click_button 'Add italic text' - expect(find('#note-body')[:value]).to eq("test\n_underline_\n") + expect(find_field('Comment').value).to eq("test\n_underline_\n") end end diff --git a/spec/features/issues/user_comments_on_issue_spec.rb b/spec/features/issues/user_comments_on_issue_spec.rb index 004488f2f64..09d3ad15641 100644 --- a/spec/features/issues/user_comments_on_issue_spec.rb +++ b/spec/features/issues/user_comments_on_issue_spec.rb @@ -57,17 +57,9 @@ RSpec.describe "User comments on issue", :js do project.add_maintainer(user) create(:label, project: project, title: 'label') - page.within '.timeline-content-form' do - find('#note-body').native.send_keys('/l') - end - - wait_for_requests - - expect(page).to have_selector('.atwho-container') + fill_in 'Comment', with: '/l' - page.within '.atwho-container #at-view-commands' do - expect(find('li', match: :first)).to have_content('/label') - end + expect(find_highlighted_autocomplete_item).to have_content('/label') end end @@ -110,4 +102,10 @@ RSpec.describe "User comments on issue", :js do end end end + + private + + def find_highlighted_autocomplete_item + find('.atwho-view li.cur', visible: true) + end end diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index 9d4a6cdb522..b8e35c9afa3 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -142,10 +142,8 @@ RSpec.describe "Issues > User edits issue", :js do it 'can remove label without removing label added via quick action', :aggregate_failures do # Add `syzygy` label with a quick action - note = find('#note-body') - page.within '.timeline-content-form' do - note.native.send_keys('/label ~syzygy') - end + fill_in 'Comment', with: '/label ~syzygy' + click_button 'Comment' wait_for_requests diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index 3099a893dc2..b6ec5b72d28 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -182,9 +182,9 @@ RSpec.describe 'Merge request > User posts notes', :js do find('.js-note-edit').click page.within('.current-note-edit-form') do - expect(find('#note_note').value).to include('This is the new content') + expect(find_field('note[note]').value).to include('This is the new content') first('.js-md').click - expect(find('#note_note').value).to include('This is the new content****') + expect(find_field('note[note]').value).to include('This is the new content****') end end diff --git a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb index ea46ae06329..b8b7fc2009f 100644 --- a/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb +++ b/spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb @@ -28,8 +28,8 @@ RSpec.describe 'Merge request > User sees notes from forked project', :js do page.within('.discussion-notes') do find_field('Reply…').click - scroll_to(page.find('#note_note', visible: false)) - find('#note_note').send_keys('A reply comment') + scroll_to(find_field('note[note]', visible: false)) + fill_in 'note[note]', with: 'A reply comment' find('.js-comment-button').click end diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb index b22778012a8..2781cfffbaf 100644 --- a/spec/features/participants_autocomplete_spec.rb +++ b/spec/features/participants_autocomplete_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' RSpec.describe 'Member autocomplete', :js do - let(:project) { create(:project, :public) } - let(:user) { create(:user) } - let(:author) { create(:user) } + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:user) { create(:user) } + let_it_be(:author) { create(:user) } let(:note) { create(:note, noteable: noteable, project: noteable.project) } before do @@ -15,20 +15,16 @@ RSpec.describe 'Member autocomplete', :js do shared_examples "open suggestions when typing @" do |resource_name| before do - page.within('.new-note') do - if resource_name == 'commit' - find('#note_note').send_keys('@') - else - find('#note-body').send_keys('@') - end + if resource_name == 'commit' + fill_in 'note[note]', with: '@' + else + fill_in 'Comment', with: '@' end end it 'suggests noteable author and note author' do - page.within('.atwho-view', visible: true) do - expect(page).to have_content(author.username) - expect(page).to have_content(note.author.username) - end + expect(find_autocomplete_menu).to have_text(author.username) + expect(find_autocomplete_menu).to have_text(note.author.username) end end @@ -51,22 +47,17 @@ RSpec.describe 'Member autocomplete', :js do stub_feature_flags(tribute_autocomplete: true) visit project_issue_path(project, noteable) - page.within('.new-note') do - find('#note-body').send_keys('@') - end + fill_in 'Comment', with: '@' end it 'suggests noteable author and note author' do - page.within('.tribute-container', visible: true) do - expect(page).to have_content(author.username) - expect(page).to have_content(note.author.username) - end + expect(find_tribute_autocomplete_menu).to have_content(author.username) + expect(find_tribute_autocomplete_menu).to have_content(note.author.username) end end end context 'adding a new note on a Merge Request' do - let(:project) { create(:project, :public, :repository) } let(:noteable) do create(:merge_request, source_project: project, target_project: project, author: author) @@ -80,7 +71,6 @@ RSpec.describe 'Member autocomplete', :js do end context 'adding a new note on a Commit' do - let(:project) { create(:project, :public, :repository) } let(:noteable) { project.commit } let(:note) { create(:note_on_commit, project: project, commit_id: project.commit.id) } @@ -94,4 +84,14 @@ RSpec.describe 'Member autocomplete', :js do include_examples "open suggestions when typing @", 'commit' end + + private + + def find_autocomplete_menu + find('.atwho-view ul', visible: true) + end + + def find_tribute_autocomplete_menu + find('.tribute-container ul', visible: true) + end end diff --git a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb index 55b9f38d8e7..b0ccb5fca94 100644 --- a/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb +++ b/spec/features/projects/files/gitlab_ci_yml_dropdown_spec.rb @@ -5,10 +5,14 @@ require 'spec_helper' RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js do include Spec::Support::Helpers::Features::EditorLiteSpecHelpers + let(:params) { {} } + let(:filename) { '.gitlab-ci.yml' } + + let_it_be(:project) { create(:project, :repository) } + before do - project = create(:project, :repository) sign_in project.owner - visit project_new_blob_path(project, 'master', file_name: '.gitlab-ci.yml') + visit project_new_blob_path(project, 'master', file_name: filename, **params) end it 'user can pick a template from the dropdown' do @@ -29,4 +33,38 @@ RSpec.describe 'Projects > Files > User wants to add a .gitlab-ci.yml file', :js expect(editor_get_value).to have_content('This file is a template, and might need editing before it works on your project') expect(editor_get_value).to have_content('jekyll build -d test') end + + context 'when template param is provided' do + let(:params) { { template: 'Jekyll' } } + + it 'uses the given template' do + wait_for_requests + + expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') + expect(editor_get_value).to have_content('This file is a template, and might need editing before it works on your project') + expect(editor_get_value).to have_content('jekyll build -d test') + end + end + + context 'when provided template param is not a valid template name' do + let(:params) { { template: 'non-existing-template' } } + + it 'leaves the editor empty' do + wait_for_requests + + expect(page).to have_css('.gitlab-ci-yml-selector .dropdown-toggle-text', text: 'Apply a template') + expect(editor_get_value).to have_content('') + end + end + + context 'when template is not available for the given file' do + let(:filename) { 'Dockerfile' } + let(:params) { { template: 'Jekyll' } } + + it 'leaves the editor empty' do + wait_for_requests + + expect(editor_get_value).to have_content('') + end + end end diff --git a/spec/features/projects/jobs/user_browses_jobs_spec.rb b/spec/features/projects/jobs/user_browses_jobs_spec.rb index 5abebf2320e..345bceeed31 100644 --- a/spec/features/projects/jobs/user_browses_jobs_spec.rb +++ b/spec/features/projects/jobs/user_browses_jobs_spec.rb @@ -24,14 +24,6 @@ RSpec.describe 'User browses jobs' do end end - it 'shows the "CI Lint" button' do - page.within('.nav-controls') do - ci_lint_tool_link = page.find_link('CI Lint') - - expect(ci_lint_tool_link[:href]).to end_with(project_ci_lint_path(project)) - end - end - context 'with a failed job' do let!(:build) { create(:ci_build, :coverage, :failed, pipeline: pipeline) } diff --git a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb index b37d40c0eed..3ccb73c88ef 100644 --- a/spec/features/projects/snippets/user_comments_on_snippet_spec.rb +++ b/spec/features/projects/snippets/user_comments_on_snippet_spec.rb @@ -29,7 +29,6 @@ RSpec.describe 'Projects > Snippets > User comments on a snippet', :js do end it 'has autocomplete' do - find('#note_note').native.send_keys('') fill_in 'note[note]', with: '@' expect(page).to have_selector('.atwho-view') diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index ce9a2d1461e..47dad9bd88e 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -108,9 +108,6 @@ RSpec.describe 'Comments on personal snippets', :js do end it 'does not have autocomplete' do - wait_for_requests - - find('#note_note').native.send_keys('') fill_in 'note[note]', with: '@' wait_for_requests diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb index 868b126dc28..11de19cfdbc 100644 --- a/spec/finders/notes_finder_spec.rb +++ b/spec/finders/notes_finder_spec.rb @@ -213,6 +213,24 @@ RSpec.describe NotesFinder do expect { described_class.new(user, params).execute }.to raise_error(RuntimeError) end end + + describe 'sorting' do + it 'allows sorting' do + params = { project: project, sort: 'id_desc' } + + expect(Note).to receive(:order_id_desc).once + + described_class.new(user, params).execute + end + + it 'defaults to sort by .fresh' do + params = { project: project } + + expect(Note).to receive(:fresh).once + + described_class.new(user, params).execute + end + end end describe '.search' do diff --git a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js index bee628c3a56..0934dde8230 100644 --- a/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js +++ b/spec/frontend/pages/projects/shared/permissions/components/settings_panel_spec.js @@ -228,7 +228,7 @@ describe('Settings Panel', () => { }); }); - describe('Pipelines', () => { + describe('CI/CD', () => { it('should enable the builds access level input when the repository is enabled', () => { wrapper = mountComponent({ currentSettings: { repositoryAccessLevel: featureAccessLevel.EVERYONE }, diff --git a/spec/frontend/vue_shared/components/lib/utils/props_utils_spec.js b/spec/frontend/vue_shared/components/lib/utils/props_utils_spec.js new file mode 100644 index 00000000000..f1c9fbb00c9 --- /dev/null +++ b/spec/frontend/vue_shared/components/lib/utils/props_utils_spec.js @@ -0,0 +1,91 @@ +import { propsUnion } from '~/vue_shared/components/lib/utils/props_utils'; + +describe('propsUnion', () => { + const stringRequired = { + type: String, + required: true, + }; + + const stringOptional = { + type: String, + required: false, + }; + + const numberOptional = { + type: Number, + required: false, + }; + + const booleanRequired = { + type: Boolean, + required: true, + }; + + const FooComponent = { + props: { foo: stringRequired }, + }; + + const BarComponent = { + props: { bar: numberOptional }, + }; + + const FooBarComponent = { + props: { + foo: stringRequired, + bar: numberOptional, + }, + }; + + const FooOptionalComponent = { + props: { + foo: stringOptional, + }, + }; + + const QuxComponent = { + props: { + foo: booleanRequired, + qux: stringRequired, + }, + }; + + it('returns an empty object given no components', () => { + expect(propsUnion([])).toEqual({}); + }); + + it('merges non-overlapping props', () => { + expect(propsUnion([FooComponent, BarComponent])).toEqual({ + ...FooComponent.props, + ...BarComponent.props, + }); + }); + + it('merges overlapping props', () => { + expect(propsUnion([FooComponent, BarComponent, FooBarComponent])).toEqual({ + ...FooComponent.props, + ...BarComponent.props, + ...FooBarComponent.props, + }); + }); + + it.each` + components + ${[FooComponent, FooOptionalComponent]} + ${[FooOptionalComponent, FooComponent]} + `('prefers required props over non-required props', ({ components }) => { + expect(propsUnion(components)).toEqual(FooComponent.props); + }); + + it('throws if given props with conflicting types', () => { + expect(() => propsUnion([FooComponent, QuxComponent])).toThrow(/incompatible prop types/); + }); + + it.each` + components + ${[{ props: ['foo', 'bar'] }]} + ${[{ props: { foo: String, bar: Number } }]} + ${[{ props: { foo: {}, bar: {} } }]} + `('throw if given a non-verbose props object', ({ components }) => { + expect(() => propsUnion(components)).toThrow(/expected verbose prop/); + }); +}); diff --git a/spec/lib/bulk_imports/common/transformers/user_reference_transformer_spec.rb b/spec/lib/bulk_imports/common/transformers/user_reference_transformer_spec.rb index ff11a10bfe9..e86a584d38a 100644 --- a/spec/lib/bulk_imports/common/transformers/user_reference_transformer_spec.rb +++ b/spec/lib/bulk_imports/common/transformers/user_reference_transformer_spec.rb @@ -8,7 +8,8 @@ RSpec.describe BulkImports::Common::Transformers::UserReferenceTransformer do let_it_be(:group) { create(:group) } let_it_be(:bulk_import) { create(:bulk_import) } let_it_be(:entity) { create(:bulk_import_entity, bulk_import: bulk_import, group: group) } - let_it_be(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } let(:hash) do { diff --git a/spec/lib/bulk_imports/groups/extractors/subgroups_extractor_spec.rb b/spec/lib/bulk_imports/groups/extractors/subgroups_extractor_spec.rb index 627247c04ab..ac8786440e9 100644 --- a/spec/lib/bulk_imports/groups/extractors/subgroups_extractor_spec.rb +++ b/spec/lib/bulk_imports/groups/extractors/subgroups_extractor_spec.rb @@ -8,8 +8,9 @@ RSpec.describe BulkImports::Groups::Extractors::SubgroupsExtractor do bulk_import = create(:bulk_import) create(:bulk_import_configuration, bulk_import: bulk_import) entity = create(:bulk_import_entity, bulk_import: bulk_import) + tracker = create(:bulk_import_tracker, entity: entity) response = [{ 'test' => 'group' }] - context = BulkImports::Pipeline::Context.new(entity) + context = BulkImports::Pipeline::Context.new(tracker) allow_next_instance_of(BulkImports::Clients::Http) do |client| allow(client).to receive(:each_page).and_return(response) diff --git a/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb index ef46da7062b..b0f8f74783b 100644 --- a/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb +++ b/spec/lib/bulk_imports/groups/graphql/get_group_query_spec.rb @@ -4,10 +4,10 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Graphql::GetGroupQuery do describe '#variables' do - let(:entity) { double(source_full_path: 'test', bulk_import: nil) } - let(:context) { BulkImports::Pipeline::Context.new(entity) } - it 'returns query variables based on entity information' do + entity = double(source_full_path: 'test', bulk_import: nil) + tracker = double(entity: entity) + context = BulkImports::Pipeline::Context.new(tracker) expected = { full_path: entity.source_full_path } expect(described_class.variables(context)).to eq(expected) diff --git a/spec/lib/bulk_imports/groups/graphql/get_labels_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_labels_query_spec.rb index 85f82be7d18..61db644a372 100644 --- a/spec/lib/bulk_imports/groups/graphql/get_labels_query_spec.rb +++ b/spec/lib/bulk_imports/groups/graphql/get_labels_query_spec.rb @@ -4,8 +4,8 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Graphql::GetLabelsQuery do it 'has a valid query' do - entity = create(:bulk_import_entity) - context = BulkImports::Pipeline::Context.new(entity) + tracker = create(:bulk_import_tracker) + context = BulkImports::Pipeline::Context.new(tracker) query = GraphQL::Query.new( GitlabSchema, diff --git a/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb index 5d05f5a2d30..d0c4bb817b2 100644 --- a/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb +++ b/spec/lib/bulk_imports/groups/graphql/get_members_query_spec.rb @@ -4,8 +4,8 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Graphql::GetMembersQuery do it 'has a valid query' do - entity = create(:bulk_import_entity) - context = BulkImports::Pipeline::Context.new(entity) + tracker = create(:bulk_import_tracker) + context = BulkImports::Pipeline::Context.new(tracker) query = GraphQL::Query.new( GitlabSchema, diff --git a/spec/lib/bulk_imports/groups/graphql/get_milestones_query_spec.rb b/spec/lib/bulk_imports/groups/graphql/get_milestones_query_spec.rb index a38505fbf85..7a0f964c5f3 100644 --- a/spec/lib/bulk_imports/groups/graphql/get_milestones_query_spec.rb +++ b/spec/lib/bulk_imports/groups/graphql/get_milestones_query_spec.rb @@ -4,8 +4,8 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Graphql::GetMilestonesQuery do it 'has a valid query' do - entity = create(:bulk_import_entity) - context = BulkImports::Pipeline::Context.new(entity) + tracker = create(:bulk_import_tracker) + context = BulkImports::Pipeline::Context.new(tracker) query = GraphQL::Query.new( GitlabSchema, diff --git a/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb b/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb index 183292722d2..533955b057c 100644 --- a/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb +++ b/spec/lib/bulk_imports/groups/loaders/group_loader_spec.rb @@ -4,12 +4,13 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Loaders::GroupLoader do describe '#load' do - let(:user) { create(:user) } - let(:data) { { foo: :bar } } + let_it_be(:user) { create(:user) } + let_it_be(:bulk_import) { create(:bulk_import, user: user) } + let_it_be(:entity) { create(:bulk_import_entity, bulk_import: bulk_import) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } let(:service_double) { instance_double(::Groups::CreateService) } - let(:bulk_import) { create(:bulk_import, user: user) } - let(:entity) { create(:bulk_import_entity, bulk_import: bulk_import) } - let(:context) { BulkImports::Pipeline::Context.new(entity) } + let(:data) { { foo: :bar } } subject { described_class.new } diff --git a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb index 61950cdd9b0..39e782dc093 100644 --- a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb @@ -4,10 +4,11 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Pipelines::GroupPipeline do describe '#run' do - let(:user) { create(:user) } - let(:parent) { create(:group) } - let(:bulk_import) { create(:bulk_import, user: user) } - let(:entity) do + let_it_be(:user) { create(:user) } + let_it_be(:parent) { create(:group) } + let_it_be(:bulk_import) { create(:bulk_import, user: user) } + + let_it_be(:entity) do create( :bulk_import_entity, bulk_import: bulk_import, @@ -17,7 +18,8 @@ RSpec.describe BulkImports::Groups::Pipelines::GroupPipeline do ) end - let(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } let(:group_data) do { @@ -37,7 +39,7 @@ RSpec.describe BulkImports::Groups::Pipelines::GroupPipeline do before do allow_next_instance_of(BulkImports::Common::Extractors::GraphqlExtractor) do |extractor| - allow(extractor).to receive(:extract).and_return([group_data]) + allow(extractor).to receive(:extract).and_return(BulkImports::Pipeline::ExtractedData.new(data: group_data)) end parent.add_owner(user) diff --git a/spec/lib/bulk_imports/groups/pipelines/labels_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/labels_pipeline_spec.rb index 3327a30f1d5..80ad5b69a61 100644 --- a/spec/lib/bulk_imports/groups/pipelines/labels_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/labels_pipeline_spec.rb @@ -3,11 +3,12 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do - let(:user) { create(:user) } - let(:group) { create(:group) } - let(:cursor) { 'cursor' } - let(:timestamp) { Time.new(2020, 01, 01).utc } - let(:entity) do + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:cursor) { 'cursor' } + let_it_be(:timestamp) { Time.new(2020, 01, 01).utc } + + let_it_be(:entity) do create( :bulk_import_entity, source_full_path: 'source/full/path', @@ -17,7 +18,8 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do ) end - let(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } subject { described_class.new(context) } @@ -72,8 +74,6 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do subject.after_run(data) - tracker = entity.trackers.find_by(relation: :labels) - expect(tracker.has_next_page).to eq(true) expect(tracker.next_page).to eq(cursor) end @@ -87,8 +87,6 @@ RSpec.describe BulkImports::Groups::Pipelines::LabelsPipeline do subject.after_run(data) - tracker = entity.trackers.find_by(relation: :labels) - expect(tracker.has_next_page).to eq(false) expect(tracker.next_page).to be_nil end diff --git a/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb index 74d3e09d263..5c82a028751 100644 --- a/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/members_pipeline_spec.rb @@ -11,7 +11,8 @@ RSpec.describe BulkImports::Groups::Pipelines::MembersPipeline do let_it_be(:cursor) { 'cursor' } let_it_be(:bulk_import) { create(:bulk_import, user: user) } let_it_be(:entity) { create(:bulk_import_entity, bulk_import: bulk_import, group: group) } - let_it_be(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } subject { described_class.new(context) } diff --git a/spec/lib/bulk_imports/groups/pipelines/milestones_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/milestones_pipeline_spec.rb index f0c34c65257..15a64a70ff3 100644 --- a/spec/lib/bulk_imports/groups/pipelines/milestones_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/milestones_pipeline_spec.rb @@ -9,7 +9,7 @@ RSpec.describe BulkImports::Groups::Pipelines::MilestonesPipeline do let_it_be(:timestamp) { Time.new(2020, 01, 01).utc } let_it_be(:bulk_import) { create(:bulk_import, user: user) } - let(:entity) do + let_it_be(:entity) do create( :bulk_import_entity, bulk_import: bulk_import, @@ -20,7 +20,8 @@ RSpec.describe BulkImports::Groups::Pipelines::MilestonesPipeline do ) end - let(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } subject { described_class.new(context) } @@ -84,8 +85,6 @@ RSpec.describe BulkImports::Groups::Pipelines::MilestonesPipeline do subject.after_run(data) - tracker = entity.trackers.find_by(relation: :milestones) - expect(tracker.has_next_page).to eq(true) expect(tracker.next_page).to eq(cursor) end @@ -99,8 +98,6 @@ RSpec.describe BulkImports::Groups::Pipelines::MilestonesPipeline do subject.after_run(data) - tracker = entity.trackers.find_by(relation: :milestones) - expect(tracker.has_next_page).to eq(false) expect(tracker.next_page).to be_nil end diff --git a/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb index 2a99646bb4a..fd7265aea34 100644 --- a/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb +++ b/spec/lib/bulk_imports/groups/pipelines/subgroup_entities_pipeline_spec.rb @@ -6,19 +6,13 @@ RSpec.describe BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline do let_it_be(:user) { create(:user) } let_it_be(:group) { create(:group, path: 'group') } let_it_be(:parent) { create(:group, name: 'imported-group', path: 'imported-group') } - let(:context) { BulkImports::Pipeline::Context.new(parent_entity) } + let_it_be(:parent_entity) { create(:bulk_import_entity, destination_namespace: parent.full_path, group: parent) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: parent_entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } subject { described_class.new(context) } describe '#run' do - let!(:parent_entity) do - create( - :bulk_import_entity, - destination_namespace: parent.full_path, - group: parent - ) - end - let(:subgroup_data) do [ { diff --git a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb index b3fe8a2ba25..75d8c15088a 100644 --- a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb +++ b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb @@ -4,11 +4,12 @@ require 'spec_helper' RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do describe '#transform' do - let(:user) { create(:user) } - let(:parent) { create(:group) } - let(:group) { create(:group, name: 'My Source Group', parent: parent) } - let(:bulk_import) { create(:bulk_import, user: user) } - let(:entity) do + let_it_be(:user) { create(:user) } + let_it_be(:parent) { create(:group) } + let_it_be(:group) { create(:group, name: 'My Source Group', parent: parent) } + let_it_be(:bulk_import) { create(:bulk_import, user: user) } + + let_it_be(:entity) do create( :bulk_import_entity, bulk_import: bulk_import, @@ -18,7 +19,8 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do ) end - let(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } let(:data) do { @@ -82,14 +84,7 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do context 'when destination namespace is empty' do it 'does not set parent id' do - entity = create( - :bulk_import_entity, - bulk_import: bulk_import, - source_full_path: 'source/full/path', - destination_name: group.name, - destination_namespace: '' - ) - context = BulkImports::Pipeline::Context.new(entity) + entity.update!(destination_namespace: '') transformed_data = subject.transform(context, data) diff --git a/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb index f66c67fc6a2..f3905a4b6e4 100644 --- a/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb +++ b/spec/lib/bulk_imports/groups/transformers/member_attributes_transformer_spec.rb @@ -8,7 +8,8 @@ RSpec.describe BulkImports::Groups::Transformers::MemberAttributesTransformer do let_it_be(:group) { create(:group) } let_it_be(:bulk_import) { create(:bulk_import, user: user) } let_it_be(:entity) { create(:bulk_import_entity, bulk_import: bulk_import, group: group) } - let_it_be(:context) { BulkImports::Pipeline::Context.new(entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } it 'returns nil when receives no data' do expect(subject.transform(context, nil)).to eq(nil) diff --git a/spec/lib/bulk_imports/importers/group_importer_spec.rb b/spec/lib/bulk_imports/importers/group_importer_spec.rb index 5d501b49e41..9579ee53251 100644 --- a/spec/lib/bulk_imports/importers/group_importer_spec.rb +++ b/spec/lib/bulk_imports/importers/group_importer_spec.rb @@ -3,18 +3,18 @@ require 'spec_helper' RSpec.describe BulkImports::Importers::GroupImporter do - let(:user) { create(:user) } - let(:group) { create(:group) } - let(:bulk_import) { create(:bulk_import) } - let(:bulk_import_entity) { create(:bulk_import_entity, :started, bulk_import: bulk_import, group: group) } - let(:bulk_import_configuration) { create(:bulk_import_configuration, bulk_import: bulk_import) } - let(:context) { BulkImports::Pipeline::Context.new(bulk_import_entity) } + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:bulk_import) { create(:bulk_import) } + let_it_be(:entity) { create(:bulk_import_entity, :started, group: group) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity, pipeline_name: described_class.name) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker) } before do allow(BulkImports::Pipeline::Context).to receive(:new).and_return(context) end - subject { described_class.new(bulk_import_entity) } + subject { described_class.new(entity) } describe '#execute' do it 'starts the entity and run its pipelines' do @@ -33,18 +33,18 @@ RSpec.describe BulkImports::Importers::GroupImporter do subject.execute - expect(bulk_import_entity.reload).to be_finished + expect(entity).to be_finished end context 'when failed' do - let(:bulk_import_entity) { create(:bulk_import_entity, :failed, bulk_import: bulk_import, group: group) } + let(:entity) { create(:bulk_import_entity, :failed, bulk_import: bulk_import, group: group) } it 'does not transition entity to finished state' do - allow(bulk_import_entity).to receive(:start!) + allow(entity).to receive(:start!) subject.execute - expect(bulk_import_entity.reload).to be_failed + expect(entity.reload).to be_failed end end end diff --git a/spec/lib/bulk_imports/pipeline/context_spec.rb b/spec/lib/bulk_imports/pipeline/context_spec.rb index c8c3fe3a861..5b7711ad5d7 100644 --- a/spec/lib/bulk_imports/pipeline/context_spec.rb +++ b/spec/lib/bulk_imports/pipeline/context_spec.rb @@ -3,29 +3,52 @@ require 'spec_helper' RSpec.describe BulkImports::Pipeline::Context do - let(:group) { instance_double(Group) } - let(:user) { instance_double(User) } - let(:bulk_import) { instance_double(BulkImport, user: user, configuration: :config) } - - let(:entity) do - instance_double( - BulkImports::Entity, - bulk_import: bulk_import, - group: group + let_it_be(:user) { create(:user) } + let_it_be(:group) { create(:group) } + let_it_be(:bulk_import) { create(:bulk_import, user: user) } + + let_it_be(:entity) do + create( + :bulk_import_entity, + source_full_path: 'source/full/path', + destination_name: 'My Destination Group', + destination_namespace: group.full_path, + group: group, + bulk_import: bulk_import + ) + end + + let_it_be(:tracker) do + create( + :bulk_import_tracker, + entity: entity, + pipeline_name: described_class.name ) end - subject { described_class.new(entity) } + subject { described_class.new(tracker, extra: :data) } + + describe '#entity' do + it { expect(subject.entity).to eq(entity) } + end describe '#group' do it { expect(subject.group).to eq(group) } end + describe '#bulk_import' do + it { expect(subject.bulk_import).to eq(bulk_import) } + end + describe '#current_user' do it { expect(subject.current_user).to eq(user) } end - describe '#current_user' do + describe '#configuration' do it { expect(subject.configuration).to eq(bulk_import.configuration) } end + + describe '#extra' do + it { expect(subject.extra).to eq(extra: :data) } + end end diff --git a/spec/lib/bulk_imports/pipeline/runner_spec.rb b/spec/lib/bulk_imports/pipeline/runner_spec.rb index 59f01c9caaa..29fd1ee3ffc 100644 --- a/spec/lib/bulk_imports/pipeline/runner_spec.rb +++ b/spec/lib/bulk_imports/pipeline/runner_spec.rb @@ -45,8 +45,9 @@ RSpec.describe BulkImports::Pipeline::Runner do stub_const('BulkImports::MyPipeline', pipeline) end - let_it_be_with_refind(:entity) { create(:bulk_import_entity) } - let(:context) { BulkImports::Pipeline::Context.new(entity, extra: :data) } + let_it_be_with_reload(:entity) { create(:bulk_import_entity) } + let_it_be(:tracker) { create(:bulk_import_tracker, entity: entity) } + let_it_be(:context) { BulkImports::Pipeline::Context.new(tracker, extra: :data) } subject { BulkImports::MyPipeline.new(context) } @@ -170,12 +171,7 @@ RSpec.describe BulkImports::Pipeline::Runner do BulkImports::MyPipeline.abort_on_failure! end - it 'marks entity as failed' do - expect { subject.run } - .to change(entity, :status_name).to(:failed) - end - - it 'logs warn message' do + it 'logs a warn message and marks entity as failed' do expect_next_instance_of(Gitlab::Import::Logger) do |logger| expect(logger).to receive(:warn) .with( @@ -188,6 +184,9 @@ RSpec.describe BulkImports::Pipeline::Runner do end subject.run + + expect(entity.status_name).to eq(:failed) + expect(tracker.status_name).to eq(:failed) end end @@ -206,11 +205,11 @@ RSpec.describe BulkImports::Pipeline::Runner do entity.fail_op! expect_next_instance_of(Gitlab::Import::Logger) do |logger| - expect(logger).to receive(:info) + expect(logger).to receive(:warn) .with( log_params( context, - message: 'Skipping due to failed pipeline status', + message: 'Skipping pipeline due to failed entity', pipeline_class: 'BulkImports::MyPipeline' ) ) diff --git a/spec/lib/bulk_imports/pipeline_spec.rb b/spec/lib/bulk_imports/pipeline_spec.rb index c882e3d26ea..dda2e41f06c 100644 --- a/spec/lib/bulk_imports/pipeline_spec.rb +++ b/spec/lib/bulk_imports/pipeline_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe BulkImports::Pipeline do + let(:context) { instance_double(BulkImports::Pipeline::Context, tracker: nil) } + before do stub_const('BulkImports::Extractor', Class.new) stub_const('BulkImports::Transformer', Class.new) @@ -44,7 +46,7 @@ RSpec.describe BulkImports::Pipeline do end it 'returns itself when retrieving extractor & loader' do - pipeline = BulkImports::AnotherPipeline.new(nil) + pipeline = BulkImports::AnotherPipeline.new(context) expect(pipeline.send(:extractor)).to eq(pipeline) expect(pipeline.send(:loader)).to eq(pipeline) @@ -83,7 +85,7 @@ RSpec.describe BulkImports::Pipeline do expect(BulkImports::Transformer).to receive(:new).with(foo: :bar) expect(BulkImports::Loader).to receive(:new).with(foo: :bar) - pipeline = BulkImports::MyPipeline.new(nil) + pipeline = BulkImports::MyPipeline.new(context) pipeline.send(:extractor) pipeline.send(:transformers) @@ -109,7 +111,7 @@ RSpec.describe BulkImports::Pipeline do expect(BulkImports::Transformer).to receive(:new).with(no_args) expect(BulkImports::Loader).to receive(:new).with(no_args) - pipeline = BulkImports::NoOptionsPipeline.new(nil) + pipeline = BulkImports::NoOptionsPipeline.new(context) pipeline.send(:extractor) pipeline.send(:transformers) @@ -135,7 +137,7 @@ RSpec.describe BulkImports::Pipeline do transformer = double allow(BulkImports::Transformer).to receive(:new).and_return(transformer) - pipeline = BulkImports::TransformersPipeline.new(nil) + pipeline = BulkImports::TransformersPipeline.new(context) expect(pipeline.send(:transformers)).to eq([pipeline, transformer]) end diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb index 67324c09d86..aaa3a7a8b9d 100644 --- a/spec/lib/gitlab/ci/lint_spec.rb +++ b/spec/lib/gitlab/ci/lint_spec.rb @@ -92,7 +92,7 @@ RSpec.describe Gitlab::Ci::Lint do it 'sets merged_config' do root_config = YAML.safe_load(content, [Symbol]) included_config = YAML.safe_load(included_content, [Symbol]) - expected_config = included_config.merge(root_config).except(:include) + expected_config = included_config.merge(root_config).except(:include).deep_stringify_keys expect(subject.merged_yaml).to eq(expected_config.to_yaml) end diff --git a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb index 7e3cd7ec254..e345cd4de9b 100644 --- a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb @@ -24,7 +24,7 @@ module Gitlab let(:included_yml) do YAML.dump( - another_test: { stage: 'test', script: 'echo 2' } + { another_test: { stage: 'test', script: 'echo 2' } }.deep_stringify_keys ) end diff --git a/spec/lib/gitlab/data_builder/build_spec.rb b/spec/lib/gitlab/data_builder/build_spec.rb index ab1728414bb..932238f281e 100644 --- a/spec/lib/gitlab/data_builder/build_spec.rb +++ b/spec/lib/gitlab/data_builder/build_spec.rb @@ -19,6 +19,9 @@ RSpec.describe Gitlab::DataBuilder::Build do it { expect(data[:tag]).to eq(build.tag) } it { expect(data[:build_id]).to eq(build.id) } it { expect(data[:build_status]).to eq(build.status) } + it { expect(data[:build_created_at]).to eq(build.created_at) } + it { expect(data[:build_started_at]).to eq(build.started_at) } + it { expect(data[:build_finished_at]).to eq(build.finished_at) } it { expect(data[:build_allow_failure]).to eq(false) } it { expect(data[:build_failure_reason]).to eq(build.failure_reason) } it { expect(data[:project_id]).to eq(build.project.id) } diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb index 17ab4d5954c..652ea431696 100644 --- a/spec/models/bulk_imports/entity_spec.rb +++ b/spec/models/bulk_imports/entity_spec.rb @@ -125,68 +125,4 @@ RSpec.describe BulkImports::Entity, type: :model do end end end - - describe "#update_tracker_for" do - let(:entity) { create(:bulk_import_entity) } - - it "inserts new tracker when it does not exist" do - expect do - entity.update_tracker_for(relation: :relation, has_next_page: false) - end.to change(BulkImports::Tracker, :count).by(1) - - tracker = entity.trackers.last - - expect(tracker.relation).to eq('relation') - expect(tracker.has_next_page).to eq(false) - expect(tracker.next_page).to eq(nil) - end - - it "updates the tracker if it already exist" do - create( - :bulk_import_tracker, - relation: :relation, - has_next_page: false, - entity: entity - ) - - expect do - entity.update_tracker_for(relation: :relation, has_next_page: true, next_page: 'nextPage') - end.not_to change(BulkImports::Tracker, :count) - - tracker = entity.trackers.last - - expect(tracker.relation).to eq('relation') - expect(tracker.has_next_page).to eq(true) - expect(tracker.next_page).to eq('nextPage') - end - end - - describe "#has_next_page?" do - it "queries for the given relation if it has more pages to be fetched" do - entity = create(:bulk_import_entity) - create( - :bulk_import_tracker, - relation: :relation, - has_next_page: false, - entity: entity - ) - - expect(entity.has_next_page?(:relation)).to eq(false) - end - end - - describe "#next_page_for" do - it "queries for the next page of the given relation" do - entity = create(:bulk_import_entity) - create( - :bulk_import_tracker, - relation: :relation, - has_next_page: false, - next_page: 'nextPage', - entity: entity - ) - - expect(entity.next_page_for(:relation)).to eq('nextPage') - end - end end diff --git a/spec/models/concerns/sortable_spec.rb b/spec/models/concerns/sortable_spec.rb index bbfdaeec64c..cfa00bab025 100644 --- a/spec/models/concerns/sortable_spec.rb +++ b/spec/models/concerns/sortable_spec.rb @@ -3,6 +3,31 @@ require 'spec_helper' RSpec.describe Sortable do + describe 'scopes' do + describe 'secondary ordering by id' do + let(:sorted_relation) { Group.all.order_created_asc } + + def arel_orders(relation) + relation.arel.orders + end + + it 'allows secondary ordering by id ascending' do + orders = arel_orders(sorted_relation.with_order_id_asc) + + expect(orders.map { |arel| arel.expr.name }).to eq(%w(created_at id)) + expect(orders).to all(be_kind_of(Arel::Nodes::Ascending)) + end + + it 'allows secondary ordering by id descending' do + orders = arel_orders(sorted_relation.with_order_id_desc) + + expect(orders.map { |arel| arel.expr.name }).to eq(%w(created_at id)) + expect(orders.first).to be_kind_of(Arel::Nodes::Ascending) + expect(orders.last).to be_kind_of(Arel::Nodes::Descending) + end + end + end + describe '.order_by' do let(:arel_table) { Group.arel_table } let(:relation) { Group.all } diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 590acfc0ac1..fec932ee339 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -20,6 +20,7 @@ RSpec.describe Note do it { is_expected.to include_module(Participable) } it { is_expected.to include_module(Mentionable) } it { is_expected.to include_module(Awardable) } + it { is_expected.to include_module(Sortable) } end describe 'validation' do @@ -856,6 +857,12 @@ RSpec.describe Note do end end + describe '.simple_sorts' do + it 'does not contain name sorts' do + expect(described_class.simple_sorts.grep(/name/)).to be_empty + end + end + describe '#for_project_snippet?' do it 'returns true for a project snippet note' do expect(build(:note_on_project_snippet).for_project_snippet?).to be true @@ -1322,7 +1329,7 @@ RSpec.describe Note do let_it_be(:note1) { create(:note, note: 'Test 345') } let_it_be(:note2) { create(:note, note: 'Test 789') } - describe '#for_note_or_capitalized_note' do + describe '.for_note_or_capitalized_note' do it 'returns the expected matching note' do notes = described_class.for_note_or_capitalized_note('Test 345') @@ -1344,7 +1351,7 @@ RSpec.describe Note do end end - describe '#like_note_or_capitalized_note' do + describe '.like_note_or_capitalized_note' do it 'returns the expected matching note' do notes = described_class.like_note_or_capitalized_note('Test 345') @@ -1367,69 +1374,69 @@ RSpec.describe Note do expect(notes.second.id).to eq(note2.id) end end + end - describe '#noteable_assignee_or_author' do - let(:user) { create(:user) } - let(:noteable) { create(:issue) } - let(:note) { create(:note, project: noteable.project, noteable: noteable) } + describe '#noteable_assignee_or_author?' do + let(:user) { create(:user) } + let(:noteable) { create(:issue) } + let(:note) { create(:note, project: noteable.project, noteable: noteable) } - subject { note.noteable_assignee_or_author?(user) } + subject { note.noteable_assignee_or_author?(user) } - shared_examples 'assignee check' do - context 'when the provided user is one of the assignees' do - before do - note.noteable.update(assignees: [user, create(:user)]) - end + shared_examples 'assignee check' do + context 'when the provided user is one of the assignees' do + before do + note.noteable.update(assignees: [user, create(:user)]) + end - it 'returns true' do - expect(subject).to be_truthy - end + it 'returns true' do + expect(subject).to be_truthy end end + end - shared_examples 'author check' do - context 'when the provided user is the author' do - before do - note.noteable.update(author: user) - end - - it 'returns true' do - expect(subject).to be_truthy - end + shared_examples 'author check' do + context 'when the provided user is the author' do + before do + note.noteable.update(author: user) end - context 'when the provided user is neither author nor assignee' do - it 'returns true' do - expect(subject).to be_falsey - end + it 'returns true' do + expect(subject).to be_truthy end end - context 'when user is nil' do - let(:user) { nil } - - it 'returns false' do + context 'when the provided user is neither author nor assignee' do + it 'returns true' do expect(subject).to be_falsey end end + end + + context 'when user is nil' do + let(:user) { nil } - context 'when noteable is an issue' do - it_behaves_like 'author check' - it_behaves_like 'assignee check' + it 'returns false' do + expect(subject).to be_falsey end + end - context 'when noteable is a merge request' do - let(:noteable) { create(:merge_request) } + context 'when noteable is an issue' do + it_behaves_like 'author check' + it_behaves_like 'assignee check' + end - it_behaves_like 'author check' - it_behaves_like 'assignee check' - end + context 'when noteable is a merge request' do + let(:noteable) { create(:merge_request) } - context 'when noteable is a snippet' do - let(:noteable) { create(:personal_snippet) } + it_behaves_like 'author check' + it_behaves_like 'assignee check' + end - it_behaves_like 'author check' - end + context 'when noteable is a snippet' do + let(:noteable) { create(:personal_snippet) } + + it_behaves_like 'author check' end end diff --git a/spec/requests/api/lint_spec.rb b/spec/requests/api/lint_spec.rb index cf8cac773f5..f26236e0253 100644 --- a/spec/requests/api/lint_spec.rb +++ b/spec/requests/api/lint_spec.rb @@ -166,7 +166,7 @@ RSpec.describe API::Lint do included_config = YAML.safe_load(included_content, [Symbol]) root_config = YAML.safe_load(yaml_content, [Symbol]) - expected_yaml = included_config.merge(root_config).except(:include).to_yaml + expected_yaml = included_config.merge(root_config).except(:include).deep_stringify_keys.to_yaml expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Hash @@ -246,7 +246,7 @@ RSpec.describe API::Lint do let(:dry_run) { false } let(:included_content) do - { another_test: { stage: 'test', script: 'echo 1' } }.to_yaml + { another_test: { stage: 'test', script: 'echo 1' } }.deep_stringify_keys.to_yaml end before do @@ -299,7 +299,7 @@ RSpec.describe API::Lint do end let(:included_content) do - { another_test: { stage: 'test', script: 'echo 1' } }.to_yaml + { another_test: { stage: 'test', script: 'echo 1' } }.deep_stringify_keys.to_yaml end before do @@ -341,7 +341,7 @@ RSpec.describe API::Lint do context 'with invalid .gitlab-ci.yml content' do let(:yaml_content) do - { image: 'ruby:2.7', services: ['postgres'] }.to_yaml + { image: 'ruby:2.7', services: ['postgres'] }.deep_stringify_keys.to_yaml end before do @@ -385,7 +385,7 @@ RSpec.describe API::Lint do included_config = YAML.safe_load(included_content, [Symbol]) root_config = YAML.safe_load(yaml_content, [Symbol]) - expected_yaml = included_config.merge(root_config).except(:include).to_yaml + expected_yaml = included_config.merge(root_config).except(:include).deep_stringify_keys.to_yaml expect(response).to have_gitlab_http_status(:ok) expect(json_response).to be_an Hash @@ -539,7 +539,7 @@ RSpec.describe API::Lint do context 'with invalid .gitlab-ci.yml content' do let(:yaml_content) do - { image: 'ruby:2.7', services: ['postgres'] }.to_yaml + { image: 'ruby:2.7', services: ['postgres'] }.deep_stringify_keys.to_yaml end context 'when running as dry run' do diff --git a/spec/support/shared_examples/models/wiki_shared_examples.rb b/spec/support/shared_examples/models/wiki_shared_examples.rb index abc6e3ecce8..50d50bee727 100644 --- a/spec/support/shared_examples/models/wiki_shared_examples.rb +++ b/spec/support/shared_examples/models/wiki_shared_examples.rb @@ -481,28 +481,53 @@ RSpec.shared_examples 'wiki model' do end describe '#delete_page' do - let(:page) { create(:wiki_page, wiki: wiki) } + shared_examples 'delete_page operations' do + let(:page) { create(:wiki_page, wiki: wiki) } - it 'deletes the page' do - subject.delete_page(page) + it 'deletes the page' do + subject.delete_page(page) - expect(subject.list_pages.count).to eq(0) - end + expect(subject.list_pages.count).to eq(0) + end - it 'sets the correct commit email' do - subject.delete_page(page) + it 'sets the correct commit email' do + subject.delete_page(page) - expect(user.commit_email).not_to eq(user.email) - expect(commit.author_email).to eq(user.commit_email) - expect(commit.committer_email).to eq(user.commit_email) + expect(user.commit_email).not_to eq(user.email) + expect(commit.author_email).to eq(user.commit_email) + expect(commit.committer_email).to eq(user.commit_email) + end + + it 'runs after_wiki_activity callbacks' do + page + + expect(subject).to receive(:after_wiki_activity) + + subject.delete_page(page) + end end - it 'runs after_wiki_activity callbacks' do - page + it_behaves_like 'delete_page operations' - expect(subject).to receive(:after_wiki_activity) + context 'when an error is raised' do + it 'logs the error and returns false' do + page = build(:wiki_page, wiki: wiki) + exception = Gitlab::Git::Index::IndexError.new('foo') + + allow(subject.repository).to receive(:delete_file).and_raise(exception) + + expect(Gitlab::ErrorTracking).to receive(:log_exception).with(exception, action: :deleted, wiki_id: wiki.id) + + expect(subject.delete_page(page)).to be_falsey + end + end + + context 'when feature flag :gitaly_replace_wiki_delete_page is disabled' do + before do + stub_feature_flags(gitaly_replace_wiki_delete_page: false) + end - subject.delete_page(page) + it_behaves_like 'delete_page operations' end end |