From b07852468f800d751ddecc9e327119d7295f538e Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 15 Dec 2020 18:10:06 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .../import_groups/graphql/client_factory.js | 29 +++ .../graphql/services/status_poller.js | 68 ++++++ app/assets/javascripts/lib/utils/keycodes.js | 1 + .../graphql/queries/ci_config.graphql | 4 +- .../pipeline_editor/pipeline_editor_app.vue | 7 +- .../queries/pipeline_stages.fragment.graphql | 12 - ...ipeline_stages_connection.fragment.graphql | 20 ++ .../gfm_autocomplete/gfm_autocomplete.vue | 6 +- app/models/ci/build_dependencies.rb | 2 +- app/models/user.rb | 4 + app/services/jira/requests/base.rb | 7 +- .../import/bulk_imports/status.html.haml | 4 +- app/views/profiles/accounts/show.html.haml | 5 + ...es_at-param-to-groupmemberbuilder-data.yml | 5 + ...e-ci-cross-pipeline-artifacts-download.yml | 5 + .../xanf-import-one-group-frontend.yml | 5 + .../ci_cross_pipeline_artifacts_download.yml | 2 +- .../active_record_table_definition.rb | 4 +- doc/administration/gitaly/index.md | 8 +- doc/administration/integration/terminal.md | 12 +- .../reference_architectures/index.md | 5 + .../gitlab_rails_cheat_sheet.md | 20 ++ .../graphql/reference/gitlab_schema.graphql | 4 +- doc/api/graphql/reference/gitlab_schema.json | 4 +- doc/api/graphql/reference/index.md | 4 +- doc/ci/yaml/README.md | 49 +++- doc/development/database_review.md | 2 +- .../documentation/styleguide/index.md | 2 +- .../incident_management/alert_integrations.md | 2 +- .../admin_area/analytics/dev_ops_report.md | 2 +- .../settings/user_and_ip_rate_limits.md | 35 +++ doc/user/group/epics/index.md | 6 +- doc/user/packages/package_registry/index.md | 1 - doc/user/packages/workflows/monorepo.md | 121 +--------- doc/user/project/integrations/webhooks.md | 1 + doc/user/project/issues/index.md | 13 +- .../project/issues/sorting_issue_lists.md | 41 +++- .../filter/merge_request_reference_filter.rb | 2 +- lib/gitlab/hook_data/group_member_builder.rb | 4 +- .../project/sample/relation_tree_restorer.rb | 4 +- .../import_export/relation_tree_restorer.rb | 2 +- lib/gitlab/rack_attack.rb | 3 + lib/gitlab/sanitizers/exif.rb | 2 +- lib/tasks/gitlab/db.rake | 16 +- locale/gitlab.pot | 33 ++- package.json | 2 +- spec/factories/projects.rb | 6 +- spec/features/issues/gfm_autocomplete_spec.rb | 112 ++++----- .../graphql/client_factory_spec.js | 43 ++++ .../graphql/services/status_poller_spec.js | 213 ++++++++++++++++++ .../gfm_autocomplete/gfm_autocomplete_spec.js | 2 +- .../hook_data/group_member_builder_spec.rb | 5 +- spec/models/user_spec.rb | 8 + .../requests/projects/list_service_spec.rb | 27 ++- spec/tasks/gitlab/db_rake_spec.rb | 14 +- yarn.lock | 10 +- 56 files changed, 735 insertions(+), 295 deletions(-) create mode 100644 app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js delete mode 100644 app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql create mode 100644 app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql create mode 100644 changelogs/unreleased/293629-add-expires_at-param-to-groupmemberbuilder-data.yml create mode 100644 changelogs/unreleased/enable-ci-cross-pipeline-artifacts-download.yml create mode 100644 changelogs/unreleased/xanf-import-one-group-frontend.yml create mode 100644 spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js index 23f4190c2d0..4fcaa1b55fc 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js +++ b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js @@ -1,8 +1,11 @@ import axios from '~/lib/utils/axios_utils'; import createDefaultClient from '~/lib/graphql'; +import { s__ } from '~/locale'; +import createFlash from '~/flash'; import { STATUSES } from '../../constants'; import availableNamespacesQuery from './queries/available_namespaces.query.graphql'; import { SourceGroupsManager } from './services/source_groups_manager'; +import { StatusPoller } from './services/status_poller'; export const clientTypenames = { BulkImportSourceGroup: 'ClientBulkImportSourceGroup', @@ -10,6 +13,8 @@ export const clientTypenames = { }; export function createResolvers({ endpoints }) { + let statusPoller; + return { Query: { async bulkImportSourceGroups(_, __, { client }) { @@ -57,6 +62,30 @@ export function createResolvers({ endpoints }) { const groupManager = new SourceGroupsManager({ client }); const group = groupManager.findById(sourceGroupId); groupManager.setImportStatus(group, STATUSES.SCHEDULING); + try { + await axios.post(endpoints.createBulkImport, { + bulk_import: [ + { + source_type: 'group_entity', + source_full_path: group.full_path, + destination_namespace: group.import_target.target_namespace, + destination_name: group.import_target.new_name, + }, + ], + }); + groupManager.setImportStatus(group, STATUSES.STARTED); + if (!statusPoller) { + statusPoller = new StatusPoller({ client, interval: 3000 }); + statusPoller.startPolling(); + } + } catch (e) { + createFlash({ + message: s__('BulkImport|Importing the group failed'), + }); + + groupManager.setImportStatus(group, STATUSES.NONE); + throw e; + } }, }, }; diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js new file mode 100644 index 00000000000..5d2922b0ba8 --- /dev/null +++ b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js @@ -0,0 +1,68 @@ +import gql from 'graphql-tag'; +import createFlash from '~/flash'; +import { s__ } from '~/locale'; +import bulkImportSourceGroupsQuery from '../queries/bulk_import_source_groups.query.graphql'; +import { STATUSES } from '../../../constants'; +import { SourceGroupsManager } from './source_groups_manager'; + +const groupId = i => `group${i}`; + +function generateGroupsQuery(groups) { + return gql`{ + ${groups + .map( + (g, idx) => + `${groupId(idx)}: group(fullPath: "${g.import_target.target_namespace}/${ + g.import_target.new_name + }") { id }`, + ) + .join('\n')} + }`; +} + +export class StatusPoller { + constructor({ client, interval }) { + this.client = client; + this.interval = interval; + this.timeoutId = null; + this.groupManager = new SourceGroupsManager({ client }); + } + + startPolling() { + if (this.timeoutId) { + return; + } + + this.checkPendingImports(); + } + + stopPolling() { + clearTimeout(this.timeoutId); + this.timeoutId = null; + } + + async checkPendingImports() { + try { + const { bulkImportSourceGroups } = this.client.readQuery({ + query: bulkImportSourceGroupsQuery, + }); + const groupsInProgress = bulkImportSourceGroups.filter(g => g.status === STATUSES.STARTED); + if (groupsInProgress.length) { + const { data: results } = await this.client.query({ + query: generateGroupsQuery(groupsInProgress), + fetchPolicy: 'no-cache', + }); + const completedGroups = groupsInProgress.filter((_, idx) => Boolean(results[groupId(idx)])); + completedGroups.forEach(group => { + this.groupManager.setImportStatus(group, STATUSES.FINISHED); + }); + } + } catch (e) { + createFlash({ + message: s__('BulkImport|Update of import statuses with realtime changes failed'), + }); + } finally { + this.timeoutId = setTimeout(() => this.checkPendingImports(), this.interval); + } + } +} diff --git a/app/assets/javascripts/lib/utils/keycodes.js b/app/assets/javascripts/lib/utils/keycodes.js index 618266f7a09..6f5cd7460f8 100644 --- a/app/assets/javascripts/lib/utils/keycodes.js +++ b/app/assets/javascripts/lib/utils/keycodes.js @@ -2,6 +2,7 @@ // See: https://gitlab.com/gitlab-org/gitlab/-/issues/216102 export const BACKSPACE_KEY_CODE = 8; +export const TAB_KEY_CODE = 9; export const ENTER_KEY_CODE = 13; export const ESC_KEY_CODE = 27; export const UP_KEY_CODE = 38; diff --git a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql index 149cb256ced..d65d9892260 100644 --- a/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql +++ b/app/assets/javascripts/pipeline_editor/graphql/queries/ci_config.graphql @@ -1,11 +1,11 @@ -#import "~/pipelines/graphql/queries/pipeline_stages.fragment.graphql" +#import "~/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql" query getCiConfigData($content: String!) { ciConfig(content: $content) { errors status stages { - ...PipelineStagesData + ...PipelineStagesConnection } } } diff --git a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue index b1c52ffa920..8a57c9b1970 100644 --- a/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue +++ b/app/assets/javascripts/pipeline_editor/pipeline_editor_app.vue @@ -10,6 +10,7 @@ import TextEditor from './components/text_editor.vue'; import commitCiFileMutation from './graphql/mutations/commit_ci_file.mutation.graphql'; import getBlobContent from './graphql/queries/blob_content.graphql'; import getCiConfigData from './graphql/queries/ci_config.graphql'; +import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils'; const MR_SOURCE_BRANCH = 'merge_request[source_branch]'; const MR_TARGET_BRANCH = 'merge_request[target_branch]'; @@ -99,7 +100,11 @@ export default { }; }, update(data) { - return data?.ciConfig ?? {}; + const { ciConfigData } = data || {}; + const stageNodes = ciConfigData?.stages?.nodes || []; + const stages = unwrapStagesWithNeeds(stageNodes); + + return { ...ciConfigData, stages }; }, error() { this.reportFailure(LOAD_FAILURE_UNKNOWN); diff --git a/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql b/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql deleted file mode 100644 index 0aef2fdfd7f..00000000000 --- a/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages.fragment.graphql +++ /dev/null @@ -1,12 +0,0 @@ -fragment PipelineStagesData on CiConfigStage { - name - groups { - name - jobs { - name - needs { - name - } - } - } -} diff --git a/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql b/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql new file mode 100644 index 00000000000..1da4fa0a72b --- /dev/null +++ b/app/assets/javascripts/pipelines/graphql/queries/pipeline_stages_connection.fragment.graphql @@ -0,0 +1,20 @@ +fragment PipelineStagesConnection on CiConfigStageConnection { + nodes { + name + groups { + nodes { + name + jobs { + nodes { + name + needs { + nodes { + name + } + } + } + } + } + } + } +} diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue index fb61c13983f..1ad0ca36bf8 100644 --- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue +++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue @@ -1,5 +1,5 @@