diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-17 00:09:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-11-17 00:09:02 +0300 |
commit | b9033ad4157010ccd8f37437de131ed70af90f45 (patch) | |
tree | 7d10ebd824040aabc585273e07dec6ebde64730f | |
parent | 6d9c4dc2ef4c63bee8e9ca095dc2f0ed683a34f5 (diff) |
Add latest changes from gitlab-org/gitlab@master
106 files changed, 1291 insertions, 177 deletions
diff --git a/app/assets/javascripts/alerts_settings/components/alert_mapping_builder.vue b/app/assets/javascripts/alerts_settings/components/alert_mapping_builder.vue index dfe4037b49a..ad1bbcd6218 100644 --- a/app/assets/javascripts/alerts_settings/components/alert_mapping_builder.vue +++ b/app/assets/javascripts/alerts_settings/components/alert_mapping_builder.vue @@ -124,14 +124,14 @@ export default { <template> <div class="gl-display-table gl-w-full gl-mt-5"> <div class="gl-display-table-row"> - <h5 class="gl-display-table-cell gl-py-3 gl-pr-3"> + <h5 id="gitlabFieldsHeader" class="gl-display-table-cell gl-py-3 gl-pr-3"> {{ $options.i18n.columns.gitlabKeyTitle }} </h5> <h5 class="gl-display-table-cell gl-py-3 gl-pr-3"> </h5> - <h5 class="gl-display-table-cell gl-py-3 gl-pr-3"> + <h5 id="parsedFieldsHeader" class="gl-display-table-cell gl-py-3 gl-pr-3"> {{ $options.i18n.columns.payloadKeyTitle }} </h5> - <h5 class="gl-display-table-cell gl-py-3 gl-pr-3"> + <h5 id="fallbackFieldsHeader" class="gl-display-table-cell gl-py-3 gl-pr-3"> {{ $options.i18n.columns.fallbackKeyTitle }} <gl-icon v-gl-tooltip @@ -144,22 +144,24 @@ export default { <div v-for="gitlabField in mappingData" :key="gitlabField.name" class="gl-display-table-row"> <div class="gl-display-table-cell gl-py-3 gl-pr-3 w-30p"> <gl-form-input + aria-labelledby="gitlabFieldsHeader" disabled :value="getFieldValue(gitlabField)" - class="gl-bg-transparent! gl-text-gray-900!" /> </div> <div class="gl-display-table-cell gl-py-3 gl-pr-3"> - <div class="right-arrow"> + <div class="right-arrow gl-vertical-align-middle gl-mt-n1"> <i class="right-arrow-head"></i> </div> </div> <div class="gl-display-table-cell gl-py-3 gl-pr-3 w-30p"> <gl-dropdown + :disabled="!gitlabField.mappingFields.length" + aria-labelledby="parsedFieldsHeader" :text="selectedValue(gitlabField.mapping)" - class="gl-w-full" + class="gl-w-full gl-vertical-align-baseline!" :header-text="$options.i18n.selectMappingKey" > <gl-search-box-by-type @input="setSearchTerm($event, 'searchTerm', gitlabField.name)" /> @@ -181,8 +183,10 @@ export default { <div class="gl-display-table-cell gl-py-3 w-30p"> <gl-dropdown v-if="Boolean(gitlabField.numberOfFallbacks)" + :disabled="!gitlabField.mappingFields.length" + aria-labelledby="fallbackFieldsHeader" :text="selectedValue(gitlabField.fallback)" - class="gl-w-full" + class="gl-w-full gl-vertical-align-baseline!" :header-text="$options.i18n.selectMappingKey" > <gl-search-box-by-type diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue index edce46babd1..ea788060853 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_form_new.vue @@ -73,11 +73,14 @@ export default { resetOk: s__('AlertSettings|Proceed with editing'), editPayload: s__('AlertSettings|Edit payload'), submitPayload: s__('AlertSettings|Submit payload'), + payloadParsedSucessMsg: s__( + 'AlertSettings|Sample payload has been parsed. You can now map the fields.', + ), }, step5: { label: s__('AlertSettings|5. Map fields (optional)'), intro: s__( - 'AlertSettings|The default GitLab alert keys are listed below. In the event an exact match could be found in the sample payload provided, that key will be mapped automatically. In all other cases, please define which payload key should map to the specified GitLab key. Any payload keys not shown in this list will not display in the alert list, but will display on the alert details page.', + "AlertSettings|If you've provided a sample alert payload, you can create a custom mapping for your endpoint. The default GitLab alert keys are listed below. Please define which payload key should map to the specified GitLab key.", ), }, prometheusFormUrl: { @@ -211,10 +214,10 @@ export default { ); }, mappingBuilderFields() { - return this.customMapping?.samplePayload?.payloadAlerFields?.nodes || []; + return this.customMapping?.samplePayload?.payloadAlerFields?.nodes; }, mappingBuilderMapping() { - return this.customMapping?.storedMapping?.nodes || []; + return this.customMapping?.storedMapping?.nodes; }, hasSamplePayload() { return Boolean(this.customMapping?.samplePayload); @@ -352,6 +355,8 @@ export default { this.customMapping = res; this.integrationTestPayload.json = res?.samplePayload.body; this.resetSamplePayloadConfirmed = false; + + this.$toast.show(this.$options.i18n.integrationFormSteps.step4.payloadParsedSucessMsg); }) .finally(() => { this.parsingPayload = false; @@ -528,6 +533,7 @@ export default { id="test-integration" :label="$options.i18n.integrationFormSteps.step4.label" label-for="test-integration" + :class="{ 'gl-mb-0!': showMappingBuilder }" :invalid-feedback="integrationTestPayload.error" > <alert-settings-form-help-block @@ -547,41 +553,44 @@ export default { max-rows="10" @input="validateJson" /> + </gl-form-group> - <template v-if="showMappingBuilder"> - <gl-button - v-if="canEditPayload" - v-gl-modal.resetPayloadModal - :disabled="!active" - class="gl-mt-3" - > - {{ $options.i18n.integrationFormSteps.step4.editPayload }} - </gl-button> + <template v-if="showMappingBuilder"> + <gl-button + v-if="canEditPayload" + v-gl-modal.resetPayloadModal + data-testid="payload-action-btn" + :disabled="!active" + class="gl-mt-3" + > + {{ $options.i18n.integrationFormSteps.step4.editPayload }} + </gl-button> - <gl-button - v-else - :disabled="!active" - :loading="parsingPayload" - class="gl-mt-3" - @click="parseMapping" - > - {{ $options.i18n.integrationFormSteps.step4.submitPayload }} - </gl-button> - <gl-modal - modal-id="resetPayloadModal" - :title="$options.i18n.integrationFormSteps.step4.resetHeader" - :ok-title="$options.i18n.integrationFormSteps.step4.resetOk" - ok-variant="danger" - @ok="resetSamplePayloadConfirmed = true" - > - {{ $options.i18n.integrationFormSteps.step4.resetBody }} - </gl-modal> - </template> - </gl-form-group> + <gl-button + v-else + data-testid="payload-action-btn" + :class="{ 'gl-mt-3': integrationTestPayload.error }" + :disabled="!active" + :loading="parsingPayload" + @click="parseMapping" + > + {{ $options.i18n.integrationFormSteps.step4.submitPayload }} + </gl-button> + <gl-modal + modal-id="resetPayloadModal" + :title="$options.i18n.integrationFormSteps.step4.resetHeader" + :ok-title="$options.i18n.integrationFormSteps.step4.resetOk" + ok-variant="danger" + @ok="resetSamplePayloadConfirmed = true" + > + {{ $options.i18n.integrationFormSteps.step4.resetBody }} + </gl-modal> + </template> <gl-form-group v-if="showMappingBuilder" id="mapping-builder" + class="gl-mt-5" :label="$options.i18n.integrationFormSteps.step5.label" label-for="mapping-builder" > diff --git a/app/assets/javascripts/alerts_settings/index.js b/app/assets/javascripts/alerts_settings/index.js index 5867991a738..41b19a675c5 100644 --- a/app/assets/javascripts/alerts_settings/index.js +++ b/app/assets/javascripts/alerts_settings/index.js @@ -1,4 +1,5 @@ import Vue from 'vue'; +import { GlToast } from '@gitlab/ui'; import { parseBoolean } from '~/lib/utils/common_utils'; import AlertSettingsWrapper from './components/alerts_settings_wrapper.vue'; import apolloProvider from './graphql'; @@ -8,6 +9,7 @@ apolloProvider.clients.defaultClient.cache.writeData({ currentIntegration: null, }, }); +Vue.use(GlToast); export default el => { if (!el) { diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue index 6bae3fdcc2e..bda2adeb62a 100644 --- a/app/assets/javascripts/monitoring/components/charts/time_series.vue +++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue @@ -402,21 +402,21 @@ export default { @updated="onChartUpdated" > <template v-if="tooltip.type === 'deployments'"> - <template slot="tooltipTitle"> + <template slot="tooltip-title"> {{ __('Deployed') }} </template> - <div slot="tooltipContent" class="d-flex align-items-center"> + <div slot="tooltip-content" class="d-flex align-items-center"> <gl-icon name="commit" class="mr-2" /> <gl-link :href="tooltip.commitUrl">{{ tooltip.sha }}</gl-link> </div> </template> <template v-else> - <template slot="tooltipTitle"> + <template slot="tooltip-title"> <div class="text-nowrap"> {{ tooltip.title }} </div> </template> - <template slot="tooltipContent" :tooltip="tooltip"> + <template slot="tooltip-content" :tooltip="tooltip"> <div v-for="(content, key) in tooltip.content" :key="key" diff --git a/app/assets/javascripts/pages/groups/dependency_proxies/index.js b/app/assets/javascripts/pages/groups/dependency_proxies/index.js index 4c0a1abb0f0..77c885d3858 100644 --- a/app/assets/javascripts/pages/groups/dependency_proxies/index.js +++ b/app/assets/javascripts/pages/groups/dependency_proxies/index.js @@ -1,17 +1,13 @@ import $ from 'jquery'; import initDependencyProxy from '~/dependency_proxy'; -document.addEventListener('DOMContentLoaded', () => { - initDependencyProxy(); -}); +initDependencyProxy(); -document.addEventListener('DOMContentLoaded', () => { - const form = document.querySelector('form.edit_dependency_proxy_group_setting'); - const toggleInput = $('input.js-project-feature-toggle-input'); +const form = document.querySelector('form.edit_dependency_proxy_group_setting'); +const toggleInput = $('input.js-project-feature-toggle-input'); - if (form && toggleInput) { - toggleInput.on('trigger-change', () => { - form.submit(); - }); - } -}); +if (form && toggleInput) { + toggleInput.on('trigger-change', () => { + form.submit(); + }); +} diff --git a/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue b/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue index a9079f91f50..6dd50958fa4 100644 --- a/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue +++ b/app/assets/javascripts/pages/projects/graphs/components/code_coverage.vue @@ -153,10 +153,10 @@ export default { :option="chartOptions" :format-tooltip-text="formatTooltipText" > - <template v-if="canShowData" #tooltipTitle> + <template v-if="canShowData" #tooltip-title> {{ tooltipTitle }} </template> - <template v-if="canShowData" #tooltipContent> + <template v-if="canShowData" #tooltip-content> <gl-sprintf :message="__('Code Coverage: %{coveragePercentage}%{percentSymbol}')"> <template #coveragePercentage> {{ coveragePercentage }} diff --git a/app/assets/javascripts/serverless/components/area.vue b/app/assets/javascripts/serverless/components/area.vue index 29a61cfbbfe..71f2e948917 100644 --- a/app/assets/javascripts/serverless/components/area.vue +++ b/app/assets/javascripts/serverless/components/area.vue @@ -138,8 +138,8 @@ export default { :width="width" :include-legend-avg-max="false" > - <template #tooltipTitle>{{ tooltipPopoverTitle }}</template> - <template #tooltipContent>{{ tooltipPopoverContent }}</template> + <template #tooltip-title>{{ tooltipPopoverTitle }}</template> + <template #tooltip-content>{{ tooltipPopoverContent }}</template> </gl-area-chart> </div> </template> diff --git a/app/finders/personal_access_tokens_finder.rb b/app/finders/personal_access_tokens_finder.rb index 93f8c520b63..4a6eed8f5ee 100644 --- a/app/finders/personal_access_tokens_finder.rb +++ b/app/finders/personal_access_tokens_finder.rb @@ -14,6 +14,7 @@ class PersonalAccessTokensFinder tokens = PersonalAccessToken.all tokens = by_current_user(tokens) tokens = by_user(tokens) + tokens = by_users(tokens) tokens = by_impersonation(tokens) tokens = by_state(tokens) @@ -37,6 +38,12 @@ class PersonalAccessTokensFinder tokens.for_user(@params[:user]) end + def by_users(tokens) + return tokens unless @params[:users] + + tokens.for_users(@params[:users]) + end + def sort(tokens) available_sort_orders = PersonalAccessToken.simple_sorts.keys diff --git a/app/graphql/mutations/custom_emoji/create.rb b/app/graphql/mutations/custom_emoji/create.rb new file mode 100644 index 00000000000..d912a29d12e --- /dev/null +++ b/app/graphql/mutations/custom_emoji/create.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +module Mutations + module CustomEmoji + class Create < BaseMutation + include Mutations::ResolvesGroup + + graphql_name 'CreateCustomEmoji' + + authorize :create_custom_emoji + + field :custom_emoji, + Types::CustomEmojiType, + null: true, + description: 'The new custom emoji' + + argument :group_path, GraphQL::ID_TYPE, + required: true, + description: 'Namespace full path the emoji is associated with' + + argument :name, GraphQL::STRING_TYPE, + required: true, + description: 'Name of the emoji' + + argument :url, GraphQL::STRING_TYPE, + required: true, + as: :file, + description: 'Location of the emoji file' + + def resolve(group_path:, **args) + group = authorized_find!(group_path: group_path) + # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911#note_444682238 + args[:external] = true + + custom_emoji = group.custom_emoji.create(args) + + { + custom_emoji: custom_emoji.valid? ? custom_emoji : nil, + errors: errors_on_object(custom_emoji) + } + end + + private + + def find_object(group_path:) + resolve_group(full_path: group_path) + end + end + end +end diff --git a/app/graphql/types/custom_emoji_type.rb b/app/graphql/types/custom_emoji_type.rb new file mode 100644 index 00000000000..f7d1a7800bc --- /dev/null +++ b/app/graphql/types/custom_emoji_type.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Types + class CustomEmojiType < BaseObject + graphql_name 'CustomEmoji' + description 'A custom emoji uploaded by user' + + authorize :read_custom_emoji + + field :id, ::Types::GlobalIDType[::CustomEmoji], + null: false, + description: 'The ID of the emoji' + + field :name, GraphQL::STRING_TYPE, + null: false, + description: 'The name of the emoji' + + field :url, GraphQL::STRING_TYPE, + null: false, + method: :file, + description: 'The link to file of the emoji' + + field :external, GraphQL::BOOLEAN_TYPE, + null: false, + description: 'Whether the emoji is an external link' + end +end diff --git a/app/graphql/types/group_type.rb b/app/graphql/types/group_type.rb index d8555684efb..2f17a4f9365 100644 --- a/app/graphql/types/group_type.rb +++ b/app/graphql/types/group_type.rb @@ -17,6 +17,10 @@ module Types group.avatar_url(only_path: false) end + field :custom_emoji, Types::CustomEmojiType.connection_type, null: true, + description: 'Custom emoji within this namespace', + feature_flag: :custom_emoji + field :share_with_group_lock, GraphQL::BOOLEAN_TYPE, null: true, description: 'Indicates if sharing a project with another group within this group is prevented' diff --git a/app/graphql/types/mutation_type.rb b/app/graphql/types/mutation_type.rb index 802e98f7d62..75ccac6d590 100644 --- a/app/graphql/types/mutation_type.rb +++ b/app/graphql/types/mutation_type.rb @@ -29,6 +29,7 @@ module Types mount_mutation Mutations::Boards::Lists::Destroy mount_mutation Mutations::Branches::Create, calls_gitaly: true mount_mutation Mutations::Commits::Create, calls_gitaly: true + mount_mutation Mutations::CustomEmoji::Create, feature_flag: :custom_emoji mount_mutation Mutations::Discussions::ToggleResolve mount_mutation Mutations::Issues::Create mount_mutation Mutations::Issues::SetAssignees diff --git a/app/graphql/types/permission_types/custom_emoji.rb b/app/graphql/types/permission_types/custom_emoji.rb new file mode 100644 index 00000000000..0b2e7da44f5 --- /dev/null +++ b/app/graphql/types/permission_types/custom_emoji.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Types + module PermissionTypes + class CustomEmoji < BasePermissionType + graphql_name 'CustomEmojiPermissions' + + abilities :create_custom_emoji, :read_custom_emoji + end + end +end diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index 7f8cb66a84f..cc43ea85a11 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -151,6 +151,13 @@ module AuthHelper current_user.allow_password_authentication_for_web? && !current_user.password_automatically_set? end + def google_tag_manager_enabled? + Gitlab.com? && + extra_config.has_key?('google_tag_manager_id') && + extra_config.google_tag_manager_id.present? && + !current_user + end + extend self end diff --git a/app/models/custom_emoji.rb b/app/models/custom_emoji.rb index 643b4060ad6..ed22d4ba231 100644 --- a/app/models/custom_emoji.rb +++ b/app/models/custom_emoji.rb @@ -3,14 +3,21 @@ class CustomEmoji < ApplicationRecord belongs_to :namespace, inverse_of: :custom_emoji + belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'namespace_id' + + # For now only external emoji are supported. See https://gitlab.com/gitlab-org/gitlab/-/issues/230467 + validates :external, inclusion: { in: [true] } + + validates :file, public_url: true, if: :external + validate :valid_emoji_name - validates :namespace, presence: true + validates :group, presence: true validates :name, uniqueness: { scope: [:namespace_id, :name] }, presence: true, length: { maximum: 36 }, - format: { with: /\A\w+\z/ } + format: { with: /\A([a-z0-9]+[-_]?)+[a-z0-9]+\z/ } private diff --git a/app/models/deploy_token.rb b/app/models/deploy_token.rb index 9355d73fae9..5fa9f2ef9f9 100644 --- a/app/models/deploy_token.rb +++ b/app/models/deploy_token.rb @@ -54,6 +54,10 @@ class DeployToken < ApplicationRecord !revoked && !expired? end + def deactivated? + !active? + end + def scopes AVAILABLE_SCOPES.select { |token_scope| read_attribute(token_scope) } end diff --git a/app/models/personal_access_token.rb b/app/models/personal_access_token.rb index e01cb0530a5..5aa5f2c842b 100644 --- a/app/models/personal_access_token.rb +++ b/app/models/personal_access_token.rb @@ -26,6 +26,7 @@ class PersonalAccessToken < ApplicationRecord scope :revoked, -> { where(revoked: true) } scope :not_revoked, -> { where(revoked: [false, nil]) } scope :for_user, -> (user) { where(user: user) } + scope :for_users, -> (users) { where(user: users) } scope :preload_users, -> { preload(:user) } scope :order_expires_at_asc, -> { reorder(expires_at: :asc) } scope :order_expires_at_desc, -> { reorder(expires_at: :desc) } diff --git a/app/policies/custom_emoji_policy.rb b/app/policies/custom_emoji_policy.rb new file mode 100644 index 00000000000..ba73b9a3782 --- /dev/null +++ b/app/policies/custom_emoji_policy.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class CustomEmojiPolicy < BasePolicy + delegate { @subject.group } +end diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index 6ff6d1359ab..231843c5f23 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -101,6 +101,7 @@ class GroupPolicy < BasePolicy enable :read_label enable :read_board enable :read_group_member + enable :read_custom_emoji end rule { ~can?(:read_group) }.policy do @@ -114,6 +115,7 @@ class GroupPolicy < BasePolicy enable :create_metrics_dashboard_annotation enable :delete_metrics_dashboard_annotation enable :update_metrics_dashboard_annotation + enable :create_custom_emoji end rule { reporter }.policy do @@ -194,6 +196,7 @@ class GroupPolicy < BasePolicy rule { write_package_registry_deploy_token }.policy do enable :create_package + enable :read_package enable :read_group end diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index da857aa2625..13073ed68a1 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -568,6 +568,7 @@ class ProjectPolicy < BasePolicy rule { write_package_registry_deploy_token }.policy do enable :create_package + enable :read_package enable :read_project end diff --git a/app/services/projects/update_pages_service.rb b/app/services/projects/update_pages_service.rb index 03dfe44a1d7..b9c579a130f 100644 --- a/app/services/projects/update_pages_service.rb +++ b/app/services/projects/update_pages_service.rb @@ -125,7 +125,7 @@ module Projects end def create_pages_deployment(artifacts_path, build) - return unless Feature.enabled?(:zip_pages_deployments, project) + return unless Feature.enabled?(:zip_pages_deployments, project, default_enabled: true) # we're using the full archive and pages daemon needs to read it # so we want the total count from entries, not only "public/" directory @@ -146,10 +146,6 @@ module Projects project.id, deployment.id ) - rescue => e - # we don't want to break current pages deployment process if something goes wrong - # TODO: remove this rescue as part of https://gitlab.com/gitlab-org/gitlab/-/issues/245308 - Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e) end def latest? diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index bb6be2af5d5..00429f1acbc 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,5 +1,8 @@ - page_title _("Sign up") - add_page_specific_style 'page_bundles/signup' +- content_for :page_specific_javascripts do + = render "layouts/google_tag_manager_head" += render "layouts/google_tag_manager_body" .signup-page = render 'devise/shared/signup_box', diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index e57220a8b14..cce0a3b926e 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,4 +1,7 @@ - page_title _("Sign in") +- content_for :page_specific_javascripts do + = render "layouts/google_tag_manager_head" += render "layouts/google_tag_manager_body" #signin-container - if any_form_based_providers_enabled? diff --git a/app/views/layouts/_google_tag_manager_body.html.haml b/app/views/layouts/_google_tag_manager_body.html.haml new file mode 100644 index 00000000000..d62e52dc91b --- /dev/null +++ b/app/views/layouts/_google_tag_manager_body.html.haml @@ -0,0 +1,4 @@ +- return unless google_tag_manager_enabled? + +<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=#{extra_config.google_tag_manager_id}" +height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript> diff --git a/app/views/layouts/_google_tag_manager_head.html.haml b/app/views/layouts/_google_tag_manager_head.html.haml new file mode 100644 index 00000000000..ab03f1e7670 --- /dev/null +++ b/app/views/layouts/_google_tag_manager_head.html.haml @@ -0,0 +1,8 @@ +- if google_tag_manager_enabled? + = javascript_tag nonce: true do + :plain + (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start': + new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0], + j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src= + 'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f); + })(window,document,'script','dataLayer','#{extra_config.google_tag_manager_id}'); diff --git a/changelogs/unreleased/223768-add-google-analytics-tracking-to-sign-in-pages.yml b/changelogs/unreleased/223768-add-google-analytics-tracking-to-sign-in-pages.yml new file mode 100644 index 00000000000..29b98310b86 --- /dev/null +++ b/changelogs/unreleased/223768-add-google-analytics-tracking-to-sign-in-pages.yml @@ -0,0 +1,5 @@ +--- +title: Add Google Tag Manger to sign in/up and trial pages +merge_request: 38395 +author: +type: changed diff --git a/changelogs/unreleased/271560-enable-ci_include_multiple_files_from_project.yml b/changelogs/unreleased/271560-enable-ci_include_multiple_files_from_project.yml new file mode 100644 index 00000000000..0945f7aa3ec --- /dev/null +++ b/changelogs/unreleased/271560-enable-ci_include_multiple_files_from_project.yml @@ -0,0 +1,5 @@ +--- +title: Implement including multiple files from a project +merge_request: 47609 +author: +type: added diff --git a/changelogs/unreleased/282499-deploy-token-read-package.yml b/changelogs/unreleased/282499-deploy-token-read-package.yml new file mode 100644 index 00000000000..da869cff69e --- /dev/null +++ b/changelogs/unreleased/282499-deploy-token-read-package.yml @@ -0,0 +1,5 @@ +--- +title: Fix deploy token permissions for write_package_registry +merge_request: 47675 +author: +type: fixed diff --git a/changelogs/unreleased/ci-enable-variable-expansion-in-rules-changes.yml b/changelogs/unreleased/ci-enable-variable-expansion-in-rules-changes.yml new file mode 100644 index 00000000000..6a5fbff68cf --- /dev/null +++ b/changelogs/unreleased/ci-enable-variable-expansion-in-rules-changes.yml @@ -0,0 +1,5 @@ +--- +title: Add variable expansion to rules:changes +merge_request: 47783 +author: +type: added diff --git a/changelogs/unreleased/zip_pages_deployments_true.yml b/changelogs/unreleased/zip_pages_deployments_true.yml new file mode 100644 index 00000000000..01c27bc35fc --- /dev/null +++ b/changelogs/unreleased/zip_pages_deployments_true.yml @@ -0,0 +1,5 @@ +--- +title: Store pages content in zip format +merge_request: 47763 +author: +type: added diff --git a/config/application.rb b/config/application.rb index 3493c76899a..db515d8a693 100644 --- a/config/application.rb +++ b/config/application.rb @@ -181,6 +181,7 @@ module Gitlab config.assets.precompile << "page_bundles/cycle_analytics.css" config.assets.precompile << "page_bundles/dev_ops_report.css" config.assets.precompile << "page_bundles/environments.css" + config.assets.precompile << "page_bundles/epics.css" config.assets.precompile << "page_bundles/error_tracking_details.css" config.assets.precompile << "page_bundles/error_tracking_index.css" config.assets.precompile << "page_bundles/signup.css" diff --git a/config/feature_flags/development/ci_include_multiple_files_from_project.yml b/config/feature_flags/development/ci_include_multiple_files_from_project.yml index afa0e1dc7ba..a291287bd4f 100644 --- a/config/feature_flags/development/ci_include_multiple_files_from_project.yml +++ b/config/feature_flags/development/ci_include_multiple_files_from_project.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/271560 milestone: '13.6' type: development group: group::pipeline authoring -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/ci_variable_expansion_in_rules_changes.yml b/config/feature_flags/development/ci_variable_expansion_in_rules_changes.yml index 3d21fb74447..a3a66295896 100644 --- a/config/feature_flags/development/ci_variable_expansion_in_rules_changes.yml +++ b/config/feature_flags/development/ci_variable_expansion_in_rules_changes.yml @@ -4,4 +4,4 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/45037 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/267192 type: development group: group::pipeline authoring -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/custom_emoji.yml b/config/feature_flags/development/custom_emoji.yml new file mode 100644 index 00000000000..64c53c29fdb --- /dev/null +++ b/config/feature_flags/development/custom_emoji.yml @@ -0,0 +1,8 @@ +--- +name: custom_emoji +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/37911 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/231317 +milestone: '13.6' +type: development +group: group::project management +default_enabled: false diff --git a/config/feature_flags/development/zip_pages_deployments.yml b/config/feature_flags/development/zip_pages_deployments.yml index 8be5fd002dd..34aa5c03fdc 100644 --- a/config/feature_flags/development/zip_pages_deployments.yml +++ b/config/feature_flags/development/zip_pages_deployments.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/245308 milestone: '13.5' type: development group: group::release management -default_enabled: false +default_enabled: true diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 21537c06b0b..ae9475aa60d 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1213,6 +1213,9 @@ production: &base ## Google analytics. Uncomment if you want it # google_analytics_id: '_your_tracking_id' + ## Google tag manager + # google_tag_manager_id: '_your_tracking_id' + ## Piwik analytics. # piwik_url: '_your_piwik_url' # piwik_site_id: '_your_piwik_site_id' diff --git a/doc/administration/geo/setup/database.md b/doc/administration/geo/setup/database.md index 51ed7ea68f1..24e55d26997 100644 --- a/doc/administration/geo/setup/database.md +++ b/doc/administration/geo/setup/database.md @@ -477,7 +477,7 @@ information, see [High Availability with Omnibus GitLab](../../postgresql/replic ## Patroni support Support for Patroni is intended to replace `repmgr` as a -[highly availabile PostgreSQL solution](../../postgresql/replication_and_failover.md) +[highly availabile PostgreSQL solution](../../postgresql/replication_and_failover.md) on the primary node, but it can also be used for PostgreSQL HA on a secondary node. @@ -496,14 +496,14 @@ This experimental implementation has the following limitations: avoid this, you can pause auto-failover by running `gitlab-ctl patroni pause`. After a reconfigure, it unpauses on its own. -For instructions about how to set up Patroni on the primary node, see the +For instructions about how to set up Patroni on the primary node, see the [PostgreSQL replication and failover with Omnibus GitLab](../../postgresql/replication_and_failover.md#patroni) page. A production-ready and secure setup requires at least three Patroni instances on the primary, and a similar configuration on the secondary nodes. Be sure to use password credentials and other database best practices. -Similar to `repmgr`, using Patroni on a secondary node is optional. +Similar to `repmgr`, using Patroni on a secondary node is optional. To set up database replication with Patroni on a secondary node, configure a _permanent replication slot_ on the primary node's Patroni cluster, and ensure @@ -516,7 +516,7 @@ On Patroni instances for the primary node, add the following to the # You need one entry for each secondary, with a unique name following PostgreSQL slot_name constraints: # # Configuration syntax will be: 'unique_slotname' => { 'type' => 'physical' }, -# We don't support setting a permanent replication slot for logical replication type +# We don't support setting a permanent replication slot for logical replication type patroni['replication_slots'] = { 'geo_secondary' => { 'type' => 'physical' } } @@ -524,7 +524,7 @@ patroni['replication_slots'] = { postgresql['md5_auth_cidr_addresses'] = [ 'PATRONI_PRIMARY1_IP/32', 'PATRONI_PRIMARY2_IP/32', 'PATRONI_PRIMARY3_IP/32', 'PATRONI_PRIMARY_PGBOUNCER/32', 'PATRONI_SECONDARY1_IP/32', 'PATRONI_SECONDARY2_IP/32', 'PATRONI_SECONDARY3_IP/32' # we list all secondary instances as they can all become a Standby Leader - # any other instance that needs access to the database as per documentation + # any other instance that needs access to the database as per documentation ] postgresql['pgbouncer_user_password'] = 'PGBOUNCER_PASSWORD_HASH' @@ -538,7 +538,7 @@ On Patroni instances for the secondary node, add the following to the ```ruby postgresql['md5_auth_cidr_addresses'] = [ 'PATRONI_SECONDARY1_IP/32', 'PATRONI_SECONDARY2_IP/32', 'PATRONI_SECONDARY3_IP/32', 'PATRONI_SECONDARY_PGBOUNCER/32', - # any other instance that needs access to the database as per documentation + # any other instance that needs access to the database as per documentation ] patroni['enable'] = true diff --git a/doc/administration/troubleshooting/img/ADFS-determine-token-signing-certificate-fingerprint.png b/doc/administration/troubleshooting/img/ADFS-determine-token-signing-certificate-fingerprint.png Binary files differindex cd1b9db31d9..e24c994e996 100644 --- a/doc/administration/troubleshooting/img/ADFS-determine-token-signing-certificate-fingerprint.png +++ b/doc/administration/troubleshooting/img/ADFS-determine-token-signing-certificate-fingerprint.png diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql index a88cf665eba..6e28801b4c3 100644 --- a/doc/api/graphql/reference/gitlab_schema.graphql +++ b/doc/api/graphql/reference/gitlab_schema.graphql @@ -3835,6 +3835,51 @@ type CreateClusterAgentPayload { } """ +Autogenerated input type of CreateCustomEmoji +""" +input CreateCustomEmojiInput { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + Namespace full path the emoji is associated with + """ + groupPath: ID! + + """ + Name of the emoji + """ + name: String! + + """ + Location of the emoji file + """ + url: String! +} + +""" +Autogenerated return type of CreateCustomEmoji +""" +type CreateCustomEmojiPayload { + """ + A unique identifier for the client performing the mutation. + """ + clientMutationId: String + + """ + The new custom emoji + """ + customEmoji: CustomEmoji + + """ + Errors encountered during execution of the mutation. + """ + errors: [String!]! +} + +""" Autogenerated input type of CreateDiffNote """ input CreateDiffNoteInput { @@ -4432,6 +4477,71 @@ interface CurrentUserTodos { } """ +A custom emoji uploaded by user +""" +type CustomEmoji { + """ + Whether the emoji is an external link + """ + external: Boolean! + + """ + The ID of the emoji + """ + id: CustomEmojiID! + + """ + The name of the emoji + """ + name: String! + + """ + The link to file of the emoji + """ + url: String! +} + +""" +The connection type for CustomEmoji. +""" +type CustomEmojiConnection { + """ + A list of edges. + """ + edges: [CustomEmojiEdge] + + """ + A list of nodes. + """ + nodes: [CustomEmoji] + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! +} + +""" +An edge in a connection. +""" +type CustomEmojiEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of the edge. + """ + node: CustomEmoji +} + +""" +Identifier of CustomEmoji +""" +scalar CustomEmojiID + +""" Autogenerated input type of DastOnDemandScanCreate """ input DastOnDemandScanCreateInput { @@ -8517,6 +8627,31 @@ type Group { containsLockedProjects: Boolean! """ + Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled + """ + customEmoji( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + ): CustomEmojiConnection + + """ Description of the namespace """ description: String @@ -13501,6 +13636,11 @@ type Mutation { createBoard(input: CreateBoardInput!): CreateBoardPayload createBranch(input: CreateBranchInput!): CreateBranchPayload createClusterAgent(input: CreateClusterAgentInput!): CreateClusterAgentPayload + + """ + . Available only when feature flag `custom_emoji` is enabled + """ + createCustomEmoji(input: CreateCustomEmojiInput!): CreateCustomEmojiPayload createDiffNote(input: CreateDiffNoteInput!): CreateDiffNotePayload createEpic(input: CreateEpicInput!): CreateEpicPayload createImageDiffNote(input: CreateImageDiffNoteInput!): CreateImageDiffNotePayload diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json index 7684b9dec3c..8e9ad05e0bb 100644 --- a/doc/api/graphql/reference/gitlab_schema.json +++ b/doc/api/graphql/reference/gitlab_schema.json @@ -10479,6 +10479,136 @@ }, { "kind": "INPUT_OBJECT", + "name": "CreateCustomEmojiInput", + "description": "Autogenerated input type of CreateCustomEmoji", + "fields": null, + "inputFields": [ + { + "name": "groupPath", + "description": "Namespace full path the emoji is associated with", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "ID", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "name", + "description": "Name of the emoji", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "url", + "description": "Location of the emoji file", + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "defaultValue": null + }, + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + } + ], + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CreateCustomEmojiPayload", + "description": "Autogenerated return type of CreateCustomEmoji", + "fields": [ + { + "name": "clientMutationId", + "description": "A unique identifier for the client performing the mutation.", + "args": [ + + ], + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "customEmoji", + "description": "The new custom emoji", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmoji", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "errors", + "description": "Errors encountered during execution of the mutation.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + } + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "INPUT_OBJECT", "name": "CreateDiffNoteInput", "description": "Autogenerated input type of CreateDiffNote", "fields": null, @@ -12101,6 +12231,213 @@ ] }, { + "kind": "OBJECT", + "name": "CustomEmoji", + "description": "A custom emoji uploaded by user", + "fields": [ + { + "name": "external", + "description": "Whether the emoji is an external link", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "Boolean", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "id", + "description": "The ID of the emoji", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "CustomEmojiID", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "name", + "description": "The name of the emoji", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "url", + "description": "The link to file of the emoji", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CustomEmojiConnection", + "description": "The connection type for CustomEmoji.", + "fields": [ + { + "name": "edges", + "description": "A list of edges.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "CustomEmojiEdge", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "nodes", + "description": "A list of nodes.", + "args": [ + + ], + "type": { + "kind": "LIST", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "CustomEmoji", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "pageInfo", + "description": "Information to aid in pagination.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "OBJECT", + "name": "PageInfo", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "OBJECT", + "name": "CustomEmojiEdge", + "description": "An edge in a connection.", + "fields": [ + { + "name": "cursor", + "description": "A cursor for use in pagination.", + "args": [ + + ], + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "SCALAR", + "name": "String", + "ofType": null + } + }, + "isDeprecated": false, + "deprecationReason": null + }, + { + "name": "node", + "description": "The item at the end of the edge.", + "args": [ + + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmoji", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + } + ], + "inputFields": null, + "interfaces": [ + + ], + "enumValues": null, + "possibleTypes": null + }, + { + "kind": "SCALAR", + "name": "CustomEmojiID", + "description": "Identifier of CustomEmoji", + "fields": null, + "inputFields": null, + "interfaces": null, + "enumValues": null, + "possibleTypes": null + }, + { "kind": "INPUT_OBJECT", "name": "DastOnDemandScanCreateInput", "description": "Autogenerated input type of DastOnDemandScanCreate", @@ -23576,6 +23913,59 @@ "deprecationReason": null }, { + "name": "customEmoji", + "description": "Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled", + "args": [ + { + "name": "after", + "description": "Returns the elements in the list that come after the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "before", + "description": "Returns the elements in the list that come before the specified cursor.", + "type": { + "kind": "SCALAR", + "name": "String", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "first", + "description": "Returns the first _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + }, + { + "name": "last", + "description": "Returns the last _n_ elements from the list.", + "type": { + "kind": "SCALAR", + "name": "Int", + "ofType": null + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CustomEmojiConnection", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "description", "description": "Description of the namespace", "args": [ @@ -37653,6 +38043,33 @@ "deprecationReason": null }, { + "name": "createCustomEmoji", + "description": ". Available only when feature flag `custom_emoji` is enabled", + "args": [ + { + "name": "input", + "description": null, + "type": { + "kind": "NON_NULL", + "name": null, + "ofType": { + "kind": "INPUT_OBJECT", + "name": "CreateCustomEmojiInput", + "ofType": null + } + }, + "defaultValue": null + } + ], + "type": { + "kind": "OBJECT", + "name": "CreateCustomEmojiPayload", + "ofType": null + }, + "isDeprecated": false, + "deprecationReason": null + }, + { "name": "createDiffNote", "description": null, "args": [ diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 71e4479eafb..78650fc1aa2 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -630,6 +630,16 @@ Autogenerated return type of CreateClusterAgent. | `clusterAgent` | ClusterAgent | Cluster agent created after mutation | | `errors` | String! => Array | Errors encountered during execution of the mutation. | +### CreateCustomEmojiPayload + +Autogenerated return type of CreateCustomEmoji. + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `clientMutationId` | String | A unique identifier for the client performing the mutation. | +| `customEmoji` | CustomEmoji | The new custom emoji | +| `errors` | String! => Array | Errors encountered during execution of the mutation. | + ### CreateDiffNotePayload Autogenerated return type of CreateDiffNote. @@ -721,6 +731,17 @@ Autogenerated return type of CreateTestCase. | `errors` | String! => Array | Errors encountered during execution of the mutation. | | `testCase` | Issue | The test case created | +### CustomEmoji + +A custom emoji uploaded by user. + +| Field | Type | Description | +| ----- | ---- | ----------- | +| `external` | Boolean! | Whether the emoji is an external link | +| `id` | CustomEmojiID! | The ID of the emoji | +| `name` | String! | The name of the emoji | +| `url` | String! | The link to file of the emoji | + ### DastOnDemandScanCreatePayload Autogenerated return type of DastOnDemandScanCreate. @@ -1392,6 +1413,7 @@ Autogenerated return type of EpicTreeReorder. | `codeCoverageActivities` | CodeCoverageActivityConnection | Represents the code coverage activity for this group. Available only when feature flag `group_coverage_data_report_graph` is enabled | | `containerRepositories` | ContainerRepositoryConnection | Container repositories of the project | | `containsLockedProjects` | Boolean! | Includes at least one project where the repository size exceeds the limit | +| `customEmoji` | CustomEmojiConnection | Custom emoji within this namespace. Available only when feature flag `custom_emoji` is enabled | | `description` | String | Description of the namespace | | `descriptionHtml` | String | The GitLab Flavored Markdown rendering of `description` | | `emailsDisabled` | Boolean | Indicates if a group has email notifications disabled | diff --git a/doc/api/oauth2.md b/doc/api/oauth2.md index 127d83b0730..b1c81ff20b6 100644 --- a/doc/api/oauth2.md +++ b/doc/api/oauth2.md @@ -4,7 +4,7 @@ stage: Manage group: Access info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technica l-writing/#designated-technical-writers --- - + # GitLab as an OAuth2 provider This document covers using the [OAuth2](https://oauth.net/2/) protocol to allow @@ -40,7 +40,7 @@ resources which the `application` can access. Upon creation, you'll obtain the To [protect redirect-based flows](https://tools.ietf.org/id/draft-ietf-oauth-security-topics-13.html#rec_redirect), the OAuth specification recommends the use of "One-time use CSRF tokens carried in the state parameter, which are securely bound to the user agent", with each request to the -`/oauth/authorize` endpoint. This can prevent +`/oauth/authorize` endpoint. This can prevent [CSRF attacks](https://wiki.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)). ### Use HTTPS in production @@ -50,7 +50,7 @@ For development, GitLab allows insecure HTTP redirect URIs. As OAuth2 bases its security entirely on the transport layer, you should not use unprotected URIs. For more information, see the [OAuth 2.0 RFC](https://tools.ietf.org/html/rfc6749#section-3.1.2.1) -and the [OAuth 2.0 Threat Model RFC](https://tools.ietf.org/html/rfc6819#section-4.4.2.1). +and the [OAuth 2.0 Threat Model RFC](https://tools.ietf.org/html/rfc6819#section-4.4.2.1). These factors are particularly important when using the [Implicit grant flow](#implicit-grant-flow), where actual credentials are included in the `redirect_uri`. diff --git a/doc/api/projects.md b/doc/api/projects.md index b14fe33ab1f..1c162e0bbd3 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1942,7 +1942,7 @@ PUT /projects/:id To upload an avatar from your file system, use the `--form` argument. This causes cURL to post data using the header `Content-Type: multipart/form-data`. The -`file=` parameter must point to an image file on your file system and be +`file=` parameter must point to an image file on your file system and be preceded by `@`. For example: Example request: diff --git a/doc/architecture/blueprints/image_resizing/index.md b/doc/architecture/blueprints/image_resizing/index.md index ed2dc01b7ed..4e4a1dc739b 100644 --- a/doc/architecture/blueprints/image_resizing/index.md +++ b/doc/architecture/blueprints/image_resizing/index.md @@ -23,7 +23,7 @@ sequenceDiagram Note right of RailsApp: Width Allowlist: https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/concerns/avatarable.rb#L10 RailsApp->>Workhorse: `send-scaled-img:` request Note right of RailsApp: Set `send-scaled-img:` Header - Workhorse->>Workhorse: Image resizing using Go lib + Workhorse->>Workhorse: Image resizing using Go lib Workhorse->>Requester: Serve the resized image else All other cases RailsApp->>Workhorse: Usual request scenario diff --git a/doc/ci/cloud_deployment/index.md b/doc/ci/cloud_deployment/index.md index e8267ec9645..cbaebde0b00 100644 --- a/doc/ci/cloud_deployment/index.md +++ b/doc/ci/cloud_deployment/index.md @@ -311,7 +311,7 @@ build_artifact: - <built artifact> ``` -### Deploy to Amazon EKS +### Deploy to Amazon EKS - [How to deploy your application to a GitLab-managed Amazon EKS cluster with Auto DevOps](https://about.gitlab.com/blog/2020/05/05/deploying-application-eks/) diff --git a/doc/ci/runners/README.md b/doc/ci/runners/README.md index a8ae5296a61..2812e7c1108 100644 --- a/doc/ci/runners/README.md +++ b/doc/ci/runners/README.md @@ -390,7 +390,7 @@ you must have Owner [permissions](../../user/permissions.md#project-members-perm You must set up a runner to be able to run all the different types of jobs that it may encounter on the projects it's shared over. This would be -problematic for large amounts of projects, if it weren't for tags. +problematic for large amounts of projects, if it weren't for tags. GitLab CI tags are not the same as Git tags. GitLab CI tags are associated with runners. Git tags are associated with commits. diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 74ef26fc4b1..d9c83825b5d 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -445,10 +445,10 @@ or template includes. ##### Multiple files from a project > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/26793) in GitLab 13.6. -> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default. -> - It's disabled on GitLab.com. -> - It's not recommended for production use. -> - To use it in GitLab self-managed instances, ask a GitLab administrator to enable it. **(CORE ONLY)** +> - It's [deployed behind a feature flag](../../user/feature_flags.md), enabled by default. +> - It's enabled on GitLab.com. +> - It's recommended for production use. +> - For GitLab self-managed instances, GitLab administrators can opt to disable it. **(CORE ONLY)** You can include multiple files from the same project: @@ -461,10 +461,10 @@ include: - '/templates/.tests.yml' ``` -Including multiple files from the same project is under development and not ready for production use. It is -deployed behind a feature flag that is **disabled by default**. +Including multiple files from the same project is under development but ready for production use. It is +deployed behind a feature flag that is **enabled by default**. [GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md) -can enable it. +can opt to disable it. To enable it: @@ -1350,10 +1350,11 @@ if there is no `if:` statement that limits the job to branch or merge request pi ##### Variables in `rules:changes` > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34272) in GitLab 13.6. -> - It's [deployed behind a feature flag](../../user/feature_flags.md), disabled by default. -> - It's disabled on GitLab.com. -> - It's not recommended for production use. -> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-variables-support-in-ruleschanges). **(CORE ONLY)** +> - It was [deployed behind a feature flag](../../user/feature_flags.md), disabled by default. +> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/267192) in GitLab 13.6. +> - It's enabled on GitLab.com. +> - It's recommended for production use. +> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-variables-support-in-ruleschanges). **(CORE ONLY)** CAUTION: **Warning:** This feature might not be available to you. Check the **version history** note above for details. @@ -1377,10 +1378,10 @@ The `$` character can be used for both variables and paths. For example, if the ###### Enable or disable variables support in `rules:changes` **(CORE ONLY)** -Variables support in `rules:changes` is under development and not ready for production use. It is -deployed behind a feature flag that is **disabled by default**. +Variables support in `rules:changes` is under development, but is ready for production use. +It is deployed behind a feature flag that is **enabled by default**. [GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md) -can enable it. +can opt to disable it. To enable it: diff --git a/doc/development/database/constraint_naming_convention.md b/doc/development/database/constraint_naming_convention.md new file mode 100644 index 00000000000..63a2d607ac5 --- /dev/null +++ b/doc/development/database/constraint_naming_convention.md @@ -0,0 +1,26 @@ +--- +stage: Enablement +group: Database +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/#designated-technical-writers +--- + +# Constraints naming conventions + +The most common option is to let Rails pick the name for database constraints and indexes or let PostgreSQL use the defaults (when applicable). However, when needing to define custom names in Rails or working in Go applications where no ORM is used, it is important to follow strict naming conventions to improve consistency and discoverability. + +The table below describes the naming conventions for custom PostgreSQL constraints. +Please note that the intent is not to retroactively change names in existing databases but rather ensure consistency of future changes. + +| Type | Syntax | Notes | Examples | +|--------------------------|---------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| +| **Primary Key** | `pk_<table name>` | | `pk_projects` | +| **Foreign Key** | `fk_<table name>_<column name>[_and_<column name>]*_<foreign table name>` | | `fk_projects_group_id_groups` | +| **Index** | `index_<table name>_on_<column name>[_and_<column name>]*[_and_<column name in partial clause>]*` | | `index_repositories_on_group_id` | +| **Unique Constraint** | `unique_<table name>_<column name>[_and_<column name>]*` | | `unique_projects_group_id_and_name` | +| **Check Constraint** | `check_<table name>_<column name>[_and_<column name>]*[_<suffix>]?` | The optional suffix should denote the type of validation, such as `length` and `enum`. It can also be used to desambiguate multiple `CHECK` constraints on the same column. | `check_projects_name_length`<br />`check_projects_type_enum`<br />`check_projects_admin1_id_and_admin2_id_differ` | +| **Exclusion Constraint** | `excl_<table name>_<column name>[_and_<column name>]*_[_<suffix>]?` | The optional suffix should denote the type of exclusion being performed. | `excl_reservations_start_at_end_at_no_overlap` | + +## Observations + +- Prefixes are preferred over suffices because they make it easier to identify the type of a given constraint quickly, as well as group them alphabetically; +- The `_and_` that joins column names can be omitted to keep the identifiers under the 63 characters' length limit defined by PostgreSQL. Additionally, the notation may be abbreviated to the best of our ability if struggling to keep under this limit. diff --git a/doc/development/database/index.md b/doc/development/database/index.md index 617a1c5de18..19159c6c0ff 100644 --- a/doc/development/database/index.md +++ b/doc/development/database/index.md @@ -58,6 +58,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w - [Creating enums](../creating_enums.md) - [Client-side connection-pool](client_side_connection_pool.md) - [Updating multiple values](setting_multiple_values.md) +- [Constraints naming conventions](constraint_naming_convention.md) ## Case studies diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index 6bc498636df..de9a9f5cb14 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -107,7 +107,7 @@ browser's developer console while on any page within GitLab. - **JavaScript that relies on CSS for calculations should use [`waitForCSSLoaded()`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/helpers/startup_css_helper.js#L34):** GitLab uses [Startup.css](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38052) to improve page performance. This can cause issues if JavaScript relies on CSS - for calculations. To fix this the JavaScript can be wrapped in the + for calculations. To fix this the JavaScript can be wrapped in the [`waitForCSSLoaded()`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/helpers/startup_css_helper.js#L34) helper function. diff --git a/doc/development/graphql_guide/pagination.md b/doc/development/graphql_guide/pagination.md index 6ac8ab19148..d5140363396 100644 --- a/doc/development/graphql_guide/pagination.md +++ b/doc/development/graphql_guide/pagination.md @@ -207,14 +207,14 @@ These types of queries are not supported. In these instances, you can use offset ### Offset pagination -There are times when the [complexity of sorting](#limitations-of-query-complexity) +There are times when the [complexity of sorting](#limitations-of-query-complexity) is more than our keyset pagination can handle. For example, in [`IssuesResolver`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/resolvers/issues_resolver.rb), when sorting by `priority_asc`, we can't use keyset pagination as the ordering is much too complex. For more information, read [`issuable.rb`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/models/concerns/issuable.rb). -In cases like this, we can fall back to regular offset pagination by returning a +In cases like this, we can fall back to regular offset pagination by returning a [`Gitlab::Graphql::Pagination::OffsetActiveRecordRelationConnection`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/graphql/pagination/offset_active_record_relation_connection.rb) instead of an `ActiveRecord::Relation`: diff --git a/doc/development/img/merge_ref_head_options_v13_6.png b/doc/development/img/merge_ref_head_options_v13_6.png Binary files differindex 30dfda8f22c..3134092cc92 100644 --- a/doc/development/img/merge_ref_head_options_v13_6.png +++ b/doc/development/img/merge_ref_head_options_v13_6.png diff --git a/doc/development/merge_request_performance_guidelines.md b/doc/development/merge_request_performance_guidelines.md index 60c6ad2dad1..a5d9a653472 100644 --- a/doc/development/merge_request_performance_guidelines.md +++ b/doc/development/merge_request_performance_guidelines.md @@ -172,7 +172,7 @@ The code introduced by a merge request, should not execute multiple duplicated c The total number of the queries (including cached ones) executed by the code modified or added by a merge request should not increase unless absolutely necessary. -The number of executed queries (including cached queries) should not depend on +The number of executed queries (including cached queries) should not depend on collection size. You can write a test by passing the `skip_cached` variable to [QueryRecorder](query_recorder.md) to detect this and prevent regressions. @@ -205,7 +205,7 @@ It will re-instantiate project object for each build, instead of using the same In this particular case the workaround is fairly easy: ```ruby -pipeline.builds.each do |build| +pipeline.builds.each do |build| build.project = pipeline.project build.to_json(only: [:name], include: [project: { only: [:name]}]) end diff --git a/doc/development/product_analytics/usage_ping.md b/doc/development/product_analytics/usage_ping.md index e6ffb052a5a..2086318c4d7 100644 --- a/doc/development/product_analytics/usage_ping.md +++ b/doc/development/product_analytics/usage_ping.md @@ -737,13 +737,20 @@ In order to add data for aggregated metrics into Usage Ping payload you should a - operator: operator that defines how aggregated metric data will be counted. Available operators are: - `ANY`: removes duplicates and counts all entries that triggered any of listed events - events: list of events names (from [`known_events.yml`](#known-events-in-usage-data-payload)) to aggregate into metric. All events in this list must have the same `redis_slot` and `aggregation` attributes. +- feature_flag: name of [development feature flag](../feature_flags/development.md#development-type) that will be checked before +metrics aggregation is performed. Corresponding feature flag should have `default_enabled` attribute set to `false`. +`feature_flag` attribute is **OPTIONAL** and can be omitted, when `feature_flag` is missing no feature flag will be checked. -Example aggregated metric entry: +Example aggregated metric entries: ```yaml - name: example_aggregated_metric operator: ANY + events: ['i_search_advanced', 'i_search_paid'] +- name: example_aggregated_metric_with_feautre_flag + operator: ANY events: ['i_search_total', 'i_search_advanced', 'i_search_paid'] + feature_flag: example_aggregated_metric ``` Aggregated metrics will be added under `aggregated_metrics` key in both `counts_weekly` and `counts_monthly` top level keys in Usage Ping payload. diff --git a/doc/development/query_recorder.md b/doc/development/query_recorder.md index d8951c64071..4a02af3348c 100644 --- a/doc/development/query_recorder.md +++ b/doc/development/query_recorder.md @@ -31,8 +31,8 @@ In some cases the query count might change slightly between runs for unrelated r ## Cached queries By default, QueryRecorder will ignore [cached queries](merge_request_performance_guidelines.md#cached-queries) in the count. However, it may be better to count -all queries to avoid introducing an N+1 query that may be masked by the statement cache. -To do this, this requires the `:use_sql_query_cache` flag to be set. +all queries to avoid introducing an N+1 query that may be masked by the statement cache. +To do this, this requires the `:use_sql_query_cache` flag to be set. You should pass the `skip_cached` variable to `QueryRecorder` and use the `exceed_all_query_limit` matcher: ```ruby diff --git a/doc/development/reference_processing.md b/doc/development/reference_processing.md index b74419ee5b6..07833c0d302 100644 --- a/doc/development/reference_processing.md +++ b/doc/development/reference_processing.md @@ -41,7 +41,7 @@ For example, the class is responsible for handling references to issues, such as `gitlab-org/gitlab#123` and `https://gitlab.com/gitlab-org/gitlab/-/issues/200048`. -All reference filters are instances of [`HTML::Pipeline::Filter`](https://www.rubydoc.info/github/jch/html-pipeline/v1.11.0/HTML/Pipeline/Filter), +All reference filters are instances of [`HTML::Pipeline::Filter`](https://www.rubydoc.info/github/jch/html-pipeline/HTML/Pipeline/Filter), and inherit (often indirectly) from [`Banzai::Filter::ReferenceFilter`](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/banzai/filter/reference_filter.rb). `HTML::Pipeline::Filter` has a simple interface consisting of `#call`, a void diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md index 616bb752694..415edce0d7d 100644 --- a/doc/gitlab-basics/create-project.md +++ b/doc/gitlab-basics/create-project.md @@ -128,10 +128,10 @@ To use a custom project template on the **New project** page: > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/26388) in GitLab 10.5. -When you create a new repository locally, instead of manually creating a new project in GitLab +When you create a new repository locally, instead of manually creating a new project in GitLab and then [cloning the repository](start-using-git.md#clone-a-repository) locally, you can directly push it to GitLab to create the new project, all without leaving -your terminal. If you have access rights to the associated namespace, GitLab +your terminal. If you have access rights to the associated namespace, GitLab automatically creates a new project under that GitLab namespace with its visibility set to Private by default (you can later change it in the [project's settings](../public_access/public_access.md#how-to-change-project-visibility)). diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md index bb72dc5aa56..a1774ddb770 100644 --- a/doc/install/aws/index.md +++ b/doc/install/aws/index.md @@ -349,6 +349,10 @@ Now that the database is created, let's move on to setting up Redis with ElastiC ElastiCache is an in-memory hosted caching solution. Redis maintains its own persistence and is used to store session data, temporary cache information, and background job queues for the GitLab application. +DANGER: **Warning:** +GitLab recommends you use ElastiCache Redis version 5.0.x, because version 6.x contains +a bug that [prevents Sidekiq from processing jobs](https://gitlab.com/gitlab-org/gitlab/-/issues/281683). + ### Create a Redis Security Group 1. Navigate to the EC2 dashboard. diff --git a/doc/user/admin_area/broadcast_messages.md b/doc/user/admin_area/broadcast_messages.md index f594f6d736f..0bbdf5bc5e7 100644 --- a/doc/user/admin_area/broadcast_messages.md +++ b/doc/user/admin_area/broadcast_messages.md @@ -73,7 +73,7 @@ To add a broadcast message: NOTE: **Note:** The **Background color** field expects the value to be a hexadecimal code because the form uses the [color_field](https://api.rubyonrails.org/v6.0.3.4/classes/ActionView/Helpers/FormHelper.html#method-i-color_field) -helper method, which generates the proper HTML to render. +helper method, which generates the proper HTML to render. NOTE: **Note:** Once a broadcast message has expired, it is no longer displayed in the UI but is still listed in the diff --git a/doc/user/admin_area/settings/sign_in_restrictions.md b/doc/user/admin_area/settings/sign_in_restrictions.md index 7f30149f5d7..7ab1d396e8b 100644 --- a/doc/user/admin_area/settings/sign_in_restrictions.md +++ b/doc/user/admin_area/settings/sign_in_restrictions.md @@ -51,7 +51,7 @@ All users will be redirect to the page represented by the configured "After sign after sign out if value is not empty. In the Sign-in restrictions section, scroll to the "Sign-in text" text box. You can add a -custom message for your users in Markdown format. +custom message for your users in Markdown format. For example, if you include the following information in the noted text box: diff --git a/doc/user/application_security/coverage_fuzzing/img/coverage_fuzzing_report_v13_6.png b/doc/user/application_security/coverage_fuzzing/img/coverage_fuzzing_report_v13_6.png Binary files differindex b3b0e5def86..bed3ca4c9df 100644 --- a/doc/user/application_security/coverage_fuzzing/img/coverage_fuzzing_report_v13_6.png +++ b/doc/user/application_security/coverage_fuzzing/img/coverage_fuzzing_report_v13_6.png diff --git a/doc/user/application_security/dependency_list/img/yarn_dependency_path_v13_6.png b/doc/user/application_security/dependency_list/img/yarn_dependency_path_v13_6.png Binary files differindex 6f1f456ab72..78e324f43c4 100644 --- a/doc/user/application_security/dependency_list/img/yarn_dependency_path_v13_6.png +++ b/doc/user/application_security/dependency_list/img/yarn_dependency_path_v13_6.png diff --git a/doc/user/application_security/dependency_scanning/index.md b/doc/user/application_security/dependency_scanning/index.md index 10f0866430b..1b164c9cecd 100644 --- a/doc/user/application_security/dependency_scanning/index.md +++ b/doc/user/application_security/dependency_scanning/index.md @@ -356,7 +356,7 @@ Here are the requirements for using dependency scanning in an offline environmen - GitLab Runner with the [`docker` or `kubernetes` executor](#requirements). - Docker Container Registry with locally available copies of dependency scanning [analyzer](https://gitlab.com/gitlab-org/security-products/analyzers) images. -- If you have a limited access environment you will need to allow access, such as using a proxy, to the advisory database: `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git`. +- If you have a limited access environment you will need to allow access, such as using a proxy, to the advisory database: `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git`. If you are unable to permit access to `https://gitlab.com/gitlab-org/security-products/gemnasium-db.git` you must host an offline copy of this `git` repository and set the `GEMNASIUM_DB_REMOTE_URL` variable to the URL of this repository. For more information on configuration variables, see [Dependency Scanning](#configuring-dependency-scanning). This advisory database is constantly being updated, so you will need to periodically sync your local copy with GitLab's. diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md index a1e99d869eb..60dea15475d 100644 --- a/doc/user/application_security/secret_detection/index.md +++ b/doc/user/application_security/secret_detection/index.md @@ -35,12 +35,12 @@ GitLab displays identified secrets visibly in a few places: Secret Detection detects a variety of common secrets by default. You can also customize the secret detection patterns using [custom rulesets](#custom-rulesets). -The [default ruleset provided by Gitleaks](https://gitlab.com/gitlab-org/security-products/analyzers/secrets/-/blob/master/gitleaks/gitleaks.toml) includes the following key types: +The [default ruleset provided by Gitleaks](https://gitlab.com/gitlab-org/security-products/analyzers/secrets/-/blob/master/gitleaks/gitleaks.toml) includes the following key types: - Cloud services: - Amazon Web Services (AWS) - - Google Cloud Platform (GCP) -Encryption keys: + - Google Cloud Platform (GCP) +Encryption keys: - PKCS8 - RSA - SSH @@ -48,7 +48,7 @@ Encryption keys: - Social media platforms: - Facebook API - Twitter API -- Cloud SaaS vendors: +- Cloud SaaS vendors: - GitHub API - Slack Token - Stripe API diff --git a/doc/user/application_security/security_dashboard/index.md b/doc/user/application_security/security_dashboard/index.md index 06c4ddba102..9f402cea9dc 100644 --- a/doc/user/application_security/security_dashboard/index.md +++ b/doc/user/application_security/security_dashboard/index.md @@ -67,13 +67,13 @@ the analyzer outputs an > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235558) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.6. -At the project level, the Security Dashboard displays a chart with the number of vulnerabilities over time. +At the project level, the Security Dashboard displays a chart with the number of vulnerabilities over time. Access it by navigating to **Security & Compliance > Security Dashboard**. Currently, we display historical data up to 365 days. ![Project Security Dashboard](img/project_security_dashboard_chart_v13_6.png) -Filter the historical data by clicking on the corresponding legend name. The image above, for example, shows +Filter the historical data by clicking on the corresponding legend name. The image above, for example, shows only the graph for vulnerabilities with **high** severity. ### Vulnerability Report diff --git a/doc/user/clusters/applications.md b/doc/user/clusters/applications.md index 4f20e3b6cd6..614c21da1a8 100644 --- a/doc/user/clusters/applications.md +++ b/doc/user/clusters/applications.md @@ -64,21 +64,35 @@ supported by GitLab before installing any of the applications. > - Introduced in GitLab 10.2 for project-level clusters. > - Introduced in GitLab 11.6 for group-level clusters. > - [Uses a local Tiller](https://gitlab.com/gitlab-org/gitlab/-/issues/209736) in GitLab 13.2 and later. +> - [Uses Helm 3](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46267) for clusters created with GitLab 13.6 and later. [Helm](https://helm.sh/docs/) is a package manager for Kubernetes and is used to install the GitLab-managed apps. GitLab runs each `helm` command in a pod within the `gitlab-managed-apps` namespace inside the cluster. -GitLab's integration uses Helm 2 with a local -[Tiller](https://v2.helm.sh/docs/glossary/#tiller) server for managing -applications. Prior to [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/209736), -GitLab used an in-cluster Tiller server in the `gitlab-managed-apps` -namespace. This server can now be safely removed. +- For clusters created on GitLab 13.6 and newer, GitLab uses Helm 3 to manage + applications. +- For clusters created on versions of GitLab prior to 13.6, GitLab uses + Helm 2 with a local [Tiller](https://v2.helm.sh/docs/glossary/#tiller) server. + Prior to [GitLab 13.2](https://gitlab.com/gitlab-org/gitlab/-/issues/209736), + GitLab used an in-cluster Tiller server in the `gitlab-managed-apps` + namespace. You can safely remove this server after upgrading to GitLab 13.2 + or newer. GitLab's Helm integration does not support installing applications behind a proxy, but a [workaround](../../topics/autodevops/index.md#install-applications-behind-a-proxy) is available. +#### Upgrade a cluster to Helm 3 + +GitLab does not currently offer a way to migrate existing application management +on existing clusters from Helm 2 to Helm 3. To migrate a cluster to Helm 3: + +1. Uninstall all applications on your cluster. +1. [Remove the cluster integration](../project/clusters/add_remove_clusters.md#removing-integration). +1. [Re-add the cluster](../project/clusters/add_remove_clusters.md#existing-kubernetes-cluster) as + an existing cluster. + ### cert-manager > Introduced in GitLab 11.6 for project- and group-level clusters. diff --git a/doc/user/gitlab_com/index.md b/doc/user/gitlab_com/index.md index 996aae4c780..321ae1e6005 100644 --- a/doc/user/gitlab_com/index.md +++ b/doc/user/gitlab_com/index.md @@ -635,7 +635,7 @@ You can view more information in our runbooks such as: By default, GitLab does not expire job logs. Job logs are retained indefinitely, and can't be configured on GitLab.com to expire. You can erase job logs [manually with the Jobs API](../../api/jobs.md#erase-a-job) or by -[deleting a pipeline](../../ci/pipelines/index.md#delete-a-pipeline). +[deleting a pipeline](../../ci/pipelines/index.md#delete-a-pipeline). ## GitLab.com at scale diff --git a/doc/user/group/img/create_new_project_from_group.png b/doc/user/group/img/create_new_project_from_group.png Binary files differdeleted file mode 100644 index df98091334c..00000000000 --- a/doc/user/group/img/create_new_project_from_group.png +++ /dev/null diff --git a/doc/user/packages/go_proxy/index.md b/doc/user/packages/go_proxy/index.md index 70ce17994fc..b642a5387c9 100644 --- a/doc/user/packages/go_proxy/index.md +++ b/doc/user/packages/go_proxy/index.md @@ -94,7 +94,7 @@ following steps work only if GitLab is configured for HTTPS: ### Enable request authentication Create a [personal access token](../../profile/personal_access_tokens.md) with -the scope set to `api` or `read_api`. +the scope set to `api` or `read_api`. Add it to [`~/.netrc`](https://ec.haxx.se/usingcurl/usingcurl-netrc): @@ -112,7 +112,7 @@ When downloading dependencies with Go 1.13 and later, fetched sources are validated against the checksum database `sum.golang.org`. If the checksum of the fetched sources doesn't match the checksum from the -database, Go doesn't build the dependency. +database, Go doesn't build the dependency. Private modules fail to build because `sum.golang.org` can't fetch the source of private modules, and so it cannot provide a checksum. diff --git a/doc/user/packages/maven_repository/index.md b/doc/user/packages/maven_repository/index.md index a46835783ed..5d0d64b310d 100644 --- a/doc/user/packages/maven_repository/index.md +++ b/doc/user/packages/maven_repository/index.md @@ -614,7 +614,7 @@ When this is completed, there are two ways to install a package. To install a package by using `mvn install`: -1. Add the dependency manually to your project `pom.xml` file. +1. Add the dependency manually to your project `pom.xml` file. To add the example created earlier, the XML would be: ```xml @@ -705,7 +705,7 @@ You can create a new package each time the `master` branch is updated. </settings> ``` -1. Make sure your `pom.xml` file includes the following. +1. Make sure your `pom.xml` file includes the following. You can either let Maven use the CI environment variables, as shown in this example, or you can hard code your project's ID. diff --git a/doc/user/packages/nuget_repository/img/visual_studio_nuget_source_added.png b/doc/user/packages/nuget_repository/img/visual_studio_nuget_source_added.png Binary files differindex bba2d680b25..8c14a14e304 100644 --- a/doc/user/packages/nuget_repository/img/visual_studio_nuget_source_added.png +++ b/doc/user/packages/nuget_repository/img/visual_studio_nuget_source_added.png diff --git a/doc/user/packages/nuget_repository/index.md b/doc/user/packages/nuget_repository/index.md index e95055ba02b..2b61c4a6c28 100644 --- a/doc/user/packages/nuget_repository/index.md +++ b/doc/user/packages/nuget_repository/index.md @@ -248,7 +248,7 @@ nuget install <package_id> -OutputDirectory <output_directory> \ - `<package_id>` is the package ID. - `<output_directory>` is the output directory, where the package is installed. -- `<package_version>` The package version. Optional. +- `<package_version>` The package version. Optional. - `<source_name>` The source name. Optional. ### Install a package with the .NET CLI diff --git a/doc/user/packages/pypi_repository/index.md b/doc/user/packages/pypi_repository/index.md index 66e5d38c331..83b29d5f53a 100644 --- a/doc/user/packages/pypi_repository/index.md +++ b/doc/user/packages/pypi_repository/index.md @@ -113,7 +113,7 @@ After you create a project, you can create a package. ```python import setuptools - + setuptools.setup( name="mypypipackage", version="0.0.1", @@ -333,7 +333,7 @@ Successfully installed mypypipackage-0.0.1 ### Package names GitLab looks for packages that use -[Python normalized names (PEP-503)](https://www.python.org/dev/peps/pep-0503/#normalized-names). +[Python normalized names (PEP-503)](https://www.python.org/dev/peps/pep-0503/#normalized-names). The characters `-`, `_`, and `.` are all treated the same, and repeated characters are removed. diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md index c0152ce7d88..dacb6c3a5a7 100644 --- a/doc/user/profile/account/two_factor_authentication.md +++ b/doc/user/profile/account/two_factor_authentication.md @@ -124,9 +124,9 @@ First configure FortiAuthenticator in GitLab. On your GitLab server: ``` 1. Save the configuration file. -1. [Reconfigure](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) +1. [Reconfigure](../../../administration/restart_gitlab.md#omnibus-gitlab-reconfigure) or [restart GitLab](../../../administration/restart_gitlab.md#installations-from-source) - for the changes to take effect if you installed GitLab via Omnibus or from + for the changes to take effect if you installed GitLab via Omnibus or from source respectively. #### Enable FortiAuthenticator integration @@ -376,7 +376,7 @@ Sign in and re-enable two-factor authentication as soon as possible. you may have cases where authorization always fails because of time differences. - The GitLab U2F implementation does _not_ work when the GitLab instance is accessed from multiple hostnames, or FQDNs. Each U2F registration is linked to the _current hostname_ at - the time of registration, and cannot be used for other hostnames/FQDNs. The same applies to + the time of registration, and cannot be used for other hostnames/FQDNs. The same applies to WebAuthn registrations. For example, if a user is trying to access a GitLab instance from `first.host.xyz` and `second.host.xyz`: diff --git a/doc/user/profile/img/busy_status_indicator_v13_6.png b/doc/user/profile/img/busy_status_indicator_v13_6.png Binary files differindex fa945264b8e..291e0fab971 100644 --- a/doc/user/profile/img/busy_status_indicator_v13_6.png +++ b/doc/user/profile/img/busy_status_indicator_v13_6.png diff --git a/doc/user/project/clusters/add_eks_clusters.md b/doc/user/project/clusters/add_eks_clusters.md index c0e45a0ff14..c3f2b96ce9f 100644 --- a/doc/user/project/clusters/add_eks_clusters.md +++ b/doc/user/project/clusters/add_eks_clusters.md @@ -139,7 +139,7 @@ To create and add a new Kubernetes cluster to your project, group, or instance: 1. Enter a role name and optional description into the fields provided. 1. Click **Create role**, the new role name will appear at the top. Click on its name and copy the `Role ARN` from the newly created role. 1. In GitLab, enter the copied role ARN into the `Role ARN` field. -1. In the **Cluster Region** field, enter the [region](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) you plan to use for your new cluster. GitLab will authenticate you have access to this region when authenticating your role. +1. In the **Cluster Region** field, enter the [region](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html) you plan to use for your new cluster. GitLab will authenticate you have access to this region when authenticating your role. 1. Click **Authenticate with AWS**. 1. Choose your cluster's settings: - **Kubernetes cluster name** - The name you wish to give the cluster. @@ -184,7 +184,7 @@ The following errors are commonly encountered when creating a new cluster. When submitting the initial authentication form, GitLab returns a status code 422 error when it can't determine the role or region you've provided. Make sure you've correctly configured your role with the **Account ID** and **External ID** -provided by GitLab. In GitLab, make sure to enter the correct **Role ARN**. +provided by GitLab. In GitLab, make sure to enter the correct **Role ARN**. Make sure you also have access to the chosen region. #### Could not load Security Groups for this VPC diff --git a/doc/user/project/clusters/securing.md b/doc/user/project/clusters/securing.md index 2d2dce275d2..2d74f67ba35 100644 --- a/doc/user/project/clusters/securing.md +++ b/doc/user/project/clusters/securing.md @@ -42,7 +42,7 @@ Minimum requirements (depending on the GitLab Manage Application you want to ins NOTE: **Note:** These diagrams use the term _Kubernetes_ for simplicity. In practice, Sidekiq connects to a Helm -Tiller daemon running in a pod in the cluster. +command runner pod in the cluster. You install GitLab Managed Apps from the GitLab web interface with a one-click setup process. GitLab uses Sidekiq (a background processing service) to facilitate this. diff --git a/doc/user/project/img/rollout_status_canary_ingress.png b/doc/user/project/img/rollout_status_canary_ingress.png Binary files differindex 593650c3a3b..fb59ba31615 100644 --- a/doc/user/project/img/rollout_status_canary_ingress.png +++ b/doc/user/project/img/rollout_status_canary_ingress.png diff --git a/doc/user/search/advanced_search_syntax.md b/doc/user/search/advanced_search_syntax.md index c4040878e02..c1414fb9ebe 100644 --- a/doc/user/search/advanced_search_syntax.md +++ b/doc/user/search/advanced_search_syntax.md @@ -65,7 +65,7 @@ The Advanced Search Syntax also supports the use of filters. The available filte - blob: Filters by Git `object ID`. Exact match only. To use them, add them to your keyword in the format `<filter_name>:<value>` without -any spaces between the colon (`:`) and the value. A keyword or an asterisk (`*`) is required for filter searches and has to be added in front of the filter separated by a space. +any spaces between the colon (`:`) and the value. A keyword or an asterisk (`*`) is required for filter searches and has to be added in front of the filter separated by a space. Examples: diff --git a/doc/user/search/img/filtering_merge_requests_by_date_v13_6.png b/doc/user/search/img/filtering_merge_requests_by_date_v13_6.png Binary files differindex 13ed7ccbb84..8f59534ef1c 100644 --- a/doc/user/search/img/filtering_merge_requests_by_date_v13_6.png +++ b/doc/user/search/img/filtering_merge_requests_by_date_v13_6.png diff --git a/doc/user/search/img/filtering_merge_requests_by_environment_v13_6.png b/doc/user/search/img/filtering_merge_requests_by_environment_v13_6.png Binary files differindex 24553ce6730..e73a0995d73 100644 --- a/doc/user/search/img/filtering_merge_requests_by_environment_v13_6.png +++ b/doc/user/search/img/filtering_merge_requests_by_environment_v13_6.png diff --git a/lib/gitlab/ci/build/rules/rule/clause/changes.rb b/lib/gitlab/ci/build/rules/rule/clause/changes.rb index ee267a33aa7..cbecce57163 100644 --- a/lib/gitlab/ci/build/rules/rule/clause/changes.rb +++ b/lib/gitlab/ci/build/rules/rule/clause/changes.rb @@ -20,7 +20,7 @@ module Gitlab end def expand_globs(pipeline, context) - return @globs unless ::Feature.enabled?(:ci_variable_expansion_in_rules_changes, pipeline.project) + return @globs unless ::Feature.enabled?(:ci_variable_expansion_in_rules_changes, pipeline.project, default_enabled: true) return @globs unless context @globs.map do |glob| diff --git a/lib/gitlab/ci/config/external/mapper.rb b/lib/gitlab/ci/config/external/mapper.rb index 7198163216e..90692eafc3f 100644 --- a/lib/gitlab/ci/config/external/mapper.rb +++ b/lib/gitlab/ci/config/external/mapper.rb @@ -54,7 +54,7 @@ module Gitlab end def expand_project_files(location) - return location unless ::Feature.enabled?(:ci_include_multiple_files_from_project, context.project, default_enabled: false) + return location unless ::Feature.enabled?(:ci_include_multiple_files_from_project, context.project, default_enabled: true) return location unless location[:project] Array.wrap(location[:file]).map do |file| diff --git a/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml b/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml index 0b029ca6aec..e1189f3de09 100644 --- a/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml +++ b/lib/gitlab/usage_data_counters/aggregated_metrics/common.yml @@ -4,10 +4,15 @@ # - "ALL": counts unique elements that were observed triggering all of following events # events: list of events names to aggregate into metric. All events in this list must have the same 'redis_slot' and 'aggregation' attributes # see from lib/gitlab/usage_data_counters/known_events/ for the list of valid events. +# feature_flag: name of development feature flag that will be checked before metrics aggregation is performed. +# Corresponding feature flag should have `default_enabled` attribute set to `false`. +# This attribute is OPTIONAL and can be omitted, when `feature_flag` is missing no feature flag will be checked. --- - name: product_analytics_test_aggregated_metrics operator: ANY events: ['i_search_total', 'i_search_advanced', 'i_search_paid'] + feature_flag: product_analytics_aggregated_metrics - name: product_analytics_test_combined_events operator: ALL events: ['i_search_total', 'i_search_advanced', 'i_search_paid'] + feature_flag: product_analytics_aggregated_metrics diff --git a/lib/gitlab/usage_data_counters/hll_redis_counter.rb b/lib/gitlab/usage_data_counters/hll_redis_counter.rb index 1f5cdf72a2a..c26c9186ce2 100644 --- a/lib/gitlab/usage_data_counters/hll_redis_counter.rb +++ b/lib/gitlab/usage_data_counters/hll_redis_counter.rb @@ -97,15 +97,11 @@ module Gitlab end def aggregated_metrics_monthly_data - aggregated_metrics.to_h do |aggregation| - [aggregation[:name], calculate_count_for_aggregation(aggregation, start_date: 4.weeks.ago.to_date, end_date: Date.current)] - end + aggregated_metrics_data(4.weeks.ago.to_date) end def aggregated_metrics_weekly_data - aggregated_metrics.to_h do |aggregation| - [aggregation[:name], calculate_count_for_aggregation(aggregation, start_date: 7.days.ago.to_date, end_date: Date.current)] - end + aggregated_metrics_data(7.days.ago.to_date) end def known_events @@ -132,6 +128,14 @@ module Gitlab Plan.all_plans end + def aggregated_metrics_data(start_date) + aggregated_metrics.each_with_object({}) do |aggregation, weekly_data| + next if aggregation[:feature_flag] && Feature.disabled?(aggregation[:feature_flag], default_enabled: false, type: :development) + + weekly_data[aggregation[:name]] = calculate_count_for_aggregation(aggregation, start_date: start_date, end_date: Date.current) + end + end + def calculate_count_for_aggregation(aggregation, start_date:, end_date:) case aggregation[:operator] when UNION_OF_AGGREGATED_METRICS diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 9b14d4951a8..31536b15e36 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -2574,6 +2574,9 @@ msgstr "" msgid "AlertSettings|If you edit the payload, the stored mapping will be reset, and you'll need to re-map the fields." msgstr "" +msgid "AlertSettings|If you've provided a sample alert payload, you can create a custom mapping for your endpoint. The default GitLab alert keys are listed below. Please define which payload key should map to the specified GitLab key." +msgstr "" + msgid "AlertSettings|In free versions of GitLab, only one integration for each type can be added. %{linkStart}Upgrade your subscription%{linkEnd} to add additional integrations." msgstr "" @@ -2613,6 +2616,9 @@ msgstr "" msgid "AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint." msgstr "" +msgid "AlertSettings|Sample payload has been parsed. You can now map the fields." +msgstr "" + msgid "AlertSettings|Save and test payload" msgstr "" @@ -2634,9 +2640,6 @@ msgstr "" msgid "AlertSettings|Test failed. Do you still want to save your changes anyway?" msgstr "" -msgid "AlertSettings|The default GitLab alert keys are listed below. In the event an exact match could be found in the sample payload provided, that key will be mapped automatically. In all other cases, please define which payload key should map to the specified GitLab key. Any payload keys not shown in this list will not display in the alert list, but will display on the alert details page." -msgstr "" - msgid "AlertSettings|There was an error updating the alert settings." msgstr "" diff --git a/package.json b/package.json index 67c9c05e042..2bdf7f644c9 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "@babel/preset-env": "^7.10.1", "@gitlab/at.js": "1.5.5", "@gitlab/svgs": "1.175.0", - "@gitlab/ui": "23.8.0", + "@gitlab/ui": "23.9.0", "@gitlab/visual-review-tools": "1.6.1", "@rails/actioncable": "^6.0.3-3", "@rails/ujs": "^6.0.3-2", diff --git a/spec/factories/custom_emoji.rb b/spec/factories/custom_emoji.rb index 2d185794ac9..ba1ae11c18d 100644 --- a/spec/factories/custom_emoji.rb +++ b/spec/factories/custom_emoji.rb @@ -4,6 +4,7 @@ FactoryBot.define do factory :custom_emoji, class: 'CustomEmoji' do sequence(:name) { |n| "custom_emoji#{n}" } namespace - file { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) } + group + file { 'https://gitlab.com/images/partyparrot.png' } end end diff --git a/spec/finders/personal_access_tokens_finder_spec.rb b/spec/finders/personal_access_tokens_finder_spec.rb index c8913329839..cece80047e1 100644 --- a/spec/finders/personal_access_tokens_finder_spec.rb +++ b/spec/finders/personal_access_tokens_finder_spec.rb @@ -62,6 +62,27 @@ RSpec.describe PersonalAccessTokensFinder do revoked_impersonation_token, expired_impersonation_token) end + describe 'with users' do + let(:user2) { create(:user) } + + before do + create(:personal_access_token, user: user2) + create(:personal_access_token, :expired, user: user2) + create(:personal_access_token, :revoked, user: user2) + create(:personal_access_token, :impersonation, user: user2) + create(:personal_access_token, :expired, :impersonation, user: user2) + create(:personal_access_token, :revoked, :impersonation, user: user2) + + params[:users] = [user] + end + + it { + is_expected.to contain_exactly(active_personal_access_token, active_impersonation_token, + revoked_personal_access_token, expired_personal_access_token, + revoked_impersonation_token, expired_impersonation_token) + } + end + describe 'with sort order' do before do params[:sort] = 'id_asc' diff --git a/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap b/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap index e4ef232a320..815aa430d87 100644 --- a/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap +++ b/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_new_spec.js.snap @@ -80,10 +80,10 @@ exports[`AlertsSettingsFormNew with default values renders the initial template <!----> <!----> <!----> - <!----> </div> </div> <!----> + <!----> </div> <div class=\\"gl-display-flex gl-justify-content-end\\"><button type=\\"reset\\" class=\\"btn gl-mr-3 js-no-auto-disable btn-default btn-md gl-button\\"> <!----> diff --git a/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js b/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js index 539ea5676ef..fbd482b1906 100644 --- a/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js +++ b/spec/frontend/alerts_settings/alerts_settings_form_new_spec.js @@ -6,14 +6,15 @@ import { GlFormInput, GlToggle, GlFormTextarea, - GlButton, } from '@gitlab/ui'; +import waitForPromises from 'helpers/wait_for_promises'; import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form_new.vue'; import { defaultAlertSettingsConfig } from './util'; import { typeSet } from '~/alerts_settings/constants'; describe('AlertsSettingsFormNew', () => { let wrapper; + const mockToastShow = jest.fn(); const createComponent = ({ data = {}, @@ -34,6 +35,11 @@ describe('AlertsSettingsFormNew', () => { glFeatures: { multipleHttpIntegrationsCustomMapping }, ...defaultAlertSettingsConfig, }, + mocks: { + $toast: { + show: mockToastShow, + }, + }, }); }; @@ -49,6 +55,7 @@ describe('AlertsSettingsFormNew', () => { wrapper.find(`[data-testid="multi-integrations-not-supported"]`); const findJsonTestSubmit = () => wrapper.find(`[data-testid="integration-test-and-submit"]`); const findJsonTextArea = () => wrapper.find(`[id = "test-payload"]`); + const findActionBtn = () => wrapper.find(`[data-testid="payload-action-btn"]`); afterEach(() => { if (wrapper) { @@ -307,12 +314,28 @@ describe('AlertsSettingsFormNew', () => { resetSamplePayloadConfirmed, }); await wrapper.vm.$nextTick(); - expect( - findTestPayloadSection() - .find(GlButton) - .text(), - ).toBe(caption); + expect(findActionBtn().text()).toBe(caption); + }); + }); + }); + + describe('Parsing payload', () => { + it('displays a toast message on successful parse', async () => { + jest.useFakeTimers(); + wrapper.setData({ + selectedIntegration: typeSet.http, + customMapping: { samplePayload: false }, }); + await wrapper.vm.$nextTick(); + + findActionBtn().vm.$emit('click'); + jest.advanceTimersByTime(1000); + + await waitForPromises(); + + expect(mockToastShow).toHaveBeenCalledWith( + 'Sample payload has been parsed. You can now map the fields.', + ); }); }); }); diff --git a/spec/frontend/monitoring/components/charts/time_series_spec.js b/spec/frontend/monitoring/components/charts/time_series_spec.js index 7f0ff534db3..8fcee80a2d8 100644 --- a/spec/frontend/monitoring/components/charts/time_series_spec.js +++ b/spec/frontend/monitoring/components/charts/time_series_spec.js @@ -226,7 +226,7 @@ describe('Time series component', () => { ]); expect( - shallowWrapperContainsSlotText(wrapper.find(GlLineChart), 'tooltipContent', value), + shallowWrapperContainsSlotText(wrapper.find(GlLineChart), 'tooltip-content', value), ).toBe(true); }); @@ -651,7 +651,7 @@ describe('Time series component', () => { return wrapper.vm.$nextTick(() => { expect( - shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', mockTitle), + shallowWrapperContainsSlotText(findChartComponent(), 'tooltip-title', mockTitle), ).toBe(true); }); }); @@ -671,7 +671,7 @@ describe('Time series component', () => { it('uses deployment title', () => { expect( - shallowWrapperContainsSlotText(findChartComponent(), 'tooltipTitle', 'Deployed'), + shallowWrapperContainsSlotText(findChartComponent(), 'tooltip-title', 'Deployed'), ).toBe(true); }); diff --git a/spec/graphql/types/custom_emoji_type_spec.rb b/spec/graphql/types/custom_emoji_type_spec.rb new file mode 100644 index 00000000000..7f3c99e4b63 --- /dev/null +++ b/spec/graphql/types/custom_emoji_type_spec.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['CustomEmoji'] do + specify { expect(described_class.graphql_name).to eq('CustomEmoji') } + + specify { expect(described_class).to require_graphql_authorizations(:read_custom_emoji) } + + specify { expect(described_class).to have_graphql_fields(:id, :name, :url, :external) } +end diff --git a/spec/helpers/auth_helper_spec.rb b/spec/helpers/auth_helper_spec.rb index e0d316baa17..b4cea7fb695 100644 --- a/spec/helpers/auth_helper_spec.rb +++ b/spec/helpers/auth_helper_spec.rb @@ -260,4 +260,41 @@ RSpec.describe AuthHelper do end end end + + describe '#google_tag_manager_enabled?' do + let(:is_gitlab_com) { true } + let(:user) { nil } + + before do + allow(Gitlab).to receive(:com?).and_return(is_gitlab_com) + stub_config(extra: { google_tag_manager_id: 'key' }) + allow(helper).to receive(:current_user).and_return(user) + end + + subject(:google_tag_manager_enabled?) { helper.google_tag_manager_enabled? } + + context 'on gitlab.com and a key set without a current user' do + it { is_expected.to be_truthy } + end + + context 'when not on gitlab.com' do + let(:is_gitlab_com) { false } + + it { is_expected.to be_falsey } + end + + context 'when current user is set' do + let(:user) { instance_double('User') } + + it { is_expected.to be_falsey } + end + + context 'when no key is set' do + before do + stub_config(extra: {}) + end + + it { is_expected.to be_falsey } + end + end end diff --git a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb index fbe139b20db..d20ea6c9202 100644 --- a/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb +++ b/spec/lib/gitlab/ci/build/rules/rule/clause/changes_spec.rb @@ -19,13 +19,11 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do let(:modified_paths) { ['helm/test.txt'] } let(:globs) { ['$HELM_DIR/**/*'] } let(:context) { double('context') } - let(:variables) { [] } subject { described_class.new(globs).satisfied_by?(pipeline, context) } before do allow(pipeline).to receive(:modified_paths).and_return(modified_paths) - allow(context).to receive(:variables).and_return(variables) end context 'when context is nil' do @@ -39,6 +37,10 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do [{ key: "HELM_DIR", value: "helm", public: true }] end + before do + allow(context).to receive(:variables).and_return(variables) + end + it { is_expected.to be_truthy } end @@ -46,6 +48,10 @@ RSpec.describe Gitlab::Ci::Build::Rules::Rule::Clause::Changes do let(:globs) { ['path/with/$in/it/*'] } let(:modified_paths) { ['path/with/$in/it/file.txt'] } + before do + allow(context).to receive(:variables).and_return([]) + end + it { is_expected.to be_truthy } end end diff --git a/spec/lib/gitlab/usage_data_counters/aggregated_metrics_spec.rb b/spec/lib/gitlab/usage_data_counters/aggregated_metrics_spec.rb index 64ccdad4076..e9fb5346eae 100644 --- a/spec/lib/gitlab/usage_data_counters/aggregated_metrics_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/aggregated_metrics_spec.rb @@ -33,7 +33,7 @@ RSpec.describe 'aggregated metrics' do end it "has expected structure" do - expect(aggregate.keys).to match_array(%w[name operator events]) + expect(aggregate.keys).to include(*%w[name operator events]) end it "uses allowed aggregation operators" do diff --git a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb index 7eb1a6fd67d..5c2d9272e77 100644 --- a/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/hll_redis_counter_spec.rb @@ -441,6 +441,28 @@ RSpec.describe Gitlab::UsageDataCounters::HLLRedisCounter, :clean_gitlab_redis_s expect(aggregated_metrics_data).to eq(results) end end + + context 'hidden behind feature flag' do + let(:enabled_feature_flag) { 'test_ff_enabled' } + let(:disabled_feature_flag) { 'test_ff_disabled' } + let(:aggregated_metrics) do + [ + # represents stable aggregated metrics that has been fully released + { name: 'gmau_without_ff', events: %w[event3_slot event5_slot], operator: "ANY" }, + # represents new aggregated metric that is under performance testing on gitlab.com + { name: 'gmau_enabled', events: %w[event4], operator: "ALL", feature_flag: enabled_feature_flag }, + # represents aggregated metric that is under development and shouldn't be yet collected even on gitlab.com + { name: 'gmau_disabled', events: %w[event4], operator: "ALL", feature_flag: disabled_feature_flag } + ].map(&:with_indifferent_access) + end + + it 'returns the number of unique events for all known events' do + skip_feature_flags_yaml_validation + stub_feature_flags(enabled_feature_flag => true, disabled_feature_flag => false) + + expect(aggregated_metrics_data).to eq('gmau_without_ff' => 2, 'gmau_enabled' => 3) + end + end end end diff --git a/spec/models/custom_emoji_spec.rb b/spec/models/custom_emoji_spec.rb index 836c4139107..62380299ea0 100644 --- a/spec/models/custom_emoji_spec.rb +++ b/spec/models/custom_emoji_spec.rb @@ -13,20 +13,28 @@ RSpec.describe CustomEmoji do describe 'exclusion of duplicated emoji' do let(:emoji_name) { Gitlab::Emoji.emojis_names.sample } + let(:group) { create(:group, :private) } it 'disallows emoji names of built-in emoji' do - new_emoji = build(:custom_emoji, name: emoji_name) + new_emoji = build(:custom_emoji, name: emoji_name, group: group) expect(new_emoji).not_to be_valid expect(new_emoji.errors.messages).to eq(name: ["#{emoji_name} is already being used for another emoji"]) end it 'disallows duplicate custom emoji names within namespace' do - old_emoji = create(:custom_emoji) - new_emoji = build(:custom_emoji, name: old_emoji.name, namespace: old_emoji.namespace) + old_emoji = create(:custom_emoji, group: group) + new_emoji = build(:custom_emoji, name: old_emoji.name, namespace: old_emoji.namespace, group: group) expect(new_emoji).not_to be_valid expect(new_emoji.errors.messages).to eq(name: ["has already been taken"]) end + + it 'disallows non http and https file value' do + emoji = build(:custom_emoji, name: 'new-name', group: group, file: 'ftp://some-url.in') + + expect(emoji).not_to be_valid + expect(emoji.errors.messages).to eq(file: ["is blocked: Only allowed schemes are http, https"]) + end end end diff --git a/spec/models/deploy_token_spec.rb b/spec/models/deploy_token_spec.rb index 60a3e3fc0e2..c7e1d5fc0d5 100644 --- a/spec/models/deploy_token_spec.rb +++ b/spec/models/deploy_token_spec.rb @@ -124,6 +124,39 @@ RSpec.describe DeployToken do end end + # override the default PolicyActor implementation that always returns false + describe "#deactivated?" do + context "when it has been revoked" do + it 'returns true' do + deploy_token.revoke! + + expect(deploy_token.deactivated?).to be_truthy + end + end + + context "when it hasn't been revoked and is not expired" do + it 'returns false' do + expect(deploy_token.deactivated?).to be_falsy + end + end + + context "when it hasn't been revoked and is expired" do + it 'returns false' do + deploy_token.update_attribute(:expires_at, Date.today - 5.days) + + expect(deploy_token.deactivated?).to be_truthy + end + end + + context "when it hasn't been revoked and has no expiry" do + let(:deploy_token) { create(:deploy_token, expires_at: nil) } + + it 'returns false' do + expect(deploy_token.deactivated?).to be_falsy + end + end + end + describe '#username' do context 'persisted records' do it 'returns a default username if none is set' do diff --git a/spec/models/personal_access_token_spec.rb b/spec/models/personal_access_token_spec.rb index 9e80d0e0886..67ecbe13c1a 100644 --- a/spec/models/personal_access_token_spec.rb +++ b/spec/models/personal_access_token_spec.rb @@ -31,6 +31,18 @@ RSpec.describe PersonalAccessToken do expect(described_class.for_user(user_1)).to contain_exactly(token_of_user_1) end end + + describe '.for_users' do + it 'returns personal access tokens for the specified users only' do + user_1 = create(:user) + user_2 = create(:user) + token_of_user_1 = create(:personal_access_token, user: user_1) + token_of_user_2 = create(:personal_access_token, user: user_2) + create_list(:personal_access_token, 3) + + expect(described_class.for_users([user_1, user_2])).to contain_exactly(token_of_user_1, token_of_user_2) + end + end end describe ".active?" do diff --git a/spec/policies/group_policy_spec.rb b/spec/policies/group_policy_spec.rb index da7c1a4dc76..7cded27e449 100644 --- a/spec/policies/group_policy_spec.rb +++ b/spec/policies/group_policy_spec.rb @@ -876,6 +876,7 @@ RSpec.describe GroupPolicy do let(:deploy_token) { create(:deploy_token, :group, write_package_registry: true) } it { is_expected.to be_allowed(:create_package) } + it { is_expected.to be_allowed(:read_package) } it { is_expected.to be_allowed(:read_group) } it { is_expected.to be_disallowed(:destroy_package) } end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index b28fb9a0255..6c281030618 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -697,6 +697,7 @@ RSpec.describe ProjectPolicy do let(:deploy_token) { create(:deploy_token, write_package_registry: true) } it { is_expected.to be_allowed(:create_package) } + it { is_expected.to be_allowed(:read_package) } it { is_expected.to be_allowed(:read_project) } it { is_expected.to be_disallowed(:destroy_package) } end diff --git a/spec/requests/api/graphql/custom_emoji_query_spec.rb b/spec/requests/api/graphql/custom_emoji_query_spec.rb new file mode 100644 index 00000000000..d5a423d0eba --- /dev/null +++ b/spec/requests/api/graphql/custom_emoji_query_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'getting custom emoji within namespace' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group, :private) } + let_it_be(:custom_emoji) { create(:custom_emoji, group: group) } + + before do + stub_feature_flags(custom_emoji: true) + group.add_developer(current_user) + end + + describe "Query CustomEmoji on Group" do + def custom_emoji_query(group) + graphql_query_for('group', 'fullPath' => group.full_path) + end + + it 'returns emojis when authorised' do + post_graphql(custom_emoji_query(group), current_user: current_user) + + expect(response).to have_gitlab_http_status(:ok) + expect(graphql_data['group']['customEmoji']['nodes'].count). to eq(1) + expect(graphql_data['group']['customEmoji']['nodes'].first['name']). to eq(custom_emoji.name) + end + + it 'returns nil when unauthorised' do + user = create(:user) + post_graphql(custom_emoji_query(group), current_user: user) + + expect(graphql_data['group']).to be_nil + end + end +end diff --git a/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb new file mode 100644 index 00000000000..c91437fa355 --- /dev/null +++ b/spec/requests/api/graphql/mutations/custom_emoji/create_spec.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Creation of a new Custom Emoji' do + include GraphqlHelpers + + let_it_be(:current_user) { create(:user) } + let_it_be(:group) { create(:group) } + + let(:attributes) do + { + name: 'my_new_emoji', + url: 'https://example.com/image.png', + group_path: group.full_path + } + end + + let(:mutation) do + graphql_mutation(:create_custom_emoji, attributes) + end + + context 'when the user has no permission' do + it 'does not create custom emoji' do + expect { post_graphql_mutation(mutation, current_user: current_user) }.not_to change(CustomEmoji, :count) + end + end + + context 'when user has permission' do + before do + group.add_developer(current_user) + end + + it 'creates custom emoji' do + expect { post_graphql_mutation(mutation, current_user: current_user) }.to change(CustomEmoji, :count).by(1) + + gql_response = graphql_mutation_response(:create_custom_emoji) + expect(gql_response['errors']).to eq([]) + expect(gql_response['customEmoji']['name']).to eq(attributes[:name]) + expect(gql_response['customEmoji']['url']).to eq(attributes[:url]) + end + end +end diff --git a/spec/requests/api/maven_packages_spec.rb b/spec/requests/api/maven_packages_spec.rb index 37748fe5ea7..33604127cf7 100644 --- a/spec/requests/api/maven_packages_spec.rb +++ b/spec/requests/api/maven_packages_spec.rb @@ -92,15 +92,30 @@ RSpec.describe API::MavenPackages do end shared_examples 'downloads with a deploy token' do - it 'allows download with deploy token' do - download_file( - package_file.file_name, - {}, - Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token.token - ) + context 'successful download' do + subject do + download_file( + package_file.file_name, + {}, + Gitlab::Auth::AuthFinders::DEPLOY_TOKEN_HEADER => deploy_token.token + ) + end - expect(response).to have_gitlab_http_status(:ok) - expect(response.media_type).to eq('application/octet-stream') + it 'allows download with deploy token' do + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.media_type).to eq('application/octet-stream') + end + + it 'allows download with deploy token with only write_package_registry scope' do + deploy_token.update!(read_package_registry: false) + + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.media_type).to eq('application/octet-stream') + end end end @@ -355,6 +370,15 @@ RSpec.describe API::MavenPackages do expect(response).to have_gitlab_http_status(:ok) expect(response.media_type).to eq('application/octet-stream') end + + it 'returns the file with only write_package_registry scope' do + deploy_token_for_group.update!(read_package_registry: false) + + subject + + expect(response).to have_gitlab_http_status(:ok) + expect(response.media_type).to eq('application/octet-stream') + end end end diff --git a/yarn.lock b/yarn.lock index 91f08a59712..a62939b98ad 100644 --- a/yarn.lock +++ b/yarn.lock @@ -866,10 +866,10 @@ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.175.0.tgz#734f341784af1cd1d62d160a17bcdfb61ff7b04d" integrity sha512-gXpc87TGSXIzfAr4QER1Qw1v3P47pBO6BXkma52blgwXVmcFNe3nhQzqsqt66wKNzrIrk3lAcB4GUyPHbPVXpg== -"@gitlab/ui@23.8.0": - version "23.8.0" - resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-23.8.0.tgz#fe1807877c191e9e38b476d2cdfc4261facbb36b" - integrity sha512-5CF2jU/d5EX5a1qLHzJujYOTaCze1ZvE9ovK1TbhJ7Va1O0SKB/N53XT8iPOb4MwOzj/zBWDOdsIs+xXxCeOcg== +"@gitlab/ui@23.9.0": + version "23.9.0" + resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-23.9.0.tgz#e21966130b41e624dbe4505911a79afb731c2d6b" + integrity sha512-IfaiIcRw6iKE9Fxx36LQ1Afa/fcdmvRQCJO9igc+wWD3MFZGU/ggsQw3SExkkYI6XYmDUr56CT/o+HYlCDjgZQ== dependencies: "@babel/standalone" "^7.0.0" "@gitlab/vue-toasted" "^1.3.0" |