diff options
125 files changed, 1432 insertions, 964 deletions
diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql index d4f4f244759..babcdea935d 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql @@ -3,8 +3,6 @@ mutation createHttpIntegration($projectPath: ID!, $name: String!, $active: Boolean!) { httpIntegrationCreate(input: { projectPath: $projectPath, name: $name, active: $active }) { errors - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql index caa258e0848..a3a50651fd0 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql @@ -3,8 +3,6 @@ mutation destroyHttpIntegration($id: ID!) { httpIntegrationDestroy(input: { id: $id }) { errors - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql index 2f30f9abb5c..c0754d8e32b 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql @@ -3,8 +3,6 @@ mutation resetHttpIntegrationToken($id: ID!) { httpIntegrationResetToken(input: { id: $id }) { errors - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql b/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql index 2cf56613673..37df9ec25eb 100644 --- a/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql +++ b/app/assets/javascripts/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql @@ -3,8 +3,6 @@ mutation updateHttpIntegration($id: ID!, $name: String!, $active: Boolean!) { httpIntegrationUpdate(input: { id: $id, name: $name, active: $active }) { errors - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available integration { ...HttpIntegrationItem } diff --git a/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql b/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql index 81cc7b4d246..0e1d11727cf 100644 --- a/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql @@ -2,8 +2,6 @@ mutation createBoardList($boardId: BoardID!, $backlog: Boolean, $labelId: LabelID) { boardListCreate(input: { boardId: $boardId, backlog: $backlog, labelId: $labelId }) { - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available list { ...BoardListFragment } diff --git a/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql b/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql index 7ea0e2f915a..b474c9acb93 100644 --- a/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/board_list_update.mutation.graphql @@ -2,8 +2,6 @@ mutation UpdateBoardList($listId: ID!, $position: Int, $collapsed: Boolean) { updateBoardList(input: { listId: $listId, position: $position, collapsed: $collapsed }) { - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available list { ...BoardListFragment } diff --git a/app/assets/javascripts/boards/graphql/board_lists.query.graphql b/app/assets/javascripts/boards/graphql/board_lists.query.graphql index e6e98864aad..8780d6fd91a 100644 --- a/app/assets/javascripts/boards/graphql/board_lists.query.graphql +++ b/app/assets/javascripts/boards/graphql/board_lists.query.graphql @@ -13,8 +13,6 @@ query BoardLists( id hideBacklogList lists(issueFilters: $filters) { - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available nodes { ...BoardListFragment } @@ -27,8 +25,6 @@ query BoardLists( id hideBacklogList lists(issueFilters: $filters) { - # We have ID in a deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available nodes { ...BoardListFragment } diff --git a/app/assets/javascripts/content_editor/components/code_block_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue index 51a84d80a65..5347f7c8712 100644 --- a/app/assets/javascripts/content_editor/components/code_block_bubble_menu.vue +++ b/app/assets/javascripts/content_editor/components/bubble_menus/code_block.vue @@ -9,11 +9,11 @@ import { } from '@gitlab/ui'; import { BubbleMenu } from '@tiptap/vue-2'; import { getParentByTagName } from '~/lib/utils/dom_utils'; -import codeBlockLanguageLoader from '../services/code_block_language_loader'; -import CodeBlockHighlight from '../extensions/code_block_highlight'; -import Diagram from '../extensions/diagram'; -import Frontmatter from '../extensions/frontmatter'; -import EditorStateObserver from './editor_state_observer.vue'; +import codeBlockLanguageLoader from '../../services/code_block_language_loader'; +import CodeBlockHighlight from '../../extensions/code_block_highlight'; +import Diagram from '../../extensions/diagram'; +import Frontmatter from '../../extensions/frontmatter'; +import EditorStateObserver from '../editor_state_observer.vue'; const CODE_BLOCK_NODE_TYPES = [CodeBlockHighlight.name, Diagram.name, Frontmatter.name]; diff --git a/app/assets/javascripts/content_editor/components/formatting_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/formatting.vue index 103079534bc..34e5caeca94 100644 --- a/app/assets/javascripts/content_editor/components/formatting_bubble_menu.vue +++ b/app/assets/javascripts/content_editor/components/bubble_menus/formatting.vue @@ -1,13 +1,13 @@ <script> import { GlButtonGroup } from '@gitlab/ui'; import { BubbleMenu } from '@tiptap/vue-2'; -import { BUBBLE_MENU_TRACKING_ACTION } from '../constants'; -import trackUIControl from '../services/track_ui_control'; -import Code from '../extensions/code'; -import CodeBlockHighlight from '../extensions/code_block_highlight'; -import Diagram from '../extensions/diagram'; -import Frontmatter from '../extensions/frontmatter'; -import ToolbarButton from './toolbar_button.vue'; +import { BUBBLE_MENU_TRACKING_ACTION } from '../../constants'; +import trackUIControl from '../../services/track_ui_control'; +import Code from '../../extensions/code'; +import CodeBlockHighlight from '../../extensions/code_block_highlight'; +import Diagram from '../../extensions/diagram'; +import Frontmatter from '../../extensions/frontmatter'; +import ToolbarButton from '../toolbar_button.vue'; export default { components: { diff --git a/app/assets/javascripts/content_editor/components/content_editor.vue b/app/assets/javascripts/content_editor/components/content_editor.vue index 5b3f4f4ddf2..585d100dfc6 100644 --- a/app/assets/javascripts/content_editor/components/content_editor.vue +++ b/app/assets/javascripts/content_editor/components/content_editor.vue @@ -4,8 +4,8 @@ import { createContentEditor } from '../services/create_content_editor'; import ContentEditorAlert from './content_editor_alert.vue'; import ContentEditorProvider from './content_editor_provider.vue'; import EditorStateObserver from './editor_state_observer.vue'; -import FormattingBubbleMenu from './formatting_bubble_menu.vue'; -import CodeBlockBubbleMenu from './code_block_bubble_menu.vue'; +import FormattingBubbleMenu from './bubble_menus/formatting.vue'; +import CodeBlockBubbleMenu from './bubble_menus/code_block.vue'; import TopToolbar from './top_toolbar.vue'; import LoadingIndicator from './loading_indicator.vue'; diff --git a/app/assets/javascripts/content_editor/components/divider.vue b/app/assets/javascripts/content_editor/components/divider.vue deleted file mode 100644 index b77bd7b7cf3..00000000000 --- a/app/assets/javascripts/content_editor/components/divider.vue +++ /dev/null @@ -1,3 +0,0 @@ -<template> - <span class="gl-mx-3 gl-border-r-solid gl-border-r-1 gl-border-gray-200"></span> -</template> diff --git a/app/assets/javascripts/content_editor/components/toolbar_button.vue b/app/assets/javascripts/content_editor/components/toolbar_button.vue index cdb877152d4..441185e28c6 100644 --- a/app/assets/javascripts/content_editor/components/toolbar_button.vue +++ b/app/assets/javascripts/content_editor/components/toolbar_button.vue @@ -42,7 +42,7 @@ export default { size: { type: String, required: false, - default: 'small', + default: 'medium', }, }, data() { diff --git a/app/assets/javascripts/content_editor/components/top_toolbar.vue b/app/assets/javascripts/content_editor/components/top_toolbar.vue index 89182b3a09f..19e150a4da9 100644 --- a/app/assets/javascripts/content_editor/components/top_toolbar.vue +++ b/app/assets/javascripts/content_editor/components/top_toolbar.vue @@ -1,6 +1,5 @@ <script> import trackUIControl from '../services/track_ui_control'; -import Divider from './divider.vue'; import ToolbarButton from './toolbar_button.vue'; import ToolbarImageButton from './toolbar_image_button.vue'; import ToolbarLinkButton from './toolbar_link_button.vue'; @@ -14,7 +13,6 @@ export default { ToolbarLinkButton, ToolbarTableButton, ToolbarImageButton, - Divider, }, methods: { trackToolbarControlExecution({ contentType, value }) { @@ -25,13 +23,13 @@ export default { </script> <template> <div - class="gl-display-flex gl-justify-content-end gl-pb-3 gl-pt-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200" + class="gl-display-flex gl-flex-wrap gl-pb-3 gl-pt-0 gl-border-b-solid gl-border-b-1 gl-border-b-gray-200" > <toolbar-text-style-dropdown data-testid="text-styles" + class="gl-mr-3" @execute="trackToolbarControlExecution" /> - <divider /> <toolbar-button data-testid="bold" content-type="bold" @@ -69,7 +67,6 @@ export default { @execute="trackToolbarControlExecution" /> <toolbar-link-button data-testid="link" @execute="trackToolbarControlExecution" /> - <divider /> <toolbar-image-button ref="imageButton" data-testid="image" diff --git a/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql b/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql index 34d683ac1ee..3200327e03d 100644 --- a/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql +++ b/app/assets/javascripts/design_management/graphql/mutations/upload_design.mutation.graphql @@ -3,7 +3,6 @@ mutation uploadDesign($files: [Upload!]!, $projectPath: ID!, $iid: ID!) { designManagementUpload(input: { projectPath: $projectPath, iid: $iid, files: $files }) { - # eslint-disable-next-line @graphql-eslint/require-id-when-available designs { ...DesignItem versions { diff --git a/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql b/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql index a5394457f73..730467c33f6 100644 --- a/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql +++ b/app/assets/javascripts/design_management/graphql/queries/get_design.query.graphql @@ -13,7 +13,6 @@ query getDesign( id designCollection { designs(atVersion: $atVersion, filenames: $filenames) { - # eslint-disable-next-line @graphql-eslint/require-id-when-available nodes { ...DesignItem issue { diff --git a/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql b/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql index 78b2cd34a5c..824997f8e33 100644 --- a/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql +++ b/app/assets/javascripts/graphql_shared/fragments/issuable_timelogs.fragment.graphql @@ -1,4 +1,5 @@ fragment TimelogFragment on Timelog { + id timeSpent user { id diff --git a/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql b/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql index 429993b37bf..0b451262b5a 100644 --- a/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql +++ b/app/assets/javascripts/graphql_shared/fragments/user_availability.fragment.graphql @@ -1,4 +1,3 @@ -# eslint-disable-next-line @graphql-eslint/require-id-when-available fragment UserAvailability on User { status { availability diff --git a/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql b/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql index b72941966c6..2d84b141f32 100644 --- a/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql +++ b/app/assets/javascripts/incidents/graphql/fragments/incident_fields.fragment.graphql @@ -1,4 +1,3 @@ -# eslint-disable-next-line @graphql-eslint/require-id-when-available fragment IncidentFields on Issue { severity escalationStatus diff --git a/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue b/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue index 8536db78dfb..d9da238358f 100644 --- a/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue +++ b/app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue @@ -54,15 +54,15 @@ export default { return { message: this.defaultMessage, openMergeRequest: false, - targetBranch: this.currentBranch, + sourceBranch: this.currentBranch, }; }, computed: { isCommitFormFilledOut() { - return this.message && this.targetBranch; + return this.message && this.sourceBranch; }, - isCurrentBranchTarget() { - return this.targetBranch === this.currentBranch; + isCurrentBranchSourceBranch() { + return this.sourceBranch === this.currentBranch; }, isSubmitDisabled() { return !this.isCommitFormFilledOut || (!this.hasUnsavedChanges && !this.isNewCiConfigFile); @@ -79,7 +79,7 @@ export default { onSubmit() { this.$emit('submit', { message: this.message, - targetBranch: this.targetBranch, + sourceBranch: this.sourceBranch, openMergeRequest: this.openMergeRequest, }); }, @@ -93,7 +93,7 @@ export default { }, i18n: { commitMessage: __('Commit message'), - targetBranch: __('Target Branch'), + sourceBranch: __('Branch'), startMergeRequest: __('Start a %{new_merge_request} with these changes'), newMergeRequest: __('new merge request'), commitChanges: __('Commit changes'), @@ -120,20 +120,20 @@ export default { /> </gl-form-group> <gl-form-group - id="target-branch-group" - :label="$options.i18n.targetBranch" + id="source-branch-group" + :label="$options.i18n.sourceBranch" label-cols-sm="2" - label-for="target-branch-field" + label-for="source-branch-field" > <gl-form-input - id="target-branch-field" - v-model="targetBranch" + id="source-branch-field" + v-model="sourceBranch" class="gl-font-monospace!" required - data-qa-selector="target_branch_field" + data-qa-selector="source_branch_field" /> <gl-form-checkbox - v-if="!isCurrentBranchTarget" + v-if="!isCurrentBranchSourceBranch" v-model="openMergeRequest" data-testid="new-mr-checkbox" data-qa-selector="new_mr_checkbox" diff --git a/app/assets/javascripts/pipeline_editor/components/commit/commit_section.vue b/app/assets/javascripts/pipeline_editor/components/commit/commit_section.vue index 4ef598d6ff3..9cbf60b1c8f 100644 --- a/app/assets/javascripts/pipeline_editor/components/commit/commit_section.vue +++ b/app/assets/javascripts/pipeline_editor/components/commit/commit_section.vue @@ -75,7 +75,7 @@ export default { }, }, methods: { - async onCommitSubmit({ message, targetBranch, openMergeRequest }) { + async onCommitSubmit({ message, sourceBranch, openMergeRequest }) { this.isSaving = true; try { @@ -88,7 +88,7 @@ export default { variables: { action: this.action, projectPath: this.projectFullPath, - branch: targetBranch, + branch: sourceBranch, startBranch: this.currentBranch, message, filePath: this.ciConfigPath, @@ -104,12 +104,11 @@ export default { if (errors?.length) { this.$emit('showError', { type: COMMIT_FAILURE, reasons: errors }); } else { - const commitBranch = targetBranch; const params = openMergeRequest ? { type: COMMIT_SUCCESS_WITH_REDIRECT, params: { - sourceBranch: commitBranch, + sourceBranch, targetBranch: this.currentBranch, }, } @@ -119,10 +118,10 @@ export default { ...params, }); - this.updateLastCommitBranch(targetBranch); - this.updateCurrentBranch(targetBranch); + this.updateLastCommitBranch(sourceBranch); + this.updateCurrentBranch(sourceBranch); - if (this.currentBranch === targetBranch) { + if (this.currentBranch === sourceBranch) { this.$emit('updateCommitSha'); } } diff --git a/app/assets/javascripts/runner/graphql/details/runner.query.graphql b/app/assets/javascripts/runner/graphql/details/runner.query.graphql index 4792a186160..df6ce19fd09 100644 --- a/app/assets/javascripts/runner/graphql/details/runner.query.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner.query.graphql @@ -1,8 +1,6 @@ #import "ee_else_ce/runner/graphql/details/runner_details.fragment.graphql" query getRunner($id: CiRunnerID!) { - # We have an id in deeply nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available runner(id: $id) { ...RunnerDetails } diff --git a/app/assets/javascripts/runner/graphql/details/runner_update.mutation.graphql b/app/assets/javascripts/runner/graphql/details/runner_update.mutation.graphql index e4bf51e2c30..352b95c1a39 100644 --- a/app/assets/javascripts/runner/graphql/details/runner_update.mutation.graphql +++ b/app/assets/javascripts/runner/graphql/details/runner_update.mutation.graphql @@ -5,8 +5,6 @@ mutation runnerUpdate($input: RunnerUpdateInput!) { runnerUpdate(input: $input) { - # We have an id in deep nested fragment - # eslint-disable-next-line @graphql-eslint/require-id-when-available runner { ...RunnerDetails } diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/author_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/author_token.vue index 696456be990..848c49c48c7 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/author_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/author_token.vue @@ -87,6 +87,7 @@ export default { :get-active-token-value="getActiveAuthor" :default-suggestions="defaultAuthors" :preloaded-suggestions="preloadedAuthors" + v-bind="$attrs" @fetch-suggestions="fetchAuthors" v-on="$listeners" > diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue index 4ecfc1cf40c..aa5161ca93c 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/branch_token.vue @@ -65,6 +65,7 @@ export default { :suggestions="branches" :suggestions-loading="loading" :get-active-token-value="getActiveBranch" + v-bind="$attrs" @fetch-suggestions="fetchBranches" v-on="$listeners" > diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue index 5a69751a2cc..210d814d22a 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue @@ -67,6 +67,7 @@ export default { :suggestions="emojis" :suggestions-loading="loading" :get-active-token-value="getActiveEmoji" + v-bind="$attrs" @fetch-suggestions="fetchEmojis" v-on="$listeners" > diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue index 3f7a8920f48..6f24955814c 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/label_token.vue @@ -104,6 +104,7 @@ export default { :suggestions="labels" :get-active-token-value="getActiveLabel" :default-suggestions="defaultLabels" + v-bind="$attrs" @fetch-suggestions="fetchLabels" v-on="$listeners" > diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue index 11c081ab4f8..69265d0fdc9 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue @@ -84,6 +84,7 @@ export default { :suggestions="milestones" :suggestions-loading="loading" :get-active-token-value="getActiveMilestone" + v-bind="$attrs" @fetch-suggestions="fetchMilestones" v-on="$listeners" > diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue index f353cc3a765..9e68c92af5d 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/tokens/release_token.vue @@ -66,6 +66,7 @@ export default { :suggestions="releases" :suggestions-loading="loading" :get-active-token-value="getActiveRelease" + v-bind="$attrs" @fetch-suggestions="fetchReleases" v-on="$listeners" > diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb index 9e16d195b00..e31ca87a5d5 100644 --- a/app/controllers/profiles/gpg_keys_controller.rb +++ b/app/controllers/profiles/gpg_keys_controller.rb @@ -3,7 +3,7 @@ class Profiles::GpgKeysController < Profiles::ApplicationController before_action :set_gpg_key, only: [:destroy, :revoke] - feature_category :users + feature_category :source_code_management def index @gpg_keys = current_user.gpg_keys.with_subkeys diff --git a/app/graphql/mutations/ci/runners_registration_token/reset.rb b/app/graphql/mutations/ci/runners_registration_token/reset.rb index 29ef7aa2e81..8c49b682ab0 100644 --- a/app/graphql/mutations/ci/runners_registration_token/reset.rb +++ b/app/graphql/mutations/ci/runners_registration_token/reset.rb @@ -23,19 +23,24 @@ module Mutations null: true, description: 'Runner token after mutation.' - def resolve(**args) + def resolve(type:, id: nil) + scope = authorized_find!(type: type, id: id) + new_token = reset_token(scope) + { - token: reset_token(**args), - errors: [] + token: new_token, + errors: errors_on_object(scope) } end private - def find_object(type:, **args) - id = args[:id] - + def find_object(type:, id: nil) case type + when 'instance_type' + raise Gitlab::Graphql::Errors::ArgumentError, "id must not be specified for '#{type}' scope" if id.present? + + ApplicationSetting.current when 'group_type' GitlabSchema.object_from_id(id, expected_type: ::Group) when 'project_type' @@ -43,20 +48,7 @@ module Mutations end end - def reset_token(type:, **args) - id = args[:id] - scope = nil - - case type - when 'instance_type' - raise Gitlab::Graphql::Errors::ArgumentError, "id must not be specified for '#{type}' scope" if id.present? - - scope = ApplicationSetting.current - authorize!(scope) - when 'group_type', 'project_type' - scope = authorized_find!(type: type, id: id) - end - + def reset_token(scope) ::Ci::Runners::ResetRegistrationTokenService.new(scope, current_user).execute if scope end end diff --git a/app/graphql/mutations/timelogs/delete.rb b/app/graphql/mutations/timelogs/delete.rb new file mode 100644 index 00000000000..3fd5f4477c1 --- /dev/null +++ b/app/graphql/mutations/timelogs/delete.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Mutations + module Timelogs + class Delete < Mutations::BaseMutation + graphql_name 'TimelogDelete' + + field :timelog, + Types::TimelogType, + null: true, + description: 'Deleted timelog.' + + argument :id, + ::Types::GlobalIDType[::Timelog], + required: true, + description: 'Global ID of the timelog.' + + authorize :admin_timelog + + def resolve(id:) + timelog = authorized_find!(id: id) + result = ::Timelogs::DeleteService.new(timelog, current_user).execute + + # Return the result payload, not the loaded timelog, so that it returns null in case of unauthorized access + { timelog: result.payload, errors: result.errors } + end + + def find_object(id:) + # TODO: Remove coercion when working on https://gitlab.com/gitlab-org/gitlab/-/issues/257883 + id = ::Types::GlobalIDType[::Timelog].coerce_isolated_input(id) + GitlabSchema.find_by_gid(id) + end + end + end +end diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 2297912ac35..47d58e5dc60 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -88,6 +88,7 @@ module Types mount_mutation Mutations::Terraform::State::Delete mount_mutation Mutations::Terraform::State::Lock mount_mutation Mutations::Terraform::State::Unlock + mount_mutation Mutations::Timelogs::Delete mount_mutation Mutations::Todos::Create mount_mutation Mutations::Todos::MarkDone mount_mutation Mutations::Todos::Restore diff --git a/app/graphql/types/timelog_type.rb b/app/graphql/types/timelog_type.rb index d348fa698fa..fd9943780d7 100644 --- a/app/graphql/types/timelog_type.rb +++ b/app/graphql/types/timelog_type.rb @@ -6,6 +6,11 @@ module Types authorize :read_issue + field :id, + GraphQL::Types::ID, + null: false, + description: 'Internal ID of the timelog.' + field :spent_at, Types::TimeType, null: true, diff --git a/app/helpers/clusters_helper.rb b/app/helpers/clusters_helper.rb index fe057fb3412..a65e7ec1d89 100644 --- a/app/helpers/clusters_helper.rb +++ b/app/helpers/clusters_helper.rb @@ -39,7 +39,7 @@ module ClustersHelper base_domain: cluster.base_domain, application_ingress_external_ip: cluster.application_ingress_external_ip, auto_devops_help_path: help_page_path('topics/autodevops/index'), - external_endpoint_help_path: help_page_path('user/project/clusters/index.md', anchor: 'base-domain') + external_endpoint_help_path: help_page_path('user/project/clusters/gitlab_managed_clusters.md', anchor: 'base-domain') } end diff --git a/app/policies/timelog_policy.rb b/app/policies/timelog_policy.rb index f71c4204639..02380604c60 100644 --- a/app/policies/timelog_policy.rb +++ b/app/policies/timelog_policy.rb @@ -2,4 +2,11 @@ class TimelogPolicy < BasePolicy delegate { @subject.issuable } + + desc "User who created the timelog" + condition(:is_author) { @user && @subject.user == @user } + + rule { is_author | can?(:maintainer_access) }.policy do + enable :admin_timelog + end end diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 9db39a5e174..cbaa7a9495b 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -111,6 +111,21 @@ module SystemNoteService ::SystemNotes::TimeTrackingService.new(noteable: noteable, project: project, author: author).change_time_spent end + # Called when a timelog is removed from a Noteable + # + # noteable - Noteable object + # project - Project owning the noteable + # author - User performing the change + # timelog - The removed timelog + # + # Example Note text: + # "deleted 2h 30m of time spent from 22-03-2022" + # + # Returns the created Note object + def remove_timelog(noteable, project, author, timelog) + ::SystemNotes::TimeTrackingService.new(noteable: noteable, project: project, author: author).remove_timelog(timelog) + end + def close_after_error_tracking_resolve(issue, project, author) ::SystemNotes::IssuablesService.new(noteable: issue, project: project, author: author).close_after_error_tracking_resolve end diff --git a/app/services/system_notes/time_tracking_service.rb b/app/services/system_notes/time_tracking_service.rb index a804a06fe4c..a9b1f6d3d37 100644 --- a/app/services/system_notes/time_tracking_service.rb +++ b/app/services/system_notes/time_tracking_service.rb @@ -76,6 +76,18 @@ module SystemNotes create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking')) end + def remove_timelog(timelog) + time_spent = timelog.time_spent + spent_at = timelog.spent_at&.to_date + + parsed_time = Gitlab::TimeTrackingFormatter.output(time_spent) + + body = "deleted #{parsed_time} of spent time" + body += " from #{spent_at}" if spent_at + + create_note(NoteSummary.new(noteable, project, author, body, action: 'time_tracking')) + end + private def issue_activity_counter diff --git a/app/services/timelogs/base_service.rb b/app/services/timelogs/base_service.rb new file mode 100644 index 00000000000..be46c26e047 --- /dev/null +++ b/app/services/timelogs/base_service.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Timelogs + class BaseService + include BaseServiceUtility + include Gitlab::Utils::StrongMemoize + + attr_accessor :timelog, :current_user + + def initialize(timelog, user) + @timelog = timelog + @current_user = user + end + end +end diff --git a/app/services/timelogs/delete_service.rb b/app/services/timelogs/delete_service.rb new file mode 100644 index 00000000000..0df888a3706 --- /dev/null +++ b/app/services/timelogs/delete_service.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module Timelogs + class DeleteService < Timelogs::BaseService + def execute + unless can?(current_user, :admin_timelog, timelog) + return ServiceResponse.error( + message: "Timelog doesn't exist or you don't have permission to delete it", + http_status: 404) + end + + if timelog.destroy + issuable = timelog.issuable + + if issuable + # Add a system note for the timelog removal + SystemNoteService.remove_timelog(issuable, issuable.project, current_user, timelog) + end + + ServiceResponse.success(payload: timelog) + else + ServiceResponse.error(message: 'Failed to remove timelog', http_status: 400) + end + end + end +end diff --git a/config/feature_categories.yml b/config/feature_categories.yml index c991d3e3720..1d707456974 100644 --- a/config/feature_categories.yml +++ b/config/feature_categories.yml @@ -32,6 +32,7 @@ - continuous_integration - continuous_integration_scaling - continuous_verification +- credential_management - database - dataops - delivery @@ -87,6 +88,7 @@ - package_registry - pages - performance_testing +- permissions - pipeline_authoring - planning_analytics - portfolio_management @@ -118,8 +120,10 @@ - static_application_security_testing - static_site_editor - subgroups +- system_access - team_planning - tracing +- user_management - users - utilization - value_stream_management diff --git a/data/deprecations/14-5-certificate-based-integration-with-kubernetes-saas.yml b/data/deprecations/14-5-certificate-based-integration-with-kubernetes-saas.yml index ebc850a9529..c8e3820fce1 100644 --- a/data/deprecations/14-5-certificate-based-integration-with-kubernetes-saas.yml +++ b/data/deprecations/14-5-certificate-based-integration-with-kubernetes-saas.yml @@ -11,6 +11,8 @@ [agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/) to connect Kubernetes clusters with GitLab. [How do I migrate?](https://docs.gitlab.com/ee/user/infrastructure/clusters/migrate_to_gitlab_agent.html) For updates and details about this deprecation, follow [this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8). + + GitLab self-managed customers can still use the feature [with a feature flag](https://docs.gitlab.com/ee/update/deprecations.html#self-managed-certificate-based-integration-with-kubernetes). stage: Configure tiers: [Free, Premium, Ultimate] issue_url: 'https://gitlab.com/groups/gitlab-org/configure/-/epics/8' diff --git a/data/whats_new/202107220001_14_1.yml b/data/whats_new/202107220001_14_1.yml index 3c67d74d3db..881d96c58d3 100644 --- a/data/whats_new/202107220001_14_1.yml +++ b/data/whats_new/202107220001_14_1.yml @@ -90,22 +90,22 @@ image_url: https://img.youtube.com/vi/-1MuKzWJXKQ/hqdefault.jpg published_at: 2021-07-22 release: 14.1 -- title: CI/CD Tunnel for Kubernetes clusters +- title: CI/CD workflow for Kubernetes clusters body: | - Until now, connecting Kubernetes clusters to GitLab CI/CD required users to open up their clusters towards GitLab. Some organizations do not encourage opening up their firewall externally due to security concerns. + Until now, connecting Kubernetes clusters to GitLab CI/CD required you to open up your clusters towards GitLab. Some organizations do not encourage opening up their firewall externally due to security concerns. - GitLab now ships with a CI/CD Tunnel that connects GitLab Runners with your Kubernetes cluster using the [GitLab Kubernetes Agent](https://docs.gitlab.com/ee/user/clusters/agent/). This enables versatile GitOps workflows where the deployment logic can be coded in the pipeline. + GitLab now ships with a CI/CD functionality that connects runners with your Kubernetes cluster by using the [GitLab agent for Kubernetes](https://docs.gitlab.com/ee/user/clusters/agent/). This enables versatile GitOps workflows where the deployment logic can be coded in the pipeline. You and your team can safely use your preferred tool to run the deployment itself using `kubectl`, `helm`, `kpt`, `tanka`, or anything else without security concerns. - To use the tunnel, define the `kubecontext` in your CI/CD pipeline to connect with your agent. To simplify this process, we plan to [automatically inject the `kubecontext`](https://gitlab.com/gitlab-org/gitlab/-/issues/324275) into the CI/CD environment in a future iteration. + Define the `kubecontext` in your CI/CD pipeline to connect with your agent. To simplify this process, we plan to [automatically inject the `kubecontext`](https://gitlab.com/gitlab-org/gitlab/-/issues/324275) into the CI/CD environment in a future iteration. - The CI/CD tunnel is currently supported only from the project where the agent was configured but we are working on [adding group-level support](https://gitlab.com/groups/gitlab-org/-/epics/5784). You can safely start using the tunnel on GitLab SaaS and self-managed instances. + This type of connection is currently supported only from the project where the agent was configured but we are working on [adding group-level support](https://gitlab.com/groups/gitlab-org/-/epics/5784). You can safely start using CI/CD in your jobs on GitLab SaaS and self-managed instances. stage: Configure self-managed: true gitlab-com: true packages: [Premium, Ultimate] - url: https://docs.gitlab.com/ee/user/clusters/agent/ci_cd_tunnel.html + url: https://docs.gitlab.com/ee/user/clusters/agent/ci_cd_workflow.html image_url: https://img.youtube.com/vi/eXxM4ScqiJs/hqdefault.jpg published_at: 2021-07-22 release: 14.1 diff --git a/db/post_migrate/20220328095848_delete_failed_reset_duplicate_ci_runners_token_migration_records.rb b/db/post_migrate/20220328095848_delete_failed_reset_duplicate_ci_runners_token_migration_records.rb new file mode 100644 index 00000000000..3c1a6a48ef5 --- /dev/null +++ b/db/post_migrate/20220328095848_delete_failed_reset_duplicate_ci_runners_token_migration_records.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class DeleteFailedResetDuplicateCiRunnersTokenMigrationRecords < Gitlab::Database::Migration[1.0] + def up + # Delete remaining records of botched migrations before we start the new migrations + Gitlab::Database::BackgroundMigrationJob + .for_migration_class('ResetDuplicateCiRunnersTokenValuesOnProjects') + .delete_all + Gitlab::Database::BackgroundMigrationJob + .for_migration_class('ResetDuplicateCiRunnersTokenEncryptedValuesOnProjects') + .delete_all + end + + def down + # no-op + end +end diff --git a/db/post_migrate/20220328100456_schedule20220328_reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb b/db/post_migrate/20220328100456_schedule20220328_reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb new file mode 100644 index 00000000000..326a8e30ecb --- /dev/null +++ b/db/post_migrate/20220328100456_schedule20220328_reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class Schedule20220328ResetDuplicateCiRunnersTokenEncryptedValuesOnProjects < Gitlab::Database::Migration[1.0] + MIGRATION = 'ResetDuplicateCiRunnersTokenEncryptedValuesOnProjects' + BATCH_SIZE = 2_000 + DELAY_INTERVAL = 2.minutes + + disable_ddl_transaction! + + class Project < ActiveRecord::Base # rubocop:disable Style/Documentation + include ::EachBatch + + self.table_name = 'projects' + + scope :base_query, -> { where.not(runners_token_encrypted: nil) } + end + + def up + queue_background_migration_jobs_by_range_at_intervals( + Project.base_query, + MIGRATION, + DELAY_INTERVAL, + batch_size: BATCH_SIZE, + track_jobs: true + ) + end + + def down + # no-op + end +end diff --git a/db/post_migrate/20220328100457_schedule20220328_reset_duplicate_ci_runners_token_values_on_projects.rb b/db/post_migrate/20220328100457_schedule20220328_reset_duplicate_ci_runners_token_values_on_projects.rb new file mode 100644 index 00000000000..d999def0078 --- /dev/null +++ b/db/post_migrate/20220328100457_schedule20220328_reset_duplicate_ci_runners_token_values_on_projects.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class Schedule20220328ResetDuplicateCiRunnersTokenValuesOnProjects < Gitlab::Database::Migration[1.0] + MIGRATION = 'ResetDuplicateCiRunnersTokenValuesOnProjects' + BATCH_SIZE = 2_000 + DELAY_INTERVAL = 2.minutes + + disable_ddl_transaction! + + class Project < ActiveRecord::Base # rubocop:disable Style/Documentation + include ::EachBatch + + self.table_name = 'projects' + + scope :base_query, -> { where.not(runners_token: nil) } + end + + def up + queue_background_migration_jobs_by_range_at_intervals( + Project.base_query, + MIGRATION, + DELAY_INTERVAL, + batch_size: BATCH_SIZE, + track_jobs: true + ) + end + + def down + # no-op + end +end diff --git a/db/schema_migrations/20220328095848 b/db/schema_migrations/20220328095848 new file mode 100644 index 00000000000..83af691ee8e --- /dev/null +++ b/db/schema_migrations/20220328095848 @@ -0,0 +1 @@ +4d75e2180a30d3cdd4efa3b6a7d107e146b755faf0316e985a8813a85644af35
\ No newline at end of file diff --git a/db/schema_migrations/20220328100456 b/db/schema_migrations/20220328100456 new file mode 100644 index 00000000000..a6017220eb0 --- /dev/null +++ b/db/schema_migrations/20220328100456 @@ -0,0 +1 @@ +a27caa521761ff1f4513318eb4ce3ea0e29d101f260493598caf4c8cb0fcc931
\ No newline at end of file diff --git a/db/schema_migrations/20220328100457 b/db/schema_migrations/20220328100457 new file mode 100644 index 00000000000..531ea3cd432 --- /dev/null +++ b/db/schema_migrations/20220328100457 @@ -0,0 +1 @@ +954217de622b1ee360edbd89dd31c5a051001cf6879ce97c7b49c228321d48d7
\ No newline at end of file diff --git a/doc/administration/job_artifacts.md b/doc/administration/job_artifacts.md index 03a0162d526..4cee2673225 100644 --- a/doc/administration/job_artifacts.md +++ b/doc/administration/job_artifacts.md @@ -181,67 +181,6 @@ _The artifacts are stored by default in 1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect. 1. [Migrate any existing local artifacts to the object storage](#migrating-to-object-storage). -### OpenStack example - -See [the available connection settings for OpenStack](object_storage.md#openstack-compatible-connection-settings). - -**In Omnibus installations:** - -_The uploads are stored by default in -`/var/opt/gitlab/gitlab-rails/shared/artifacts`._ - -1. Edit `/etc/gitlab/gitlab.rb` and add the following lines, substituting - the values you want: - - ```ruby - gitlab_rails['artifacts_enabled'] = true - gitlab_rails['artifacts_object_store_enabled'] = true - gitlab_rails['artifacts_object_store_remote_directory'] = "artifacts" - gitlab_rails['artifacts_object_store_connection'] = { - 'provider' => 'OpenStack', - 'openstack_username' => 'OS_USERNAME', - 'openstack_api_key' => 'OS_PASSWORD', - 'openstack_temp_url_key' => 'OS_TEMP_URL_KEY', - 'openstack_auth_url' => 'https://auth.cloud.ovh.net', - 'openstack_region' => 'GRA', - 'openstack_tenant_id' => 'OS_TENANT_ID', - } - ``` - -1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. -1. [Migrate any existing local artifacts to the object storage](#migrating-to-object-storage). - ---- - -**In installations from source:** - -_The uploads are stored by default in -`/home/git/gitlab/shared/artifacts`._ - -1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following - lines: - - ```yaml - uploads: - object_store: - enabled: true - direct_upload: false - background_upload: true - proxy_download: false - remote_directory: "artifacts" - connection: - provider: OpenStack - openstack_username: OS_USERNAME - openstack_api_key: OS_PASSWORD - openstack_temp_url_key: OS_TEMP_URL_KEY - openstack_auth_url: 'https://auth.cloud.ovh.net' - openstack_region: GRA - openstack_tenant_id: OS_TENANT_ID - ``` - -1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect. -1. [Migrate any existing local artifacts to the object storage](#migrating-to-object-storage). - ### Migrating to object storage After [configuring the object storage](#using-object-storage), use the following task to diff --git a/doc/administration/object_storage.md b/doc/administration/object_storage.md index 6ea433f95e9..0987d716ec4 100644 --- a/doc/administration/object_storage.md +++ b/doc/administration/object_storage.md @@ -19,7 +19,7 @@ GitLab has been tested by vendors and customers on a number of object storage pr - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](https://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatible mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors, whose list is not officially established. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. @@ -386,52 +386,6 @@ If you are using a custom Azure storage domain, configuration. This information is exchanged in an API call between GitLab Rails and Workhorse. -#### OpenStack-compatible connection settings - -Although OpenStack Swift provides S3 compatibility, some users may want to use -the [Swift API](https://docs.openstack.org/swift/latest/api/object_api_v1_overview.html). - -This isn't compatible with the consolidated object storage form. OpenStack Swift -is supported only with the storage-specific form. If you want to use the -consolidated form, see the [S3 settings](#s3-compatible-connection-settings). - -Here are the valid connection settings for the Swift API, provided by -[fog-openstack](https://github.com/fog/fog-openstack): - -| Setting | Description | Default | -|--------------------------|----------------------|---------| -| `provider` | Always `OpenStack` for compatible hosts. | `OpenStack` | -| `openstack_username` | OpenStack username. | | -| `openstack_api_key` | OpenStack API key. | | -| `openstack_temp_url_key` | OpenStack key for generating temporary URLs | | -| `openstack_auth_url` | OpenStack authentication endpoint | | -| `openstack_region` | OpenStack region. | | -| `openstack_tenant` | OpenStack tenant ID. | | - -#### Rackspace Cloud Files - -The following table describes the valid connection parameters for -Rackspace Cloud, provided by [fog-rackspace](https://github.com/fog/fog-rackspace/). - -This isn't compatible with the consolidated object storage form. -Rackspace Cloud is supported only with the storage-specific form. - -| Setting | Description | Example | -|--------------------------|----------------|-------------| -| `provider` | Provider name. | `Rackspace` | -| `rackspace_username` | Username of the Rackspace account with access to the container. | `joe.smith` | -| `rackspace_api_key` | API key of the Rackspace account with access to the container. | `ABC123DEF456ABC123DEF456ABC123DE` | -| `rackspace_region` | Rackspace storage region to use, a three letter code from the [list of service access endpoints](https://docs.rackspace.com/docs/cloud-files/v1/general-api-info/service-access/). | `iad` | -| `rackspace_temp_url_key` | Private key you set in the Rackspace API for [temporary URLs](https://docs.rackspace.com/docs/cloud-files/v1/use-cases/public-access-to-your-cloud-files-account/#tempurl). | `ABC123DEF456ABC123DEF456ABC123DE` | - -Regardless of whether the container has public access enabled or disabled, Fog -uses the TempURL method to grant access to LFS objects. If you see error -messages in logs that refer to instantiating storage with a `temp-url-key`, -be sure you have set the key properly both in the Rackspace API and in -`gitlab.rb`. You can verify the value of the key Rackspace has set by sending a -GET request with token header to the service access endpoint URL and comparing -the output of the returned headers. - ### Object-specific configuration The following YAML shows how the `object_store` section defines @@ -799,3 +753,46 @@ to run the following command: ```ruby Feature.disable(:s3_multithreaded_uploads) ``` + +## Migrate objects to a different object storage provider + +You may need to migrate GitLab data in object storage to a different object storage provider. The following steps show you how do this using [Rclone](https://rclone.org/). + +The steps assume you are moving the `uploads` bucket, but the same process works for other buckets. + +Prerequisites: + +- Choose the computer to run Rclone on. Depending on how much data you are migrating, Rclone may have to run for a long time so you should avoid using a laptop or desktop computer that can go into power saving. You can use your GitLab server to run Rclone. + +1. [Install](https://rclone.org/downloads/) Rclone. +1. Configure Rclone by running the following: + + ```shell + rclone config + ``` + + The configuration process is interactive. Add at least two "remotes": one for the object storage provider your data is currently on (`old`), and one for the provider you are moving to (`new`). + +1. Verify that you can read the old data. The following example refers to the `uploads` bucket , but your bucket may have a different name: + + ```shell + rclone ls old:uploads | head + ``` + + This should print a partial list of the objects currently stored in your `uploads` bucket. If you get an error, or if + the list is empty, go back and update your Rclone configuration using `rclone config`. + +1. Perform an initial copy. You do not need to take your GitLab server offline for this step. + + ```shell + rclone sync -P old:uploads new:uploads + ``` + +1. After the first sync completes, use the web UI or command-line interface of your new object storage provider to + verify that there are objects in the new bucket. If there are none, or if you encounter an error while running `rclone + sync`, check your Rclone configuration and try again. + +After you have done at least one successful Rclone copy from the old location to the new location, schedule maintenance and take your GitLab server offline. During your maintenance window you must do two things: + +1. Perform a final `rclone sync` run, knowing that your users cannot add new objects so you will not leave any behind in the old bucket. +1. Update the object storage configuration of your GitLab server to use the new provider for `uploads`. diff --git a/doc/administration/operations/extra_sidekiq_routing.md b/doc/administration/operations/extra_sidekiq_routing.md index bb8eb184302..cd3a53b7c63 100644 --- a/doc/administration/operations/extra_sidekiq_routing.md +++ b/doc/administration/operations/extra_sidekiq_routing.md @@ -88,8 +88,8 @@ components: > [Introduced](https://gitlab.com/gitlab-com/gl-infra/scalability/-/issues/261) in GitLab 13.1 (`tags`). -Queue matching query works upon the worker attributes, described in [Sidekiq -style guide](../../development/sidekiq_style_guide.md). We support querying +Queue matching query works upon the worker attributes, described in +[Sidekiq style guide](../../development/sidekiq/index.md). We support querying based on a subset of worker attributes: - `feature_category` - the [GitLab feature diff --git a/doc/administration/reference_architectures/10k_users.md b/doc/administration/reference_architectures/10k_users.md index 2ca79bbeae4..ff43bda4ba1 100644 --- a/doc/administration/reference_architectures/10k_users.md +++ b/doc/administration/reference_architectures/10k_users.md @@ -2169,7 +2169,7 @@ GitLab has been tested on a number of object storage providers: - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](http://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. diff --git a/doc/administration/reference_architectures/25k_users.md b/doc/administration/reference_architectures/25k_users.md index 2a1d344508e..dfe395eb769 100644 --- a/doc/administration/reference_architectures/25k_users.md +++ b/doc/administration/reference_architectures/25k_users.md @@ -2173,7 +2173,7 @@ GitLab has been tested on a number of object storage providers: - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](http://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. diff --git a/doc/administration/reference_architectures/2k_users.md b/doc/administration/reference_architectures/2k_users.md index f417d1e2ab5..3d800ee6a4f 100644 --- a/doc/administration/reference_architectures/2k_users.md +++ b/doc/administration/reference_architectures/2k_users.md @@ -891,7 +891,7 @@ GitLab has been tested on a number of object storage providers: - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](http://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. diff --git a/doc/administration/reference_architectures/3k_users.md b/doc/administration/reference_architectures/3k_users.md index 9d8be3e90b6..83db5134526 100644 --- a/doc/administration/reference_architectures/3k_users.md +++ b/doc/administration/reference_architectures/3k_users.md @@ -2108,7 +2108,7 @@ GitLab has been tested on a number of object storage providers: - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](http://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. diff --git a/doc/administration/reference_architectures/50k_users.md b/doc/administration/reference_architectures/50k_users.md index 6c4e2227b18..8500256408c 100644 --- a/doc/administration/reference_architectures/50k_users.md +++ b/doc/administration/reference_architectures/50k_users.md @@ -2189,7 +2189,7 @@ GitLab has been tested on a number of object storage providers: - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](http://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. diff --git a/doc/administration/reference_architectures/5k_users.md b/doc/administration/reference_architectures/5k_users.md index dd7209a3a3a..012505b0041 100644 --- a/doc/administration/reference_architectures/5k_users.md +++ b/doc/administration/reference_architectures/5k_users.md @@ -2108,7 +2108,7 @@ GitLab has been tested on a number of object storage providers: - [Google Cloud Storage](https://cloud.google.com/storage) - [Digital Ocean Spaces](http://www.digitalocean.com/products/spaces) - [Oracle Cloud Infrastructure](https://docs.cloud.oracle.com/en-us/iaas/Content/Object/Tasks/s3compatibleapi.htm) -- [OpenStack Swift](https://docs.openstack.org/swift/latest/s3_compat.html) +- [OpenStack Swift (S3 compatibility mode)](https://docs.openstack.org/swift/latest/s3_compat.html) - [Azure Blob storage](https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-introduction) - On-premises hardware and appliances from various storage vendors. - MinIO. We have [a guide to deploying this](https://docs.gitlab.com/charts/advanced/external-object-storage/minio.html) within our Helm Chart documentation. diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md index 54d934c8986..699868a187a 100644 --- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md +++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md @@ -798,6 +798,39 @@ To find features that can be toggled, run `pp p.project_feature`. Available permission levels are listed in [concerns/featurable.rb](https://gitlab.com/gitlab-org/gitlab/blob/master/app/models/concerns/featurable.rb). +### Get all error messages associated with groups, subgroups, members, and requesters + +Collect error messages associated with groups, subgroups, members, and requesters. This +captures error messages that may not appear in the Web interface. This can be especially helpful +for troubleshooting issues with [LDAP group sync](../auth/ldap/ldap_synchronization.md#group-sync) +and unexpected behavior with users and their membership in groups and subgroups. + +```ruby +# Find the group and subgroup +group = Group.find_by_full_path("parent_group") +subgroup = Group.find_by_full_path("parent_group/child_group") + +# Group and subgroup errors +group.valid? +group.errors.map(&:full_messages) + +subgroup.valid? +subgroup.errors.map(&:full_messages) + +# Group and subgroup errors for the members AND requesters +group.requesters.map(&:valid?) +group.requesters.map(&:errors).map(&:full_messages) +group.members.map(&:valid?) +group.members.map(&:errors).map(&:full_messages) +group.members_and_requesters.map(&:errors).map(&:full_messages) + +subgroup.requesters.map(&:valid?) +subgroup.requesters.map(&:errors).map(&:full_messages) +subgroup.members.map(&:valid?) +subgroup.members.map(&:errors).map(&:full_messages) +subgroup.members_and_requesters.map(&:errors).map(&:full_messages) +``` + ## Authentication ### Re-enable standard web sign-in form diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md index aba7b5fc318..376c1668444 100644 --- a/doc/administration/uploads.md +++ b/doc/administration/uploads.md @@ -130,60 +130,3 @@ _The uploads are stored by default in 1. Save the file and [restart GitLab](restart_gitlab.md#installations-from-source) for the changes to take effect. 1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md). - -#### OpenStack example - -**In Omnibus installations:** - -_The uploads are stored by default in -`/var/opt/gitlab/gitlab-rails/uploads`._ - -1. Edit `/etc/gitlab/gitlab.rb` and add the following lines by replacing with - the values you want: - - ```ruby - gitlab_rails['uploads_object_store_remote_directory'] = "OPENSTACK_OBJECT_CONTAINER_NAME" - gitlab_rails['uploads_object_store_connection'] = { - 'provider' => 'OpenStack', - 'openstack_username' => 'OPENSTACK_USERNAME', - 'openstack_api_key' => 'OPENSTACK_PASSWORD', - 'openstack_temp_url_key' => 'OPENSTACK_TEMP_URL_KEY', - 'openstack_auth_url' => 'https://auth.cloud.ovh.net/v2.0/', - 'openstack_region' => 'DE1', - 'openstack_tenant' => 'TENANT_ID', - } - ``` - -1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. -1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md). - ---- - -**In installations from source:** - -_The uploads are stored by default in -`/home/git/gitlab/public/uploads`._ - -1. Edit `/home/git/gitlab/config/gitlab.yml` and add or amend the following - lines: - - ```yaml - uploads: - object_store: - enabled: true - direct_upload: false - background_upload: true - proxy_download: false - remote_directory: OPENSTACK_OBJECT_CONTAINER_NAME - connection: - provider: OpenStack - openstack_username: OPENSTACK_USERNAME - openstack_api_key: OPENSTACK_PASSWORD - openstack_temp_url_key: OPENSTACK_TEMP_URL_KEY - openstack_auth_url: 'https://auth.cloud.ovh.net/v2.0/' - openstack_region: DE1 - openstack_tenant: 'TENANT_ID' - ``` - -1. Save the file and [reconfigure GitLab](restart_gitlab.md#omnibus-gitlab-reconfigure) for the changes to take effect. -1. Migrate any existing local uploads to the object storage using [`gitlab:uploads:migrate:all` Rake task](raketasks/uploads/migrate.md). diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md index 91378f7264b..9408e7c25a6 100644 --- a/doc/api/api_resources.md +++ b/doc/api/api_resources.md @@ -24,7 +24,7 @@ The following API resources are available in the project context: | Resource | Available endpoints | |:------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [Access requests](access_requests.md) | `/projects/:id/access_requests` (also available for groups) | -| [Access tokens](resource_access_tokens.md) | `/projects/:id/access_tokens` (also available for groups) | +| [Access tokens](project_access_tokens.md) | `/projects/:id/access_tokens` (also available for groups) | | [Agents](cluster_agents.md) | `/projects/:id/cluster_agents` | | [Award emoji](award_emoji.md) | `/projects/:id/issues/.../award_emoji`, `/projects/:id/merge_requests/.../award_emoji`, `/projects/:id/snippets/.../award_emoji` | | [Branches](branches.md) | `/projects/:id/repository/branches/`, `/projects/:id/repository/merged_branches` | diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 4bfe4cac616..b88e52456c1 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -4543,6 +4543,25 @@ Input type: `TimelineEventUpdateInput` | <a id="mutationtimelineeventupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | | <a id="mutationtimelineeventupdatetimelineevent"></a>`timelineEvent` | [`TimelineEventType`](#timelineeventtype) | Timeline event. | +### `Mutation.timelogDelete` + +Input type: `TimelogDeleteInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="mutationtimelogdeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| <a id="mutationtimelogdeleteid"></a>`id` | [`TimelogID!`](#timelogid) | Global ID of the timelog. | + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="mutationtimelogdeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. | +| <a id="mutationtimelogdeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. | +| <a id="mutationtimelogdeletetimelog"></a>`timelog` | [`Timelog`](#timelog) | Deleted timelog. | + ### `Mutation.todoCreate` Input type: `TodoCreateInput` @@ -16591,6 +16610,7 @@ Describes an incident management timeline event. | Name | Type | Description | | ---- | ---- | ----------- | +| <a id="timelogid"></a>`id` | [`ID!`](#id) | Internal ID of the timelog. | | <a id="timelogissue"></a>`issue` | [`Issue`](#issue) | Issue that logged time was added to. | | <a id="timelogmergerequest"></a>`mergeRequest` | [`MergeRequest`](#mergerequest) | Merge request that logged time was added to. | | <a id="timelognote"></a>`note` | [`Note`](#note) | Note where the quick action was executed to add the logged time. | @@ -19824,6 +19844,12 @@ For example: "2021-03-09T14:58:50+00:00". See `https://www.iso.org/iso-8601-date-and-time-format.html`. +### `TimelogID` + +A `TimelogID` is a global ID. It is encoded as a string. + +An example `TimelogID` is: `"gid://gitlab/Timelog/1"`. + ### `TodoID` A `TodoID` is a global ID. It is encoded as a string. diff --git a/doc/api/resource_access_tokens.md b/doc/api/resource_access_tokens.md deleted file mode 100644 index a9c43625193..00000000000 --- a/doc/api/resource_access_tokens.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -redirect_to: 'project_access_tokens.md' -remove_date: '2022-04-06' ---- - -This document was moved to [another location](project_access_tokens.md). - -<!-- This redirect file can be deleted after <2022-04-06>. --> -<!-- Redirects that point to other docs in the same project expire in three months. --> -<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/development/experiment_guide/experimentation.md b/doc/development/experiment_guide/experimentation.md deleted file mode 100644 index 28100564555..00000000000 --- a/doc/development/experiment_guide/experimentation.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -redirect_to: 'gitlab_experiment.md' -remove_date: '2022-04-13' ---- - -This document was moved to [another location](gitlab_experiment.md). - -<!-- This redirect file can be deleted after <2022-04-13>. --> -<!-- Redirects that point to other docs in the same project expire in three months. --> -<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/development/gitlab_flavored_markdown/index.md b/doc/development/gitlab_flavored_markdown/index.md index 682d8011cd8..7f7781cbc62 100644 --- a/doc/development/gitlab_flavored_markdown/index.md +++ b/doc/development/gitlab_flavored_markdown/index.md @@ -4,13 +4,13 @@ group: Editor 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 --- -# Markdown developer documentation **(FREE)** +# GitLab Flavored Markdown (GLFM) developer documentation **(FREE)** -This page contains the MVC for the developer documentation for GitLab Flavored Markdown. +This page contains the MVC for the developer documentation for GitLab Flavored Markdown (GLFM). For the user documentation about Markdown in GitLab, refer to [GitLab Flavored Markdown](../../user/markdown.md). -## GitLab Flavored Markdown specification guide +## GitLab Flavored Markdown (GLFM) specification guide The [specification guide](specification_guide/index.md) includes: @@ -18,3 +18,4 @@ The [specification guide](specification_guide/index.md) includes: - [Parsing and rendering](specification_guide/index.md#parsing-and-rendering). - [Goals](specification_guide/index.md#goals). - [Implementation](specification_guide/index.md#implementation) of the spec. +- [Workflows](specification_guide/index.md#workflows). diff --git a/doc/development/gitlab_flavored_markdown/specification_guide/index.md b/doc/development/gitlab_flavored_markdown/specification_guide/index.md index 021f7bafce9..c5e9b63aea3 100644 --- a/doc/development/gitlab_flavored_markdown/specification_guide/index.md +++ b/doc/development/gitlab_flavored_markdown/specification_guide/index.md @@ -385,20 +385,57 @@ subgraph output:<br/>GLFM specification files end ``` +#### `canonicalize-html.rb` script + +The `scripts/glfm/canonicalize-html.rb` handles the +["canonicalization" of HTML](#canonicalization-of-html). It is a pipe-through +helper script which takes as input a static or WYSIWYG HTML string containing +extra HTML, and outputs a canonical HTML string. + +It is implemented as a standalone, modular, single-purpose script, based on the +[Unix philosophy](https://en.wikipedia.org/wiki/Unix_philosophy#:~:text=The%20Unix%20philosophy%20emphasizes%20building,developers%20other%20than%20its%20creators.). +It's easy to use when running the standard CommonMark `spec_tests.py` +script, which expects canonical HTML, against the GitLab renderer implementations. + +#### `run-spec-tests.sh` script + +`scripts/glfm/run-spec-tests.sh` is a convenience shell script which runs +conformance specs via the CommonMark standard `spec_tests.py` script, +which uses the `glfm_specification/output/spec.txt` file and `scripts/glfm/canonicalize-html.rb` +helper script to test the GLFM renderer implementations' support for rendering Markdown +specification examples to canonical HTML. + +```mermaid +graph LR +subgraph scripts: + A{run-spec-tests.sh} --> C + subgraph specification testing process + B[canonicalize-html.sh] --> C + C[spec_tests.py] + end +end +subgraph input + D[spec.txt GLFM specification] --> C + E((GLFM static<br/>renderer implementation)) --> B + F((GLFM WYSIWYG<br/>renderer implementation)) --> B +end +subgraph output:<br/>test results/output + C --> G[spec_tests.py output] +end +``` + #### `update-example-snapshots.rb` script -The `scripts/glfm/update-example-snapshots.rb` script uses input specification -files to update example snapshots: +The `scripts/glfm/update-example-snapshots.rb` script uses the GLFM `spec.txt` specification +file to update example snapshots: ```mermaid graph LR subgraph script: A{update-example-snapshots.rb} end -subgraph input:<br/>input specification files - B[downloaded gfm_spec_v_0.29.txt] --> A - C[glfm_canonical_examples.txt] --> A - D[glfm_example_status.yml] --> A +subgraph input:<br/>input specification file + B[spec.txt] --> A end subgraph output:<br/>example snapshot files A --> E[examples_index.yml] @@ -437,7 +474,7 @@ code. It contains only shell scripting commands for the relevant graph LR subgraph script: A{run-snapshopt-tests.sh} --> B - B[relevant rspec/jest test files] + B[relevant rspec+jest test files] end subgraph input:<br/>YAML C[examples_index.yml] --> B @@ -450,45 +487,6 @@ subgraph output:<br/>test results/output end ``` -#### `canonicalize-html.rb` script - -The `scripts/glfm/canonicalize-html.rb` handles the -["canonicalization" of HTML](#canonicalization-of-html). It is a pipe-through -helper script which takes as input a static or WYSIWYG HTML string containing -extra HTML, and outputs a canonical HTML string. - -It is implemented as a standalone, modular, single-purpose script, based on the -[Unix philosophy](https://en.wikipedia.org/wiki/Unix_philosophy#:~:text=The%20Unix%20philosophy%20emphasizes%20building,developers%20other%20than%20its%20creators.). -It's easy to use when running the standard CommonMark `spec_tests.py` -script, which expects canonical HTML, against the GitLab renderer implementations. - -#### `run-spec-tests.sh` script - -`scripts/glfm/run-spec-tests.sh` is a convenience shell script which runs -conformance specs via the CommonMark standard `spec_tests.py` script, -which uses the `glfm_specification/output/spec.txt` file and `scripts/glfm/canonicalize-html.rb` -helper script to test the GLFM renderer implementations' support for rendering Markdown -specification examples to canonical HTML. - -```mermaid -graph LR -subgraph scripts: - A{run-spec-tests.sh} --> C - subgraph specification testing process - B[canonicalize-html.sh] --> C - C[spec_tests.py] - end -end -subgraph input - D[spec.txt GLFM specification] --> C - E((GLFM static<br/>renderer implementation)) --> B - F((GLFM WYSIWYG<br/>renderer implementation)) --> B -end -subgraph output:<br/>test results/output - C --> G[spec_tests.py output] -end -``` - ### Specification files These files represent the GLFM specification itself. They are all @@ -528,12 +526,14 @@ updated, as in the case of all GFM files. ```yaml 07_99_an_example_with_incomplete_wysiwyg_implementation_1: - skip_update_example_snapshots: true - skip_running_snapshot_static_html_tests: false - skip_running_snapshot_wysiwyg_html_tests: true - skip_running_snapshot_prosemirror_json_tests: true + skip_update_example_snapshots: false + skip_update_example_snapshot_html_static: false + skip_update_example_snapshot_html_wysiwyg: false skip_running_conformance_static_tests: false - skip_running_conformance_wysiwyg_tests: true + skip_running_conformance_wysiwyg_tests: false + skip_running_snapshot_static_html_tests: false + skip_running_snapshot_wysiwyg_html_tests: false + skip_running_snapshot_prosemirror_json_tests: false ``` #### Output specification files @@ -634,7 +634,7 @@ for each entry in `spec/fixtures/glfm/example_snapshots/examples_index.yml` `spec/fixtures/glfm/example_snapshots/markdown.yml` sample entry: ```yaml -06_04_inlines_emphasis_and_strong_emphasis_1: |- +06_04_inlines_emphasis_and_strong_emphasis_1: | *foo bar* ``` @@ -670,11 +670,11 @@ Any exceptions or failures which occur when generating HTML are replaced with an ```yaml 06_04_inlines_emphasis_and_strong_emphasis_1: - canonical: |- + canonical: | <p><em>foo bar</em></p> - static: |- + static: | <p data-sourcepos="1:1-1:9" dir="auto"><strong>foo bar</strong></p> - wysiwyg: |- + wysiwyg: | <p><strong>foo bar</strong></p> ``` @@ -715,3 +715,28 @@ JSON for each entry in `spec/fixtures/glfm/example_snapshots/examples_index.yml` ] } ``` + +## Workflows + +This section describes how the scripts can be used to manage the GLFM specification and tests. + +### Update the GLFM specification and run conformance tests + +1. Run [`update-specification.rb`](#update-specificationrb-script) to update the GLFM specification [output specification files](#output-specification-files). +1. Visually inspect and confirm any resulting changes to the [output specification files](#output-specification-files). +1. Run [`run-spec-tests.sh`](http://gdk.test:3005/ee/development/gitlab_flavored_markdown/specification_guide/index.html#run-spec-testssh-script) to run the conformance tests against the canonicalized GLFM specification. +1. Commit any changes to the [output specification files](#output-specification-files). + +### Update the example snapshots and run snapshot tests + +1. If you are working on an in-progress feature or bug, make any necessary manual updates to the [input specification files](#input-specification-files). This may include: + 1. Updating the canonical Markdown or HTML examples in `glfm_specification/input/gitlab_flavored_markdown/glfm_canonical_examples.txt`. + 1. Updating `glfm_specification/input/gitlab_flavored_markdown/glfm_example_status.yml` to reflect the current status of the examples or tests. +1. Run [`update-specification.rb`](#update-specificationrb-script) to update the `spec.txt` to reflect any changes which were made to the [input specification files](#input-specification-files). +1. Visually inspect and confirm any resulting changes to the [output specification files](#output-specification-files). +1. Run [`update-example-snapshots.rb`](#update-example-snapshotsrb-script) to update the [example snapshot files](#example-snapshot-files). +1. Visually inspect and confirm any resulting changes to the [example snapshot files](#example-snapshot-files). +1. Run [`run-snapshot-tests.sh`](#run-snapshot-testssh-script) as a convenience script to run all relevant frontend (RSpec) and backend (Jest) tests which use the example snapshots. + 1. Any frontend or backend snapshot test may also be run individually. + 1. All frontend and backend tests are also run as part of the continuous integration suite, as they normally are. +1. Commit any changes to the [input specification files](#input-specification-files), [output specification files](#output-specification-files), or [example snapshot files](#example-snapshot-files). diff --git a/doc/development/kubernetes.md b/doc/development/kubernetes.md index a6d9c754838..ee261769d82 100644 --- a/doc/development/kubernetes.md +++ b/doc/development/kubernetes.md @@ -54,7 +54,7 @@ webserver, and can lead to a denial-of-service (DoS) attack in GitLab as the Kubernetes cluster response times are outside of our control. The easiest way to ensure your calls happen a background process is to -delegate any such work to happen in a [Sidekiq worker](sidekiq_style_guide.md). +delegate any such work to happen in a [Sidekiq worker](sidekiq/index.md). You may want to make calls to Kubernetes and return the response, but a background worker isn't a good fit. Consider using diff --git a/doc/development/redis.md b/doc/development/redis.md index 75170b8c746..f01dc005b49 100644 --- a/doc/development/redis.md +++ b/doc/development/redis.md @@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w GitLab uses [Redis](https://redis.io) for the following distinct purposes: - Caching (mostly via `Rails.cache`). -- As a job processing queue with [Sidekiq](sidekiq_style_guide.md). +- As a job processing queue with [Sidekiq](sidekiq/index.md). - To manage the shared application state. - To store CI trace chunks. - As a Pub/Sub queue backend for ActionCable. diff --git a/doc/development/sidekiq_style_guide.md b/doc/development/sidekiq_style_guide.md deleted file mode 100644 index 1b5e7addf29..00000000000 --- a/doc/development/sidekiq_style_guide.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -redirect_to: 'sidekiq/index.md' -remove_date: '2022-04-13' ---- - -This document was moved to [another location](sidekiq/index.md). - -<!-- This redirect file can be deleted after <2022-04-13>. --> -<!-- Redirects that point to other docs in the same project expire in three months. --> -<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> -<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html --> diff --git a/doc/topics/autodevops/customize.md b/doc/topics/autodevops/customize.md index 503774ef6b5..f84abca1ff2 100644 --- a/doc/topics/autodevops/customize.md +++ b/doc/topics/autodevops/customize.md @@ -431,7 +431,7 @@ applications. | `HELM_UPGRADE_EXTRA_ARGS` | Allows extra options in `helm upgrade` commands when deploying the application. Note that using quotes doesn't prevent word splitting. | | `INCREMENTAL_ROLLOUT_MODE` | If present, can be used to enable an [incremental rollout](#incremental-rollout-to-production) of your application for the production environment. Set to `manual` for manual deployment jobs or `timed` for automatic rollout deployments with a 5 minute delay each one. | | `K8S_SECRET_*` | Any variable prefixed with [`K8S_SECRET_`](#application-secret-variables) is made available by Auto DevOps as environment variables to the deployed application. | -| `KUBE_CONTEXT` | From GitLab 14.5, can be used to select a context to use from `KUBECONFIG`. When `KUBE_CONTEXT` is blank, the default context in `KUBECONFIG` (if any) is used. A context must be selected when used [with the agent for Kubernetes](../../user/clusters/agent/ci_cd_tunnel.md). | +| `KUBE_CONTEXT` | From GitLab 14.5, can be used to select a context to use from `KUBECONFIG`. When `KUBE_CONTEXT` is blank, the default context in `KUBECONFIG` (if any) is used. A context must be selected when used [with the agent for Kubernetes](../../user/clusters/agent/ci_cd_workflow.md). | | `KUBE_INGRESS_BASE_DOMAIN` | Can be used to set a domain per cluster. See [cluster domains](../../user/project/clusters/gitlab_managed_clusters.md#base-domain) for more information. | | `KUBE_NAMESPACE` | The namespace used for deployments. When using certificate-based clusters, [this value should not be overwritten directly](../../user/project/clusters/deploy_to_cluster.md#custom-namespace). | | `KUBECONFIG` | The kubeconfig to use for deployments. User-provided values take priority over GitLab-provided values. | diff --git a/doc/topics/release_your_application.md b/doc/topics/release_your_application.md index c791b1f7185..c6d52896345 100644 --- a/doc/topics/release_your_application.md +++ b/doc/topics/release_your_application.md @@ -37,7 +37,7 @@ approach to manage Kubernetes deployments. #### Deploy to Kubernetes from GitLab CI/CD With the [GitLab agent for Kubernetes](../user/clusters/agent/install/index.md), you can perform [push-based -deployments](../user/clusters/agent/ci_cd_tunnel.md) from GitLab CI/CD. The agent provides +deployments](../user/clusters/agent/ci_cd_workflow.md) from GitLab CI/CD. The agent provides a secure and reliable connection between GitLab and your Kubernetes cluster. ### Deploy to AWS with GitLab CI/CD diff --git a/doc/tutorials/index.md b/doc/tutorials/index.md index cf3c23a99a7..caeeb12fd35 100644 --- a/doc/tutorials/index.md +++ b/doc/tutorials/index.md @@ -20,7 +20,7 @@ and running quickly. | <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Use GitLab for DevOps](https://www.youtube.com/watch?v=7q9Y1Cv-ib0) (12m 34s) | Use GitLab through the entire DevOps lifecycle, from planning to monitoring. | **{star}** | | [Use Markdown at GitLab](../user/markdown.md) | GitLab Flavored Markdown (GLFM) is used in many areas of GitLab, for example, in merge requests. | **{star}** | | [GitLab 201](https://gitlab.edcast.com/pathways/ECL-44010cf6-7a9c-4b9b-b684-fa08508a3252) | Go beyond the basics to learn more about using GitLab for your work. | | -| Learn GitLab project | You might already have the **Learn GitLab** project, which has tutorial-style issues to help you learn GitLab. If not, download [this export file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/project_templates/learn_gitlab_ultimate.tar.gz) and [import it to a new project](../user/project/settings/import_export.md#import-a-project-and-its-data). | | +| <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Learn GitLab project walkthrough](https://www.youtube.com/watch?v=-oaI2WEKdI4&list=PL05JrBw4t0KofkHq4GZJ05FnNGa11PQ4d) (59m 2s) | Step through the tutorial-style issues in the **Learn GitLab** project. If you don't have this project, download [the export file](https://gitlab.com/gitlab-org/gitlab/-/blob/master/vendor/project_templates/learn_gitlab_ultimate.tar.gz) and [import it to a new project](../user/project/settings/import_export.md#import-a-project-and-its-data). | | | [Productivity tips](https://about.gitlab.com/blog/2021/02/18/improve-your-gitlab-productivity-with-these-10-tips/) | Get tips to help make you a productive GitLab user. | | | <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Structure a multi-team organization](https://www.youtube.com/watch?v=KmASFwSap7c) (37m 37s) | Learn to use issues, milestones, epics, labels, and more to plan and manage your work. | | diff --git a/doc/update/deprecations.md b/doc/update/deprecations.md index 7373ad6030c..e3afdbfac35 100644 --- a/doc/update/deprecations.md +++ b/doc/update/deprecations.md @@ -1349,6 +1349,8 @@ For a more robust, secure, forthcoming, and reliable integration with Kubernetes For updates and details about this deprecation, follow [this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8). +GitLab self-managed customers can still use the feature [with a feature flag](https://docs.gitlab.com/ee/update/deprecations.html#self-managed-certificate-based-integration-with-kubernetes). + **Planned removal milestone: 15.0 (2022-05-22)** ### Self-managed certificate-based integration with Kubernetes diff --git a/doc/user/clusters/agent/ci_cd_tunnel.md b/doc/user/clusters/agent/ci_cd_tunnel.md index c15041f6b0d..1b99fcf9739 100644 --- a/doc/user/clusters/agent/ci_cd_tunnel.md +++ b/doc/user/clusters/agent/ci_cd_tunnel.md @@ -1,261 +1,11 @@ --- -stage: Configure -group: Configure -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 +redirect_to: 'ci_cd_workflow.md' +remove_date: '2022-07-20' --- -# Using a GitLab CI/CD workflow for Kubernetes **(FREE)** +This document was moved to [another location](ci_cd_workflow.md). -> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327409) in GitLab 14.1. -> - The pre-configured `KUBECONFIG` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/324275) in GitLab 14.2. -> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) the `ci_access` attribute in GitLab 14.3. -> - The ability to authorize groups was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) in GitLab 14.3. -> - [Moved](https://gitlab.com/groups/gitlab-org/-/epics/6290) to GitLab Free in 14.5. -> - Support for Omnibus installations was [introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5686) in GitLab 14.5. -> - The ability to switch between certificate-based clusters and agents was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335089) in GitLab 14.9. The certificate-based cluster context is always called `gitlab-deploy`. - -You can use a GitLab CI/CD workflow to safely deploy to and update your Kubernetes clusters. - -To do so, you must first [install an agent in your cluster](install/index.md). When done, you have a Kubernetes context and can -run Kubernetes API commands in your GitLab CI/CD pipeline. - -To ensure access to your cluster is safe: - -- Each agent has a separate context (`kubecontext`). -- Only the project where the agent is configured, and any additional projects you authorize, can access the agent in your cluster. - -You do not need to have a runner in the cluster with the agent. - -## GitLab CI/CD workflow steps - -To update a Kubernetes cluster by using GitLab CI/CD, complete the following steps. - -1. Ensure you have a working Kubernetes cluster and the manifests are in a GitLab project. -1. In the same GitLab project, [register and install the GitLab agent](install/index.md). -1. [Update your `.gitlab-ci.yml` file](#update-your-gitlab-ciyml-file-to-run-kubectl-commands) to - select the agent's Kubernetes context and run the Kubernetes API commands. -1. Run your pipeline to deploy to or update the cluster. - -If you have multiple GitLab projects that contain Kubernetes manifests: - -1. [Install the GitLab agent](install/index.md) in its own project, or in one of the - GitLab projects where you keep Kubernetes manifests. -1. [Authorize the agent](#authorize-the-agent) to access your GitLab projects. -1. Optional. For added security, [use impersonation](#use-impersonation-to-restrict-project-and-group-access). -1. [Update your `.gitlab-ci.yml` file](#update-your-gitlab-ciyml-file-to-run-kubectl-commands) to - select the agent's Kubernetes context and run the Kubernetes API commands. -1. Run your pipeline to deploy to or update the cluster. - -## Authorize the agent - -You must authorize the agent to access the project where you keep your Kubernetes manifests. -You can authorize the agent to access individual projects, or authorize a group or subgroup, -so all projects within have access. For added security, you can also -[use impersonation](#use-impersonation-to-restrict-project-and-group-access). - -### Authorize the agent to access your projects - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327850) in GitLab 14.4. - -To authorize the agent to access the GitLab project where you keep Kubernetes manifests: - -1. On the top bar, select **Menu > Projects** and find the project that contains the agent configuration file (`config.yaml`). -1. Edit the file. Under the `ci_access` keyword, add the `projects` attribute. -1. For the `id`, add the path: - - ```yaml - ci_access: - projects: - - id: path/to/project - ``` - - - The Kubernetes projects must be in the same group hierarchy as the project where the agent's configuration is. - - You can install additional agents into the same cluster to accommodate additional hierarchies. - - You can authorize up to 100 projects. - -All CI/CD jobs now include a `KUBECONFIG` with contexts for every shared agent connection. -Choose the context to run `kubectl` commands from your CI/CD scripts. - -### Authorize the agent to access projects in your groups - -> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) in GitLab 14.3. - -To authorize the agent to access all of the GitLab projects in a group or subgroup: - -1. On the top bar, select **Menu > Projects** and find the project that contains the agent configuration file (`config.yaml`). -1. Edit the file. Under the `ci_access` keyword, add the `groups` attribute. -1. For the `id`, add the path: - - ```yaml - ci_access: - groups: - - id: path/to/group/subgroup - ``` - - - The Kubernetes projects must be in the same group hierarchy as the project where the agent's configuration is. - - You can install additional agents into the same cluster to accommodate additional hierarchies. - - All of the subgroups of an authorized group also have access to the same agent (without being specified individually). - - You can authorize up to 100 groups. - -All the projects that belong to the group and its subgroups are now authorized to access the agent. -All CI/CD jobs now include a `KUBECONFIG` with contexts for every shared agent connection. -Choose the context to run `kubectl` commands from your CI/CD scripts. - -## Update your `.gitlab-ci.yml` file to run `kubectl` commands - -In the project where you want to run Kubernetes commands, edit your project's `.gitlab-ci.yml` file. - -In the first command under the `script` keyword, set your agent's context. -Use the format `path/to/agent/repository:agent-name`. For example: - -```yaml - deploy: - image: - name: bitnami/kubectl:latest - entrypoint: [""] - script: - - kubectl config get-contexts - - kubectl config use-context path/to/agent/repository:agent-name - - kubectl get pods -``` - -If you are not sure what your agent's context is, open a terminal and connect to your cluster. -Run `kubectl config get-contexts`. - -### Environments with both certificate-based and agent-based connections - -When you deploy to an environment that has both a [certificate-based -cluster](../../infrastructure/clusters/index.md) (deprecated) and an agent connection: - -- The certificate-based cluster's context is called `gitlab-deploy`. This context - is always selected by default. -- In GitLab 14.9 and later, agent contexts are included in the - `KUBECONFIG`. You can select them by using `kubectl config use-context - path/to/agent/repository:agent-name`. -- In GitLab 14.8 and earlier, you can still use agent connections, but for environments that - already have a certificate-based cluster, the agent connections are not included in the `KUBECONFIG`. - -To use an agent connection when certificate-based connections are present, you can manually configure a new `kubectl` -configuration context. For example: - - ```yaml - deploy: - variables: - KUBE_CONTEXT: my-context # The name to use for the new context - AGENT_ID: 1234 # replace with your agent's numeric ID - K8S_PROXY_URL: wss://kas.gitlab.com/k8s-proxy/ # replace with your agent server (KAS) Kubernetes proxy URL - # ... any other variables you have configured - before_script: - - kubectl config set-credentials agent:$AGENT_ID --token="ci:${AGENT_ID}:${CI_JOB_TOKEN}" - - kubectl config set-cluster gitlab --server="${K8S_PROXY_URL}" - - kubectl config set-context "$KUBE_CONTEXT" --cluster=gitlab --user="agent:${AGENT_ID}" - - kubectl config use-context "$KUBE_CONTEXT" - # ... rest of your job configuration - ``` - -## Use impersonation to restrict project and group access **(PREMIUM)** - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345014) in GitLab 14.5. - -By default, your CI/CD job inherits all the permissions from the service account used to install the -agent in the cluster. -To restrict access to your cluster, you can use [impersonation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation). - -To specify impersonations, use the `access_as` attribute in your agent configuration file and use Kubernetes RBAC rules to manage impersonated account permissions. - -You can impersonate: - -- The agent itself (default). -- The CI/CD job that accesses the cluster. -- A specific user or system account defined within the cluster. - -### Impersonate the agent - -The agent is impersonated by default. You don't need to do anything to impersonate it. - -### Impersonate the CI/CD job that accesses the cluster - -To impersonate the CI/CD job that accesses the cluster, under the `access_as` key, add the `ci_job: {}` key-value. - -When the agent makes the request to the actual Kubernetes API, it sets the -impersonation credentials in the following way: - -- `UserName` is set to `gitlab:ci_job:<job id>`. Example: `gitlab:ci_job:1074499489`. -- `Groups` is set to: - - `gitlab:ci_job` to identify all requests coming from CI jobs. - - The list of IDs of groups the project is in. - - The project ID. - - The slug of the environment this job belongs to. - - Example: for a CI job in `group1/group1-1/project1` where: - - - Group `group1` has ID 23. - - Group `group1/group1-1` has ID 25. - - Project `group1/group1-1/project1` has ID 150. - - Job running in a prod environment. - - Group list would be `[gitlab:ci_job, gitlab:group:23, gitlab:group:25, gitlab:project:150, gitlab:project_env:150:prod]`. - -- `Extra` carries extra information about the request. The following properties are set on the impersonated identity: - -| Property | Description | -| -------- | ----------- | -| `agent.gitlab.com/id` | Contains the agent ID. | -| `agent.gitlab.com/config_project_id` | Contains the agent's configuration project ID. | -| `agent.gitlab.com/project_id` | Contains the CI project ID. | -| `agent.gitlab.com/ci_pipeline_id` | Contains the CI pipeline ID. | -| `agent.gitlab.com/ci_job_id` | Contains the CI job ID. | -| `agent.gitlab.com/username` | Contains the username of the user the CI job is running as. | -| `agent.gitlab.com/environment_slug` | Contains the slug of the environment. Only set if running in an environment. | - -Example to restrict access by the CI/CD job's identity: - -```yaml -ci_access: - projects: - - id: path/to/project - access_as: - ci_job: {} -``` - -### Impersonate a static identity - -For a given connection, you can use a static identity for the impersonation. - -Under the `access_as` key, add the `impersonate` key to make the request using the provided identity. - -The identity can be specified with the following keys: - -- `username` (required) -- `uid` -- `groups` -- `extra` - -See the [official Kubernetes documentation for details](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation). - -## Troubleshooting - -### `kubectl` commands not supported - -The commands `kubectl exec`, `kubectl cp`, and `kubectl attach` are not supported. -Anything that uses these API endpoints does not work, because they use the deprecated -SPDY protocol. -[An issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/346248) to add support for these commands. - -### Grant write permissions to `~/.kube/cache` - -Tools like `kubectl`, Helm, `kpt`, and `kustomize` cache information about -the cluster in `~/.kube/cache`. If this directory is not writable, the tool fetches information on each invocation, -making interactions slower and creating unnecessary load on the cluster. For the best experience, in the -image you use in your .`gitlab-ci.yml` file, ensure this directory is writable. - -### Enable TLS - -If you are on a self-managed GitLab instance, ensure your instance is configured with Transport Layer Security (TLS). - -If you attempt to use `kubectl` without TLS, you might get an error like: - -```shell -$ kubectl get pods -error: You must be logged in to the server (the server has asked for the client to provide credentials) -``` +<!-- This redirect file can be deleted after <2022-07-20>. --> +<!-- Redirects that point to other docs in the same project expire in three months. --> +<!-- Redirects that point to docs in a different project or site (for example, link is not relative and starts with `https:`) expire in one year. --> +<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
\ No newline at end of file diff --git a/doc/user/clusters/agent/ci_cd_workflow.md b/doc/user/clusters/agent/ci_cd_workflow.md new file mode 100644 index 00000000000..c15041f6b0d --- /dev/null +++ b/doc/user/clusters/agent/ci_cd_workflow.md @@ -0,0 +1,261 @@ +--- +stage: Configure +group: Configure +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 +--- + +# Using a GitLab CI/CD workflow for Kubernetes **(FREE)** + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327409) in GitLab 14.1. +> - The pre-configured `KUBECONFIG` was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/324275) in GitLab 14.2. +> - [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) the `ci_access` attribute in GitLab 14.3. +> - The ability to authorize groups was [introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) in GitLab 14.3. +> - [Moved](https://gitlab.com/groups/gitlab-org/-/epics/6290) to GitLab Free in 14.5. +> - Support for Omnibus installations was [introduced](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/5686) in GitLab 14.5. +> - The ability to switch between certificate-based clusters and agents was [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335089) in GitLab 14.9. The certificate-based cluster context is always called `gitlab-deploy`. + +You can use a GitLab CI/CD workflow to safely deploy to and update your Kubernetes clusters. + +To do so, you must first [install an agent in your cluster](install/index.md). When done, you have a Kubernetes context and can +run Kubernetes API commands in your GitLab CI/CD pipeline. + +To ensure access to your cluster is safe: + +- Each agent has a separate context (`kubecontext`). +- Only the project where the agent is configured, and any additional projects you authorize, can access the agent in your cluster. + +You do not need to have a runner in the cluster with the agent. + +## GitLab CI/CD workflow steps + +To update a Kubernetes cluster by using GitLab CI/CD, complete the following steps. + +1. Ensure you have a working Kubernetes cluster and the manifests are in a GitLab project. +1. In the same GitLab project, [register and install the GitLab agent](install/index.md). +1. [Update your `.gitlab-ci.yml` file](#update-your-gitlab-ciyml-file-to-run-kubectl-commands) to + select the agent's Kubernetes context and run the Kubernetes API commands. +1. Run your pipeline to deploy to or update the cluster. + +If you have multiple GitLab projects that contain Kubernetes manifests: + +1. [Install the GitLab agent](install/index.md) in its own project, or in one of the + GitLab projects where you keep Kubernetes manifests. +1. [Authorize the agent](#authorize-the-agent) to access your GitLab projects. +1. Optional. For added security, [use impersonation](#use-impersonation-to-restrict-project-and-group-access). +1. [Update your `.gitlab-ci.yml` file](#update-your-gitlab-ciyml-file-to-run-kubectl-commands) to + select the agent's Kubernetes context and run the Kubernetes API commands. +1. Run your pipeline to deploy to or update the cluster. + +## Authorize the agent + +You must authorize the agent to access the project where you keep your Kubernetes manifests. +You can authorize the agent to access individual projects, or authorize a group or subgroup, +so all projects within have access. For added security, you can also +[use impersonation](#use-impersonation-to-restrict-project-and-group-access). + +### Authorize the agent to access your projects + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/327850) in GitLab 14.4. + +To authorize the agent to access the GitLab project where you keep Kubernetes manifests: + +1. On the top bar, select **Menu > Projects** and find the project that contains the agent configuration file (`config.yaml`). +1. Edit the file. Under the `ci_access` keyword, add the `projects` attribute. +1. For the `id`, add the path: + + ```yaml + ci_access: + projects: + - id: path/to/project + ``` + + - The Kubernetes projects must be in the same group hierarchy as the project where the agent's configuration is. + - You can install additional agents into the same cluster to accommodate additional hierarchies. + - You can authorize up to 100 projects. + +All CI/CD jobs now include a `KUBECONFIG` with contexts for every shared agent connection. +Choose the context to run `kubectl` commands from your CI/CD scripts. + +### Authorize the agent to access projects in your groups + +> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5784) in GitLab 14.3. + +To authorize the agent to access all of the GitLab projects in a group or subgroup: + +1. On the top bar, select **Menu > Projects** and find the project that contains the agent configuration file (`config.yaml`). +1. Edit the file. Under the `ci_access` keyword, add the `groups` attribute. +1. For the `id`, add the path: + + ```yaml + ci_access: + groups: + - id: path/to/group/subgroup + ``` + + - The Kubernetes projects must be in the same group hierarchy as the project where the agent's configuration is. + - You can install additional agents into the same cluster to accommodate additional hierarchies. + - All of the subgroups of an authorized group also have access to the same agent (without being specified individually). + - You can authorize up to 100 groups. + +All the projects that belong to the group and its subgroups are now authorized to access the agent. +All CI/CD jobs now include a `KUBECONFIG` with contexts for every shared agent connection. +Choose the context to run `kubectl` commands from your CI/CD scripts. + +## Update your `.gitlab-ci.yml` file to run `kubectl` commands + +In the project where you want to run Kubernetes commands, edit your project's `.gitlab-ci.yml` file. + +In the first command under the `script` keyword, set your agent's context. +Use the format `path/to/agent/repository:agent-name`. For example: + +```yaml + deploy: + image: + name: bitnami/kubectl:latest + entrypoint: [""] + script: + - kubectl config get-contexts + - kubectl config use-context path/to/agent/repository:agent-name + - kubectl get pods +``` + +If you are not sure what your agent's context is, open a terminal and connect to your cluster. +Run `kubectl config get-contexts`. + +### Environments with both certificate-based and agent-based connections + +When you deploy to an environment that has both a [certificate-based +cluster](../../infrastructure/clusters/index.md) (deprecated) and an agent connection: + +- The certificate-based cluster's context is called `gitlab-deploy`. This context + is always selected by default. +- In GitLab 14.9 and later, agent contexts are included in the + `KUBECONFIG`. You can select them by using `kubectl config use-context + path/to/agent/repository:agent-name`. +- In GitLab 14.8 and earlier, you can still use agent connections, but for environments that + already have a certificate-based cluster, the agent connections are not included in the `KUBECONFIG`. + +To use an agent connection when certificate-based connections are present, you can manually configure a new `kubectl` +configuration context. For example: + + ```yaml + deploy: + variables: + KUBE_CONTEXT: my-context # The name to use for the new context + AGENT_ID: 1234 # replace with your agent's numeric ID + K8S_PROXY_URL: wss://kas.gitlab.com/k8s-proxy/ # replace with your agent server (KAS) Kubernetes proxy URL + # ... any other variables you have configured + before_script: + - kubectl config set-credentials agent:$AGENT_ID --token="ci:${AGENT_ID}:${CI_JOB_TOKEN}" + - kubectl config set-cluster gitlab --server="${K8S_PROXY_URL}" + - kubectl config set-context "$KUBE_CONTEXT" --cluster=gitlab --user="agent:${AGENT_ID}" + - kubectl config use-context "$KUBE_CONTEXT" + # ... rest of your job configuration + ``` + +## Use impersonation to restrict project and group access **(PREMIUM)** + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345014) in GitLab 14.5. + +By default, your CI/CD job inherits all the permissions from the service account used to install the +agent in the cluster. +To restrict access to your cluster, you can use [impersonation](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation). + +To specify impersonations, use the `access_as` attribute in your agent configuration file and use Kubernetes RBAC rules to manage impersonated account permissions. + +You can impersonate: + +- The agent itself (default). +- The CI/CD job that accesses the cluster. +- A specific user or system account defined within the cluster. + +### Impersonate the agent + +The agent is impersonated by default. You don't need to do anything to impersonate it. + +### Impersonate the CI/CD job that accesses the cluster + +To impersonate the CI/CD job that accesses the cluster, under the `access_as` key, add the `ci_job: {}` key-value. + +When the agent makes the request to the actual Kubernetes API, it sets the +impersonation credentials in the following way: + +- `UserName` is set to `gitlab:ci_job:<job id>`. Example: `gitlab:ci_job:1074499489`. +- `Groups` is set to: + - `gitlab:ci_job` to identify all requests coming from CI jobs. + - The list of IDs of groups the project is in. + - The project ID. + - The slug of the environment this job belongs to. + + Example: for a CI job in `group1/group1-1/project1` where: + + - Group `group1` has ID 23. + - Group `group1/group1-1` has ID 25. + - Project `group1/group1-1/project1` has ID 150. + - Job running in a prod environment. + + Group list would be `[gitlab:ci_job, gitlab:group:23, gitlab:group:25, gitlab:project:150, gitlab:project_env:150:prod]`. + +- `Extra` carries extra information about the request. The following properties are set on the impersonated identity: + +| Property | Description | +| -------- | ----------- | +| `agent.gitlab.com/id` | Contains the agent ID. | +| `agent.gitlab.com/config_project_id` | Contains the agent's configuration project ID. | +| `agent.gitlab.com/project_id` | Contains the CI project ID. | +| `agent.gitlab.com/ci_pipeline_id` | Contains the CI pipeline ID. | +| `agent.gitlab.com/ci_job_id` | Contains the CI job ID. | +| `agent.gitlab.com/username` | Contains the username of the user the CI job is running as. | +| `agent.gitlab.com/environment_slug` | Contains the slug of the environment. Only set if running in an environment. | + +Example to restrict access by the CI/CD job's identity: + +```yaml +ci_access: + projects: + - id: path/to/project + access_as: + ci_job: {} +``` + +### Impersonate a static identity + +For a given connection, you can use a static identity for the impersonation. + +Under the `access_as` key, add the `impersonate` key to make the request using the provided identity. + +The identity can be specified with the following keys: + +- `username` (required) +- `uid` +- `groups` +- `extra` + +See the [official Kubernetes documentation for details](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation). + +## Troubleshooting + +### `kubectl` commands not supported + +The commands `kubectl exec`, `kubectl cp`, and `kubectl attach` are not supported. +Anything that uses these API endpoints does not work, because they use the deprecated +SPDY protocol. +[An issue exists](https://gitlab.com/gitlab-org/gitlab/-/issues/346248) to add support for these commands. + +### Grant write permissions to `~/.kube/cache` + +Tools like `kubectl`, Helm, `kpt`, and `kustomize` cache information about +the cluster in `~/.kube/cache`. If this directory is not writable, the tool fetches information on each invocation, +making interactions slower and creating unnecessary load on the cluster. For the best experience, in the +image you use in your .`gitlab-ci.yml` file, ensure this directory is writable. + +### Enable TLS + +If you are on a self-managed GitLab instance, ensure your instance is configured with Transport Layer Security (TLS). + +If you attempt to use `kubectl` without TLS, you might get an error like: + +```shell +$ kubectl get pods +error: You must be logged in to the server (the server has asked for the client to provide credentials) +``` diff --git a/doc/user/clusters/agent/index.md b/doc/user/clusters/agent/index.md index bab3f3137fe..87a1d7bbe4c 100644 --- a/doc/user/clusters/agent/index.md +++ b/doc/user/clusters/agent/index.md @@ -35,7 +35,7 @@ In a [**GitOps** workflow](gitops.md), you keep your Kubernetes manifests in Git any time you update your manifests, the agent updates the cluster. This workflow is fully driven with Git and is considered pull-based, because the cluster is pulling updates from your GitLab repository. -In a [**CI/CD** workflow](ci_cd_tunnel.md), you use GitLab CI/CD to query and update your cluster by using the Kubernetes API. +In a [**CI/CD** workflow](ci_cd_workflow.md), you use GitLab CI/CD to query and update your cluster by using the Kubernetes API. This workflow is considered push-based, because GitLab is pushing requests from GitLab CI/CD to your cluster. ## Supported cluster versions @@ -65,7 +65,7 @@ Read about how to [migrate to the agent for Kubernetes](../../infrastructure/clu ## Related topics - [GitOps workflow](gitops.md) -- [GitLab CI/CD workflow](ci_cd_tunnel.md) +- [GitLab CI/CD workflow](ci_cd_workflow.md) - [Install the agent](install/index.md) - [Work with the agent](repository.md) - [Troubleshooting](troubleshooting.md) diff --git a/doc/user/clusters/agent/install/index.md b/doc/user/clusters/agent/install/index.md index e76ef9e827d..5de6583e036 100644 --- a/doc/user/clusters/agent/install/index.md +++ b/doc/user/clusters/agent/install/index.md @@ -44,7 +44,7 @@ In GitLab 14.10, a [flag](../../../../administration/feature_flags.md) named `ce Prerequisites: -- For a [GitLab CI/CD workflow](../ci_cd_tunnel.md), ensure that +- For a [GitLab CI/CD workflow](../ci_cd_workflow.md), ensure that [GitLab CI/CD is enabled](../../../../ci/enable_or_disable_ci.md#enable-cicd-in-a-project). To register an agent with GitLab: @@ -68,7 +68,7 @@ The agent is configured through a configuration file. This file is optional. Wit You need a configuration file if: - You want to use [a GitOps workflow](../gitops.md#gitops-configuration-reference). -- You want to authorize a different project to use the agent for a [GitLab CI/CD workflow](../ci_cd_tunnel.md#authorize-the-agent). +- You want to authorize a different project to use the agent for a [GitLab CI/CD workflow](../ci_cd_workflow.md#authorize-the-agent). To create an agent configuration file, go to the GitLab project. In the repository, create a file called `config.yaml` at this path: diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md index ab17e462c6a..03a63f7b5fe 100644 --- a/doc/user/clusters/management_project_template.md +++ b/doc/user/clusters/management_project_template.md @@ -32,7 +32,7 @@ If you have already configured the agent and connected a cluster with GitLab: 1. [Create a project from the cluster management project template](#create-a-project-based-on-the-cluster-management-project-template). 1. In the project where you configured your agent, - [grant the agent access to the new project](agent/ci_cd_tunnel.md#authorize-the-agent). + [grant the agent access to the new project](agent/ci_cd_workflow.md#authorize-the-agent). 1. In the new project, create an [environment variable](../../ci/variables/index.md#add-a-cicd-variable-to-a-project) named `$KUBE_CONTEXT` and set the value to `path/to/agent-configuration-project:your-agent-name`. diff --git a/doc/user/infrastructure/clusters/index.md b/doc/user/infrastructure/clusters/index.md index cd7c5feb284..114b4096091 100644 --- a/doc/user/infrastructure/clusters/index.md +++ b/doc/user/infrastructure/clusters/index.md @@ -67,5 +67,5 @@ The concept of [project-level](../../project/clusters/index.md), [instance-level](../../instance/clusters/index.md) clusters becomes extinct in the new model, although the functionality remains to some extent. -The agent is always configured in a single GitLab project and you can expose the cluster connection to other projects and groups to [access it from GitLab CI/CD](../../clusters/agent/ci_cd_tunnel.md). +The agent is always configured in a single GitLab project and you can expose the cluster connection to other projects and groups to [access it from GitLab CI/CD](../../clusters/agent/ci_cd_workflow.md). By doing so, you are granting these projects and groups access to the same cluster, which is similar to group-level clusters' use case. diff --git a/doc/user/infrastructure/clusters/migrate_to_gitlab_agent.md b/doc/user/infrastructure/clusters/migrate_to_gitlab_agent.md index 84dba6bf4e8..d1397a8463e 100644 --- a/doc/user/infrastructure/clusters/migrate_to_gitlab_agent.md +++ b/doc/user/infrastructure/clusters/migrate_to_gitlab_agent.md @@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w To connect your Kubernetes cluster with GitLab, you can use: - [A GitOps workflow](../../clusters/agent/gitops.md). -- [A GitLab CI/CD workflow](../../clusters/agent/ci_cd_tunnel.md). +- [A GitLab CI/CD workflow](../../clusters/agent/ci_cd_workflow.md). - [A certificate-based integration](index.md). The certificate-based integration is @@ -23,7 +23,7 @@ in GitLab 14.5. The removal dates are: If you are using the certificate-based integration, you should move to another workflow as soon as possible. As a general rule, to migrate clusters that rely on GitLab CI/CD, -you can use the [CI/CD workflow](../../clusters/agent/ci_cd_tunnel.md). +you can use the [CI/CD workflow](../../clusters/agent/ci_cd_workflow.md). This workflow uses an agent to connect to your cluster. The agent: - Is not exposed to the internet. @@ -41,7 +41,7 @@ Some features are currently available only when using certificate-based integrat With GitLab-managed clusters, GitLab creates separate service accounts and namespaces for every branch and deploys by using these resources. -The GitLab agent uses [impersonation](../../clusters/agent/ci_cd_tunnel.md#use-impersonation-to-restrict-project-and-group-access) +The GitLab agent uses [impersonation](../../clusters/agent/ci_cd_workflow.md#use-impersonation-to-restrict-project-and-group-access) strategies to deploy to your cluster with restricted account access. To do so: 1. Choose the impersonation strategy that suits your needs. @@ -92,7 +92,7 @@ For an example, [view this project](https://gitlab.com/gitlab-examples/ops/gitop ### Migrate generic deployments -Follow the process for the [CI/CD workflow](../../clusters/agent/ci_cd_tunnel.md). +Follow the process for the [CI/CD workflow](../../clusters/agent/ci_cd_workflow.md). ## Migrate from GitLab Managed applications diff --git a/doc/user/project/clusters/deploy_to_cluster.md b/doc/user/project/clusters/deploy_to_cluster.md index c1cdf754c11..fc41533b17c 100644 --- a/doc/user/project/clusters/deploy_to_cluster.md +++ b/doc/user/project/clusters/deploy_to_cluster.md @@ -11,7 +11,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w WARNING: This feature was [deprecated](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) in GitLab 14.5. To connect your cluster to GitLab, use the [GitLab agent](../../clusters/agent/index.md). -To deploy with the agent, use the [CI/CD workflow](../../clusters/agent/ci_cd_tunnel.md). +To deploy with the agent, use the [CI/CD workflow](../../clusters/agent/ci_cd_workflow.md). A Kubernetes cluster can be the destination for a deployment job. If diff --git a/doc/user/project/import/github.md b/doc/user/project/import/github.md index 329d91916e8..f6abb31db0b 100644 --- a/doc/user/project/import/github.md +++ b/doc/user/project/import/github.md @@ -52,7 +52,7 @@ self-managed GitLab instance. pull requests) with matching GitLab users. - If you're importing to a self-managed GitLab instance, you can alternatively use the [GitHub Rake task](../../../administration/raketasks/github_import.md) to import - projects without the constraints of a [Sidekiq](../../../development/sidekiq_style_guide.md) worker. + projects without the constraints of a [Sidekiq](../../../development/sidekiq/index.md) worker. - If you're importing from GitHub Enterprise to your self-managed GitLab instance: - You must first enable [GitHub integration](../../../integration/github.md). - To import projects from GitHub Enterprise to GitLab.com, use the [Import API](../../../api/import.md). diff --git a/doc/user/project/time_tracking.md b/doc/user/project/time_tracking.md index 5f747d99ce7..0891e02f3f7 100644 --- a/doc/user/project/time_tracking.md +++ b/doc/user/project/time_tracking.md @@ -114,6 +114,18 @@ so if you remove more time than already entered, GitLab ignores the subtraction. To remove all the time spent at once, use the `/remove_time_spent` [quick action](quick_actions.md). +### Delete time spent + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/356796) in GitLab 15.0. + +A timelog is a single entry of time spent, either positive or negative. + +Prerequisites: + +- You must be the author of the timelog or have at least the Maintainer role for the project. + +You can [delete timelogs](../../api/graphql/reference/index.md#mutationtimelogdelete) using the GraphQL API. + ## View a time tracking report > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/271409) in GitLab 13.12. diff --git a/lib/api/members.rb b/lib/api/members.rb index 01e859c94c4..fbac6a96c1e 100644 --- a/lib/api/members.rb +++ b/lib/api/members.rb @@ -6,12 +6,14 @@ module API before { authenticate! } - feature_category :authentication_and_authorization urgency :low helpers ::API::Helpers::MembersHelpers - %w[group project].each do |source_type| + { + "group" => :subgroups, + "project" => :projects + }.each do |source_type, feature_category| params do requires :id, type: String, desc: "The #{source_type} ID" end @@ -27,7 +29,7 @@ module API use :pagination end - get ":id/members" do + get ":id/members", feature_category: feature_category do source = find_source(source_type, params[:id]) members = paginate(retrieve_members(source, params: params)) @@ -46,7 +48,7 @@ module API use :pagination end - get ":id/members/all" do + get ":id/members/all", feature_category: feature_category do source = find_source(source_type, params[:id]) members = paginate(retrieve_members(source, params: params, deep: true)) @@ -61,7 +63,7 @@ module API requires :user_id, type: Integer, desc: 'The user ID of the member' end # rubocop: disable CodeReuse/ActiveRecord - get ":id/members/:user_id" do + get ":id/members/:user_id", feature_category: feature_category do source = find_source(source_type, params[:id]) members = source_members(source) @@ -78,7 +80,7 @@ module API requires :user_id, type: Integer, desc: 'The user ID of the member' end # rubocop: disable CodeReuse/ActiveRecord - get ":id/members/all/:user_id" do + get ":id/members/all/:user_id", feature_category: feature_category do source = find_source(source_type, params[:id]) members = find_all_members(source) @@ -100,7 +102,7 @@ module API optional :tasks_project_id, type: Integer, desc: 'The project ID in which to create the task issues' end - post ":id/members" do + post ":id/members", feature_category: feature_category do source = find_source(source_type, params[:id]) authorize_admin_source!(source_type, source) @@ -123,7 +125,7 @@ module API optional :expires_at, type: DateTime, desc: 'Date string in the format YEAR-MONTH-DAY' end # rubocop: disable CodeReuse/ActiveRecord - put ":id/members/:user_id" do + put ":id/members/:user_id", feature_category: feature_category do source = find_source(source_type, params.delete(:id)) authorize_admin_source!(source_type, source) @@ -152,7 +154,7 @@ module API desc: 'Flag indicating if the removed member should be unassigned from any issues or merge requests within given group or project' end # rubocop: disable CodeReuse/ActiveRecord - delete ":id/members/:user_id" do + delete ":id/members/:user_id", feature_category: feature_category do source = find_source(source_type, params[:id]) member = source_members(source).find_by!(user_id: params[:user_id]) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 398e392277e..ab39790f02f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -729,7 +729,7 @@ module API params do requires :id, type: String, desc: 'ID of a project' end - get ':id/storage', feature_category: :projects do + get ':id/storage', feature_category: :source_code_management do authenticated_as_admin! present user_project, with: Entities::ProjectRepositoryStorage, current_user: current_user diff --git a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb index 80ca76ef37f..190e2fc22fb 100644 --- a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb +++ b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects.rb @@ -5,24 +5,24 @@ module Gitlab # A job to nullify duplicate runners_token_encrypted values in projects table in batches class ResetDuplicateCiRunnersTokenEncryptedValuesOnProjects class Project < ActiveRecord::Base # rubocop:disable Style/Documentation - include ::EachBatch + include EachBatch self.table_name = 'projects' - scope :base_query, -> do - where.not(runners_token_encrypted: nil) - end + scope :base_query, -> { where.not(runners_token_encrypted: nil) } end def perform(start_id, end_id) # Reset duplicate runner tokens that would prevent creating an unique index. + batch_records = Project.base_query.where(id: start_id..end_id) + duplicate_tokens = Project.base_query - .where(id: start_id..end_id) + .where(runners_token_encrypted: batch_records.select(:runners_token_encrypted).distinct) .group(:runners_token_encrypted) .having('COUNT(*) > 1') .pluck(:runners_token_encrypted) - Project.where(runners_token_encrypted: duplicate_tokens).update_all(runners_token_encrypted: nil) if duplicate_tokens.any? + batch_records.where(runners_token_encrypted: duplicate_tokens).update_all(runners_token_encrypted: nil) if duplicate_tokens.any? mark_job_as_succeeded(start_id, end_id) end @@ -30,7 +30,10 @@ module Gitlab private def mark_job_as_succeeded(*arguments) - Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded('ResetDuplicateCiRunnersTokenEncryptedValuesOnProjects', arguments) + ::Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded( + self.class.name.demodulize, + arguments + ) end end end diff --git a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects.rb b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects.rb index d87ce6c88d3..b58eefa0ab3 100644 --- a/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects.rb +++ b/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects.rb @@ -5,24 +5,24 @@ module Gitlab # A job to nullify duplicate ci_runners_token values in projects table in batches class ResetDuplicateCiRunnersTokenValuesOnProjects class Project < ActiveRecord::Base # rubocop:disable Style/Documentation - include ::EachBatch + include EachBatch self.table_name = 'projects' - scope :base_query, -> do - where.not(runners_token: nil) - end + scope :base_query, -> { where.not(runners_token: nil) } end def perform(start_id, end_id) # Reset duplicate runner tokens that would prevent creating an unique index. + batch_records = Project.base_query.where(id: start_id..end_id) + duplicate_tokens = Project.base_query - .where(id: start_id..end_id) + .where(runners_token: batch_records.select(:runners_token).distinct) .group(:runners_token) .having('COUNT(*) > 1') .pluck(:runners_token) - Project.where(runners_token: duplicate_tokens).update_all(runners_token: nil) if duplicate_tokens.any? + batch_records.where(runners_token: duplicate_tokens).update_all(runners_token: nil) if duplicate_tokens.any? mark_job_as_succeeded(start_id, end_id) end @@ -30,7 +30,10 @@ module Gitlab private def mark_job_as_succeeded(*arguments) - Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded('ResetDuplicateCiRunnerValuesTokensOnProjects', arguments) + ::Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded( + self.class.name.demodulize, + arguments + ) end end end diff --git a/package.json b/package.json index cb175f823ab..2d0748ff2a7 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "@gitlab/at.js": "1.5.7", "@gitlab/favicon-overlay": "2.0.0", "@gitlab/svgs": "2.8.0", - "@gitlab/ui": "38.8.1", + "@gitlab/ui": "39.0.0", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "6.1.4-7", "@rails/ujs": "6.1.4-7", @@ -205,7 +205,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.10.1", "@gitlab/eslint-plugin": "12.0.1", "@gitlab/stylelint-config": "4.0.0", - "@graphql-eslint/eslint-plugin": "3.0.0", + "@graphql-eslint/eslint-plugin": "3.10.2", "@testing-library/dom": "^7.16.2", "@types/jest": "^26.0.24", "@vue/test-utils": "1.3.0", diff --git a/qa/qa/page/project/pipeline_editor/show.rb b/qa/qa/page/project/pipeline_editor/show.rb index 1a8e1e07994..16bdbb54f95 100644 --- a/qa/qa/page/project/pipeline_editor/show.rb +++ b/qa/qa/page/project/pipeline_editor/show.rb @@ -12,7 +12,7 @@ module QA end view 'app/assets/javascripts/pipeline_editor/components/commit/commit_form.vue' do - element :target_branch_field, required: true + element :source_branch_field, required: true end view 'app/assets/javascripts/pipeline_editor/components/editor/ci_editor_header.vue' do @@ -57,8 +57,8 @@ module QA wait_for_requests end - def target_branch_name - find_element(:target_branch_field).value + def source_branch_name + find_element(:source_branch_field).value end def editing_content @@ -76,8 +76,8 @@ module QA wait_for_requests end - def set_target_branch(name) - find_element(:target_branch_field).fill_in(with: name) + def set_source_branch(name) + find_element(:source_branch_field).fill_in(with: name) end def current_branch diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb index 8d2af3ea0df..ac91a9dd2d3 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_branch_switcher_spec.rb @@ -73,7 +73,7 @@ module QA show.select_branch_from_dropdown(random_test_string) aggregate_failures do - expect(show.target_branch_name).to eq(random_test_string), 'Target branch field is not showing expected branch name.' + expect(show.source_branch_name).to eq(random_test_string), 'Branch field is not showing expected branch name.' expect(show.editing_content).to have_content(random_test_string), 'Editor content does not include expected test string.' end @@ -81,7 +81,7 @@ module QA show.select_branch_from_dropdown(project.default_branch) aggregate_failures do - expect(show.target_branch_name).to eq(project.default_branch), 'Target branch field is not showing expected branch name.' + expect(show.source_branch_name).to eq(project.default_branch), 'Branch field is not showing expected branch name.' expect(show.editing_content).to have_content(project.default_branch), 'Editor content does not include expected test string.' end end diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb index b9f616aa733..931bb97ba32 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/pipeline_editor_can_create_merge_request_spec.rb @@ -34,8 +34,8 @@ module QA expect(show).to have_no_new_mr_checkbox end - # The new MR checkbox is visible after a new target branch name is set - show.set_target_branch(SecureRandom.hex(10)) + # The new MR checkbox is visible after a new branch name is set + show.set_source_branch(SecureRandom.hex(10)) expect(show).to have_new_mr_checkbox show.select_new_mr_checkbox diff --git a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb index 00c5d4c74d4..d34df17c477 100644 --- a/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb +++ b/qa/qa/specs/features/browser_ui/4_verify/pipeline/update_ci_file_with_pipeline_editor_spec.rb @@ -53,13 +53,13 @@ module QA it 'creates new pipeline and target branch', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349005' do Page::Project::PipelineEditor::Show.perform do |show| show.write_to_editor(random_test_string) - show.set_target_branch(random_test_string) + show.set_source_branch(random_test_string) show.submit_changes Support::Waiter.wait_until { project.pipelines.size > 1 } aggregate_failures do - expect(show.target_branch_name).to eq(random_test_string) + expect(show.source_branch_name).to eq(random_test_string) expect(show.current_branch).to eq(random_test_string) expect(show.editing_content).to have_content(random_test_string) expect { show.pipeline_id }.to eventually_eq(project.pipelines.pluck(:id).max).within(max_duration: 60, sleep_interval: 3) diff --git a/spec/features/projects/ci/editor_spec.rb b/spec/features/projects/ci/editor_spec.rb index ad4381a526a..6fcdffeb801 100644 --- a/spec/features/projects/ci/editor_spec.rb +++ b/spec/features/projects/ci/editor_spec.rb @@ -53,7 +53,7 @@ RSpec.describe 'Pipeline Editor', :js do end it 'displays new branch as selected after commiting on a new branch' do - find('#target-branch-field').set('new_branch', clear: :backspace) + find('#source-branch-field').set('new_branch', clear: :backspace) page.within('#source-editor-') do find('textarea').send_keys '123' @@ -112,7 +112,7 @@ RSpec.describe 'Pipeline Editor', :js do it 'user who creates a MR is taken to the merge request page without warnings' do expect(page).not_to have_content('New merge request') - find_field('Target Branch').set 'new_branch' + find_field('Branch').set 'new_branch' find_field('Start a new merge request with these changes').click click_button 'Commit changes' diff --git a/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap b/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap index e508cddd6f9..a63cca006da 100644 --- a/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap +++ b/spec/frontend/content_editor/components/__snapshots__/toolbar_button_spec.js.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`content_editor/components/toolbar_button displays tertiary, small button with a provided label and icon 1`] = ` -"<b-button-stub size=\\"sm\\" variant=\\"default\\" type=\\"button\\" tag=\\"button\\" aria-label=\\"Bold\\" title=\\"Bold\\" class=\\"gl-button btn-default-tertiary btn-icon\\"> +exports[`content_editor/components/toolbar_button displays tertiary, medium button with a provided label and icon 1`] = ` +"<b-button-stub size=\\"md\\" variant=\\"default\\" type=\\"button\\" tag=\\"button\\" aria-label=\\"Bold\\" title=\\"Bold\\" class=\\"gl-button btn-default-tertiary btn-icon\\"> <!----> <gl-icon-stub name=\\"bold\\" size=\\"16\\" class=\\"gl-button-icon\\"></gl-icon-stub> <!----> diff --git a/spec/frontend/content_editor/components/code_block_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js index d3ab5bd762a..2323410992a 100644 --- a/spec/frontend/content_editor/components/code_block_bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/code_block_spec.js @@ -2,13 +2,13 @@ import { BubbleMenu } from '@tiptap/vue-2'; import { GlDropdown, GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui'; import Vue from 'vue'; import { mountExtended } from 'helpers/vue_test_utils_helper'; -import CodeBlockBubbleMenu from '~/content_editor/components/code_block_bubble_menu.vue'; +import CodeBlockBubbleMenu from '~/content_editor/components/bubble_menus/code_block.vue'; import eventHubFactory from '~/helpers/event_hub_factory'; import CodeBlockHighlight from '~/content_editor/extensions/code_block_highlight'; import codeBlockLanguageLoader from '~/content_editor/services/code_block_language_loader'; -import { createTestEditor, emitEditorEvent } from '../test_utils'; +import { createTestEditor, emitEditorEvent } from '../../test_utils'; -describe('content_editor/components/code_block_bubble_menu', () => { +describe('content_editor/components/bubble_menus/code_block', () => { let wrapper; let tiptapEditor; let bubbleMenu; diff --git a/spec/frontend/content_editor/components/formatting_bubble_menu_spec.js b/spec/frontend/content_editor/components/bubble_menus/formatting_spec.js index 192ddee78c6..889acd63be3 100644 --- a/spec/frontend/content_editor/components/formatting_bubble_menu_spec.js +++ b/spec/frontend/content_editor/components/bubble_menus/formatting_spec.js @@ -1,15 +1,15 @@ import { BubbleMenu } from '@tiptap/vue-2'; import { mockTracking } from 'helpers/tracking_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import FormattingBubbleMenu from '~/content_editor/components/formatting_bubble_menu.vue'; +import FormattingBubbleMenu from '~/content_editor/components/bubble_menus/formatting.vue'; import { BUBBLE_MENU_TRACKING_ACTION, CONTENT_EDITOR_TRACKING_LABEL, } from '~/content_editor/constants'; -import { createTestEditor } from '../test_utils'; +import { createTestEditor } from '../../test_utils'; -describe('content_editor/components/formatting_bubble_menu', () => { +describe('content_editor/components/bubble_menus/formatting', () => { let wrapper; let trackingSpy; let tiptapEditor; diff --git a/spec/frontend/content_editor/components/content_editor_spec.js b/spec/frontend/content_editor/components/content_editor_spec.js index 73fcfeab8bc..9ee3b017831 100644 --- a/spec/frontend/content_editor/components/content_editor_spec.js +++ b/spec/frontend/content_editor/components/content_editor_spec.js @@ -4,7 +4,7 @@ import ContentEditor from '~/content_editor/components/content_editor.vue'; import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue'; import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue'; import EditorStateObserver from '~/content_editor/components/editor_state_observer.vue'; -import FormattingBubbleMenu from '~/content_editor/components/formatting_bubble_menu.vue'; +import FormattingBubbleMenu from '~/content_editor/components/bubble_menus/formatting.vue'; import TopToolbar from '~/content_editor/components/top_toolbar.vue'; import LoadingIndicator from '~/content_editor/components/loading_indicator.vue'; import { emitEditorEvent } from '../test_utils'; diff --git a/spec/frontend/content_editor/components/toolbar_button_spec.js b/spec/frontend/content_editor/components/toolbar_button_spec.js index ce50482302d..1f1f7b338c6 100644 --- a/spec/frontend/content_editor/components/toolbar_button_spec.js +++ b/spec/frontend/content_editor/components/toolbar_button_spec.js @@ -46,7 +46,7 @@ describe('content_editor/components/toolbar_button', () => { wrapper.destroy(); }); - it('displays tertiary, small button with a provided label and icon', () => { + it('displays tertiary, medium button with a provided label and icon', () => { buildWrapper(); expect(findButton().html()).toMatchSnapshot(); diff --git a/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js b/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js index ce8e482cc16..92ce3925a90 100644 --- a/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js +++ b/spec/frontend/jobs/components/filtered_search/tokens/job_status_token_spec.js @@ -21,6 +21,7 @@ describe('Job Status Token', () => { value: { data: '', }, + cursorPosition: 'start', }; const createComponent = () => { diff --git a/spec/frontend/logs/components/tokens/token_with_loading_state_spec.js b/spec/frontend/logs/components/tokens/token_with_loading_state_spec.js index d98d7d05c92..f667a590a36 100644 --- a/spec/frontend/logs/components/tokens/token_with_loading_state_spec.js +++ b/spec/frontend/logs/components/tokens/token_with_loading_state_spec.js @@ -11,7 +11,10 @@ describe('TokenWithLoadingState', () => { const initWrapper = (props = {}, options) => { wrapper = shallowMount(TokenWithLoadingState, { - propsData: props, + propsData: { + cursorPosition: 'start', + ...props, + }, ...options, }); }; diff --git a/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js b/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js index 26b2f3b359f..d0c111bae2d 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js +++ b/spec/frontend/packages_and_registries/package_registry/components/list/tokens/package_type_token_spec.js @@ -11,7 +11,10 @@ describe('packages_filter', () => { const mountComponent = ({ attrs, listeners } = {}) => { wrapper = shallowMount(component, { - attrs, + attrs: { + cursorPosition: 'start', + ...attrs, + }, listeners, }); }; diff --git a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js index 59bd71b0e60..bec6c2a8d0c 100644 --- a/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js +++ b/spec/frontend/pipeline_editor/components/commit/commit_form_spec.js @@ -71,7 +71,7 @@ describe('Pipeline Editor | Commit Form', () => { expect(wrapper.emitted('submit')[0]).toEqual([ { message: mockCommitMessage, - targetBranch: mockDefaultBranch, + sourceBranch: mockDefaultBranch, openMergeRequest: false, }, ]); @@ -127,7 +127,7 @@ describe('Pipeline Editor | Commit Form', () => { expect(wrapper.emitted('submit')[0]).toEqual([ { message: anotherMessage, - targetBranch: anotherBranch, + sourceBranch: anotherBranch, openMergeRequest: true, }, ]); diff --git a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js index 42ae154fb5e..ba478363d04 100644 --- a/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js +++ b/spec/frontend/pipelines/tokens/pipeline_branch_name_token_spec.js @@ -34,6 +34,7 @@ describe('Pipeline Branch Name Token', () => { value: { data: '', }, + cursorPosition: 'start', }; const optionsWithDefaultBranchName = (options) => { diff --git a/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js index 684d2d0664a..b8abf2c1727 100644 --- a/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js +++ b/spec/frontend/pipelines/tokens/pipeline_source_token_spec.js @@ -20,6 +20,7 @@ describe('Pipeline Source Token', () => { value: { data: '', }, + cursorPosition: 'start', }; const createComponent = () => { diff --git a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js index 1db736ba01e..2c5fa8b00e2 100644 --- a/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js +++ b/spec/frontend/pipelines/tokens/pipeline_status_token_spec.js @@ -20,6 +20,7 @@ describe('Pipeline Status Token', () => { value: { data: '', }, + cursorPosition: 'start', }; const createComponent = () => { diff --git a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js index b03dbb73b95..596a9218c39 100644 --- a/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js +++ b/spec/frontend/pipelines/tokens/pipeline_tag_name_token_spec.js @@ -29,6 +29,7 @@ describe('Pipeline Branch Name Token', () => { value: { data: '', }, + cursorPosition: 'start', }; const createComponent = (options, data) => { diff --git a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js index 7ddbbb3b005..397dbdf95a9 100644 --- a/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js +++ b/spec/frontend/pipelines/tokens/pipeline_trigger_author_token_spec.js @@ -24,6 +24,7 @@ describe('Pipeline Trigger Author Token', () => { value: { data: '', }, + cursorPosition: 'start', }; const createComponent = (data) => { diff --git a/spec/frontend/sidebar/components/time_tracking/mock_data.js b/spec/frontend/sidebar/components/time_tracking/mock_data.js index 3f1b3fa8ec1..ba2781118d9 100644 --- a/spec/frontend/sidebar/components/time_tracking/mock_data.js +++ b/spec/frontend/sidebar/components/time_tracking/mock_data.js @@ -9,6 +9,7 @@ export const getIssueTimelogsQueryResponse = { nodes: [ { __typename: 'Timelog', + id: 'gid://gitlab/Timelog/18', timeSpent: 14400, user: { id: 'user-1', @@ -25,6 +26,7 @@ export const getIssueTimelogsQueryResponse = { }, { __typename: 'Timelog', + id: 'gid://gitlab/Timelog/20', timeSpent: 1800, user: { id: 'user-2', @@ -37,6 +39,7 @@ export const getIssueTimelogsQueryResponse = { }, { __typename: 'Timelog', + id: 'gid://gitlab/Timelog/25', timeSpent: 14400, user: { id: 'user-2', @@ -68,6 +71,7 @@ export const getMrTimelogsQueryResponse = { nodes: [ { __typename: 'Timelog', + id: 'gid://gitlab/Timelog/13', timeSpent: 1800, user: { id: 'user-1', @@ -84,6 +88,7 @@ export const getMrTimelogsQueryResponse = { }, { __typename: 'Timelog', + id: 'gid://gitlab/Timelog/22', timeSpent: 3600, user: { id: 'user-1', @@ -96,6 +101,7 @@ export const getMrTimelogsQueryResponse = { }, { __typename: 'Timelog', + id: 'gid://gitlab/Timelog/64', timeSpent: 300, user: { id: 'user-1', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js index 87066b70023..3f24d5df858 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/author_token_spec.js @@ -51,6 +51,7 @@ function createComponent(options = {}) { config, value, active, + cursorPosition: 'start', }, provide: { portalName: 'fake target', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js index af8a2a496ea..ca8cd419d87 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/base_token_spec.js @@ -78,6 +78,7 @@ const mockProps = { suggestionsLoading: false, defaultSuggestions: DEFAULT_NONE_ANY, getActiveTokenValue: (labels, data) => labels.find((label) => label.title === data), + cursorPosition: 'start', }; function createComponent({ diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js index 7a7db434052..7b495ec9bee 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/branch_token_spec.js @@ -39,6 +39,7 @@ function createComponent(options = {}) { config, value, active, + cursorPosition: 'start', }, provide: { portalName: 'fake target', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js index b163563cea4..dcb0d095b1b 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/emoji_token_spec.js @@ -45,6 +45,7 @@ function createComponent(options = {}) { config, value, active, + cursorPosition: 'start', }, provide: { portalName: 'fake target', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js index 52df27c2d00..f03a2e7934f 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/label_token_spec.js @@ -45,6 +45,7 @@ function createComponent(options = {}) { config, value, active, + cursorPosition: 'start', }, provide: { portalName: 'fake target', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js index de9ec863dd5..7c545f76c0b 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/milestone_token_spec.js @@ -42,6 +42,7 @@ function createComponent(options = {}) { config, value, active, + cursorPosition: 'start', }, provide: { portalName: 'fake target', diff --git a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js index 8be21b35414..4bbbaab9b7a 100644 --- a/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js +++ b/spec/frontend/vue_shared/components/filtered_search_bar/tokens/release_token_spec.js @@ -18,6 +18,7 @@ describe('ReleaseToken', () => { active: false, config, value, + cursorPosition: 'start', }, provide: { portalName: 'fake target', diff --git a/spec/graphql/mutations/timelogs/delete_spec.rb b/spec/graphql/mutations/timelogs/delete_spec.rb new file mode 100644 index 00000000000..5012d10f32e --- /dev/null +++ b/spec/graphql/mutations/timelogs/delete_spec.rb @@ -0,0 +1,91 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Mutations::Timelogs::Delete do + let_it_be(:author) { create(:user) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:administrator) { create(:user, :admin) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be_with_reload(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800) } + + let(:mutation) { described_class.new(object: nil, context: { current_user: current_user }, field: nil) } + let(:timelog_id) { timelog.to_global_id.to_s } + let(:mutation_arguments) { { id: timelog_id } } + + describe '#resolve' do + subject(:resolve) do + mutation.resolve(**mutation_arguments) + end + + context 'when the timelog id is not valid' do + let(:current_user) { author } + let(:timelog_id) { 'gid://gitlab/Timelog/%d' % non_existing_record_id } + + it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when the current user is not the timelog\'s author, not a maintainer and not an admin' do + let(:current_user) { create(:user) } + + it 'raises Gitlab::Graphql::Errors::ResourceNotAvailable' do + expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable) + end + end + + context 'when the current user is the timelog\'s author' do + let(:current_user) { author } + + it 'deletes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the deleted timelog' do + expect(subject[:timelog]).to eq(timelog) + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + + context 'when the current user is not the timelog\'s author but a maintainer of the project' do + let(:current_user) { maintainer } + + before do + project.add_maintainer(maintainer) + end + + it 'deletes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the deleted timelog' do + expect(subject[:timelog]).to eq(timelog) + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + + context 'when the current user is not the timelog\'s author, not a maintainer but an admin', :enable_admin_mode do + let(:current_user) { administrator } + + it 'deletes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the deleted timelog' do + expect(subject[:timelog]).to eq(timelog) + end + + it 'returns no errors' do + expect(subject[:errors]).to be_empty + end + end + end +end diff --git a/spec/graphql/types/timelog_type_spec.rb b/spec/graphql/types/timelog_type_spec.rb index dc1b1e2253e..56303e8c1ab 100644 --- a/spec/graphql/types/timelog_type_spec.rb +++ b/spec/graphql/types/timelog_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['Timelog'] do - let(:fields) { %i[spent_at time_spent user issue merge_request note summary] } + let(:fields) { %i[id spent_at time_spent user issue merge_request note summary] } it { expect(described_class.graphql_name).to eq('Timelog') } it { expect(described_class).to have_graphql_fields(fields) } diff --git a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects_spec.rb b/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects_spec.rb index d02f7245c15..71020746fa7 100644 --- a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects_spec.rb +++ b/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_encrypted_values_on_projects_spec.rb @@ -6,32 +6,47 @@ RSpec.describe Gitlab::BackgroundMigration::ResetDuplicateCiRunnersTokenEncrypte let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } - let(:perform) { described_class.new.perform(1, 4) } + subject(:background_migration) { described_class.new } before do namespaces.create!(id: 123, name: 'sample', path: 'sample') projects.create!(id: 1, namespace_id: 123, runners_token_encrypted: 'duplicate') projects.create!(id: 2, namespace_id: 123, runners_token_encrypted: 'a-runners-token') - projects.create!(id: 3, namespace_id: 123, runners_token_encrypted: 'duplicate') + projects.create!(id: 3, namespace_id: 123, runners_token_encrypted: 'duplicate-2') projects.create!(id: 4, namespace_id: 123, runners_token_encrypted: nil) projects.create!(id: 5, namespace_id: 123, runners_token_encrypted: 'duplicate-2') - projects.create!(id: 6, namespace_id: 123, runners_token_encrypted: 'duplicate-2') + projects.create!(id: 6, namespace_id: 123, runners_token_encrypted: 'duplicate') + projects.create!(id: 7, namespace_id: 123, runners_token_encrypted: 'another-runners-token') + projects.create!(id: 8, namespace_id: 123, runners_token_encrypted: 'another-runners-token') end describe '#up' do - before do - stub_const("#{described_class}::SUB_BATCH_SIZE", 2) - end - it 'nullifies duplicate tokens', :aggregate_failures do - perform + background_migration.perform(1, 2) + background_migration.perform(3, 4) - expect(projects.count).to eq(6) + expect(projects.count).to eq(8) expect(projects.all.pluck(:id, :runners_token_encrypted).to_h).to eq( - { 1 => nil, 2 => 'a-runners-token', 3 => nil, 4 => nil, 5 => 'duplicate-2', 6 => 'duplicate-2' } - ) - expect(projects.pluck(:runners_token_encrypted).uniq).to match_array [nil, 'a-runners-token', 'duplicate-2'] + { + 1 => nil, + 2 => 'a-runners-token', + 3 => nil, + 4 => nil, + 5 => 'duplicate-2', + 6 => 'duplicate', + 7 => 'another-runners-token', + 8 => 'another-runners-token' + }) + expect(projects.pluck(:runners_token_encrypted).uniq).to match_array [ + nil, 'a-runners-token', 'duplicate', 'duplicate-2', 'another-runners-token' + ] + end + + it 'does not touch projects outside id range' do + expect do + background_migration.perform(1, 2) + end.not_to change { projects.where(id: [3..8]).each(&:reload).map(&:updated_at) } end end end diff --git a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects_spec.rb b/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects_spec.rb index fd61047d851..7d3df69bee2 100644 --- a/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects_spec.rb +++ b/spec/lib/gitlab/background_migration/reset_duplicate_ci_runners_token_values_on_projects_spec.rb @@ -6,32 +6,47 @@ RSpec.describe Gitlab::BackgroundMigration::ResetDuplicateCiRunnersTokenValuesOn let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } - let(:perform) { described_class.new.perform(1, 4) } + subject(:background_migration) { described_class.new } before do namespaces.create!(id: 123, name: 'sample', path: 'sample') projects.create!(id: 1, namespace_id: 123, runners_token: 'duplicate') projects.create!(id: 2, namespace_id: 123, runners_token: 'a-runners-token') - projects.create!(id: 3, namespace_id: 123, runners_token: 'duplicate') + projects.create!(id: 3, namespace_id: 123, runners_token: 'duplicate-2') projects.create!(id: 4, namespace_id: 123, runners_token: nil) projects.create!(id: 5, namespace_id: 123, runners_token: 'duplicate-2') - projects.create!(id: 6, namespace_id: 123, runners_token: 'duplicate-2') + projects.create!(id: 6, namespace_id: 123, runners_token: 'duplicate') + projects.create!(id: 7, namespace_id: 123, runners_token: 'another-runners-token') + projects.create!(id: 8, namespace_id: 123, runners_token: 'another-runners-token') end describe '#up' do - before do - stub_const("#{described_class}::SUB_BATCH_SIZE", 2) - end - it 'nullifies duplicate tokens', :aggregate_failures do - perform + background_migration.perform(1, 2) + background_migration.perform(3, 4) - expect(projects.count).to eq(6) + expect(projects.count).to eq(8) expect(projects.all.pluck(:id, :runners_token).to_h).to eq( - { 1 => nil, 2 => 'a-runners-token', 3 => nil, 4 => nil, 5 => 'duplicate-2', 6 => 'duplicate-2' } - ) - expect(projects.pluck(:runners_token).uniq).to match_array [nil, 'a-runners-token', 'duplicate-2'] + { + 1 => nil, + 2 => 'a-runners-token', + 3 => nil, + 4 => nil, + 5 => 'duplicate-2', + 6 => 'duplicate', + 7 => 'another-runners-token', + 8 => 'another-runners-token' + }) + expect(projects.pluck(:runners_token).uniq).to match_array [ + nil, 'a-runners-token', 'duplicate', 'duplicate-2', 'another-runners-token' + ] + end + + it 'does not touch projects outside id range' do + expect do + background_migration.perform(1, 2) + end.not_to change { projects.where(id: [3..8]).each(&:reload).map(&:updated_at) } end end end diff --git a/spec/policies/timelog_policy_spec.rb b/spec/policies/timelog_policy_spec.rb new file mode 100644 index 00000000000..97e61cfe5ce --- /dev/null +++ b/spec/policies/timelog_policy_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe TimelogPolicy, models: true do + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} + + let(:user) { nil } + let(:policy) { described_class.new(user, timelog) } + + describe '#rules' do + context 'when user is anonymus' do + it 'prevents adimistration of timelog' do + expect(policy).to be_disallowed(:admin_timelog) + end + end + + context 'when user is the author of the timelog' do + let(:user) { author } + + it 'allows adimistration of timelog' do + expect(policy).to be_allowed(:admin_timelog) + end + end + + context 'when user is not the author of the timelog but maintainer of the project' do + let(:user) { create(:user) } + + before do + project.add_maintainer(user) + end + + it 'allows adimistration of timelog' do + expect(policy).to be_allowed(:admin_timelog) + end + end + + context 'when user is not the timelog\'s author, not a maintainer but an administrator', :enable_admin_mode do + let(:user) { create(:user, :admin) } + + it 'allows adimistration of timelog' do + expect(policy).to be_allowed(:admin_timelog) + end + end + + context 'when user is not the author of the timelog nor a maintainer of the project nor an administrator' do + let(:user) { create(:user) } + + it 'prevents adimistration of timelog' do + expect(policy).to be_disallowed(:admin_timelog) + end + end + end +end diff --git a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb index 12368e7e9c5..6818ba33e74 100644 --- a/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb +++ b/spec/requests/api/graphql/mutations/ci/runners_registration_token/reset_spec.rb @@ -64,11 +64,10 @@ RSpec.describe 'RunnersRegistrationTokenReset' do context 'applied to project' do let_it_be(:project) { create_default(:project) } + let(:target) { project } let(:input) { { type: 'PROJECT_TYPE', id: project.to_global_id.to_s } } - include_context 'when unauthorized', 'project' do - let(:target) { project } - end + include_context('when unauthorized', 'project') include_context 'when authorized', 'project' do let_it_be(:user) { project.first_owner } @@ -82,11 +81,10 @@ RSpec.describe 'RunnersRegistrationTokenReset' do context 'applied to group' do let_it_be(:group) { create_default(:group) } + let(:target) { group } let(:input) { { type: 'GROUP_TYPE', id: group.to_global_id.to_s } } - include_context 'when unauthorized', 'group' do - let(:target) { group } - end + include_context('when unauthorized', 'group') include_context 'when authorized', 'group' do let_it_be(:user) { create_default(:group_member, :owner, user: create(:user), group: group ).user } @@ -99,10 +97,12 @@ RSpec.describe 'RunnersRegistrationTokenReset' do context 'applied to instance' do before do - ApplicationSetting.create_from_defaults + target stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') end + let_it_be(:target) { ApplicationSetting.create_from_defaults } + let(:input) { { type: 'INSTANCE_TYPE' } } context 'when unauthorized' do diff --git a/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb new file mode 100644 index 00000000000..b674e77f093 --- /dev/null +++ b/spec/requests/api/graphql/mutations/timelogs/delete_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Delete a timelog' do + include GraphqlHelpers + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} + + let(:current_user) { nil } + let(:mutation) { graphql_mutation(:timelogDelete, { 'id' => timelog.to_global_id.to_s }) } + let(:mutation_response) { graphql_mutation_response(:timelog_delete) } + + context 'when the user is not allowed to delete a timelog' do + let(:current_user) { create(:user) } + + before do + post_graphql_mutation(mutation, current_user: current_user) + end + + it_behaves_like 'a mutation that returns a top-level access error' + end + + context 'when user has permissions to delete a timelog' do + let(:current_user) { author } + + it 'deletes the timelog' do + expect do + post_graphql_mutation(mutation, current_user: current_user) + end.to change(Timelog, :count).by(-1) + + expect(response).to have_gitlab_http_status(:success) + expect(mutation_response['timelog']).to include('id' => timelog.to_global_id.to_s) + end + end +end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index c322ec35e86..b8fe5964353 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -431,6 +431,19 @@ RSpec.describe SystemNoteService do end end + describe '.remove_timelog' do + let(:issue) { create(:issue, project: project) } + let(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} + + it 'calls TimeTrackingService' do + expect_next_instance_of(::SystemNotes::TimeTrackingService) do |service| + expect(service).to receive(:remove_timelog) + end + + described_class.remove_timelog(noteable, project, author, timelog) + end + end + describe '.handle_merge_request_draft' do it 'calls MergeRequestsService' do expect_next_instance_of(::SystemNotes::MergeRequestsService) do |service| diff --git a/spec/services/system_notes/time_tracking_service_spec.rb b/spec/services/system_notes/time_tracking_service_spec.rb index ec126cb5447..fdf18f4f29a 100644 --- a/spec/services/system_notes/time_tracking_service_spec.rb +++ b/spec/services/system_notes/time_tracking_service_spec.rb @@ -106,6 +106,30 @@ RSpec.describe ::SystemNotes::TimeTrackingService do end end + describe '#remove_timelog' do + subject { described_class.new(noteable: noteable, project: project, author: author).remove_timelog(timelog) } + + context 'when the timelog has a positive time spent value' do + let_it_be(:noteable, reload: true) { create(:issue, project: project) } + + let(:timelog) { create(:timelog, user: author, issue: noteable, time_spent: 1800, spent_at: '2022-03-30T00:00:00.000Z')} + + it 'sets the note text' do + expect(subject.note).to eq "deleted 30m of spent time from 2022-03-30" + end + end + + context 'when the timelog has a negative time spent value' do + let_it_be(:noteable, reload: true) { create(:issue, project: project) } + + let(:timelog) { create(:timelog, user: author, issue: noteable, time_spent: -1800, spent_at: '2022-03-30T00:00:00.000Z')} + + it 'sets the note text' do + expect(subject.note).to eq "deleted -30m of spent time from 2022-03-30" + end + end + end + describe '#change_time_spent' do subject { described_class.new(noteable: noteable, project: project, author: author).change_time_spent } diff --git a/spec/services/timelogs/delete_service_spec.rb b/spec/services/timelogs/delete_service_spec.rb new file mode 100644 index 00000000000..c52cebdc5bf --- /dev/null +++ b/spec/services/timelogs/delete_service_spec.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Timelogs::DeleteService do + let_it_be(:author) { create(:user) } + let_it_be(:project) { create(:project, :public) } + let_it_be(:issue) { create(:issue, project: project) } + let_it_be(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} + + let(:service) { described_class.new(timelog, user) } + + describe '#execute' do + subject { service.execute } + + context 'when the timelog exists' do + let(:user) { author } + + it 'removes the timelog' do + expect { subject }.to change { Timelog.count }.by(-1) + end + + it 'returns the removed timelog' do + expect(subject).to be_success + expect(subject.payload).to eq(timelog) + end + end + + context 'when the timelog does not exist' do + let(:user) { create(:user) } + let!(:timelog) { nil } + + it 'returns an error' do + expect(subject).to be_error + expect(subject.message).to eq('Timelog doesn\'t exist or you don\'t have permission to delete it') + expect(subject.http_status).to eq(404) + end + end + + context 'when the user does not have permission' do + let(:user) { create(:user) } + + it 'returns an error' do + expect(subject).to be_error + expect(subject.message).to eq('Timelog doesn\'t exist or you don\'t have permission to delete it') + expect(subject.http_status).to eq(404) + end + end + + context 'when the timelog deletion fails' do + let(:user) { author } + let!(:timelog) { create(:timelog, user: author, issue: issue, time_spent: 1800)} + + before do + allow(timelog).to receive(:destroy).and_return(false) + end + + it 'returns an error' do + expect(subject).to be_error + expect(subject.message).to eq('Failed to remove timelog') + expect(subject.http_status).to eq(400) + end + end + end +end diff --git a/yarn.lock b/yarn.lock index 382eeb7d040..a49a2e75d03 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,14 +34,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" - integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== - dependencies: - "@babel/highlight" "^7.16.0" - -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.16.7": +"@babel/code-frame@7.16.7", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== @@ -90,10 +83,10 @@ dependencies: eslint-rule-composer "^0.3.0" -"@babel/generator@^7.15.4", "@babel/generator@^7.17.3", "@babel/generator@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" - integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== +"@babel/generator@^7.17.7", "@babel/generator@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.9.tgz#f4af9fd38fa8de143c29fce3f71852406fc1e2fc" + integrity sha512-rAdDousTwxbIxbz5I7GEQ3lUip+xVCXooZNbsydCWs3xA7ZsYOv+CFRdzGxRX78BmQHu9B1Eso59AOZQOJDEdQ== dependencies: "@babel/types" "^7.17.0" jsesc "^2.5.1" @@ -169,23 +162,22 @@ "@babel/traverse" "^7.10.1" "@babel/types" "^7.10.1" -"@babel/helper-function-name@^7.10.1", "@babel/helper-function-name@^7.15.4", "@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== +"@babel/helper-function-name@^7.10.1", "@babel/helper-function-name@^7.15.4", "@babel/helper-function-name@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz#136fcd54bc1da82fcb47565cf16fd8e444b1ff12" + integrity sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg== dependencies: - "@babel/helper-get-function-arity" "^7.16.7" "@babel/template" "^7.16.7" - "@babel/types" "^7.16.7" + "@babel/types" "^7.17.0" -"@babel/helper-get-function-arity@^7.10.1", "@babel/helper-get-function-arity@^7.16.7": +"@babel/helper-get-function-arity@^7.10.1": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== dependencies: "@babel/types" "^7.16.7" -"@babel/helper-hoist-variables@^7.10.1", "@babel/helper-hoist-variables@^7.15.4", "@babel/helper-hoist-variables@^7.16.7": +"@babel/helper-hoist-variables@^7.10.1", "@babel/helper-hoist-variables@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== @@ -281,7 +273,7 @@ dependencies: "@babel/types" "^7.16.7" -"@babel/helper-validator-identifier@^7.14.9", "@babel/helper-validator-identifier@^7.15.7", "@babel/helper-validator-identifier@^7.16.7": +"@babel/helper-validator-identifier@^7.15.7", "@babel/helper-validator-identifier@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== @@ -310,7 +302,7 @@ "@babel/traverse" "^7.17.3" "@babel/types" "^7.17.0" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.0", "@babel/highlight@^7.16.7": +"@babel/highlight@^7.10.4", "@babel/highlight@^7.16.7": version "7.16.10" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== @@ -319,15 +311,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@7.15.8": - version "7.15.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.15.8.tgz#7bacdcbe71bdc3ff936d510c15dcea7cf0b99016" - integrity sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA== - -"@babel/parser@^7.1.0", "@babel/parser@^7.15.4", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3", "@babel/parser@^7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" - integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== +"@babel/parser@^7.1.0", "@babel/parser@^7.16.7", "@babel/parser@^7.16.8", "@babel/parser@^7.17.8", "@babel/parser@^7.17.9": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.9.tgz#9c94189a6062f0291418ca021077983058e171ef" + integrity sha512-vqUSBLP8dQHFPdPi9bc5GK9vRkYHJ49fsZdtoJ8EQ8ibpwk5rPKfvNIwChB0KVXcIjcepEBBd2VHC5r9Gy8ueg== "@babel/plugin-proposal-async-generator-functions@^7.10.1": version "7.10.1" @@ -872,46 +859,23 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@7.15.4": - version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.15.4.tgz#ff8510367a144bfbff552d9e18e28f3e2889c22d" - integrity sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA== - dependencies: - "@babel/code-frame" "^7.14.5" - "@babel/generator" "^7.15.4" - "@babel/helper-function-name" "^7.15.4" - "@babel/helper-hoist-variables" "^7.15.4" - "@babel/helper-split-export-declaration" "^7.15.4" - "@babel/parser" "^7.15.4" - "@babel/types" "^7.15.4" - debug "^4.1.0" - globals "^11.1.0" - -"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.15.4", "@babel/traverse@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== +"@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.15.4", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.3": + version "7.17.9" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.9.tgz#1f9b207435d9ae4a8ed6998b2b82300d83c37a0d" + integrity sha512-PQO8sDIJ8SIwipTPiR71kJQCKQYB5NGImbOviK8K+kg5xkNSYXLBupuX9QhatFowrsvo9Hj8WgArg3W7ijNAQw== dependencies: "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" + "@babel/generator" "^7.17.9" "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" + "@babel/helper-function-name" "^7.17.9" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" + "@babel/parser" "^7.17.9" "@babel/types" "^7.17.0" debug "^4.1.0" globals "^11.1.0" -"@babel/types@7.15.6": - version "7.15.6" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.15.6.tgz#99abdc48218b2881c058dd0a7ab05b99c9be758f" - integrity sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig== - dependencies: - "@babel/helper-validator-identifier" "^7.14.9" - to-fast-properties "^2.0.0" - -"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.15.4", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.0.0-beta.49", "@babel/types@^7.10.1", "@babel/types@^7.10.2", "@babel/types@^7.15.4", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.17.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== @@ -1010,10 +974,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.8.0.tgz#b32f3672d9cffa2d59f5edb6828ae931a36d220f" integrity sha512-N1D6q5xKze3HwPMjLnsXMZOPQGX4CT+jEQgZYkB8akVx/rqT/YSZ9pZaxWoRdq1Tiwi9B2ArctopRgNiN8fqdw== -"@gitlab/ui@38.8.1": - version "38.8.1" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-38.8.1.tgz#f4892ffd51c4cacf30cb94ffca31487afdac2b0c" - integrity sha512-eTGt+LODmox1GZRkLfFH9/zl4dG9/6ewpYzXvIo1B4uzHz27lhEgVSM57nZRPXmk4o05LQMnm6eelHoBdMX13g== +"@gitlab/ui@39.0.0": + version "39.0.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-39.0.0.tgz#12e658fe84e94b494fec926d824989cbf1334e5c" + integrity sha512-QsD8Os3eXgIq4xlxIvhxmhKPDWYyqCAlDGMw4afo2ynQriIg73KoV6Me3QRwGhaNfzO77Sk9reRxdHLG3L+iNA== dependencies: "@babel/standalone" "^7.0.0" bootstrap-vue "2.20.1" @@ -1033,162 +997,164 @@ resolved "https://registry.yarnpkg.com/@gitlab/visual-review-tools/-/visual-review-tools-1.6.1.tgz#0d8f3ff9f51b05f7c80b9a107727703d48997e4e" integrity sha512-vY8K1igwZFoEOmU0h4E7XTLlilsQ4ylPr27O01UsSe6ZTKi6oEMREsRAEpNIUgRlxUARCsf+Opp4pgSFzFkFcw== -"@graphql-eslint/eslint-plugin@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@graphql-eslint/eslint-plugin/-/eslint-plugin-3.0.0.tgz#d0f7d6e4f6f772312500abbf6c94c59d5cb52c12" - integrity sha512-EfkMABrCbWhhArEGg4w2r/z8sEPp1fL0Ar3xFWBX9c11t5+T5XqGAGVxUi5vuEx9PrSqhYisPrxTibqNoxuEzQ== - dependencies: - "@babel/code-frame" "7.16.0" - "@graphql-tools/code-file-loader" "7.2.2" - "@graphql-tools/graphql-tag-pluck" "7.1.3" - "@graphql-tools/import" "6.6.1" - "@graphql-tools/utils" "8.5.3" - graphql-config "4.1.0" +"@graphql-eslint/eslint-plugin@3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@graphql-eslint/eslint-plugin/-/eslint-plugin-3.10.2.tgz#b8b271aef219623e6a0517cfababe6063072077f" + integrity sha512-UJwpeMC4q3/Ofeh3aOp9aJOtomJjQEz7zk8lqXeexqkDBXI0d9dedYlWWL5MqcFhKxtBxsU5xq0w4th0c+0aAQ== + dependencies: + "@babel/code-frame" "7.16.7" + "@graphql-tools/code-file-loader" "^7.2.8" + "@graphql-tools/graphql-tag-pluck" "^7.2.0" + "@graphql-tools/utils" "^8.6.5" + chalk "4.1.2" + debug "4.3.4" + fast-glob "3.2.11" + graphql-config "^4.3.0" graphql-depth-limit "1.1.0" lodash.lowercase "4.3.0" -"@graphql-tools/batch-execute@^8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-8.3.1.tgz#0b74c54db5ac1c5b9a273baefc034c2343ebbb74" - integrity sha512-63kHY8ZdoO5FoeDXYHnAak1R3ysMViMPwWC2XUblFckuVLMUPmB2ONje8rjr2CvzWBHAW8c1Zsex+U3xhKtGIA== +"@graphql-tools/batch-execute@8.4.1": + version "8.4.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/batch-execute/-/batch-execute-8.4.1.tgz#bc5e96ad22c545676da523bae3c3dc94e57bdf3e" + integrity sha512-63+lNWrwXmofjZVa7ML+n9CBviClF3K+RP3Xx3hxGQ8BrhvB1pWS1yzaUZqrkiiKdTu1v3mJGVfmooHwzlyPwQ== dependencies: - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/utils" "8.6.5" dataloader "2.0.0" tslib "~2.3.0" value-or-promise "1.0.11" -"@graphql-tools/code-file-loader@7.2.2": - version "7.2.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-7.2.2.tgz#79f8ce5723ee87ecb4d490d1497ac7e616340358" - integrity sha512-AADyxqipGWLBl4N59CGPgv3i35UF1fQpJvbC5a6TXmcppnghD2olDLewOh1pIQrwxGAAh1S75XVIi28PTKYZhg== +"@graphql-tools/code-file-loader@^7.2.8": + version "7.2.10" + resolved "https://registry.yarnpkg.com/@graphql-tools/code-file-loader/-/code-file-loader-7.2.10.tgz#cdae206399061b198652964213b32309e5980af1" + integrity sha512-41QkLztHhoDXBp2EtbKwQNQHv4HEDzpEmbOD0y3OVOXf8TBVUnFUMlnGn77a6f4zVi3rHWxHgJJ79iyJ0MYQ5w== dependencies: - "@graphql-tools/graphql-tag-pluck" "^7.1.3" - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/graphql-tag-pluck" "7.2.2" + "@graphql-tools/utils" "8.6.5" globby "^11.0.3" tslib "~2.3.0" unixify "^1.0.0" -"@graphql-tools/delegate@^8.4.1", "@graphql-tools/delegate@^8.4.2": - version "8.4.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-8.4.2.tgz#a61d45719855720304e3656800342cfa17d82558" - integrity sha512-CjggOhiL4WtyG2I3kux+1/p8lQxSFHBj0gwa0NxnQ6Vsnpw7Ig5VP1ovPnitFuBv2k4QdC37Nj2xv2n7DRn8fw== +"@graphql-tools/delegate@8.7.1": + version "8.7.1" + resolved "https://registry.yarnpkg.com/@graphql-tools/delegate/-/delegate-8.7.1.tgz#f30b9d035a76dc7a8e9292f31bb073fb4d6d9d83" + integrity sha512-e98/NRaOH5wQy624bRd5i5qUKz5tCs8u4xBmxW89d7t6V6CveXj7pvAgmnR9DbwOkO6IA3P799p/aa/YG/pWTA== dependencies: - "@graphql-tools/batch-execute" "^8.3.1" - "@graphql-tools/schema" "^8.3.1" - "@graphql-tools/utils" "^8.5.3" + "@graphql-tools/batch-execute" "8.4.1" + "@graphql-tools/schema" "8.3.6" + "@graphql-tools/utils" "8.6.5" dataloader "2.0.0" + graphql-executor "0.0.22" tslib "~2.3.0" value-or-promise "1.0.11" -"@graphql-tools/graphql-file-loader@^7.3.2": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.3.3.tgz#7cee2f84f08dc13fa756820b510248b857583d36" - integrity sha512-6kUJZiNpYKVhum9E5wfl5PyLLupEDYdH7c8l6oMrk6c7EPEVs6iSUyB7yQoWrtJccJLULBW2CRQ5IHp5JYK0mA== +"@graphql-tools/graphql-file-loader@^7.3.7": + version "7.3.7" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.3.7.tgz#f5cb05b0e3cd462d74eae47c5b9c08ed6b989837" + integrity sha512-fwXLycYvabPhusGtYuFrOPbjeIvLWr6viGkQc9KmiBm2Z2kZrlNRNUlYkXXRzMoiqRkzqFJYhOgWDE7LsOnbjw== dependencies: - "@graphql-tools/import" "^6.5.7" - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/import" "6.6.9" + "@graphql-tools/utils" "8.6.5" globby "^11.0.3" tslib "~2.3.0" unixify "^1.0.0" -"@graphql-tools/graphql-tag-pluck@7.1.3", "@graphql-tools/graphql-tag-pluck@^7.1.3": - version "7.1.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.1.3.tgz#2c638aac84f279f95bf3da50b71f2b4b82641539" - integrity sha512-zxVYLiAnNxFg6bnDZdNpLJNfjf6GHYLQsVHDcbYyQcWJzIaeWPylX/Q1gyvw8MFO4ICYExNPqgBA/is2kZBlHw== +"@graphql-tools/graphql-tag-pluck@7.2.2", "@graphql-tools/graphql-tag-pluck@^7.2.0": + version "7.2.2" + resolved "https://registry.yarnpkg.com/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.2.2.tgz#449bb0516a2aceb9c0251c321c8cde46c7b42b7d" + integrity sha512-5gYk6Cj35eU6N9+2WtV4tsCcJACVPK2F3+xci2WgoPrDZXYQshx6tyuIQIFszyhxWNa1KViwCZyxVy6U1UnqzA== dependencies: - "@babel/parser" "7.15.8" - "@babel/traverse" "7.15.4" - "@babel/types" "7.15.6" - "@graphql-tools/utils" "^8.5.1" + "@babel/parser" "^7.16.8" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + "@graphql-tools/utils" "8.6.5" tslib "~2.3.0" -"@graphql-tools/import@6.6.1", "@graphql-tools/import@^6.5.7": - version "6.6.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-6.6.1.tgz#2a7e1ceda10103ffeb8652a48ddc47150b035485" - integrity sha512-i9WA6k+erJMci822o9w9DoX+uncVBK60LGGYW8mdbhX0l7wEubUpA000thJ1aarCusYh0u+ZT9qX0HyVPXu25Q== +"@graphql-tools/import@6.6.9": + version "6.6.9" + resolved "https://registry.yarnpkg.com/@graphql-tools/import/-/import-6.6.9.tgz#53e1517074c756b5191d23d4f1528246913d44ba" + integrity sha512-sKaLqvPmNLQlY4te+nnBhRrf5WBISoiyVkbriCLz0kHw805iHdJaU2KxUoHsRTR7WlYq0g9gzB0oVaRh99Q5aA== dependencies: - "@graphql-tools/utils" "8.5.3" + "@graphql-tools/utils" "8.6.5" resolve-from "5.0.0" tslib "~2.3.0" -"@graphql-tools/json-file-loader@^7.3.2": - version "7.3.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-7.3.3.tgz#45cfde77b9dc4ab6c21575305ae537d2814d237f" - integrity sha512-CN2Qk9rt+Gepa3rb3X/mpxYA5MIYLwZBPj2Njw6lbZ6AaxG+O1ArDCL5ACoiWiBimn1FCOM778uhRM9znd0b3Q== +"@graphql-tools/json-file-loader@^7.3.7": + version "7.3.7" + resolved "https://registry.yarnpkg.com/@graphql-tools/json-file-loader/-/json-file-loader-7.3.7.tgz#3ddae0b15d3c57d1980fa5203541c2e6cd6a5ff4" + integrity sha512-dm0LcfiWYin7cUR4RWC33C9bNppujvSU7hwTH+sHmSguNnat9Kn8dBntVSgrY3qCbKuGfz/PshQHIODXrRwAKg== dependencies: - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/utils" "8.6.5" globby "^11.0.3" tslib "~2.3.0" unixify "^1.0.0" -"@graphql-tools/load@^7.4.1": - version "7.4.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-7.4.1.tgz#aa572fcef11d6028097b6ef39c13fa9d62e5a441" - integrity sha512-UvBodW5hRHpgBUBVz5K5VIhJDOTFIbRRAGD6sQ2l9J5FDKBEs3u/6JjZDzbdL96br94D5cEd2Tk6auaHpTn7mQ== +"@graphql-tools/load@^7.5.5": + version "7.5.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/load/-/load-7.5.6.tgz#d0ee8149ba4cbc799dbeae30e4843144773f8296" + integrity sha512-IocEP4METGdbDzV44VaeiXO387NOYSW4cTuBP8qybHZX0XlIp8bEv7c8GKS3m8DeRop/9SnOL7HyiAfNMA4Chg== dependencies: - "@graphql-tools/schema" "8.3.1" - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/schema" "8.3.6" + "@graphql-tools/utils" "8.6.5" p-limit "3.1.0" tslib "~2.3.0" -"@graphql-tools/merge@^8.2.1": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.1.tgz#bf83aa06a0cfc6a839e52a58057a84498d0d51ff" - integrity sha512-Q240kcUszhXiAYudjuJgNuLgy9CryDP3wp83NOZQezfA6h3ByYKU7xI6DiKrdjyVaGpYN3ppUmdj0uf5GaXzMA== +"@graphql-tools/merge@8.2.6", "@graphql-tools/merge@^8.2.6": + version "8.2.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/merge/-/merge-8.2.6.tgz#7fb615fa9c143c3151ff025e501d52bd48186d19" + integrity sha512-dkwTm4czMISi/Io47IVvq2Fl9q4TIGKpJ0VZjuXYdEFkECyH6A5uwxZfPVandZG+gQs8ocFFoa6RisiUJLZrJw== dependencies: - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/utils" "8.6.5" tslib "~2.3.0" -"@graphql-tools/schema@8.3.1", "@graphql-tools/schema@^8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.1.tgz#1ee9da494d2da457643b3c93502b94c3c4b68c74" - integrity sha512-3R0AJFe715p4GwF067G5i0KCr/XIdvSfDLvTLEiTDQ8V/hwbOHEKHKWlEBHGRQwkG5lwFQlW1aOn7VnlPERnWQ== +"@graphql-tools/schema@8.3.6": + version "8.3.6" + resolved "https://registry.yarnpkg.com/@graphql-tools/schema/-/schema-8.3.6.tgz#80cfe3eba53eb6390a60a30078d7efbdaa5cc0b7" + integrity sha512-7tWYRQ8hB/rv2zAtv2LtnQl4UybyJPtRz/VLKRmgi7+F5t8iYBahmmsxMDAYMWMmWMqEDiKk54TvAes+J069rQ== dependencies: - "@graphql-tools/merge" "^8.2.1" - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/merge" "8.2.6" + "@graphql-tools/utils" "8.6.5" tslib "~2.3.0" value-or-promise "1.0.11" -"@graphql-tools/url-loader@^7.4.2": - version "7.5.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-7.5.2.tgz#fb3737fd1269ab61b195b63052179b6049d90ce1" - integrity sha512-EilHqbhUY/qg55SSEdklDhPXgSz9+9a63SX3mcD8J2qwZHJD/wOLcyKs8m6BXfuGwUiuB0j3fmDSEVmva2onBg== +"@graphql-tools/url-loader@^7.9.7": + version "7.9.8" + resolved "https://registry.yarnpkg.com/@graphql-tools/url-loader/-/url-loader-7.9.8.tgz#8e50ca05fb670bf91b98abdcb5d8d9cb116003f3" + integrity sha512-nRMXwwoIDLt7ohBWvKKjEEH61YS1nnWs6BVgGStePfmRGrhxECpLWmfAmKLNXPqDJN7Nu6ykFJYjt65j5l6qsw== dependencies: - "@graphql-tools/delegate" "^8.4.1" - "@graphql-tools/utils" "^8.5.1" - "@graphql-tools/wrap" "^8.3.1" - "@n1ru4l/graphql-live-query" "0.9.0" - "@types/websocket" "1.0.4" + "@graphql-tools/delegate" "8.7.1" + "@graphql-tools/utils" "8.6.5" + "@graphql-tools/wrap" "8.4.10" + "@n1ru4l/graphql-live-query" "^0.9.0" + "@types/websocket" "^1.0.4" "@types/ws" "^8.0.0" - cross-undici-fetch "^0.0.20" + cross-undici-fetch "^0.1.19" dset "^3.1.0" - extract-files "11.0.0" + extract-files "^11.0.0" graphql-sse "^1.0.1" graphql-ws "^5.4.1" - isomorphic-ws "4.0.1" - meros "1.1.4" + isomorphic-ws "^4.0.1" + meros "^1.1.4" subscriptions-transport-ws "^0.11.0" - sync-fetch "0.3.1" - tslib "~2.3.0" - valid-url "1.0.9" - value-or-promise "1.0.11" - ws "8.2.3" + sync-fetch "^0.3.1" + tslib "^2.3.0" + value-or-promise "^1.0.11" + ws "^8.3.0" -"@graphql-tools/utils@8.5.3", "@graphql-tools/utils@^8.5.1", "@graphql-tools/utils@^8.5.3": - version "8.5.3" - resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.5.3.tgz#404062e62cae9453501197039687749c4885356e" - integrity sha512-HDNGWFVa8QQkoQB0H1lftvaO1X5xUaUDk1zr1qDe0xN1NL0E/CrQdJ5UKLqOvH4hkqVUPxQsyOoAZFkaH6rLHg== +"@graphql-tools/utils@8.6.5", "@graphql-tools/utils@^8.6.5": + version "8.6.5" + resolved "https://registry.yarnpkg.com/@graphql-tools/utils/-/utils-8.6.5.tgz#ac04571b03f854c7a938b2ab700516a6c6d32335" + integrity sha512-mjOtaWiS2WIqRz/cq5gaeM3sVrllcu2xbtHROw1su1v3xWa3D3dKgn8Lrl7+tvWs5WUVySsBss/VZ3WdoPkCrA== dependencies: tslib "~2.3.0" -"@graphql-tools/wrap@^8.3.1": - version "8.3.2" - resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-8.3.2.tgz#d3bcecb7529d071e4ecc4dfc75b9566e3da79d4f" - integrity sha512-7DcOBFB+Dd84x9dxSm7qS4iJONMyfLnCJb8A19vGPffpu4SMJ3sFcgwibKFu5l6mMUiigKgXna2RRgWI+02bKQ== +"@graphql-tools/wrap@8.4.10": + version "8.4.10" + resolved "https://registry.yarnpkg.com/@graphql-tools/wrap/-/wrap-8.4.10.tgz#010be7d4bafa5d79cd1917c65d09f2682bcb9d54" + integrity sha512-1/pcKRDTGIUspUl6uhlfQ0u1l4j15TVGkOkijI+gX25Q9sfAJclT0bovKBksP39G6v4hZnolpOU2txJ47MxxEg== dependencies: - "@graphql-tools/delegate" "^8.4.2" - "@graphql-tools/schema" "^8.3.1" - "@graphql-tools/utils" "^8.5.3" + "@graphql-tools/delegate" "8.7.1" + "@graphql-tools/schema" "8.3.6" + "@graphql-tools/utils" "8.6.5" tslib "~2.3.0" value-or-promise "1.0.11" @@ -1431,7 +1397,7 @@ resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2" integrity sha512-M/BexG/p05C5lFfMunxo/QcgIJnMT2vDVCd00wNqK2ImZONIlEETZwWJu1QtLxtmYlSHlCFl3JNzp0tLe7OJ5g== -"@n1ru4l/graphql-live-query@0.9.0": +"@n1ru4l/graphql-live-query@^0.9.0": version "0.9.0" resolved "https://registry.yarnpkg.com/@n1ru4l/graphql-live-query/-/graphql-live-query-0.9.0.tgz#defaebdd31f625bee49e6745934f36312532b2bc" integrity sha512-BTpWy1e+FxN82RnLz4x1+JcEewVdfmUhV1C6/XYD5AjS7PQp9QFF7K8bCD6gzPTr2l+prvqOyVueQhFJxB1vfg== @@ -2210,10 +2176,10 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== -"@types/websocket@1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.4.tgz#1dc497280d8049a5450854dd698ee7e6ea9e60b8" - integrity sha512-qn1LkcFEKK8RPp459jkjzsfpbsx36BBt3oC3pITYtkoBw/aVX+EZFa5j3ThCRTNpLFvIMr5dSTD4RaMdilIOpA== +"@types/websocket@^1.0.4": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/websocket/-/websocket-1.0.5.tgz#3fb80ed8e07f88e51961211cd3682a3a4a81569c" + integrity sha512-NbsqiNX9CnEfC1Z0Vf4mE1SgAJ07JnRYcNex7AJ9zAVzmiGHmjKFEk7O4TJIsgv2B1sLEb6owKFZrACwdYngsQ== dependencies: "@types/node" "*" @@ -3416,6 +3382,14 @@ catharsis@~0.8.9: dependencies: underscore-contrib "~0.3.0" +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3433,14 +3407,6 @@ chalk@^3.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -3679,7 +3645,7 @@ colorette@^2.0.10, colorette@^2.0.14: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4023,15 +3989,17 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -cross-undici-fetch@^0.0.20: - version "0.0.20" - resolved "https://registry.yarnpkg.com/cross-undici-fetch/-/cross-undici-fetch-0.0.20.tgz#6b7c5ac82a3601edd439f37275ac0319d77a120a" - integrity sha512-5d3WBC4VRHpFndECK9bx4TngXrw0OUXdhX561Ty1ZoqMASz9uf55BblhTC1CO6GhMWnvk9SOqYEXQliq6D2P4A== +cross-undici-fetch@^0.1.19: + version "0.1.28" + resolved "https://registry.yarnpkg.com/cross-undici-fetch/-/cross-undici-fetch-0.1.28.tgz#40b7071b9ab2d1d6aff889836205e1972092e8d1" + integrity sha512-/nLMyVE5IC9PQdBtmgjpGZfK0wo8UupomAPx+7HlbEgVDkZOa9xCiZP9goo5aLYofP0gHXgovjXdXrE2obANag== dependencies: abort-controller "^3.0.0" - form-data "^4.0.0" - node-fetch "^2.6.5" - undici "^4.9.3" + form-data-encoder "^1.7.1" + formdata-node "^4.3.1" + node-fetch "^2.6.7" + undici "^5.0.0" + web-streams-polyfill "^3.2.0" crypt@~0.0.1: version "0.0.2" @@ -4732,6 +4700,13 @@ debug@3.1.0: dependencies: ms "2.0.0" +debug@4.3.4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.3: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.1.1, debug@^3.2.6, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -4739,13 +4714,6 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.6, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.3: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" @@ -5790,16 +5758,16 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" -extract-files@11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" - integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== - extract-files@^10.0.0: version "10.0.0" resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-10.0.0.tgz#228b1da1d910971cf8d7f1ed259653c6001ba5ad" integrity sha512-4KXYOSf8SlMlQCj94Ygy89xIZU2GTs0HU2Nz9mG2/F5TKsHyq/3sDWGjHgHmfw9RhXF3hO+pBKyC6JfIHD52bw== +extract-files@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/extract-files/-/extract-files-11.0.0.tgz#b72d428712f787eef1f5193aff8ab5351ca8469a" + integrity sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ== + extract-from-css@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/extract-from-css/-/extract-from-css-0.4.4.tgz#1ea7df2e7c7c6eb9922fa08e8adaea486f6f8f92" @@ -5822,7 +5790,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.2.4, fast-glob@^3.2.9: +fast-glob@3.2.11, fast-glob@^3.2.11, fast-glob@^3.2.4, fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== @@ -6019,14 +5987,10 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" +form-data-encoder@^1.7.1: + version "1.7.2" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" + integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== form-data@~2.3.2: version "2.3.3" @@ -6042,6 +6006,14 @@ format@^0.2.0: resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" integrity sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs= +formdata-node@^4.3.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.3.2.tgz#0262e94931e36db7239c2b08bdb6aaf18ec47d21" + integrity sha512-k7lYJyzDOSL6h917favP8j1L0/wNyylzU+x+1w4p5haGVHNlP58dbpdJhiCUsDbWsa9HwEtLp89obQgXl2e0qg== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.1" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -6319,21 +6291,21 @@ graphlib@^2.1.8: dependencies: lodash "^4.17.15" -graphql-config@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-4.1.0.tgz#a3b28d3fb537952ebeb69c75e4430605a10695e3" - integrity sha512-Myqay6pmdcmX3KqoH+bMbeKZ1cTODpHS2CxF1ZzNnfTE+YUpGTcp01bOw6LpzamRb0T/WTYtGFbZeXGo9Hab2Q== +graphql-config@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/graphql-config/-/graphql-config-4.3.0.tgz#b9bb7bf9c892a90e66ea937e8d7ed170eb1fd5e2" + integrity sha512-Uiu3X7+s5c056WyrvdZVz2vG1fhAipMlYmtiCU/4Z2mX79OXDr1SqIon2MprC/pExIWJfAQZCcjYDY76fPBUQg== dependencies: "@endemolshinegroup/cosmiconfig-typescript-loader" "3.0.2" - "@graphql-tools/graphql-file-loader" "^7.3.2" - "@graphql-tools/json-file-loader" "^7.3.2" - "@graphql-tools/load" "^7.4.1" - "@graphql-tools/merge" "^8.2.1" - "@graphql-tools/url-loader" "^7.4.2" - "@graphql-tools/utils" "^8.5.1" + "@graphql-tools/graphql-file-loader" "^7.3.7" + "@graphql-tools/json-file-loader" "^7.3.7" + "@graphql-tools/load" "^7.5.5" + "@graphql-tools/merge" "^8.2.6" + "@graphql-tools/url-loader" "^7.9.7" + "@graphql-tools/utils" "^8.6.5" cosmiconfig "7.0.1" cosmiconfig-toml-loader "1.0.0" - minimatch "3.0.4" + minimatch "4.2.1" string-env-interpolation "1.0.1" graphql-depth-limit@1.1.0: @@ -6343,6 +6315,11 @@ graphql-depth-limit@1.1.0: dependencies: arrify "^1.0.1" +graphql-executor@0.0.22: + version "0.0.22" + resolved "https://registry.yarnpkg.com/graphql-executor/-/graphql-executor-0.0.22.tgz#14bc466bb27ab38346998e0b375cba55685eed94" + integrity sha512-WbKSnSHFn6REKKH4T6UAwDM3mLUnYMQlQLNG0Fw+Lkb3ilCnL3m5lkJ7411LAI9sF7BvPbthovVZhsEUh9Xfag== + graphql-sse@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/graphql-sse/-/graphql-sse-1.0.4.tgz#051598b0e06c225327aac659f19fcc18bcaa0191" @@ -7244,7 +7221,7 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= -isomorphic-ws@4.0.1: +isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== @@ -8588,10 +8565,10 @@ mermaid@^8.13.10: moment-mini "^2.24.0" stylis "^4.0.10" -meros@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/meros/-/meros-1.1.4.tgz#c17994d3133db8b23807f62bec7f0cb276cfd948" - integrity sha512-E9ZXfK9iQfG9s73ars9qvvvbSIkJZF5yOo9j4tcwM5tN8mUKfj/EKN5PzOr3ZH0y5wL7dLAHw3RVEfpQV9Q7VQ== +meros@^1.1.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/meros/-/meros-1.2.0.tgz#096cdede2eb0b1610b219b1031b935260de1ad08" + integrity sha512-3QRZIS707pZQnijHdhbttXRWwrHhZJ/gzolneoxKVz9N/xmsvY/7Ls8lpnI9gxbgxjcHsAVEW3mgwiZCo6kkJQ== methods@~1.1.2: version "1.1.2" @@ -8882,7 +8859,14 @@ minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.4: +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4, minimatch@~3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -9123,15 +9107,20 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== +node-domexception@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" + integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== + node-ensure@^0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/node-ensure/-/node-ensure-0.0.0.tgz#ecae764150de99861ec5c810fd5d096b183932a7" integrity sha1-7K52QVDemYYexcgQ/V0Jaxg5Mqc= -node-fetch@^2.6.1, node-fetch@^2.6.5: - version "2.6.6" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.6.tgz#1751a7c01834e8e1697758732e9efb6eeadfaf89" - integrity sha512-Z8/6vRlTUChSdIgMa51jxQ4lrw/Jy5SOW10ObaA47/RElsAN2c5Pn8bTgFGWn/ibwzXTE8qwr1Yzx28vsecXEA== +node-fetch@^2.6.1, node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== dependencies: whatwg-url "^5.0.0" @@ -11652,7 +11641,7 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -sync-fetch@0.3.1: +sync-fetch@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/sync-fetch/-/sync-fetch-0.3.1.tgz#62aa82c4b4d43afd6906bfd7b5f92056458509f0" integrity sha512-xj5qiCDap/03kpci5a+qc5wSJjc8ZSixgG2EUmH1B8Ea2sfWclQA7eH40hiHPCtkCn6MCk4Wb+dqcXdCy2PP3g== @@ -12100,10 +12089,10 @@ underscore@~1.8.3: resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI= -undici@^4.9.3: - version "4.10.2" - resolved "https://registry.yarnpkg.com/undici/-/undici-4.10.2.tgz#27e360f2d4202ef98dfc1c8e13dcd329660a6d7c" - integrity sha512-QoQH4PpV3dqJwr4h1HazggbB4f5CBknvYANjI9hxXCml+AAzLoh4HBkce0Jc0wW/pmVbrus8Gfeo8QounE+/9g== +undici@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-5.0.0.tgz#3c1e08c7f0df90c485d5d8dbb0517e11e34f2090" + integrity sha512-VhUpiZ3No1DOPPQVQnsDZyfcbTTcHdcgWej1PdFnSvOeJmOVDgiOHkunJmBLfmjt4CqgPQddPVjSWW0dsTs5Yg== unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" @@ -12398,11 +12387,6 @@ v8-to-istanbul@^5.0.1: convert-source-map "^1.6.0" source-map "^0.7.3" -valid-url@1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" - integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -12411,7 +12395,7 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -value-or-promise@1.0.11: +value-or-promise@1.0.11, value-or-promise@^1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/value-or-promise/-/value-or-promise-1.0.11.tgz#3e90299af31dd014fe843fe309cefa7c1d94b140" integrity sha512-41BrgH+dIbCFXClcSapVs5M6GkENd3gQOJpEfPDNa71LsUGMXDL0jMWpI/Rh7WhX+Aalfz2TTS3Zt5pUsbnhLg== @@ -12712,6 +12696,16 @@ web-namespaces@^2.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-2.0.1.tgz#1010ff7c650eccb2592cebeeaf9a1b253fd40692" integrity sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ== +web-streams-polyfill@4.0.0-beta.1: + version "4.0.0-beta.1" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.1.tgz#3b19b9817374b7cee06d374ba7eeb3aeb80e8c95" + integrity sha512-3ux37gEX670UUphBF9AMCq8XM6iQ8Ac6A+DSRRjDoRBm1ufCkaCDdNVbaqq60PsEkdNlLKrGtv/YBP4EJXqNtQ== + +web-streams-polyfill@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz#a6b74026b38e4885869fb5c589e90b95ccfc7965" + integrity sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA== + web-vitals@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-0.2.4.tgz#ec3df43c834a207fd7cdefd732b2987896e08511" @@ -12989,17 +12983,12 @@ write-file-atomic@^4.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^4.0.0" -ws@8.2.3: - version "8.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.2.3.tgz#63a56456db1b04367d0b721a0b80cae6d8becbba" - integrity sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA== - "ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.2.3, ws@^7.3.1: version "7.5.5" resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== -ws@^8.4.2: +ws@^8.3.0, ws@^8.4.2: version "8.5.0" resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f" integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg== |