diff options
47 files changed, 373 insertions, 142 deletions
diff --git a/.haml-lint.yml b/.haml-lint.yml index 39090a48d1c..efbf14b2e22 100644 --- a/.haml-lint.yml +++ b/.haml-lint.yml @@ -137,7 +137,6 @@ linters: - Style/ParenthesesAroundCondition - Style/RedundantParentheses - Style/SelfAssignment - - Style/Semicolon - Style/TernaryParentheses - Style/TrailingCommaInHashLiteral - Style/UnlessElse diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index a9d42925fc7..1b3658930d2 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -4ea88e921af65ba0577c40f8b54830c97adaa56c +8752fc1097114316889560502579ddf477a20a2d diff --git a/app/assets/javascripts/design_management/components/design_notes/design_note.vue b/app/assets/javascripts/design_management/components/design_notes/design_note.vue index 2b867217327..833d7081a2c 100644 --- a/app/assets/javascripts/design_management/components/design_notes/design_note.vue +++ b/app/assets/javascripts/design_management/components/design_notes/design_note.vue @@ -1,6 +1,7 @@ <script> import { GlTooltipDirective, GlIcon, GlLink, GlSafeHtmlDirective } from '@gitlab/ui'; import { ApolloMutation } from 'vue-apollo'; +import { __ } from '~/locale'; import TimelineEntryItem from '~/vue_shared/components/notes/timeline_entry_item.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; @@ -10,6 +11,9 @@ import { findNoteId, extractDesignNoteId } from '../../utils/design_management_u import DesignReplyForm from './design_reply_form.vue'; export default { + i18n: { + editCommentLabel: __('Edit comment'), + }, components: { UserAvatarLink, TimelineEntryItem, @@ -113,7 +117,8 @@ export default { v-if="isEditButtonVisible" v-gl-tooltip type="button" - :title="__('Edit comment')" + :title="$options.i18n.editCommentLabel" + :aria-label="$options.i18n.editCommentLabel" class="note-action-button js-note-edit btn btn-transparent qa-note-edit-button" @click="isEditing = true" > diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue index d0d457d8582..5e05ec87f84 100644 --- a/app/assets/javascripts/diffs/components/diff_discussions.vue +++ b/app/assets/javascripts/diffs/components/diff_discussions.vue @@ -68,6 +68,7 @@ export default { }" type="button" class="js-diff-notes-toggle" + :aria-label="__('Show comments')" @click="toggleDiscussion({ discussionId: discussion.id })" > <gl-icon v-if="discussion.expanded" name="collapse" class="collapse-icon" /> diff --git a/app/assets/javascripts/diffs/components/image_diff_overlay.vue b/app/assets/javascripts/diffs/components/image_diff_overlay.vue index 3d05202fb2d..5572338908f 100644 --- a/app/assets/javascripts/diffs/components/image_diff_overlay.vue +++ b/app/assets/javascripts/diffs/components/image_diff_overlay.vue @@ -122,6 +122,7 @@ export default { :disabled="!shouldToggleDiscussion" class="js-image-badge" type="button" + :aria-label="__('Show comments')" @click="clickedToggle(discussion)" > <gl-icon v-if="showCommentIcon" name="image-comment-dark" :size="24" /> diff --git a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue index fd6c69e22c6..25403b1547e 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_table_row.vue @@ -146,6 +146,7 @@ export default { type="button" class="add-diff-note note-button js-add-diff-note-button" :disabled="line.commentsDisabled" + :aria-label="addCommentTooltip" @click="handleCommentButton" > <gl-icon :size="12" name="comment" /> diff --git a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue index 147741fa2bb..96946d0fd88 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_table_row.vue @@ -195,6 +195,7 @@ export default { type="button" class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" :disabled="line.left.commentsDisabled" + :aria-label="addCommentTooltipLeft" @click="handleCommentButton(line.left)" > <gl-icon :size="12" name="comment" /> @@ -252,6 +253,7 @@ export default { type="button" class="add-diff-note note-button js-add-diff-note-button qa-diff-comment" :disabled="line.right.commentsDisabled" + :aria-label="addCommentTooltipRight" @click="handleCommentButton(line.right)" > <gl-icon :size="12" name="comment" /> diff --git a/app/assets/javascripts/emoji/components/picker.vue b/app/assets/javascripts/emoji/components/picker.vue index 156bbb28ce6..cbcc5dcff3a 100644 --- a/app/assets/javascripts/emoji/components/picker.vue +++ b/app/assets/javascripts/emoji/components/picker.vue @@ -105,6 +105,7 @@ export default { }" type="button" class="gl-border-0 gl-border-b-2 gl-border-b-solid gl-flex-fill-1 gl-text-gray-300 gl-pt-3 gl-pb-3 gl-bg-transparent emoji-picker-category-tab" + :aria-label="category.name" @click="scrollToCategory(category.name)" > <gl-icon :name="category.icon" :size="12" /> diff --git a/app/assets/javascripts/error_tracking/components/error_tracking_actions.vue b/app/assets/javascripts/error_tracking/components/error_tracking_actions.vue index db61957d452..9438900c736 100644 --- a/app/assets/javascripts/error_tracking/components/error_tracking_actions.vue +++ b/app/assets/javascripts/error_tracking/components/error_tracking_actions.vue @@ -51,6 +51,7 @@ export default { v-gl-tooltip.hover class="gl-display-block gl-mb-4 mb-md-0 gl-w-full" :title="ignoreBtn.title" + :aria-label="ignoreBtn.title" @click="$emit('update-issue-status', { errorId: error.id, status: ignoreBtn.status })" > <gl-icon class="gl-display-none d-md-inline gl-m-0" :name="ignoreBtn.icon" :size="12" /> @@ -62,6 +63,7 @@ export default { v-gl-tooltip.hover class="gl-display-block gl-mb-4 mb-md-0 gl-w-full" :title="resolveBtn.title" + :aria-label="resolveBtn.title" @click="$emit('update-issue-status', { errorId: error.id, status: resolveBtn.status })" > <gl-icon class="gl-display-none d-md-inline gl-m-0" :name="resolveBtn.icon" :size="12" /> diff --git a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue index f4859b9f312..6e1929a1948 100644 --- a/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue +++ b/app/assets/javascripts/ide/components/jobs/detail/scroll_button.vue @@ -55,6 +55,7 @@ export default { :disabled="disabled" class="btn-scroll btn-transparent btn-blank" type="button" + :aria-label="tooltipTitle" @click="clickedScroll" > <gl-icon :name="iconName" /> diff --git a/app/assets/javascripts/projects/commit/store/actions.js b/app/assets/javascripts/projects/commit/store/actions.js index c72704303ca..2b25082eced 100644 --- a/app/assets/javascripts/projects/commit/store/actions.js +++ b/app/assets/javascripts/projects/commit/store/actions.js @@ -22,8 +22,8 @@ export const fetchBranches = ({ commit, dispatch, state }, query) => { .get(state.branchesEndpoint, { params: { search: query }, }) - .then(({ data }) => { - commit(types.RECEIVE_BRANCHES_SUCCESS, data.Branches || []); + .then(({ data = [] }) => { + commit(types.RECEIVE_BRANCHES_SUCCESS, data.Branches?.length ? data.Branches : data); }) .catch(() => { createFlash({ message: PROJECT_BRANCHES_ERROR }); diff --git a/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue b/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue index 5fb7217db74..d16850cd889 100644 --- a/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue +++ b/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue @@ -9,10 +9,13 @@ import { GlSkeletonLoader, GlTooltipDirective, } from '@gitlab/ui'; - +import { __ } from '~/locale'; import { ANY_OPTION } from '../constants'; export default { + i18n: { + clearLabel: __('Clear'), + }, name: 'SearchableDropdown', components: { GlDropdown, @@ -96,7 +99,8 @@ export default { v-gl-tooltip name="clear" category="tertiary" - :title="__('Clear')" + :title="$options.i18n.clearLabel" + :aria-label="$options.i18n.clearLabel" class="gl-p-0! gl-mr-2" @keydown.enter.stop="resetDropdown" @click.stop="resetDropdown" diff --git a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_action_button.vue b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_action_button.vue index cc3efae565a..b25c0cc0d96 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_action_button.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/deployment/deployment_action_button.vue @@ -68,6 +68,7 @@ export default { category="primary" size="small" :title="buttonTitle" + :aria-label="buttonTitle" :loading="isLoading" :disabled="isActionInProgress" :class="`inline gl-ml-2 ${containerClasses}`" diff --git a/app/assets/javascripts/vue_shared/components/help_popover.vue b/app/assets/javascripts/vue_shared/components/help_popover.vue index 7222bd82df0..f36b9107a6e 100644 --- a/app/assets/javascripts/vue_shared/components/help_popover.vue +++ b/app/assets/javascripts/vue_shared/components/help_popover.vue @@ -25,7 +25,7 @@ export default { </script> <template> <span> - <gl-button ref="popoverTrigger" variant="link" icon="question" tabindex="0" /> + <gl-button ref="popoverTrigger" variant="link" icon="question" :aria-label="__('Help')" /> <gl-popover :target="() => $refs.popoverTrigger.$el" v-bind="options"> <template v-if="options.title" #title> <span v-safe-html="options.title"></span> diff --git a/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue b/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue index 4271f6053ed..85a67c087bb 100644 --- a/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue +++ b/app/assets/javascripts/vue_shared/components/rich_content_editor/toolbar_item.vue @@ -21,7 +21,11 @@ export default { }; </script> <template> - <button v-gl-tooltip="{ title: tooltip }" class="p-0 gl-display-flex toolbar-button"> + <button + v-gl-tooltip="{ title: tooltip }" + :aria-label="tooltip" + class="p-0 gl-display-flex toolbar-button" + > <gl-icon class="gl-mx-auto gl-align-self-center" :name="icon" /> </button> </template> diff --git a/app/finders/concerns/packages/finder_helper.rb b/app/finders/concerns/packages/finder_helper.rb index 244bd7f6f86..39c018818d1 100644 --- a/app/finders/concerns/packages/finder_helper.rb +++ b/app/finders/concerns/packages/finder_helper.rb @@ -13,7 +13,7 @@ module Packages return ::Packages::Package.none unless within_group return ::Packages::Package.none unless Ability.allowed?(user, :read_group, within_group) - projects = projects_visible_to_reporters(user, within_group.self_and_descendants.select(:id)) + projects = projects_visible_to_reporters(user, within_group: within_group) ::Packages::Package.for_projects(projects.select(:id)) end @@ -21,12 +21,16 @@ module Packages return ::Project.none unless within_group return ::Project.none unless Ability.allowed?(user, :read_group, within_group) - projects_visible_to_reporters(user, within_group.self_and_descendants.select(:id)) + projects_visible_to_reporters(user, within_group: within_group) end - def projects_visible_to_reporters(user, namespace_ids) - ::Project.in_namespace(namespace_ids) - .public_or_visible_to_user(user, ::Gitlab::Access::REPORTER) + def projects_visible_to_reporters(user, within_group:) + if user.is_a?(DeployToken) && Feature.enabled?(:packages_finder_helper_deploy_token) + user.accessible_projects + else + within_group.all_projects + .public_or_visible_to_user(user, ::Gitlab::Access::REPORTER) + end end def package_type diff --git a/app/finders/packages/maven/package_finder.rb b/app/finders/packages/maven/package_finder.rb index 973496ca9c4..eefcdaba3c8 100644 --- a/app/finders/packages/maven/package_finder.rb +++ b/app/finders/packages/maven/package_finder.rb @@ -76,7 +76,7 @@ module Packages def group_level_improvements? strong_memoize(:group_level_improvements) do - Feature.enabled?(:maven_packages_group_level_improvements) + Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml) end end end diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 1e44321e148..478c7cd156f 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -137,14 +137,6 @@ module Issuable scope :references_project, -> { references(:project) } scope :non_archived, -> { join_project.where(projects: { archived: false }) } - scope :includes_for_bulk_update, -> do - associations = %i[author assignees epic group labels metrics project source_project target_project].select do |association| - reflect_on_association(association) - end - - includes(*associations) - end - attr_mentionable :title, pipeline: :single_line attr_mentionable :description diff --git a/app/models/concerns/milestoneable.rb b/app/models/concerns/milestoneable.rb index d42417bb6c1..ccb334343ff 100644 --- a/app/models/concerns/milestoneable.rb +++ b/app/models/concerns/milestoneable.rb @@ -39,13 +39,11 @@ module Milestoneable private def milestone_is_valid - errors.add(:milestone_id, 'is invalid') if respond_to?(:milestone_id) && !milestone_available? + errors.add(:milestone_id, 'is invalid') if respond_to?(:milestone_id) && milestone_id.present? && !milestone_available? end end def milestone_available? - return true if milestone_id.blank? - project_id == milestone&.project_id || project.ancestors_upto.compact.include?(milestone&.group) end diff --git a/app/models/packages/package.rb b/app/models/packages/package.rb index 08e9f06a6a1..e510432be8f 100644 --- a/app/models/packages/package.rb +++ b/app/models/packages/package.rb @@ -138,7 +138,7 @@ class Packages::Package < ApplicationRecord after_commit :update_composer_cache, on: :destroy, if: -> { composer? } def self.for_projects(projects) - unless Feature.enabled?(:maven_packages_group_level_improvements) + unless Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml) return none unless projects.any? end diff --git a/app/services/issuable/bulk_update_service.rb b/app/services/issuable/bulk_update_service.rb index 13e289716ef..d3d543edcd7 100644 --- a/app/services/issuable/bulk_update_service.rb +++ b/app/services/issuable/bulk_update_service.rb @@ -15,7 +15,7 @@ module Issuable set_update_params(type) items = update_issuables(type, ids) - response_success(payload: { count: items.size }) + response_success(payload: { count: items.count }) rescue ArgumentError => e response_error(e.message, 422) end @@ -59,17 +59,10 @@ module Issuable def find_issuables(parent, model_class, ids) if parent.is_a?(Project) - projects = parent + model_class.id_in(ids).of_projects(parent) elsif parent.is_a?(Group) - projects = parent.all_projects - else - return + model_class.id_in(ids).of_projects(parent.all_projects) end - - model_class - .id_in(ids) - .of_projects(projects) - .includes_for_bulk_update end def response_success(message: nil, payload: nil) diff --git a/app/services/merge_requests/base_service.rb b/app/services/merge_requests/base_service.rb index 0c0b6764019..3a3765355d8 100644 --- a/app/services/merge_requests/base_service.rb +++ b/app/services/merge_requests/base_service.rb @@ -143,8 +143,12 @@ module MergeRequests merge_request, merge_request.project, current_user, old_reviewers) end - def create_pipeline_for(merge_request, user) - MergeRequests::CreatePipelineService.new(project, user).execute(merge_request) + def create_pipeline_for(merge_request, user, async: false) + if async + MergeRequests::CreatePipelineWorker.perform_async(project.id, user.id, merge_request.id) + else + MergeRequests::CreatePipelineService.new(project, user).execute(merge_request) + end end def abort_auto_merge(merge_request, reason) diff --git a/app/services/merge_requests/refresh_service.rb b/app/services/merge_requests/refresh_service.rb index 0fb16597aff..e04c5168cef 100644 --- a/app/services/merge_requests/refresh_service.rb +++ b/app/services/merge_requests/refresh_service.rb @@ -162,9 +162,12 @@ module MergeRequests end def refresh_pipelines_on_merge_requests(merge_request) - create_pipeline_for(merge_request, current_user) - - UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id) + if Feature.enabled?(:code_review_async_pipeline_creation, project, default_enabled: :yaml) + create_pipeline_for(merge_request, current_user, async: true) + else + create_pipeline_for(merge_request, current_user, async: false) + UpdateHeadPipelineForMergeRequestWorker.perform_async(merge_request.id) + end end def abort_auto_merges(merge_request) diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml index 35fefe40d39..433337602f1 100644 --- a/app/views/layouts/_flash.html.haml +++ b/app/views/layouts/_flash.html.haml @@ -1,5 +1,5 @@ -# We currently only support `alert`, `notice`, `success`, 'toast' -- icons = {'alert' => 'error', 'notice' => 'information-o', 'success' => 'check-circle'}; +- icons = {'alert' => 'error', 'notice' => 'information-o', 'success' => 'check-circle'} .flash-container.flash-container-page.sticky{ data: { qa_selector: 'flash_container' } } - flash.each do |key, value| - if key == 'toast' && value diff --git a/app/views/shared/blob/_markdown_buttons.html.haml b/app/views/shared/blob/_markdown_buttons.html.haml index 085206714c6..73f3d2a8fcd 100644 --- a/app/views/shared/blob/_markdown_buttons.html.haml +++ b/app/views/shared/blob/_markdown_buttons.html.haml @@ -1,4 +1,4 @@ -- modifier_key = client_js_flags[:isMac] ? '⌘' : s_('KeyboardKey|Ctrl+'); +- modifier_key = client_js_flags[:isMac] ? '⌘' : s_('KeyboardKey|Ctrl+') .md-header-toolbar.active = markdown_toolbar_button({ icon: "bold", diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index ef7b5eb026e..f14497509e1 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -1227,6 +1227,14 @@ :weight: 4 :idempotent: :tags: [] +- :name: pipeline_creation:merge_requests_create_pipeline + :feature_category: :continuous_integration + :has_external_dependencies: + :urgency: :high + :resource_boundary: :cpu + :weight: 4 + :idempotent: true + :tags: [] - :name: pipeline_creation:run_pipeline_schedule :feature_category: :continuous_integration :has_external_dependencies: diff --git a/app/workers/merge_requests/create_pipeline_worker.rb b/app/workers/merge_requests/create_pipeline_worker.rb new file mode 100644 index 00000000000..244ba1af300 --- /dev/null +++ b/app/workers/merge_requests/create_pipeline_worker.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module MergeRequests + class CreatePipelineWorker + include ApplicationWorker + include PipelineQueue + + queue_namespace :pipeline_creation + feature_category :continuous_integration + urgency :high + worker_resource_boundary :cpu + idempotent! + + def perform(project_id, user_id, merge_request_id) + project = Project.find_by_id(project_id) + return unless project + + user = User.find_by_id(user_id) + return unless user + + merge_request = MergeRequest.find_by_id(merge_request_id) + return unless merge_request + + MergeRequests::CreatePipelineService.new(project, user).execute(merge_request) + merge_request.update_head_pipeline + end + end +end diff --git a/changelogs/unreleased/21068-optimize-issueable-updates.yml b/changelogs/unreleased/21068-optimize-issueable-updates.yml deleted file mode 100644 index 214fd3fe0ab..00000000000 --- a/changelogs/unreleased/21068-optimize-issueable-updates.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Optimize issuable updates -merge_request: 58114 -author: -type: performance diff --git a/changelogs/unreleased/220680-update-gatsby-project-template.yml b/changelogs/unreleased/220680-update-gatsby-project-template.yml new file mode 100644 index 00000000000..d3bbe24b992 --- /dev/null +++ b/changelogs/unreleased/220680-update-gatsby-project-template.yml @@ -0,0 +1,5 @@ +--- +title: Update gatsby project template to address the pipeline failure +merge_request: 37410 +author: Takuya Noguchi +type: fixed diff --git a/changelogs/unreleased/326099-enabled-by-default.yml b/changelogs/unreleased/326099-enabled-by-default.yml new file mode 100644 index 00000000000..e73620bfc76 --- /dev/null +++ b/changelogs/unreleased/326099-enabled-by-default.yml @@ -0,0 +1,5 @@ +--- +title: Reduce the number of SQL queries executed on Maven file API endpoints +merge_request: 59136 +author: +type: performance diff --git a/changelogs/unreleased/327064-fix-revert-query.yml b/changelogs/unreleased/327064-fix-revert-query.yml new file mode 100644 index 00000000000..0235c022a1c --- /dev/null +++ b/changelogs/unreleased/327064-fix-revert-query.yml @@ -0,0 +1,5 @@ +--- +title: Fix revert commit query +merge_request: 59356 +author: +type: fixed diff --git a/changelogs/unreleased/cngo-add-aria-labels-to-icon-only-buttons-3.yml b/changelogs/unreleased/cngo-add-aria-labels-to-icon-only-buttons-3.yml new file mode 100644 index 00000000000..8e72b9c9d7c --- /dev/null +++ b/changelogs/unreleased/cngo-add-aria-labels-to-icon-only-buttons-3.yml @@ -0,0 +1,5 @@ +--- +title: Add aria labels to icon-only buttons +merge_request: 59037 +author: +type: fixed diff --git a/changelogs/unreleased/move_pipeline_creation_async.yml b/changelogs/unreleased/move_pipeline_creation_async.yml new file mode 100644 index 00000000000..2017a518f29 --- /dev/null +++ b/changelogs/unreleased/move_pipeline_creation_async.yml @@ -0,0 +1,5 @@ +--- +title: Create the pipelines asynchronously when refreshing merge requests +merge_request: 58542 +author: +type: performance diff --git a/config/feature_flags/development/code_review_async_pipeline_creation.yml b/config/feature_flags/development/code_review_async_pipeline_creation.yml new file mode 100644 index 00000000000..d0e5a3286aa --- /dev/null +++ b/config/feature_flags/development/code_review_async_pipeline_creation.yml @@ -0,0 +1,8 @@ +--- +name: code_review_async_pipeline_creation +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58542 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/327559 +milestone: '13.11' +type: development +group: group::code review +default_enabled: false diff --git a/config/feature_flags/development/maven_packages_group_level_improvements.yml b/config/feature_flags/development/maven_packages_group_level_improvements.yml index 6b8a8ac5b11..8dfd5ab0f8b 100644 --- a/config/feature_flags/development/maven_packages_group_level_improvements.yml +++ b/config/feature_flags/development/maven_packages_group_level_improvements.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326099 milestone: '13.11' type: development group: group::package -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/packages_finder_helper_deploy_token.yml b/config/feature_flags/development/packages_finder_helper_deploy_token.yml new file mode 100644 index 00000000000..fcc73cafd64 --- /dev/null +++ b/config/feature_flags/development/packages_finder_helper_deploy_token.yml @@ -0,0 +1,8 @@ +--- +name: packages_finder_helper_deploy_token +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/58497 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326808 +milestone: '13.11' +type: development +group: group::package +default_enabled: false diff --git a/doc/update/index.md b/doc/update/index.md index 5b62e0642c8..75bc1ef62f6 100644 --- a/doc/update/index.md +++ b/doc/update/index.md @@ -177,7 +177,7 @@ Find where your version sits in the upgrade path below, and upgrade GitLab accordingly, while also consulting the [version-specific upgrade instructions](#version-specific-upgrading-instructions): -`8.11.Z` -> `8.12.0` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> `13.5.4` - > [latest `13.Y.Z`](https://about.gitlab.com/releases/categories/releases/) +`8.11.Z` -> `8.12.0` -> `8.17.7` -> `9.5.10` -> `10.8.7` -> `11.11.8` -> `12.0.12` -> `12.1.17` -> `12.10.14` -> `13.0.14` -> `13.1.11` -> [latest `13.Y.Z`](https://about.gitlab.com/releases/categories/releases/) The following table, while not exhaustive, shows some examples of the supported upgrade paths. diff --git a/lib/api/maven_packages.rb b/lib/api/maven_packages.rb index 5d255c309f7..879f1ea5d50 100644 --- a/lib/api/maven_packages.rb +++ b/lib/api/maven_packages.rb @@ -80,7 +80,7 @@ module API def fetch_package(file_name:, project: nil, group: nil) order_by_package_file = false - if Feature.enabled?(:maven_packages_group_level_improvements) + if Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml) order_by_package_file = file_name.include?(::Packages::Maven::Metadata.filename) && !params[:path].include?(::Packages::Maven::FindOrCreatePackageService::SNAPSHOT_TERM) end diff --git a/spec/factories/services.rb b/spec/factories/services.rb index 7b9d7bfb3e0..25ef75880bb 100644 --- a/spec/factories/services.rb +++ b/spec/factories/services.rb @@ -62,6 +62,7 @@ FactoryBot.define do project_key { nil } vulnerabilities_enabled { false } vulnerabilities_issuetype { nil } + deployment_type { 'cloud' } end before(:create) do |service, evaluator| @@ -72,7 +73,7 @@ FactoryBot.define do jira_issue_transition_id: evaluator.jira_issue_transition_id, username: evaluator.username, password: evaluator.password, issues_enabled: evaluator.issues_enabled, project_key: evaluator.project_key, vulnerabilities_enabled: evaluator.vulnerabilities_enabled, - vulnerabilities_issuetype: evaluator.vulnerabilities_issuetype + vulnerabilities_issuetype: evaluator.vulnerabilities_issuetype, deployment_type: evaluator.deployment_type ) end end diff --git a/spec/finders/concerns/packages/finder_helper_spec.rb b/spec/finders/concerns/packages/finder_helper_spec.rb index 73f77647573..c1740ee1796 100644 --- a/spec/finders/concerns/packages/finder_helper_spec.rb +++ b/spec/finders/concerns/packages/finder_helper_spec.rb @@ -6,7 +6,6 @@ RSpec.describe ::Packages::FinderHelper do describe '#packages_visible_to_user' do using RSpec::Parameterized::TableSyntax - let_it_be(:user) { create(:user) } let_it_be_with_reload(:group) { create(:group) } let_it_be_with_reload(:project1) { create(:project, namespace: group) } let_it_be(:package1) { create(:package, project: project1) } @@ -44,41 +43,87 @@ RSpec.describe ::Packages::FinderHelper do it { is_expected.to be_empty } end - where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both packages' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning package1' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning package1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning package1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning package1' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no packages' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no packages' + context 'with a user' do + let_it_be(:user) { create(:user) } + + where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning package1' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning package1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning package1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning package1' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no packages' + end + + with_them do + before do + unless user_role == :anonymous + group.send("add_#{user_role}", user) + subgroup.send("add_#{user_role}", user) + project1.send("add_#{user_role}", user) + project2.send("add_#{user_role}", user) + end + + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end end - with_them do - before do - unless user_role == :anonymous - group.send("add_#{user_role}", user) - subgroup.send("add_#{user_role}", user) - project1.send("add_#{user_role}", user) - project2.send("add_#{user_role}", user) + context 'with a group deploy token' do + let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) } + let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) } + + shared_examples 'handling all conditions' do + where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both packages' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both packages' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both packages' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both packages' + end + + with_them do + before do + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end + end + + context 'with packages_finder_helper_deploy_token enabled' do + before do + expect(group).not_to receive(:all_projects) end - project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) - subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) - project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) - group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + it_behaves_like 'handling all conditions' end - it_behaves_like params[:shared_example_name] + context 'with packages_finder_helper_deploy_token disabled' do + before do + stub_feature_flags(packages_finder_helper_deploy_token: false) + expect(group).to receive(:all_projects).and_call_original + end + + it_behaves_like 'handling all conditions' + end end end @@ -121,41 +166,87 @@ RSpec.describe ::Packages::FinderHelper do it { is_expected.to be_empty } end - where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both projects' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning project1' - 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning project1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning project1' - 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning project1' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no project' - 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no project' + context 'with a user' do + let_it_be(:user) { create(:user) } + + where(:group_visibility, :subgroup_visibility, :project2_visibility, :user_role, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :maintainer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :developer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :guest | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | :anonymous | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :maintainer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :developer | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :guest | 'returning project1' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | :anonymous | 'returning project1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning project1' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning project1' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :maintainer | 'returning both projects' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :developer | 'returning both projects' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :guest | 'returning no project' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | :anonymous | 'returning no project' + end + + with_them do + before do + unless user_role == :anonymous + group.send("add_#{user_role}", user) + subgroup.send("add_#{user_role}", user) + project1.send("add_#{user_role}", user) + project2.send("add_#{user_role}", user) + end + + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end end - with_them do - before do - unless user_role == :anonymous - group.send("add_#{user_role}", user) - subgroup.send("add_#{user_role}", user) - project1.send("add_#{user_role}", user) - project2.send("add_#{user_role}", user) + context 'with a group deploy token' do + let_it_be(:user) { create(:deploy_token, :group, read_package_registry: true) } + let_it_be(:group_deploy_token) { create(:group_deploy_token, deploy_token: user, group: group) } + + shared_examples 'handling all conditions' do + where(:group_visibility, :subgroup_visibility, :project2_visibility, :shared_example_name) do + 'PUBLIC' | 'PUBLIC' | 'PUBLIC' | 'returning both projects' + 'PUBLIC' | 'PUBLIC' | 'PRIVATE' | 'returning both projects' + 'PUBLIC' | 'PRIVATE' | 'PRIVATE' | 'returning both projects' + 'PRIVATE' | 'PRIVATE' | 'PRIVATE' | 'returning both projects' end - project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) - subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) - project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) - group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + with_them do + before do + project2.update!(visibility_level: Gitlab::VisibilityLevel.const_get(project2_visibility, false)) + subgroup.update!(visibility_level: Gitlab::VisibilityLevel.const_get(subgroup_visibility, false)) + project1.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + group.update!(visibility_level: Gitlab::VisibilityLevel.const_get(group_visibility, false)) + end + + it_behaves_like params[:shared_example_name] + end end - it_behaves_like params[:shared_example_name] + context 'with packages_finder_helper_deploy_token enabled' do + before do + expect(group).not_to receive(:all_projects) + end + + it_behaves_like 'handling all conditions' + end + + context 'with packages_finder_helper_deploy_token disabled' do + before do + stub_feature_flags(packages_finder_helper_deploy_token: false) + expect(group).to receive(:all_projects).and_call_original + end + + it_behaves_like 'handling all conditions' + end end end end diff --git a/spec/frontend/vue_shared/components/help_popover_spec.js b/spec/frontend/vue_shared/components/help_popover_spec.js index cf5428ba4c3..30c6fa04032 100644 --- a/spec/frontend/vue_shared/components/help_popover_spec.js +++ b/spec/frontend/vue_shared/components/help_popover_spec.js @@ -34,7 +34,6 @@ describe('HelpPopover', () => { icon: 'question', variant: 'link', }); - expect(findQuestionButton().attributes().tabindex).toBe('0'); }); it('renders popover that uses the question button as target', () => { diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 14db9b530db..1df70f38707 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -65,23 +65,6 @@ RSpec.describe Issuable do it { expect(issuable_class).to respond_to(:opened) } it { expect(issuable_class).to respond_to(:closed) } it { expect(issuable_class).to respond_to(:assigned) } - - describe '.includes_for_bulk_update' do - before do - stub_const('Example', Class.new(ActiveRecord::Base)) - - Example.class_eval do - include Issuable # adds :labels and :metrics, among others - - belongs_to :author - has_many :assignees - end - end - - it 'includes available associations' do - expect(Example.includes_for_bulk_update.includes_values).to eq([:author, :assignees, :labels, :metrics]) - end - end end describe 'author_name' do diff --git a/spec/models/concerns/milestoneable_spec.rb b/spec/models/concerns/milestoneable_spec.rb index 961eac4710d..5fb3b39f734 100644 --- a/spec/models/concerns/milestoneable_spec.rb +++ b/spec/models/concerns/milestoneable_spec.rb @@ -50,13 +50,13 @@ RSpec.describe Milestoneable do it 'returns true with a milestone from the issue project' do milestone = create(:milestone, project: project) - expect(build_milestoneable(milestone.id).milestone_available?).to be(true) + expect(build_milestoneable(milestone.id).milestone_available?).to be_truthy end it 'returns true with a milestone from the issue project group' do milestone = create(:milestone, group: group) - expect(build_milestoneable(milestone.id).milestone_available?).to be(true) + expect(build_milestoneable(milestone.id).milestone_available?).to be_truthy end it 'returns true with a milestone from the the parent of the issue project group' do @@ -64,23 +64,19 @@ RSpec.describe Milestoneable do group.update!(parent: parent) milestone = create(:milestone, group: parent) - expect(build_milestoneable(milestone.id).milestone_available?).to be(true) - end - - it 'returns true with a blank milestone' do - expect(build_milestoneable('').milestone_available?).to be(true) + expect(build_milestoneable(milestone.id).milestone_available?).to be_truthy end it 'returns false with a milestone from another project' do milestone = create(:milestone) - expect(build_milestoneable(milestone.id).milestone_available?).to be(false) + expect(build_milestoneable(milestone.id).milestone_available?).to be_falsey end it 'returns false with a milestone from another group' do milestone = create(:milestone, group: create(:group)) - expect(build_milestoneable(milestone.id).milestone_available?).to be(false) + expect(build_milestoneable(milestone.id).milestone_available?).to be_falsey end end end diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb index 93310d3e90f..07c00a338f6 100644 --- a/spec/requests/api/maven_packages_spec.rb +++ b/spec/requests/api/maven_packages_spec.rb @@ -387,7 +387,7 @@ RSpec.describe API::MavenPackages do subject - status = Feature.enabled?(:maven_packages_group_level_improvements) ? :not_found : :forbidden + status = Feature.enabled?(:maven_packages_group_level_improvements, default_enabled: :yaml) ? :not_found : :forbidden expect(response).to have_gitlab_http_status(status) end diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb index 2abe7a23bfe..f9b76db877b 100644 --- a/spec/services/merge_requests/refresh_service_spec.rb +++ b/spec/services/merge_requests/refresh_service_spec.rb @@ -198,7 +198,7 @@ RSpec.describe MergeRequests::RefreshService do end end - describe 'Pipelines for merge requests' do + shared_examples 'Pipelines for merge requests' do before do stub_ci_pipeline_yaml_file(config) end @@ -256,7 +256,7 @@ RSpec.describe MergeRequests::RefreshService do stub_feature_flags(ci_disallow_to_create_merge_request_pipelines_in_target_project: false) end - it 'creates detached merge request pipeline for fork merge request', :sidekiq_inline do + it 'creates detached merge request pipeline for fork merge request' do expect { subject } .to change { @fork_merge_request.pipelines_for_merge_request.count }.by(1) @@ -364,6 +364,18 @@ RSpec.describe MergeRequests::RefreshService do end end + context 'when the code_review_async_pipeline_creation feature flag is on', :sidekiq_inline do + it_behaves_like 'Pipelines for merge requests' + end + + context 'when the code_review_async_pipeline_creation feature flag is off', :sidekiq_inline do + before do + stub_feature_flags(code_review_async_pipeline_creation: false) + end + + it_behaves_like 'Pipelines for merge requests' + end + context 'push to origin repo source branch' do let(:refresh_service) { service.new(@project, @user) } let(:notification_service) { spy('notification_service') } diff --git a/spec/workers/merge_requests/create_pipeline_worker_spec.rb b/spec/workers/merge_requests/create_pipeline_worker_spec.rb new file mode 100644 index 00000000000..8efce5220be --- /dev/null +++ b/spec/workers/merge_requests/create_pipeline_worker_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::CreatePipelineWorker do + subject(:worker) { described_class.new } + + describe '#perform' do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:merge_request) { create(:merge_request) } + + context 'when the objects exist' do + it 'calls the merge request create pipeline service and calls update head pipeline' do + aggregate_failures do + expect_next_instance_of(MergeRequests::CreatePipelineService, project, user) do |service| + expect(service).to receive(:execute).with(merge_request) + end + + expect(MergeRequest).to receive(:find_by_id).with(merge_request.id).and_return(merge_request) + expect(merge_request).to receive(:update_head_pipeline) + + subject.perform(project.id, user.id, merge_request.id) + end + end + end + + shared_examples 'when object does not exist' do + it 'does not call the create pipeline service' do + expect(MergeRequests::CreatePipelineService).not_to receive(:new) + + expect { subject.perform(project.id, user.id, merge_request.id) } + .not_to raise_exception + end + end + + context 'when the project does not exist' do + before do + project.destroy! + end + + it_behaves_like 'when object does not exist' + end + + context 'when the user does not exist' do + before do + user.destroy! + end + + it_behaves_like 'when object does not exist' + end + + context 'when the merge request does not exist' do + before do + merge_request.destroy! + end + + it_behaves_like 'when object does not exist' + end + end +end diff --git a/vendor/project_templates/gatsby.tar.gz b/vendor/project_templates/gatsby.tar.gz Binary files differindex a4ae5f99047..52bb056630e 100644 --- a/vendor/project_templates/gatsby.tar.gz +++ b/vendor/project_templates/gatsby.tar.gz |