diff options
53 files changed, 654 insertions, 284 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index de484f2ce84..bfc38e73bb5 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -143,7 +143,7 @@ rspec-ee frontend_fixture: extends: - .frontend-fixtures-base - .frontend:rules:default-frontend-jobs-ee - parallel: 2 + parallel: 3 graphql-schema-dump: variables: diff --git a/.gitlab/ci/test-metadata.gitlab-ci.yml b/.gitlab/ci/test-metadata.gitlab-ci.yml index 5a7a2db32e8..08c5a7267c2 100644 --- a/.gitlab/ci/test-metadata.gitlab-ci.yml +++ b/.gitlab/ci/test-metadata.gitlab-ci.yml @@ -26,7 +26,6 @@ update-tests-metadata: - .test-metadata:rules:update-tests-metadata stage: post-test dependencies: - - retrieve-tests-metadata - setup-test-env - rspec migration pg12 - rspec frontend_fixture diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index dc6779942cb..99c31a13179 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -ff6a28eeb5c58185a178f7bbacc5617ac6b80ef4 +ce833c4ea66902f46b197d336e168a79ac29be81 diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue index d7aea7b7290..cd803d842d8 100644 --- a/app/assets/javascripts/boards/components/board_form.vue +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -18,7 +18,7 @@ const boardDefaults = { id: false, name: '', labels: [], - milestone_id: undefined, + milestone: {}, iteration_id: undefined, assignee: {}, weight: null, @@ -190,10 +190,9 @@ export default { return { weight: this.board.weight, assigneeId: this.board.assignee?.id || null, - milestoneId: - this.board.milestone?.id || this.board.milestone?.id === 0 - ? convertToGraphQLId(TYPE_MILESTONE, this.board.milestone.id) - : null, + milestoneId: this.board.milestone?.id + ? convertToGraphQLId(TYPE_MILESTONE, this.board.milestone.id) + : null, iterationId: this.board.iteration_id ? convertToGraphQLId(TYPE_ITERATION, this.board.iteration_id) : null, @@ -304,9 +303,14 @@ export default { }); }, setAssignee(assigneeId) { - this.board.assignee = { + this.$set(this.board, 'assignee', { id: assigneeId, - }; + }); + }, + setMilestone(milestoneId) { + this.$set(this.board, 'milestone', { + id: milestoneId, + }); }, }, }; @@ -376,6 +380,7 @@ export default { @set-iteration="setIteration" @set-board-labels="setBoardLabels" @set-assignee="setAssignee" + @set-milestone="setMilestone" /> </form> </gl-modal> diff --git a/app/assets/javascripts/cycle_analytics/constants.js b/app/assets/javascripts/cycle_analytics/constants.js index 755977f87df..a41a9ad989f 100644 --- a/app/assets/javascripts/cycle_analytics/constants.js +++ b/app/assets/javascripts/cycle_analytics/constants.js @@ -1,4 +1,4 @@ -import { s__ } from '~/locale'; +import { __, s__ } from '~/locale'; export const DEFAULT_DAYS_IN_PAST = 30; export const DEFAULT_DAYS_TO_DISPLAY = 30; @@ -22,3 +22,11 @@ export const PAGINATION_SORT_DIRECTION_ASC = 'asc'; export const STAGE_TITLE_STAGING = 'staging'; export const STAGE_TITLE_TEST = 'test'; + +export const I18N_VSA_ERROR_STAGES = __( + 'There was an error fetching value stream analytics stages.', +); +export const I18N_VSA_ERROR_STAGE_MEDIAN = __('There was an error fetching median data for stages'); +export const I18N_VSA_ERROR_SELECTED_STAGE = __( + 'There was an error fetching data for the selected stage', +); diff --git a/app/assets/javascripts/cycle_analytics/store/actions.js b/app/assets/javascripts/cycle_analytics/store/actions.js index 955f0c7271e..5a7dbbd28bb 100644 --- a/app/assets/javascripts/cycle_analytics/store/actions.js +++ b/app/assets/javascripts/cycle_analytics/store/actions.js @@ -7,7 +7,11 @@ import { } from '~/api/analytics_api'; import createFlash from '~/flash'; import { __ } from '~/locale'; -import { DEFAULT_DAYS_TO_DISPLAY, DEFAULT_VALUE_STREAM } from '../constants'; +import { + DEFAULT_DAYS_TO_DISPLAY, + DEFAULT_VALUE_STREAM, + I18N_VSA_ERROR_STAGE_MEDIAN, +} from '../constants'; import * as types from './mutation_types'; export const setSelectedValueStream = ({ commit, dispatch }, valueStream) => { @@ -120,9 +124,7 @@ export const fetchStageMedians = ({ .then((data) => commit(types.RECEIVE_STAGE_MEDIANS_SUCCESS, data)) .catch((error) => { commit(types.RECEIVE_STAGE_MEDIANS_ERROR, error); - createFlash({ - message: __('There was an error fetching median data for stages'), - }); + createFlash({ message: I18N_VSA_ERROR_STAGE_MEDIAN }); }); }; diff --git a/app/assets/javascripts/graphql_shared/utils.js b/app/assets/javascripts/graphql_shared/utils.js index 18f9a50bbce..828ddd95ffc 100644 --- a/app/assets/javascripts/graphql_shared/utils.js +++ b/app/assets/javascripts/graphql_shared/utils.js @@ -2,6 +2,21 @@ import { isArray } from 'lodash'; /** * Ids generated by GraphQL endpoints are usually in the format + * gid://gitlab/Environments/123. This method checks if the passed id follows that format + * + * @param {String|Number} id The id value + * @returns {Boolean} + */ +export const isGid = (id) => { + if (typeof id === 'string' && id.startsWith('gid://gitlab/')) { + return true; + } + + return false; +}; + +/** + * Ids generated by GraphQL endpoints are usually in the format * gid://gitlab/Environments/123. This method extracts Id number * from the Id path * @@ -35,6 +50,10 @@ export const convertToGraphQLId = (type, id) => { throw new TypeError(`id must be a number or string; got ${typeof id}`); } + if (isGid(id)) { + return id; + } + return `gid://gitlab/${type}/${id}`; }; diff --git a/app/assets/javascripts/ide/components/commit_sidebar/form.vue b/app/assets/javascripts/ide/components/commit_sidebar/form.vue index 2897f4cbf77..9ec4a07a3d0 100644 --- a/app/assets/javascripts/ide/components/commit_sidebar/form.vue +++ b/app/assets/javascripts/ide/components/commit_sidebar/form.vue @@ -186,7 +186,7 @@ export default { data-testid="commit-button" class="qa-commit-button" category="primary" - variant="success" + variant="confirm" @click="commit" > {{ __('Commit') }} diff --git a/app/assets/javascripts/projects/compare/components/app.vue b/app/assets/javascripts/projects/compare/components/app.vue index f7cfc82db11..f2c1c843878 100644 --- a/app/assets/javascripts/projects/compare/components/app.vue +++ b/app/assets/javascripts/projects/compare/components/app.vue @@ -122,7 +122,7 @@ export default { /> </div> <div class="gl-mt-4"> - <gl-button category="primary" variant="success" @click="onSubmit"> + <gl-button category="primary" variant="confirm" @click="onSubmit"> {{ s__('CompareRevisions|Compare') }} </gl-button> <gl-button data-testid="swapRevisionsButton" class="btn btn-default" @click="onSwapRevision"> diff --git a/app/assets/javascripts/sidebar/queries/group_milestones.query.graphql b/app/assets/javascripts/sidebar/queries/group_milestones.query.graphql new file mode 100644 index 00000000000..dceab61ed26 --- /dev/null +++ b/app/assets/javascripts/sidebar/queries/group_milestones.query.graphql @@ -0,0 +1,20 @@ +#import "./milestone.fragment.graphql" + +query groupMilestones($fullPath: ID!, $title: String, $state: MilestoneStateEnum) { + workspace: group(fullPath: $fullPath) { + __typename + id + attributes: milestones( + searchTitle: $title + state: $state + sort: EXPIRED_LAST_DUE_DATE_ASC + first: 20 + includeAncestors: true + ) { + nodes { + ...MilestoneFragment + state + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js new file mode 100644 index 00000000000..eeed5e9dc3a --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js @@ -0,0 +1,27 @@ +/* eslint-disable @gitlab/require-i18n-strings */ + +import { __ } from '~/locale'; +import DropdownWidget from './dropdown_widget.vue'; + +export default { + component: DropdownWidget, + title: 'vue_shared/components/dropdown/dropdown_widget/dropdown_widget', +}; + +const Template = (args, { argTypes }) => ({ + components: { DropdownWidget }, + props: Object.keys(argTypes), + template: '<dropdown-widget v-bind="$props" v-on="$props" />', +}); + +export const Default = Template.bind({}); +Default.args = { + options: [ + { id: 'gid://gitlab/Milestone/-1', title: __('Any Milestone') }, + { id: 'gid://gitlab/Milestone/0', title: __('No Milestone') }, + { id: 'gid://gitlab/Milestone/-2', title: __('Upcoming') }, + { id: 'gid://gitlab/Milestone/-3', title: __('Started') }, + ], + selectText: 'Select', + searchText: 'Search', +}; diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue new file mode 100644 index 00000000000..857131e544e --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue @@ -0,0 +1,148 @@ +<script> +import { + GlLoadingIcon, + GlDropdown, + GlDropdownForm, + GlDropdownDivider, + GlDropdownItem, + GlSearchBoxByType, +} from '@gitlab/ui'; +import { __ } from '~/locale'; + +export default { + components: { + GlLoadingIcon, + GlDropdown, + GlDropdownForm, + GlDropdownDivider, + GlDropdownItem, + GlSearchBoxByType, + }, + props: { + selectText: { + type: String, + required: false, + default: __('Select'), + }, + searchText: { + type: String, + required: false, + default: __('Search'), + }, + presetOptions: { + type: Array, + required: false, + default: () => [], + }, + options: { + type: Array, + required: false, + default: () => [], + }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, + selected: { + type: Object, + required: false, + default: () => {}, + }, + searchTerm: { + type: String, + required: false, + default: '', + }, + }, + computed: { + isSearchEmpty() { + return this.searchTerm === '' && !this.isLoading; + }, + noOptionsFound() { + return !this.isSearchEmpty && this.options.length === 0; + }, + }, + methods: { + selectOption(option) { + this.$emit('set-option', option || null); + }, + isSelected(option) { + return this.selected && this.selected.title === option.title; + }, + showDropdown() { + this.$refs.dropdown.show(); + }, + setFocus() { + this.$refs.search.focusInput(); + }, + setSearchTerm(search) { + this.$emit('set-search', search); + }, + }, + i18n: { + noMatchingResults: __('No matching results'), + }, +}; +</script> + +<template> + <gl-dropdown + ref="dropdown" + :text="selectText" + lazy + menu-class="gl-w-full!" + class="gl-w-full" + v-on="$listeners" + @shown="setFocus" + > + <template #header> + <gl-search-box-by-type + ref="search" + :value="searchTerm" + :placeholder="searchText" + class="js-dropdown-input-field" + @input="setSearchTerm" + /> + </template> + <gl-dropdown-form class="gl-relative gl-min-h-7"> + <gl-loading-icon + v-if="isLoading" + size="md" + class="gl-absolute gl-left-0 gl-top-0 gl-right-0" + /> + <template v-else> + <template v-if="isSearchEmpty && presetOptions.length > 0"> + <gl-dropdown-item + v-for="option in presetOptions" + :key="option.id" + :is-checked="isSelected(option)" + :is-check-centered="true" + :is-check-item="true" + @click="selectOption(option)" + > + {{ option.title }} + </gl-dropdown-item> + <gl-dropdown-divider /> + </template> + <gl-dropdown-item + v-for="option in options" + :key="option.id" + :is-checked="isSelected(option)" + :is-check-centered="true" + :is-check-item="true" + data-testid="unselected-option" + @click="selectOption(option)" + > + {{ option.title }} + </gl-dropdown-item> + <gl-dropdown-item v-if="noOptionsFound" class="gl-pl-6!"> + {{ $options.i18n.noMatchingResults }} + </gl-dropdown-item> + </template> + </gl-dropdown-form> + <template #footer> + <slot name="footer"></slot> + </template> + </gl-dropdown> +</template> diff --git a/app/models/packages/package_file.rb b/app/models/packages/package_file.rb index 799242a639a..b90843be3a7 100644 --- a/app/models/packages/package_file.rb +++ b/app/models/packages/package_file.rb @@ -5,7 +5,7 @@ class Packages::PackageFile < ApplicationRecord delegate :project, :project_id, to: :package delegate :conan_file_type, to: :conan_file_metadatum - delegate :file_type, :component, :architecture, :fields, to: :debian_file_metadatum, prefix: :debian + delegate :file_type, :dsc?, :component, :architecture, :fields, to: :debian_file_metadatum, prefix: :debian delegate :channel, :metadata, to: :helm_file_metadatum, prefix: :helm belongs_to :package @@ -33,6 +33,8 @@ class Packages::PackageFile < ApplicationRecord scope :with_file_name_like, ->(file_name) { where(arel_table[:file_name].matches(file_name)) } scope :with_files_stored_locally, -> { where(file_store: ::Packages::PackageFileUploader::Store::LOCAL) } scope :with_format, ->(format) { where(::Packages::PackageFile.arel_table[:file_name].matches("%.#{format}")) } + + scope :preload_package, -> { preload(:package) } scope :preload_conan_file_metadata, -> { preload(:conan_file_metadatum) } scope :preload_debian_file_metadata, -> { preload(:debian_file_metadatum) } scope :preload_helm_file_metadata, -> { preload(:helm_file_metadatum) } diff --git a/app/services/packages/debian/generate_distribution_service.rb b/app/services/packages/debian/generate_distribution_service.rb index d3ffe75f6ee..74b07e05aa6 100644 --- a/app/services/packages/debian/generate_distribution_service.rb +++ b/app/services/packages/debian/generate_distribution_service.rb @@ -12,7 +12,7 @@ module Packages DEFAULT_LEASE_TIMEOUT = 1.hour.to_i.freeze # From https://salsa.debian.org/ftp-team/dak/-/blob/991aaa27a7f7aa773bb9c0cf2d516e383d9cffa0/setup/core-init.d/080_metadatakeys#L9 - BINARIES_METADATA = %w( + METADATA_KEYS = %w( Package Source Binary @@ -89,15 +89,18 @@ module Packages @distribution.components.ordered_by_name.each do |component| @distribution.architectures.ordered_by_name.each do |architecture| generate_component_file(component, :packages, architecture, :deb) + generate_component_file(component, :di_packages, architecture, :udeb) end + generate_component_file(component, :source, nil, :dsc) end end def generate_component_file(component, component_file_type, architecture, package_file_type) paragraphs = @distribution.package_files + .preload_package .preload_debian_file_metadata .with_debian_component_name(component.name) - .with_debian_architecture_name(architecture.name) + .with_debian_architecture_name(architecture&.name) .with_debian_file_type(package_file_type) .find_each .map(&method(:package_stanza_from_fields)) @@ -106,21 +109,49 @@ module Packages def package_stanza_from_fields(package_file) [ - BINARIES_METADATA.map do |metadata_key| - rfc822_field(metadata_key, package_file.debian_fields[metadata_key]) + METADATA_KEYS.map do |metadata_key| + metadata_name = metadata_key + metadata_value = package_file.debian_fields[metadata_key] + + if package_file.debian_dsc? + metadata_name = 'Package' if metadata_key == 'Source' + checksum = case metadata_key + when 'Files' then package_file.file_md5 + when 'Checksums-Sha256' then package_file.file_sha256 + when 'Checksums-Sha1' then package_file.file_sha1 + end + + if checksum + metadata_value = "\n#{checksum} #{package_file.size} #{package_file.file_name}#{metadata_value}" + end + end + + rfc822_field(metadata_name, metadata_value) end, rfc822_field('Section', package_file.debian_fields['Section'] || 'misc'), rfc822_field('Priority', package_file.debian_fields['Priority'] || 'extra'), - rfc822_field('Filename', package_filename(package_file)), - rfc822_field('Size', package_file.size), - rfc822_field('MD5sum', package_file.file_md5), - rfc822_field('SHA256', package_file.file_sha256) + package_file_extra_fields(package_file) ].flatten.compact.join('') end - def package_filename(package_file) + def package_file_extra_fields(package_file) + if package_file.debian_dsc? + [ + rfc822_field('Directory', package_dirname(package_file)) + ] + else + [ + rfc822_field('Filename', "#{package_dirname(package_file)}/#{package_file.file_name}"), + rfc822_field('Size', package_file.size), + rfc822_field('MD5sum', package_file.file_md5), + rfc822_field('SHA256', package_file.file_sha256) + ] + end + end + + def package_dirname(package_file) letter = package_file.package.name.start_with?('lib') ? package_file.package.name[0..3] : package_file.package.name[0] - "#{pool_prefix(package_file)}/#{letter}/#{package_file.package.name}/#{package_file.package.version}/#{package_file.file_name}" + "#{pool_prefix(package_file)}/#{letter}/#{package_file.package.name}/#{package_file.package.version}" end def pool_prefix(package_file) @@ -206,7 +237,8 @@ module Packages return unless condition return if value.blank? - "#{name}: #{value.to_s.gsub("\n\n", "\n.\n").gsub("\n", "\n ")}\n" + value = " #{value}" unless value[0] == "\n" + "#{name}:#{value.to_s.gsub("\n\n", "\n.\n").gsub("\n", "\n ")}\n" end def valid_until_field diff --git a/app/workers/authorized_project_update/project_recalculate_worker.rb b/app/workers/authorized_project_update/project_recalculate_worker.rb index b3ddaef6ecb..4d350d95e7e 100644 --- a/app/workers/authorized_project_update/project_recalculate_worker.rb +++ b/app/workers/authorized_project_update/project_recalculate_worker.rb @@ -26,7 +26,7 @@ module AuthorizedProjectUpdate private def lock_key(project) - "#{self.class.name.underscore}/#{project.root_namespace.id}" + "#{self.class.name.underscore}/projects/#{project.id}" end end end diff --git a/doc/administration/git_annex.md b/doc/administration/git_annex.md deleted file mode 100644 index d7fb8a37b9c..00000000000 --- a/doc/administration/git_annex.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'index.md' -remove_date: '2021-07-22' ---- - -This document was moved to [another location](index.md). - -<!-- This redirect file can be deleted after <2021-07-22>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/api/dora4_group_analytics.md b/doc/api/dora4_group_analytics.md deleted file mode 100644 index 501bf824f03..00000000000 --- a/doc/api/dora4_group_analytics.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'dora/metrics.md' -remove_date: '2021-07-25' ---- - -This document was moved to [another location](dora/metrics.md). - -<!-- This redirect file can be deleted after <2021-07-25>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md index a1e08a9c19b..9ee56a6d517 100644 --- a/doc/development/documentation/site_architecture/index.md +++ b/doc/development/documentation/site_architecture/index.md @@ -241,7 +241,7 @@ reports. ## Monthly release process (versions) The docs website supports versions and each month we add the latest one to the list. -For more information, read about the [monthly release process](release_process.md). +For more information, read about the [monthly release process](https://about.gitlab.com/handbook/engineering/ux/technical-writing/workflow/#monthly-documentation-releases). ## Review Apps for documentation merge requests diff --git a/doc/development/documentation/site_architecture/release_process.md b/doc/development/documentation/site_architecture/release_process.md deleted file mode 100644 index 46c74335932..00000000000 --- a/doc/development/documentation/site_architecture/release_process.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'https://about.gitlab.com/handbook/engineering/ux/technical-writing/workflow/#monthly-documentation-releases' -remove_date: '2021-07-12' ---- - -This file was moved to [another location](https://about.gitlab.com/handbook/engineering/ux/technical-writing/workflow/#monthly-documentation-releases). - -<!-- This redirect file can be deleted after <2021-07-12>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/development/stage_group_dashboards.md b/doc/development/stage_group_dashboards.md index 8d44b36bc4a..61a98ece892 100644 --- a/doc/development/stage_group_dashboards.md +++ b/doc/development/stage_group_dashboards.md @@ -112,7 +112,7 @@ component means. For example, see the `server` component of the ![web-pages-server-component SLI](img/stage_group_dashboards_service_sli_detail.png) -## Usage of the dasbhoard +## Usage of the dashboard Inside a stage group dashboard, there are some notable components. Let's take the [Source Code group's dashboard](https://dashboards.gitlab.net/d/stage-groups-source_code/stage-groups-group-dashboard-create-source-code?orgId=1) as an example. diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md deleted file mode 100644 index abf49d31de2..00000000000 --- a/doc/development/what_requires_downtime.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'avoiding_downtime_in_migrations.md' -remove_date: '2021-07-01' ---- - -This document was moved to [another location](avoiding_downtime_in_migrations.md). - -<!-- This redirect file can be deleted after <2021-07-01>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/gitlab-basics/create-your-ssh-keys.md b/doc/gitlab-basics/create-your-ssh-keys.md deleted file mode 100644 index 673fb2911fa..00000000000 --- a/doc/gitlab-basics/create-your-ssh-keys.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: '../ssh/index.md' -remove_date: '2021-07-04' ---- - -This document was moved to [another location](../ssh/index.md). - -<!-- This redirect file can be deleted after <2021-07-04>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page -->
\ No newline at end of file diff --git a/doc/integration/jira_development_panel.md b/doc/integration/jira_development_panel.md deleted file mode 100644 index 7bfebc18f47..00000000000 --- a/doc/integration/jira_development_panel.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'jira/index.md' -remove_date: '2021-06-24' ---- - -This document was moved to [another location](jira/index.md). - -<!-- This redirect file can be deleted after <2021-06-24>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/security/cicd_variables.md b/doc/security/cicd_variables.md deleted file mode 100644 index 06fe0ff4276..00000000000 --- a/doc/security/cicd_variables.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: '../ci/variables/index.md#cicd-variable-security' -remove_date: '2021-07-04' ---- - -This document was moved to [another location](../ci/variables/index.md#cicd-variable-security). - -<!-- This redirect file can be deleted after <2021-07-04>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md b/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md deleted file mode 100644 index d7fb8a37b9c..00000000000 --- a/doc/topics/git/lfs/migrate_from_git_annex_to_git_lfs.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'index.md' -remove_date: '2021-07-22' ---- - -This document was moved to [another location](index.md). - -<!-- This redirect file can be deleted after <2021-07-22>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/university/training/topics/agile_git.md b/doc/university/training/topics/agile_git.md deleted file mode 100644 index 00ff778a241..00000000000 --- a/doc/university/training/topics/agile_git.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: '../../../user/project/issue_board.md' -remove_date: '2021-07-23' ---- - -Information about using Agile concepts in GitLab can be found in [another location](../../../user/project/issue_board.md). - -<!-- This redirect file can be deleted after <2021-07-23>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/user/abuse_reports.md b/doc/user/abuse_reports.md deleted file mode 100644 index c84c3541366..00000000000 --- a/doc/user/abuse_reports.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'report_abuse.md' -remove_date: '2021-07-21' ---- - -This file was moved to [another location](report_abuse.md). - -<!-- This redirect file can be deleted after <2021-07-21>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/user/admin_area/abuse_reports.md b/doc/user/admin_area/abuse_reports.md deleted file mode 100644 index 4bfa277fc9f..00000000000 --- a/doc/user/admin_area/abuse_reports.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'review_abuse_reports.md' -remove_date: '2021-07-21' ---- - -This file was moved to [another location](review_abuse_reports.md). - -<!-- This redirect file can be deleted after <2021-07-21>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/user/application_security/vulnerabilities/index.md b/doc/user/application_security/vulnerabilities/index.md index 6437f2325e8..a727dc88ffc 100644 --- a/doc/user/application_security/vulnerabilities/index.md +++ b/doc/user/application_security/vulnerabilities/index.md @@ -75,7 +75,7 @@ The issue is then opened so you can take further action. Prerequisites: -- [Enable Jira integration](../../project/integrations/jira.md). +- [Enable Jira integration](../../../integration/jira/index.md). The **Enable Jira issues creation from vulnerabilities** option must be selected as part of the configuration. - Each user must have a personal Jira user account with permission to create issues in the target project. diff --git a/doc/user/project/import/jira.md b/doc/user/project/import/jira.md index 07419080d7d..3e0faec0a49 100644 --- a/doc/user/project/import/jira.md +++ b/doc/user/project/import/jira.md @@ -46,7 +46,7 @@ GitLab project that you wish to import into. ### Jira integration -This feature uses the existing GitLab [Jira integration](../integrations/jira.md). +This feature uses the existing GitLab [Jira integration](../../../integration/jira/index.md). Make sure you have the integration set up before trying to import Jira issues. @@ -68,7 +68,7 @@ To import Jira issues to a GitLab project: The **Import from Jira** option is only visible if you have the [correct permissions](#permissions). The following form appears. - If you've previously set up the [Jira integration](../integrations/jira.md), you can now see + If you've previously set up the [Jira integration](../../../integration/jira/index.md), you can now see the Jira projects that you have access to in the dropdown. ![Import issues from Jira form](img/jira/import_issues_from_jira_form_v13_2.png) diff --git a/doc/user/project/integrations/jira.md b/doc/user/project/integrations/jira.md deleted file mode 100644 index 521f15f330e..00000000000 --- a/doc/user/project/integrations/jira.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: '../../../integration/jira/index.md' -remove_date: '2021-07-07' ---- - -This document was moved to [another location](../../../integration/jira/index.md). - -<!-- This redirect file can be deleted after 2021-07-07. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/user/project/integrations/jira_integrations.md b/doc/user/project/integrations/jira_integrations.md deleted file mode 100644 index 3aacf051c22..00000000000 --- a/doc/user/project/integrations/jira_integrations.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: '../../../integration/jira/index.md' -remove_date: '2021-07-13' ---- - -This document was moved to [another location](../../../integration/jira/index.md). - -<!-- This redirect file can be deleted after <2021-07-13>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/doc/user/project/integrations/overview.md b/doc/user/project/integrations/overview.md index b75bb4ff605..d03afac3221 100644 --- a/doc/user/project/integrations/overview.md +++ b/doc/user/project/integrations/overview.md @@ -44,7 +44,7 @@ Click on the service links to see further configuration instructions and details | [irker (IRC gateway)](irker.md) | Send IRC messages. | **{dotted-circle}** No | | [Jenkins](../../../integration/jenkins.md) | Run CI/CD pipelines with Jenkins. | **{check-circle}** Yes | | JetBrains TeamCity CI | Run CI/CD pipelines with TeamCity. | **{check-circle}** Yes | -| [Jira](jira.md) | Use Jira as the issue tracker. | **{dotted-circle}** No | +| [Jira](../../../integration/jira/index.md) | Use Jira as the issue tracker. | **{dotted-circle}** No | | [Mattermost notifications](mattermost.md) | Send notifications about project events to Mattermost channels. | **{dotted-circle}** No | | [Mattermost slash commands](mattermost_slash_commands.md) | Perform common tasks with slash commands. | **{dotted-circle}** No | | [Microsoft Teams notifications](microsoft_teams.md) | Receive event notifications. | **{dotted-circle}** No | diff --git a/doc/user/project/merge_requests/merge_request_approvals.md b/doc/user/project/merge_requests/merge_request_approvals.md deleted file mode 100644 index 42de04085a9..00000000000 --- a/doc/user/project/merge_requests/merge_request_approvals.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -redirect_to: 'approvals/index.md' -remove_date: '2021-07-27' ---- - -This document was moved to [another location](approvals/index.md). - -<!-- This redirect file can be deleted after <2021-07-27>. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/#move-or-rename-a-page --> diff --git a/locale/gitlab.pot b/locale/gitlab.pot index aedb7f59978..44b3b308b51 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3891,6 +3891,9 @@ msgstr "" msgid "Any Author" msgstr "" +msgid "Any Milestone" +msgstr "" + msgid "Any branch" msgstr "" @@ -5309,9 +5312,15 @@ msgstr "" msgid "BoardNewIssue|Select a project" msgstr "" +msgid "BoardScope|An error occurred while getting milestones, please try again." +msgstr "" + msgid "BoardScope|An error occurred while searching for users, please try again." msgstr "" +msgid "BoardScope|Any Milestone" +msgstr "" + msgid "BoardScope|Any assignee" msgstr "" @@ -5321,12 +5330,30 @@ msgstr "" msgid "BoardScope|Edit" msgstr "" +msgid "BoardScope|Milestone" +msgstr "" + msgid "BoardScope|No matching results" msgstr "" +msgid "BoardScope|No milestone" +msgstr "" + +msgid "BoardScope|Search milestones" +msgstr "" + msgid "BoardScope|Select assignee" msgstr "" +msgid "BoardScope|Select milestone" +msgstr "" + +msgid "BoardScope|Started" +msgstr "" + +msgid "BoardScope|Upcoming" +msgstr "" + msgid "Boards" msgstr "" @@ -22169,6 +22196,9 @@ msgstr "" msgid "No Matching Results" msgstr "" +msgid "No Milestone" +msgstr "" + msgid "No Scopes" msgstr "" diff --git a/scripts/rspec_helpers.sh b/scripts/rspec_helpers.sh index 9a318caad24..a788c3417c2 100644 --- a/scripts/rspec_helpers.sh +++ b/scripts/rspec_helpers.sh @@ -1,33 +1,23 @@ #!/usr/bin/env bash function retrieve_tests_metadata() { - mkdir -p $(dirname "$KNAPSACK_RSPEC_SUITE_REPORT_PATH") $(dirname "$FLAKY_RSPEC_SUITE_REPORT_PATH") rspec_profiling/ + mkdir -p knapsack/ rspec_flaky/ rspec_profiling/ - if [[ -z "${RETRIEVE_TESTS_METADATA_FROM_ARTIFACTS}" ]]; then - if [[ ! -f "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" ]]; then - curl --location -o "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" "https://gitlab-org.gitlab.io/gitlab/${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" || echo "{}" > "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" - fi - - if [[ ! -f "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ]]; then - curl --location -o "${FLAKY_RSPEC_SUITE_REPORT_PATH}" "https://gitlab-org.gitlab.io/gitlab/${FLAKY_RSPEC_SUITE_REPORT_PATH}" || echo "{}" > "${FLAKY_RSPEC_SUITE_REPORT_PATH}" - fi - else - # ${CI_DEFAULT_BRANCH} might not be master in other forks but we want to - # always target the canonical project here, so the branch must be hardcoded - local project_path="gitlab-org/gitlab" - local artifact_branch="master" - local test_metadata_job_id + # ${CI_DEFAULT_BRANCH} might not be master in other forks but we want to + # always target the canonical project here, so the branch must be hardcoded + local project_path="gitlab-org/gitlab" + local artifact_branch="master" + local test_metadata_job_id - # Ruby - test_metadata_job_id=$(scripts/api/get_job_id.rb --project "${project_path}" -q "status=success" -q "ref=${artifact_branch}" -q "username=gitlab-bot" -Q "scope=success" --job-name "update-tests-metadata") + # Ruby + test_metadata_job_id=$(scripts/api/get_job_id.rb --project "${project_path}" -q "status=success" -q "ref=${artifact_branch}" -q "username=gitlab-bot" -Q "scope=success" --job-name "update-tests-metadata") - if [[ ! -f "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" ]]; then - scripts/api/download_job_artifact.rb --project "${project_path}" --job-id "${test_metadata_job_id}" --artifact-path "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" || echo "{}" > "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" - fi + if [[ ! -f "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" ]]; then + scripts/api/download_job_artifact.rb --project "${project_path}" --job-id "${test_metadata_job_id}" --artifact-path "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" || echo "{}" > "${KNAPSACK_RSPEC_SUITE_REPORT_PATH}" + fi - if [[ ! -f "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ]]; then - scripts/api/download_job_artifact.rb --project "${project_path}" --job-id "${test_metadata_job_id}" --artifact-path "${FLAKY_RSPEC_SUITE_REPORT_PATH}" || echo "{}" > "${FLAKY_RSPEC_SUITE_REPORT_PATH}" - fi + if [[ ! -f "${FLAKY_RSPEC_SUITE_REPORT_PATH}" ]]; then + scripts/api/download_job_artifact.rb --project "${project_path}" --job-id "${test_metadata_job_id}" --artifact-path "${FLAKY_RSPEC_SUITE_REPORT_PATH}" || echo "{}" > "${FLAKY_RSPEC_SUITE_REPORT_PATH}" fi } @@ -50,24 +40,18 @@ function update_tests_metadata() { } function retrieve_tests_mapping() { - mkdir -p $(dirname "$RSPEC_PACKED_TESTS_MAPPING_PATH") + mkdir -p crystalball/ - if [[ -z "${RETRIEVE_TESTS_METADATA_FROM_ARTIFACTS}" ]]; then - if [[ ! -f "${RSPEC_PACKED_TESTS_MAPPING_PATH}" ]]; then - (curl --location -o "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz" "https://gitlab-org.gitlab.io/gitlab/${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz" && gzip -d "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz") || echo "{}" > "${RSPEC_PACKED_TESTS_MAPPING_PATH}" - fi - else - # ${CI_DEFAULT_BRANCH} might not be master in other forks but we want to - # always target the canonical project here, so the branch must be hardcoded - local project_path="gitlab-org/gitlab" - local artifact_branch="master" - local test_metadata_with_mapping_job_id + # ${CI_DEFAULT_BRANCH} might not be master in other forks but we want to + # always target the canonical project here, so the branch must be hardcoded + local project_path="gitlab-org/gitlab" + local artifact_branch="master" + local test_metadata_with_mapping_job_id - test_metadata_with_mapping_job_id=$(scripts/api/get_job_id.rb --project "${project_path}" -q "status=success" -q "ref=${artifact_branch}" -q "username=gitlab-bot" -Q "scope=success" --job-name "update-tests-metadata" --artifact-path "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz") + test_metadata_with_mapping_job_id=$(scripts/api/get_job_id.rb --project "${project_path}" -q "status=success" -q "ref=${artifact_branch}" -q "username=gitlab-bot" -Q "scope=success" --job-name "update-tests-metadata" --artifact-path "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz") - if [[ ! -f "${RSPEC_PACKED_TESTS_MAPPING_PATH}" ]]; then - (scripts/api/download_job_artifact.rb --project "${project_path}" --job-id "${test_metadata_with_mapping_job_id}" --artifact-path "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz" && gzip -d "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz") || echo "{}" > "${RSPEC_PACKED_TESTS_MAPPING_PATH}" - fi + if [[ ! -f "${RSPEC_PACKED_TESTS_MAPPING_PATH}" ]]; then + (scripts/api/download_job_artifact.rb --project "${project_path}" --job-id "${test_metadata_with_mapping_job_id}" --artifact-path "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz" && gzip -d "${RSPEC_PACKED_TESTS_MAPPING_PATH}.gz") || echo "{}" > "${RSPEC_PACKED_TESTS_MAPPING_PATH}" fi scripts/unpack-test-mapping "${RSPEC_PACKED_TESTS_MAPPING_PATH}" "${RSPEC_TESTS_MAPPING_PATH}" diff --git a/spec/factories/alert_management/alerts.rb b/spec/factories/alert_management/alerts.rb index f63a3c9f7f5..589a62a68bb 100644 --- a/spec/factories/alert_management/alerts.rb +++ b/spec/factories/alert_management/alerts.rb @@ -15,9 +15,9 @@ FactoryBot.define do end end - trait :with_issue do + trait :with_incident do after(:create) do |alert| - create(:issue, alert_management_alert: alert, project: alert.project) + create(:incident, alert_management_alert: alert, project: alert.project) end end @@ -128,7 +128,7 @@ FactoryBot.define do end trait :all_fields do - with_issue + with_incident with_assignee with_fingerprint with_service diff --git a/spec/factories/packages/debian/file_metadatum.rb b/spec/factories/packages/debian/file_metadatum.rb index f761dd18b4e..505b9975f79 100644 --- a/spec/factories/packages/debian/file_metadatum.rb +++ b/spec/factories/packages/debian/file_metadatum.rb @@ -26,7 +26,27 @@ FactoryBot.define do file_type { 'dsc' } component { 'main' } architecture { nil } - fields { { 'a': 'b' } } + fields do + { + 'Format' => '3.0 (native)', + 'Source' => package_file.package.name, + 'Binary' => 'sample-dev, libsample0, sample-udeb', + 'Architecture' => 'any', + 'Version': package_file.package.version, + 'Maintainer' => "#{FFaker::Name.name} <#{FFaker::Internet.email}>", + 'Homepage' => FFaker::Internet.http_url, + 'Standards-Version' => '4.5.0', + 'Build-Depends' => 'debhelper-compat (= 13)', + 'Package-List' => <<~EOF.rstrip, + libsample0 deb libs optional arch=any', + sample-dev deb libdevel optional arch=any', + sample-udeb udeb libs optional arch=any', + EOF + 'Checksums-Sha1' => "\nc5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz", + 'Checksums-Sha256' => "\n40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz", + 'Files' => "\nd5ca476e4229d135a88f9c729c7606c9 864 sample_1.2.3~alpha2.tar.xz" + } + end end trait(:deb) do diff --git a/spec/frontend/cycle_analytics/mock_data.js b/spec/frontend/cycle_analytics/mock_data.js index e0dea4c9a98..cedc31a3273 100644 --- a/spec/frontend/cycle_analytics/mock_data.js +++ b/spec/frontend/cycle_analytics/mock_data.js @@ -131,9 +131,7 @@ export const convertedData = { export const rawIssueEvents = stageFixtures.issue; export const issueEvents = deepCamelCase(rawIssueEvents); -export const planEvents = deepCamelCase(stageFixtures.plan); export const reviewEvents = deepCamelCase(stageFixtures.review); -export const codeEvents = deepCamelCase(stageFixtures.code); export const testEvents = deepCamelCase(stageFixtures.test); export const stagingEvents = deepCamelCase(stageFixtures.staging); diff --git a/spec/frontend/fixtures/analytics.rb b/spec/frontend/fixtures/analytics.rb index f4cbaf274fc..87cfbb72382 100644 --- a/spec/frontend/fixtures/analytics.rb +++ b/spec/frontend/fixtures/analytics.rb @@ -2,74 +2,15 @@ require 'spec_helper' RSpec.describe 'Analytics (JavaScript fixtures)', :sidekiq_inline do - include JavaScriptFixturesHelpers + include_context 'Analytics fixtures shared context' let_it_be(:value_stream_id) { 'default' } - let_it_be(:group) { create(:group) } - let_it_be(:project) { create(:project, :repository, namespace: group) } - let_it_be(:user) { create(:user, :admin) } - let_it_be(:milestone) { create(:milestone, project: project) } - - let(:issue) { create(:issue, project: project, created_at: 4.days.ago) } - let(:issue_1) { create(:issue, project: project, created_at: 5.days.ago) } - let(:issue_2) { create(:issue, project: project, created_at: 4.days.ago, milestone: milestone) } - let(:issue_3) { create(:issue, project: project, created_at: 3.days.ago, milestone: milestone) } - - let(:mr_1) { create(:merge_request, source_project: project, allow_broken: true, created_at: 5.days.ago) } - let(:mr_2) { create(:merge_request, source_project: project, allow_broken: true, created_at: 4.days.ago) } - - let(:pipeline_1) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr_1.source_branch, sha: mr_1.source_branch_sha, head_pipeline_of: mr_1) } - let(:pipeline_2) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr_2.source_branch, sha: mr_2.source_branch_sha, head_pipeline_of: mr_2) } - - let(:build_1) { create(:ci_build, :success, pipeline: pipeline_1, author: user) } - let(:build_2) { create(:ci_build, :success, pipeline: pipeline_2, author: user) } - - def prepare_cycle_analytics_data - group.add_maintainer(user) - project.add_maintainer(user) - - create_commit_referencing_issue(issue_1) - create_commit_referencing_issue(issue_2) - - create_merge_request_closing_issue(user, project, issue_1) - create_merge_request_closing_issue(user, project, issue_2) - merge_merge_requests_closing_issue(user, project, issue_3) - end - - def create_deployment - deploy_master(user, project, environment: 'staging') - deploy_master(user, project) - end - - def update_metrics - issue_1.metrics.update!(first_added_to_board_at: 3.days.ago, first_mentioned_in_commit_at: 2.days.ago) - issue_2.metrics.update!(first_added_to_board_at: 2.days.ago, first_mentioned_in_commit_at: 1.day.ago) - - mr_1.metrics.update!({ - merged_at: 5.days.ago, - first_deployed_to_production_at: 1.day.ago, - latest_build_started_at: 5.days.ago, - latest_build_finished_at: 1.day.ago, - pipeline: build_1.pipeline - }) - - mr_2.metrics.update!({ - merged_at: 10.days.ago, - first_deployed_to_production_at: 5.days.ago, - latest_build_started_at: 9.days.ago, - latest_build_finished_at: 7.days.ago, - pipeline: build_2.pipeline - }) - end before(:all) do clean_frontend_fixtures('projects/analytics/value_stream_analytics/') end before do - stub_licensed_features(cycle_analytics_for_groups: true) - - prepare_cycle_analytics_data update_metrics create_deployment end diff --git a/spec/frontend/graphql_shared/utils_spec.js b/spec/frontend/graphql_shared/utils_spec.js index 56bfb02ea4a..1732f24eeff 100644 --- a/spec/frontend/graphql_shared/utils_spec.js +++ b/spec/frontend/graphql_shared/utils_spec.js @@ -1,4 +1,5 @@ import { + isGid, getIdFromGraphQLId, convertToGraphQLId, convertToGraphQLIds, @@ -10,6 +11,16 @@ const mockType = 'Group'; const mockId = 12; const mockGid = `gid://gitlab/Group/12`; +describe('isGid', () => { + it('returns true if passed id is gid', () => { + expect(isGid(mockGid)).toBe(true); + }); + + it('returns false if passed id is not gid', () => { + expect(isGid(mockId)).toBe(false); + }); +}); + describe('getIdFromGraphQLId', () => { [ { @@ -67,6 +78,10 @@ describe('convertToGraphQLId', () => { `('throws TypeError with "$message" if a param is missing', ({ type, id, message }) => { expect(() => convertToGraphQLId(type, id)).toThrow(new TypeError(message)); }); + + it('returns id as is if it follows the gid format', () => { + expect(convertToGraphQLId(mockType, mockGid)).toStrictEqual(mockGid); + }); }); describe('convertToGraphQLIds', () => { diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js index 2da007fb549..b1005aed4c3 100644 --- a/spec/frontend/sidebar/mock_data.js +++ b/spec/frontend/sidebar/mock_data.js @@ -585,6 +585,19 @@ export const mockProjectMilestonesResponse = { }, }; +export const mockGroupMilestonesResponse = { + data: { + workspace: { + id: 'gid://gitlab/Group/1', + attributes: { + nodes: [mockMilestone1, mockMilestone2], + }, + __typename: 'MilestoneConnection', + }, + __typename: 'Group', + }, +}; + export const noCurrentMilestoneResponse = { data: { workspace: { diff --git a/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js b/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js new file mode 100644 index 00000000000..929bd34c10f --- /dev/null +++ b/spec/frontend/vue_shared/components/dropdown/dropdown_widget_spec.js @@ -0,0 +1,79 @@ +import { GlDropdown, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; + +import DropdownWidget from '~/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue'; + +describe('DropdownWidget component', () => { + let wrapper; + + const findDropdown = () => wrapper.findComponent(GlDropdown); + const findDropdownItems = () => wrapper.findAll(GlDropdownItem); + const findSearch = () => wrapper.findComponent(GlSearchBoxByType); + + const createComponent = ({ props = {} } = {}) => { + wrapper = shallowMount(DropdownWidget, { + propsData: { + ...props, + options: [ + { + id: '1', + title: 'Option 1', + }, + { + id: '2', + title: 'Option 2', + }, + ], + }, + stubs: { + GlDropdown, + }, + }); + + // We need to mock out `showDropdown` which + // invokes `show` method of BDropdown used inside GlDropdown. + // Context: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54895#note_524281679 + jest.spyOn(wrapper.vm, 'showDropdown').mockImplementation(); + }; + + beforeEach(() => { + createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + wrapper = null; + }); + + it('passes default selectText prop to dropdown', () => { + expect(findDropdown().props('text')).toBe('Select'); + }); + + describe('when dropdown is open', () => { + beforeEach(async () => { + findDropdown().vm.$emit('show'); + await wrapper.vm.$nextTick(); + }); + + it('emits search event when typing in search box', () => { + const searchTerm = 'searchTerm'; + findSearch().vm.$emit('input', searchTerm); + + expect(wrapper.emitted('set-search')).toEqual([[searchTerm]]); + }); + + it('renders one selectable item per passed option', async () => { + expect(findDropdownItems()).toHaveLength(2); + }); + + it('emits set-option event when clicking on an option', async () => { + wrapper + .findAll('[data-testid="unselected-option"]') + .at(1) + .vm.$emit('click', new Event('click')); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted('set-option')).toEqual([[wrapper.props().options[1]]]); + }); + }); +}); diff --git a/spec/mailers/emails/projects_spec.rb b/spec/mailers/emails/projects_spec.rb index 4855d5becfa..b9c71e35bc6 100644 --- a/spec/mailers/emails/projects_spec.rb +++ b/spec/mailers/emails/projects_spec.rb @@ -48,7 +48,7 @@ RSpec.describe Emails::Projects do end context 'with incident' do - let(:alert) { create(:alert_management_alert, :with_issue, :from_payload, payload: payload, project: project) } + let(:alert) { create(:alert_management_alert, :with_incident, :from_payload, payload: payload, project: project) } let(:incident) { alert.issue } it 'has expected X-GitLab incident headers', :aggregate_failures do diff --git a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb index 05a98a9dd9c..29896c16f5b 100644 --- a/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb +++ b/spec/requests/api/graphql/project/alert_management/alert/issue_spec.rb @@ -40,7 +40,7 @@ RSpec.describe 'getting Alert Management Alert Issue' do context 'with gitlab alert' do before do - create(:alert_management_alert, :with_issue, project: project, payload: payload) + create(:alert_management_alert, :with_incident, project: project, payload: payload) end it 'includes the correct alert issue payload data' do @@ -57,7 +57,7 @@ RSpec.describe 'getting Alert Management Alert Issue' do context 'with gitlab alert' do before do - create(:alert_management_alert, :with_issue, project: project, payload: payload) + create(:alert_management_alert, :with_incident, project: project, payload: payload) end it 'avoids N+1 queries' do diff --git a/spec/requests/api/graphql/project/issues_spec.rb b/spec/requests/api/graphql/project/issues_spec.rb index 434f788b940..ff0d7ecceb5 100644 --- a/spec/requests/api/graphql/project/issues_spec.rb +++ b/spec/requests/api/graphql/project/issues_spec.rb @@ -323,7 +323,7 @@ RSpec.describe 'getting an issue list for a project' do it 'avoids N+1 queries' do control = ActiveRecord::QueryRecorder.new { post_graphql(query, current_user: current_user) } - create(:alert_management_alert, :with_issue, project: project) + create(:alert_management_alert, :with_incident, project: project) expect { post_graphql(query, current_user: current_user) }.not_to exceed_query_limit(control) end diff --git a/spec/services/packages/debian/generate_distribution_service_spec.rb b/spec/services/packages/debian/generate_distribution_service_spec.rb index 7da14ac2a18..53805d03655 100644 --- a/spec/services/packages/debian/generate_distribution_service_spec.rb +++ b/spec/services/packages/debian/generate_distribution_service_spec.rb @@ -6,6 +6,9 @@ RSpec.describe Packages::Debian::GenerateDistributionService do describe '#execute' do subject { described_class.new(distribution).execute } + let(:subject2) { described_class.new(distribution).execute } + let(:subject3) { described_class.new(distribution).execute } + include_context 'with published Debian package' [:project, :group].each do |container_type| diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index e9bd40b058b..5aff5149dcf 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -745,7 +745,7 @@ RSpec.describe SystemNoteService do end describe '.new_alert_issue' do - let(:alert) { build(:alert_management_alert, :with_issue) } + let(:alert) { build(:alert_management_alert, :with_incident) } it 'calls AlertManagementService' do expect_next_instance_of(SystemNotes::AlertManagementService) do |service| diff --git a/spec/services/system_notes/alert_management_service_spec.rb b/spec/services/system_notes/alert_management_service_spec.rb index 1c36a4036cc..6e6bfeaa205 100644 --- a/spec/services/system_notes/alert_management_service_spec.rb +++ b/spec/services/system_notes/alert_management_service_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe ::SystemNotes::AlertManagementService do let_it_be(:author) { create(:user) } let_it_be(:project) { create(:project, :repository) } - let_it_be(:noteable) { create(:alert_management_alert, :with_issue, :acknowledged, project: project) } + let_it_be(:noteable) { create(:alert_management_alert, :with_incident, :acknowledged, project: project) } describe '#create_new_alert' do subject { described_class.new(noteable: noteable, project: project).create_new_alert('Some Service') } diff --git a/spec/support/shared_contexts/fixtures/analytics_shared_context.rb b/spec/support/shared_contexts/fixtures/analytics_shared_context.rb new file mode 100644 index 00000000000..13d3697a378 --- /dev/null +++ b/spec/support/shared_contexts/fixtures/analytics_shared_context.rb @@ -0,0 +1,70 @@ +# frozen_string_literal: true + +RSpec.shared_context 'Analytics fixtures shared context' do + include JavaScriptFixturesHelpers + + let_it_be(:group) { create(:group) } + let_it_be(:project) { create(:project, :repository, namespace: group) } + let_it_be(:user) { create(:user, :admin) } + let_it_be(:milestone) { create(:milestone, project: project) } + + let(:issue) { create(:issue, project: project, created_at: 4.days.ago) } + let(:issue_1) { create(:issue, project: project, created_at: 5.days.ago) } + let(:issue_2) { create(:issue, project: project, created_at: 4.days.ago, milestone: milestone) } + let(:issue_3) { create(:issue, project: project, created_at: 3.days.ago, milestone: milestone) } + + let(:mr_1) { create(:merge_request, source_project: project, allow_broken: true, created_at: 20.days.ago) } + let(:mr_2) { create(:merge_request, source_project: project, allow_broken: true, created_at: 19.days.ago) } + + let(:pipeline_1) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr_1.source_branch, sha: mr_1.source_branch_sha, head_pipeline_of: mr_1) } + let(:pipeline_2) { create(:ci_empty_pipeline, status: 'created', project: project, ref: mr_2.source_branch, sha: mr_2.source_branch_sha, head_pipeline_of: mr_2) } + + let(:build_1) { create(:ci_build, :success, pipeline: pipeline_1, author: user) } + let(:build_2) { create(:ci_build, :success, pipeline: pipeline_2, author: user) } + + let(:params) { { created_after: 3.months.ago, created_before: Time.now, group_id: group.full_path } } + + def prepare_cycle_analytics_data + group.add_maintainer(user) + project.add_maintainer(user) + + create_commit_referencing_issue(issue_1) + create_commit_referencing_issue(issue_2) + + create_merge_request_closing_issue(user, project, issue_1) + create_merge_request_closing_issue(user, project, issue_2) + merge_merge_requests_closing_issue(user, project, issue_3) + end + + def create_deployment + deploy_master(user, project, environment: 'staging') + deploy_master(user, project) + end + + def update_metrics + issue_1.metrics.update!(first_added_to_board_at: 3.days.ago, first_mentioned_in_commit_at: 2.days.ago) + issue_2.metrics.update!(first_added_to_board_at: 2.days.ago, first_mentioned_in_commit_at: 1.day.ago) + + mr_1.metrics.update!({ + merged_at: 5.days.ago, + first_deployed_to_production_at: 1.day.ago, + latest_build_started_at: 5.days.ago, + latest_build_finished_at: 1.day.ago, + pipeline: build_1.pipeline + }) + + mr_2.metrics.update!({ + merged_at: 10.days.ago, + first_deployed_to_production_at: 5.days.ago, + latest_build_started_at: 9.days.ago, + latest_build_finished_at: 7.days.ago, + pipeline: build_2.pipeline + }) + end + + before do + stub_licensed_features(cycle_analytics_for_groups: true) + + prepare_cycle_analytics_data + end +end diff --git a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb index 17daa183a7e..c979fdc2bb0 100644 --- a/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb +++ b/spec/support/shared_examples/services/packages/debian/generate_distribution_shared_examples.rb @@ -57,10 +57,13 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do travel_to(current_time) do expect(Gitlab::ErrorTracking).not_to receive(:log_exception) + components_count = 2 + architectures_count = 3 + initial_count = 6 destroyed_count = 2 - # updated_count = 1 - created_count = 5 + updated_count = 1 + created_count = components_count * (architectures_count * 2 + 1) - updated_count expect { subject } .to not_change { Packages::Package.count } @@ -69,7 +72,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do .and change { distribution.component_files.reset.count }.from(initial_count).to(initial_count - destroyed_count + created_count) .and change { component_file1.reload.updated_at }.to(current_time.round) - debs = package.package_files.with_debian_file_type(:deb).preload_debian_file_metadata.to_a + package_files = package.package_files.order(id: :asc).preload_debian_file_metadata.to_a pool_prefix = 'pool/unstable' pool_prefix += "/#{project.id}" if container_type == :group pool_prefix += "/p/#{package.name}/#{package.version}" @@ -78,26 +81,26 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do Source: #{package.name} Version: #{package.version} Installed-Size: 7 - Maintainer: #{debs[0].debian_fields['Maintainer']} + Maintainer: #{package_files[2].debian_fields['Maintainer']} Architecture: amd64 Description: Some mostly empty lib Used in GitLab tests. . Testing another paragraph. Multi-Arch: same - Homepage: #{debs[0].debian_fields['Homepage']} + Homepage: #{package_files[2].debian_fields['Homepage']} Section: libs Priority: optional Filename: #{pool_prefix}/libsample0_1.2.3~alpha2_amd64.deb Size: 409600 - MD5sum: #{debs[0].file_md5} - SHA256: #{debs[0].file_sha256} + MD5sum: #{package_files[2].file_md5} + SHA256: #{package_files[2].file_sha256} Package: sample-dev Source: #{package.name} (#{package.version}) Version: 1.2.3~binary Installed-Size: 7 - Maintainer: #{debs[1].debian_fields['Maintainer']} + Maintainer: #{package_files[3].debian_fields['Maintainer']} Architecture: amd64 Depends: libsample0 (= 1.2.3~binary) Description: Some mostly empty development files @@ -105,23 +108,68 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do . Testing another paragraph. Multi-Arch: same - Homepage: #{debs[1].debian_fields['Homepage']} + Homepage: #{package_files[3].debian_fields['Homepage']} Section: libdevel Priority: optional Filename: #{pool_prefix}/sample-dev_1.2.3~binary_amd64.deb Size: 409600 - MD5sum: #{debs[1].file_md5} - SHA256: #{debs[1].file_sha256} + MD5sum: #{package_files[3].file_md5} + SHA256: #{package_files[3].file_sha256} + EOF + + expected_main_amd64_di_content = <<~EOF + Section: misc + Priority: extra + Filename: #{pool_prefix}/sample-udeb_1.2.3~alpha2_amd64.udeb + Size: 409600 + MD5sum: #{package_files[4].file_md5} + SHA256: #{package_files[4].file_sha256} + EOF + + expected_main_source_content = <<~EOF + Package: #{package.name} + Binary: sample-dev, libsample0, sample-udeb + Version: #{package.version} + Maintainer: #{package_files[1].debian_fields['Maintainer']} + Build-Depends: debhelper-compat (= 13) + Architecture: any + Standards-Version: 4.5.0 + Format: 3.0 (native) + Files: + #{package_files[1].file_md5} #{package_files[1].size} #{package_files[1].file_name} + d5ca476e4229d135a88f9c729c7606c9 864 sample_1.2.3~alpha2.tar.xz + Checksums-Sha256: + #{package_files[1].file_sha256} #{package_files[1].size} #{package_files[1].file_name} + 40e4682bb24a73251ccd7c7798c0094a649091e5625d6a14bcec9b4e7174f3da 864 sample_1.2.3~alpha2.tar.xz + Checksums-Sha1: + #{package_files[1].file_sha1} #{package_files[1].size} #{package_files[1].file_name} + c5cfc111ea924842a89a06d5673f07dfd07de8ca 864 sample_1.2.3~alpha2.tar.xz + Homepage: #{package_files[1].debian_fields['Homepage']} + Section: misc + Priority: extra + Directory: #{pool_prefix} EOF check_component_file(current_time.round, 'main', :packages, 'all', nil) check_component_file(current_time.round, 'main', :packages, 'amd64', expected_main_amd64_content) check_component_file(current_time.round, 'main', :packages, 'arm64', nil) + check_component_file(current_time.round, 'main', :di_packages, 'all', nil) + check_component_file(current_time.round, 'main', :di_packages, 'amd64', expected_main_amd64_di_content) + check_component_file(current_time.round, 'main', :di_packages, 'arm64', nil) + + check_component_file(current_time.round, 'main', :source, nil, expected_main_source_content) + check_component_file(current_time.round, 'contrib', :packages, 'all', nil) check_component_file(current_time.round, 'contrib', :packages, 'amd64', nil) check_component_file(current_time.round, 'contrib', :packages, 'arm64', nil) + check_component_file(current_time.round, 'contrib', :di_packages, 'all', nil) + check_component_file(current_time.round, 'contrib', :di_packages, 'amd64', nil) + check_component_file(current_time.round, 'contrib', :di_packages, 'arm64', nil) + + check_component_file(current_time.round, 'contrib', :source, nil, nil) + main_amd64_size = expected_main_amd64_content.length main_amd64_md5sum = Digest::MD5.hexdigest(expected_main_amd64_content) main_amd64_sha256 = Digest::SHA256.hexdigest(expected_main_amd64_content) @@ -130,6 +178,14 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do contrib_all_md5sum = component_file1.file_md5 contrib_all_sha256 = component_file1.file_sha256 + main_amd64_di_size = expected_main_amd64_di_content.length + main_amd64_di_md5sum = Digest::MD5.hexdigest(expected_main_amd64_di_content) + main_amd64_di_sha256 = Digest::SHA256.hexdigest(expected_main_amd64_di_content) + + main_source_size = expected_main_source_content.length + main_source_md5sum = Digest::MD5.hexdigest(expected_main_source_content) + main_source_sha256 = Digest::SHA256.hexdigest(expected_main_source_content) + expected_release_content = <<~EOF Codename: unstable Date: Sat, 25 Jan 2020 15:17:18 +0000 @@ -138,22 +194,44 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do Components: contrib main MD5Sum: #{contrib_all_md5sum} #{contrib_all_size} contrib/binary-all/Packages + d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-all/Packages d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-amd64/Packages + d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-amd64/Packages d41d8cd98f00b204e9800998ecf8427e 0 contrib/binary-arm64/Packages + d41d8cd98f00b204e9800998ecf8427e 0 contrib/debian-installer/binary-arm64/Packages + d41d8cd98f00b204e9800998ecf8427e 0 contrib/source/Source d41d8cd98f00b204e9800998ecf8427e 0 main/binary-all/Packages + d41d8cd98f00b204e9800998ecf8427e 0 main/debian-installer/binary-all/Packages #{main_amd64_md5sum} #{main_amd64_size} main/binary-amd64/Packages + #{main_amd64_di_md5sum} #{main_amd64_di_size} main/debian-installer/binary-amd64/Packages d41d8cd98f00b204e9800998ecf8427e 0 main/binary-arm64/Packages + d41d8cd98f00b204e9800998ecf8427e 0 main/debian-installer/binary-arm64/Packages + #{main_source_md5sum} #{main_source_size} main/source/Source SHA256: #{contrib_all_sha256} #{contrib_all_size} contrib/binary-all/Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-all/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-amd64/Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-amd64/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/binary-arm64/Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/debian-installer/binary-arm64/Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 contrib/source/Source e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-all/Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/debian-installer/binary-all/Packages #{main_amd64_sha256} #{main_amd64_size} main/binary-amd64/Packages + #{main_amd64_di_sha256} #{main_amd64_di_size} main/debian-installer/binary-amd64/Packages e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/binary-arm64/Packages + e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 0 main/debian-installer/binary-arm64/Packages + #{main_source_sha256} #{main_source_size} main/source/Source EOF check_release_files(expected_release_content) end + + create_list(:debian_package, 10, project: project, published_in: project_distribution) + control_count = ActiveRecord::QueryRecorder.new { subject2 }.count + + create_list(:debian_package, 10, project: project, published_in: project_distribution) + expect { subject3 }.not_to exceed_query_limit(control_count) end end diff --git a/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb b/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb index 403793a15e2..a9a15565580 100644 --- a/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb +++ b/spec/workers/authorized_project_update/project_recalculate_worker_spec.rb @@ -43,7 +43,7 @@ RSpec.describe AuthorizedProjectUpdate::ProjectRecalculateWorker do end context 'exclusive lease' do - let(:lock_key) { "#{described_class.name.underscore}/#{project.root_namespace.id}" } + let(:lock_key) { "#{described_class.name.underscore}/projects/#{project.id}" } let(:timeout) { 10.seconds } context 'when exclusive lease has not been taken' do diff --git a/spec/workers/packages/debian/generate_distribution_worker_spec.rb b/spec/workers/packages/debian/generate_distribution_worker_spec.rb index a8751ccceae..a4627ec5d36 100644 --- a/spec/workers/packages/debian/generate_distribution_worker_spec.rb +++ b/spec/workers/packages/debian/generate_distribution_worker_spec.rb @@ -9,6 +9,9 @@ RSpec.describe Packages::Debian::GenerateDistributionWorker, type: :worker do subject { described_class.new.perform(container_type, distribution_id) } + let(:subject2) { described_class.new.perform(container_type, distribution_id) } + let(:subject3) { described_class.new.perform(container_type, distribution_id) } + include_context 'with published Debian package' [:project, :group].each do |container_type| |