summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/issue_templates/Feature Flag Roll Out.md2
-rw-r--r--app/assets/javascripts/registry/settings/components/registry_settings_app.vue49
-rw-r--r--app/assets/javascripts/registry/settings/store/actions.js6
-rw-r--r--app/assets/javascripts/registry/settings/store/getters.js4
-rw-r--r--app/assets/javascripts/registry/settings/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/registry/settings/store/mutations.js11
-rw-r--r--app/assets/javascripts/registry/settings/store/state.js16
-rw-r--r--app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js2
-rw-r--r--app/controllers/application_controller.rb4
-rw-r--r--app/controllers/explore/application_controller.rb2
-rw-r--r--app/controllers/help_controller.rb2
-rw-r--r--app/helpers/explore_helper.rb4
-rw-r--r--app/helpers/services_helper.rb2
-rw-r--r--app/models/project_services/alerts_service.rb2
-rw-r--r--app/services/groups/import_export/export_service.rb7
-rw-r--r--app/views/layouts/devise.html.haml6
-rw-r--r--app/views/layouts/devise_empty.html.haml5
-rw-r--r--app/views/projects/registry/settings/_index.haml5
-rw-r--r--app/views/projects/services/_form.html.haml2
-rw-r--r--app/views/projects/services/alerts/_help.html.haml4
-rw-r--r--app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml10
-rw-r--r--app/views/projects/services/slack_slash_commands/_help.html.haml10
-rw-r--r--changelogs/unreleased/55241-rate-limit-issue-creation-api.yml5
-rw-r--r--changelogs/unreleased/fix-admin-mode-sidekiq-admin-ui.yml5
-rw-r--r--changelogs/unreleased/winniehell-ogg-music.yml5
-rw-r--r--config/routes/sidekiq.rb3
-rw-r--r--doc/api/README.md2
-rw-r--r--doc/api/issues.md8
-rw-r--r--doc/development/README.md2
-rw-r--r--doc/development/changelog.md29
-rw-r--r--doc/development/code_review.md6
-rw-r--r--doc/development/contributing/issue_workflow.md11
-rw-r--r--doc/development/documentation/styleguide.md11
-rw-r--r--doc/development/ee_features.md9
-rw-r--r--doc/development/feature_flags/controls.md5
-rw-r--r--doc/development/file_storage.md15
-rw-r--r--doc/development/interacting_components.md4
-rw-r--r--doc/development/performance.md7
-rw-r--r--doc/install/aws/index.md2
-rw-r--r--doc/public_access/public_access.md10
-rw-r--r--doc/user/admin_area/settings/visibility_and_access_controls.md2
-rw-r--r--doc/user/project/import/img/jira/import_issues_from_jira_button_v12_10.pngbin0 -> 31779 bytes
-rw-r--r--doc/user/project/import/img/jira/import_issues_from_jira_form_v12_10.pngbin0 -> 89735 bytes
-rw-r--r--doc/user/project/import/img/jira/import_issues_from_jira_projects_v12_10.pngbin0 -> 230008 bytes
-rw-r--r--doc/user/project/import/index.md1
-rw-r--r--doc/user/project/import/jira.md57
-rw-r--r--lib/api/helpers/rate_limiter.rb28
-rw-r--r--lib/api/issues.rb3
-rw-r--r--lib/api/project_export.rb17
-rw-r--r--lib/api/project_import.rb17
-rw-r--r--lib/constraints/admin_constrainer.rb25
-rw-r--r--lib/gitlab/import_export/group/legacy_tree_saver.rb (renamed from lib/gitlab/import_export/group/tree_saver.rb)2
-rw-r--r--locale/gitlab.pot21
-rw-r--r--spec/controllers/explore/groups_controller_spec.rb14
-rw-r--r--spec/controllers/explore/projects_controller_spec.rb12
-rw-r--r--spec/controllers/help_controller_spec.rb14
-rw-r--r--spec/features/explore/groups_spec.rb12
-rw-r--r--spec/features/explore/user_explores_projects_spec.rb11
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js50
-rw-r--r--spec/frontend/registry/settings/store/actions_spec.js11
-rw-r--r--spec/frontend/registry/settings/store/getters_spec.js16
-rw-r--r--spec/frontend/registry/settings/store/mutations_spec.js34
-rw-r--r--spec/lib/constraints/admin_constrainer_spec.rb69
-rw-r--r--spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb (renamed from spec/lib/gitlab/import_export/group/tree_saver_spec.rb)4
-rw-r--r--spec/requests/api/issues/post_projects_issues_spec.rb14
-rw-r--r--spec/services/groups/import_export/export_service_spec.rb2
66 files changed, 543 insertions, 188 deletions
diff --git a/.gitlab/issue_templates/Feature Flag Roll Out.md b/.gitlab/issue_templates/Feature Flag Roll Out.md
index e0de8fab4a7..7cb8871f5bc 100644
--- a/.gitlab/issue_templates/Feature Flag Roll Out.md
+++ b/.gitlab/issue_templates/Feature Flag Roll Out.md
@@ -37,7 +37,7 @@ If applicable, any groups/projects that are happy to have this feature turned on
- [ ] Coordinate a time to enable the flag with `#production` and `#g_delivery` on slack.
- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com
- [ ] Enable on GitLab.com by running chatops command in `#production`
-- [ ] Cross post chatops slack command to `#support_gitlab-com` and in your team channel
+- [ ] Cross post chatops slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel
- [ ] Announce on the issue that the flag has been enabled
- [ ] Remove feature flag and add changelog entry
- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
diff --git a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
index 4d767f1a578..b4a59fd0178 100644
--- a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
+++ b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
@@ -1,5 +1,5 @@
<script>
-import { mapActions, mapState } from 'vuex';
+import { mapActions, mapGetters, mapState } from 'vuex';
import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import { s__ } from '~/locale';
@@ -15,8 +15,15 @@ export default {
GlLink,
},
i18n: {
- unavailableFeatureText: s__(
- 'ContainerRegistry|Currently, the Container Registry tag expiration feature is not available for projects created before GitLab version 12.8. For updates and more information, visit Issue %{linkStart}#196124%{linkEnd}',
+ unavailableFeatureTitle: s__(
+ `ContainerRegistry|Container Registry tag expiration and retention policy is disabled`,
+ ),
+ unavailableFeatureIntroText: s__(
+ `ContainerRegistry|The Container Registry tag expiration and retention policies for this project have not been enabled.`,
+ ),
+ unavailableUserFeatureText: s__(`ContainerRegistry|Please contact your administrator.`),
+ unavailableAdminFeatureText: s__(
+ `ContainerRegistry| Please visit the %{linkStart}administration settings%{linkEnd} to enable this feature.`,
),
fetchSettingsErrorText: FETCH_SETTINGS_ERROR_MESSAGE,
},
@@ -26,10 +33,19 @@ export default {
};
},
computed: {
- ...mapState(['isDisabled']),
+ ...mapState(['isAdmin', 'adminSettingsPath']),
+ ...mapGetters({ isDisabled: 'getIsDisabled' }),
showSettingForm() {
return !this.isDisabled && !this.fetchSettingsError;
},
+ showDisabledFormMessage() {
+ return this.isDisabled && !this.fetchSettingsError;
+ },
+ unavailableFeatureMessage() {
+ return this.isAdmin
+ ? this.$options.i18n.unavailableAdminFeatureText
+ : this.$options.i18n.unavailableUserFeatureText;
+ },
},
mounted() {
this.fetchSettings().catch(() => {
@@ -59,16 +75,21 @@ export default {
</ul>
<settings-form v-if="showSettingForm" />
<template v-else>
- <gl-alert v-if="isDisabled" :dismissible="false">
- <p>
- <gl-sprintf :message="$options.i18n.unavailableFeatureText">
- <template #link="{content}">
- <gl-link href="https://gitlab.com/gitlab-org/gitlab/issues/196124" target="_blank">
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </p>
+ <gl-alert
+ v-if="showDisabledFormMessage"
+ :dismissible="false"
+ :title="$options.i18n.unavailableFeatureTitle"
+ variant="tip"
+ >
+ {{ $options.i18n.unavailableFeatureIntroText }}
+
+ <gl-sprintf :message="unavailableFeatureMessage">
+ <template #link="{ content }">
+ <gl-link :href="adminSettingsPath" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
</gl-alert>
<gl-alert v-else-if="fetchSettingsError" variant="warning" :dismissible="false">
<gl-sprintf :message="$options.i18n.fetchSettingsErrorText" />
diff --git a/app/assets/javascripts/registry/settings/store/actions.js b/app/assets/javascripts/registry/settings/store/actions.js
index d0379d05164..be1f62334fa 100644
--- a/app/assets/javascripts/registry/settings/store/actions.js
+++ b/app/assets/javascripts/registry/settings/store/actions.js
@@ -5,11 +5,7 @@ export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_ST
export const updateSettings = ({ commit }, data) => commit(types.UPDATE_SETTINGS, data);
export const toggleLoading = ({ commit }) => commit(types.TOGGLE_LOADING);
export const receiveSettingsSuccess = ({ commit }, data) => {
- if (data) {
- commit(types.SET_SETTINGS, data);
- } else {
- commit(types.SET_IS_DISABLED, true);
- }
+ commit(types.SET_SETTINGS, data);
};
export const resetSettings = ({ commit }) => commit(types.RESET_SETTINGS);
diff --git a/app/assets/javascripts/registry/settings/store/getters.js b/app/assets/javascripts/registry/settings/store/getters.js
index 639becebeec..ef4b4f0ba02 100644
--- a/app/assets/javascripts/registry/settings/store/getters.js
+++ b/app/assets/javascripts/registry/settings/store/getters.js
@@ -19,3 +19,7 @@ export const getSettings = (state, getters) => ({
});
export const getIsEdited = state => !isEqual(state.original, state.settings);
+
+export const getIsDisabled = state => {
+ return !(state.original || state.enableHistoricEntries);
+};
diff --git a/app/assets/javascripts/registry/settings/store/mutation_types.js b/app/assets/javascripts/registry/settings/store/mutation_types.js
index 2d071567c1f..db499ffa761 100644
--- a/app/assets/javascripts/registry/settings/store/mutation_types.js
+++ b/app/assets/javascripts/registry/settings/store/mutation_types.js
@@ -3,4 +3,3 @@ export const UPDATE_SETTINGS = 'UPDATE_SETTINGS';
export const TOGGLE_LOADING = 'TOGGLE_LOADING';
export const SET_SETTINGS = 'SET_SETTINGS';
export const RESET_SETTINGS = 'RESET_SETTINGS';
-export const SET_IS_DISABLED = 'SET_IS_DISABLED';
diff --git a/app/assets/javascripts/registry/settings/store/mutations.js b/app/assets/javascripts/registry/settings/store/mutations.js
index f562137db1a..bb7071b020b 100644
--- a/app/assets/javascripts/registry/settings/store/mutations.js
+++ b/app/assets/javascripts/registry/settings/store/mutations.js
@@ -1,3 +1,4 @@
+import { parseBoolean } from '~/lib/utils/common_utils';
import * as types from './mutation_types';
export default {
@@ -8,19 +9,19 @@ export default {
keepN: JSON.parse(initialState.keepNOptions),
olderThan: JSON.parse(initialState.olderThanOptions),
};
+ state.enableHistoricEntries = parseBoolean(initialState.enableHistoricEntries);
+ state.isAdmin = parseBoolean(initialState.isAdmin);
+ state.adminSettingsPath = initialState.adminSettingsPath;
},
[types.UPDATE_SETTINGS](state, data) {
state.settings = { ...state.settings, ...data.settings };
},
[types.SET_SETTINGS](state, settings) {
- state.settings = settings;
+ state.settings = settings ?? state.settings;
state.original = Object.freeze(settings);
},
- [types.SET_IS_DISABLED](state, isDisabled) {
- state.isDisabled = isDisabled;
- },
[types.RESET_SETTINGS](state) {
- state.settings = { ...state.original };
+ state.settings = Object.assign({}, state.original);
},
[types.TOGGLE_LOADING](state) {
state.isLoading = !state.isLoading;
diff --git a/app/assets/javascripts/registry/settings/store/state.js b/app/assets/javascripts/registry/settings/store/state.js
index 582e18e5465..fccc0991c1c 100644
--- a/app/assets/javascripts/registry/settings/store/state.js
+++ b/app/assets/javascripts/registry/settings/store/state.js
@@ -8,9 +8,17 @@ export default () => ({
*/
isLoading: false,
/*
- * Boolean to determine if the user is allowed to interact with the form
+ * Boolean to determine if the user is an admin
*/
- isDisabled: false,
+ isAdmin: false,
+ /*
+ * String containing the full path to the admin config page for CI/CD
+ */
+ adminSettingsPath: '',
+ /*
+ * Boolean to determine if project created before 12.8 can use this feature
+ */
+ enableHistoricEntries: false,
/*
* This contains the data shown and manipulated in the UI
* Has the following structure:
@@ -24,9 +32,9 @@ export default () => ({
*/
settings: {},
/*
- * Same structure as settings, above but Frozen object and used only in case the user clicks 'cancel'
+ * Same structure as settings, above but Frozen object and used only in case the user clicks 'cancel', initialized to null
*/
- original: {},
+ original: null,
/*
* Contains the options used to populate the form selects
*/
diff --git a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
index bffaa096210..2f6640232dd 100644
--- a/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
+++ b/app/assets/javascripts/vue_shared/components/file_icon/file_icon_map.js
@@ -202,7 +202,7 @@ const fileExtensionIcons = {
flv: 'movie',
vob: 'movie',
ogv: 'movie',
- ogg: 'movie',
+ ogg: 'music',
gifv: 'movie',
avi: 'movie',
mov: 'movie',
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index c5c586ea489..b2496427924 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -496,6 +496,10 @@ class ApplicationController < ActionController::Base
html_request? && !devise_controller?
end
+ def public_visibility_restricted?
+ Gitlab::CurrentSettings.restricted_visibility_levels.include? Gitlab::VisibilityLevel::PUBLIC
+ end
+
def set_usage_stats_consent_flag
return unless current_user
return if sessionless_user?
diff --git a/app/controllers/explore/application_controller.rb b/app/controllers/explore/application_controller.rb
index 8eee3742d89..9d33135d4c1 100644
--- a/app/controllers/explore/application_controller.rb
+++ b/app/controllers/explore/application_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class Explore::ApplicationController < ApplicationController
- skip_before_action :authenticate_user!
+ skip_before_action :authenticate_user!, unless: :public_visibility_restricted?
layout 'explore'
end
diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb
index 97895d6461c..91bba1eb617 100644
--- a/app/controllers/help_controller.rb
+++ b/app/controllers/help_controller.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
class HelpController < ApplicationController
- skip_before_action :authenticate_user!
+ skip_before_action :authenticate_user!, unless: :public_visibility_restricted?
layout 'help'
diff --git a/app/helpers/explore_helper.rb b/app/helpers/explore_helper.rb
index 1b36f60c316..b341cc795a0 100644
--- a/app/helpers/explore_helper.rb
+++ b/app/helpers/explore_helper.rb
@@ -51,6 +51,10 @@ module ExploreHelper
links.any? { |link| explore_nav_link?(link) }
end
+ def public_visibility_restricted?
+ Gitlab::CurrentSettings.restricted_visibility_levels.include? Gitlab::VisibilityLevel::PUBLIC
+ end
+
private
def get_explore_nav_links
diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb
index a4b6e613100..f3f4cdc857f 100644
--- a/app/helpers/services_helper.rb
+++ b/app/helpers/services_helper.rb
@@ -74,7 +74,7 @@ module ServicesHelper
def scoped_integration_path(integration)
if @project.present?
- project_settings_integration_path(@project, integration)
+ project_service_path(@project, integration)
elsif @group.present?
group_settings_integration_path(@group, integration)
else
diff --git a/app/models/project_services/alerts_service.rb b/app/models/project_services/alerts_service.rb
index 2f7902d9617..16bf37fd189 100644
--- a/app/models/project_services/alerts_service.rb
+++ b/app/models/project_services/alerts_service.rb
@@ -15,6 +15,8 @@ class AlertsService < Service
before_validation :ensure_token, if: :activated?
def url
+ return if instance? || template?
+
url_helpers.project_alerts_notify_url(project, format: :json)
end
diff --git a/app/services/groups/import_export/export_service.rb b/app/services/groups/import_export/export_service.rb
index 86e2eeda21f..f8715b57d6e 100644
--- a/app/services/groups/import_export/export_service.rb
+++ b/app/services/groups/import_export/export_service.rb
@@ -56,7 +56,12 @@ module Groups
end
def tree_exporter
- Gitlab::ImportExport::Group::TreeSaver.new(group: @group, current_user: @current_user, shared: @shared, params: @params)
+ Gitlab::ImportExport::Group::LegacyTreeSaver.new(
+ group: @group,
+ current_user: @current_user,
+ shared: @shared,
+ params: @params
+ )
end
def file_saver
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index d36e08f44a4..6a261bbbc46 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -38,7 +38,9 @@
%hr.footer-fixed
.container.footer-container
.footer-links
- = link_to _("Explore"), explore_root_path
- = link_to _("Help"), help_path
+ - if !public_visibility_restricted?
+ = link_to _("Explore"), explore_root_path
+ = link_to _("Help"), help_path
= link_to _("About GitLab"), "https://about.gitlab.com/"
+
= footer_message
diff --git a/app/views/layouts/devise_empty.html.haml b/app/views/layouts/devise_empty.html.haml
index ff2b00ea376..6ac80a5aba3 100644
--- a/app/views/layouts/devise_empty.html.haml
+++ b/app/views/layouts/devise_empty.html.haml
@@ -14,7 +14,8 @@
%hr
.container
.footer-links
- = link_to _("Explore"), explore_root_path
- = link_to _("Help"), help_path
+ - if !public_visibility_restricted?
+ = link_to _("Explore"), explore_root_path
+ = link_to _("Help"), help_path
= link_to _("About GitLab"), "https://about.gitlab.com/"
= footer_message
diff --git a/app/views/projects/registry/settings/_index.haml b/app/views/projects/registry/settings/_index.haml
index 0e0341a9923..c0cef8503e0 100644
--- a/app/views/projects/registry/settings/_index.haml
+++ b/app/views/projects/registry/settings/_index.haml
@@ -1,4 +1,7 @@
#js-registry-settings{ data: { project_id: @project.id,
cadence_options: cadence_options.to_json,
keep_n_options: keep_n_options.to_json,
- older_than_options: older_than_options.to_json} }
+ older_than_options: older_than_options.to_json,
+ is_admin: current_user&.admin.to_s,
+ admin_settings_path: ci_cd_admin_application_settings_path(anchor: 'js-registry-settings'),
+ enable_historic_entries: Gitlab::CurrentSettings.try(:container_expiration_policies_enable_historic_entries).to_s} }
diff --git a/app/views/projects/services/_form.html.haml b/app/views/projects/services/_form.html.haml
index a0d9d29a7ae..bd9defe5f74 100644
--- a/app/views/projects/services/_form.html.haml
+++ b/app/views/projects/services/_form.html.haml
@@ -10,7 +10,7 @@
- if @service.respond_to?(:detailed_description)
%p= @service.detailed_description
.col-lg-9
- = form_for(@service, as: :service, url: project_service_path(@project, @service.to_param), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
+ = form_for(@service, as: :service, url: scoped_integration_path(@service), method: :put, html: { class: 'gl-show-field-errors integration-settings-form js-integration-settings-form', data: { 'can-test' => @service.can_test?, 'test-url' => test_project_service_path(@project, @service) } }) do |form|
= render 'shared/service_settings', form: form, service: @service
- if @service.editable?
.footer-block.row-content-block
diff --git a/app/views/projects/services/alerts/_help.html.haml b/app/views/projects/services/alerts/_help.html.haml
index be910203125..ef3ab8d8d04 100644
--- a/app/views/projects/services/alerts/_help.html.haml
+++ b/app/views/projects/services/alerts/_help.html.haml
@@ -1,3 +1,3 @@
.js-alerts-service-settings{ data: { activated: @service.activated?.to_s,
- form_path: project_service_path(@project, @service.to_param),
- authorization_key: @service.token, url: @service.url, learn_more_url: 'https://docs.gitlab.com/ee/user/project/integrations/generic_alerts.html' } }
+ form_path: scoped_integration_path(@service),
+ authorization_key: @service.token, url: @service.url || _('<namespace / project>'), learn_more_url: 'https://docs.gitlab.com/ee/user/project/integrations/generic_alerts.html' } }
diff --git a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
index 395df502ddb..cf73a7055c6 100644
--- a/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
+++ b/app/views/projects/services/mattermost_slash_commands/_detailed_help.html.haml
@@ -1,4 +1,5 @@
-- run_actions_text = s_("ProjectService|Perform common operations on GitLab project: %{project_name}") % { project_name: @project.full_name }
+- pretty_name = @project&.full_name || _('<project name>')
+- run_actions_text = s_("ProjectService|Perform common operations on GitLab project: %{project_name}") % { project_name: pretty_name }
%p= s_("ProjectService|To set up this service:")
%ul.list-unstyled.indent-list
@@ -20,7 +21,7 @@
.form-group
= label_tag :display_name, _('Display name'), class: 'col-12 col-form-label label-bold'
.col-12.input-group
- = text_field_tag :display_name, "GitLab / #{@project.full_name}", class: 'form-control form-control-sm', readonly: 'readonly'
+ = text_field_tag :display_name, "GitLab / #{pretty_name}", class: 'form-control form-control-sm', readonly: 'readonly'
.input-group-append
= clipboard_button(target: '#display_name', class: 'input-group-text')
@@ -38,8 +39,9 @@
%p
= s_('MattermostService|Suggestions:')
%code= 'gitlab'
- %code= @project.path # Path contains no spaces, but dashes
- %code= @project.full_path
+ - if @project
+ %code= @project.path # Path contains no spaces, but dashes
+ %code= @project.full_path
.form-group
= label_tag :request_url, s_('MattermostService|Request URL'), class: 'col-12 col-form-label label-bold'
diff --git a/app/views/projects/services/slack_slash_commands/_help.html.haml b/app/views/projects/services/slack_slash_commands/_help.html.haml
index 7f6717e298c..93ea17a3a3d 100644
--- a/app/views/projects/services/slack_slash_commands/_help.html.haml
+++ b/app/views/projects/services/slack_slash_commands/_help.html.haml
@@ -1,5 +1,5 @@
-- pretty_name = defined?(@project) ? @project.full_name : 'namespace / path'
-- run_actions_text = "Perform common operations on GitLab project: #{pretty_name}"
+- pretty_name = @project&.full_name || _('<project name>')
+- run_actions_text = s_("ProjectService|Perform common operations on GitLab project: %{project_name}") % { project_name: pretty_name }
.info-well
.well-segment
@@ -31,8 +31,10 @@
%p
= _("Suggestions:")
%code= 'gitlab'
- %code= @project.path # Path contains no spaces, but dashes
- %code= @project.full_path
+ %code= 'project'
+ - if @project
+ %code= @project.path # Path contains no spaces, but dashes
+ %code= @project.full_path
.form-group
= label_tag :url, 'URL', class: 'col-12 col-form-label label-bold'
diff --git a/changelogs/unreleased/55241-rate-limit-issue-creation-api.yml b/changelogs/unreleased/55241-rate-limit-issue-creation-api.yml
new file mode 100644
index 00000000000..e685e83fd2e
--- /dev/null
+++ b/changelogs/unreleased/55241-rate-limit-issue-creation-api.yml
@@ -0,0 +1,5 @@
+---
+title: Introduce rate limit for creating issues via API
+merge_request: 28130
+author:
+type: performance
diff --git a/changelogs/unreleased/fix-admin-mode-sidekiq-admin-ui.yml b/changelogs/unreleased/fix-admin-mode-sidekiq-admin-ui.yml
new file mode 100644
index 00000000000..3d940372c6b
--- /dev/null
+++ b/changelogs/unreleased/fix-admin-mode-sidekiq-admin-ui.yml
@@ -0,0 +1,5 @@
+---
+title: Protect sidekiq admin UI with admin mode
+merge_request: 28164
+author: Diego Louzán
+type: fixed
diff --git a/changelogs/unreleased/winniehell-ogg-music.yml b/changelogs/unreleased/winniehell-ogg-music.yml
new file mode 100644
index 00000000000..7504bb3af79
--- /dev/null
+++ b/changelogs/unreleased/winniehell-ogg-music.yml
@@ -0,0 +1,5 @@
+---
+title: Use music icon for files with .ogg extension
+merge_request: 29514
+author:
+type: fixed
diff --git a/config/routes/sidekiq.rb b/config/routes/sidekiq.rb
index 0fa23f2b3d0..36ec8bc1d54 100644
--- a/config/routes/sidekiq.rb
+++ b/config/routes/sidekiq.rb
@@ -1,4 +1,3 @@
-constraint = lambda { |request| request.env['warden'].authenticate? && request.env['warden'].user.admin? }
-constraints constraint do
+constraints ::Constraints::AdminConstrainer.new do
mount Sidekiq::Web, at: '/admin/sidekiq', as: :sidekiq
end
diff --git a/doc/api/README.md b/doc/api/README.md
index 24b81852dc5..3c8d3dc4902 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -390,7 +390,7 @@ CAUTION: **Caution:**
For performance reasons since
[GitLab 11.8](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/23931)
and **behind the `api_kaminari_count_with_limit`
-[feature flag](../development/feature_flags.md)**, if the number of resources is
+[feature flag](../development/feature_flags/index.md)**, if the number of resources is
more than 10,000, the `X-Total` and `X-Total-Pages` headers as well as the
`rel="last"` `Link` are not present in the response headers.
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 89b81c9ee97..14f81d7d327 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -740,6 +740,14 @@ the `weight` parameter:
**Note**: The `closed_by` attribute was [introduced in GitLab 10.6](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042). This value will only be present for issues which were closed after GitLab 10.6 and when the user account that closed the issue still exists.
+## Rate limits
+
+To help avoid abuse, users are limited to:
+
+| Request Type | Limit |
+| ---------------- | --------------------------- |
+| Create | 300 issues per minute |
+
## Edit issue
Updates an existing project issue. This call is also used to mark an issue as
diff --git a/doc/development/README.md b/doc/development/README.md
index b505fa38618..16858b0c58e 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -63,7 +63,7 @@ Complementary reads:
styleguide if you are contributing to the [GraphQL API](../api/graphql/index.md)
- [Sidekiq guidelines](sidekiq_style_guide.md) for working with Sidekiq workers
- [Working with Gitaly](gitaly.md)
-- [Manage feature flags](feature_flags.md)
+- [Manage feature flags](feature_flags/index.md)
- [Licensed feature availability](licensed_feature_availability.md)
- [View sent emails or preview mailers](emails.md)
- [Shell commands](shell_commands.md) in the GitLab codebase
diff --git a/doc/development/changelog.md b/doc/development/changelog.md
index bc1ba4eb50b..2007c26403c 100644
--- a/doc/development/changelog.md
+++ b/doc/development/changelog.md
@@ -5,9 +5,9 @@ file, as well as information and history about our changelog process.
## Overview
-Each bullet point, or **entry**, in our [`CHANGELOG.md`][changelog.md] file is
-generated from a single data file in the [`changelogs/unreleased/`][unreleased]
-(or corresponding EE) folder. The file is expected to be a [YAML] file in the
+Each bullet point, or **entry**, in our [`CHANGELOG.md`](https://gitlab.com/gitlab-org/gitlab/blob/master/CHANGELOG.md) file is
+generated from a single data file in the [`changelogs/unreleased/`](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/changelogs/)
+(or corresponding EE) folder. The file is expected to be a [YAML](https://en.wikipedia.org/wiki/YAML) file in the
following format:
```yaml
@@ -27,15 +27,12 @@ valid options are: added, fixed, changed, deprecated, removed, security, perform
Community contributors and core team members are encouraged to add their name to
the `author` field. GitLab team members **should not**.
-[changelog.md]: https://gitlab.com/gitlab-org/gitlab/blob/master/CHANGELOG.md
-[unreleased]: https://gitlab.com/gitlab-org/gitlab-foss/tree/master/changelogs/
-[YAML]: https://en.wikipedia.org/wiki/YAML
-
## What warrants a changelog entry?
- Any change that introduces a database migration, whether it's regular, post,
or data migration, **must** have a changelog entry.
-- [Security fixes] **must** have a changelog entry, without `merge_request` value
+- [Security fixes](https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md)
+ **must** have a changelog entry, without `merge_request` value
and with `type` set to `security`.
- Any user-facing change **should** have a changelog entry. Example: "GitLab now
uses system fonts for all text."
@@ -269,13 +266,14 @@ as the other was merged. When we had dozens of merge requests fighting for the
same changelog entry location, this quickly became a major source of merge
conflicts and delays in development.
-This led us to a [boring solution] of "add your entry in a random location in
+This led us to a [boring solution](https://about.gitlab.com/handbook/values/#boring-solutions) of "add your entry in a random location in
the list." This actually worked pretty well as we got further along in each
monthly release cycle, but at the start of a new cycle, when a new version
section was added and there were fewer places to "randomly" add an entry, the
conflicts became a problem again until we had a sufficient number of entries.
-On top of all this, it created an entirely different headache for [release managers]
+On top of all this, it created an entirely different headache for
+[release managers](https://gitlab.com/gitlab-org/release/docs/blob/master/quickstart/release-manager.md)
when they cherry-picked a commit into a stable branch for a patch release. If
the commit included an entry in the `CHANGELOG`, it would include the entire
changelog for the latest version in `master`, so the release manager would have
@@ -283,16 +281,11 @@ to manually remove the later entries. They often would have had to do this
multiple times per patch release. This was compounded when we had to release
multiple patches at once due to a security issue.
-We needed to automate all of this manual work. So we [started brainstorming].
+We needed to automate all of this manual work. So we
+[started brainstorming](https://gitlab.com/gitlab-org/gitlab-foss/issues/17826).
After much discussion we settled on the current solution of one file per entry,
and then compiling the entries into the overall `CHANGELOG.md` file during the
-[release process].
-
-[boring solution]: https://about.gitlab.com/handbook/values/#boring-solutions
-[release managers]: https://gitlab.com/gitlab-org/release/docs/blob/master/quickstart/release-manager.md
-[started brainstorming]: https://gitlab.com/gitlab-org/gitlab-foss/issues/17826
-[release process]: https://gitlab.com/gitlab-org/release-tools
-[Security fixes]: https://gitlab.com/gitlab-org/release/docs/blob/master/general/security/developer.md
+[release process](https://gitlab.com/gitlab-org/release-tools).
---
diff --git a/doc/development/code_review.md b/doc/development/code_review.md
index 52a0672259f..5220f29bd60 100644
--- a/doc/development/code_review.md
+++ b/doc/development/code_review.md
@@ -490,15 +490,11 @@ A good example of collaboration on an MR touching multiple parts of the codebase
### Credits
-Largely based on the [thoughtbot code review guide].
-
-[thoughtbot code review guide]: https://github.com/thoughtbot/guides/tree/master/code-review
+Largely based on the [thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
---
[Return to Development documentation](README.md)
-[projects]: https://about.gitlab.com/handbook/engineering/projects/
-[build handbook]: https://about.gitlab.com/handbook/build/handbook/build#how-to-work-with-build
[^1]: Please note that specs other than JavaScript specs are considered backend code.
[^2]: We encourage you to seek guidance from a database maintainer if your merge request is potentially introducing expensive queries. It is most efficient to comment on the line of code in question with the SQL queries so they can give their advice.
diff --git a/doc/development/contributing/issue_workflow.md b/doc/development/contributing/issue_workflow.md
index 5df357eee9e..c8705a174af 100644
--- a/doc/development/contributing/issue_workflow.md
+++ b/doc/development/contributing/issue_workflow.md
@@ -402,7 +402,8 @@ below will make it easy to manage this, without unnecessary overhead.
Every monthly release has a corresponding issue on the CE issue tracker to keep
track of functionality broken by that release and any fixes that need to be
-included in a patch release (see [8.3 Regressions] as an example).
+included in a patch release (see
+[8.3 Regressions](https://gitlab.com/gitlab-org/gitlab-foss/issues/4127) as an example).
As outlined in the issue description, the intended workflow is to post one note
with a reference to an issue describing the regression, and then to update that
@@ -412,11 +413,9 @@ If you're a contributor who doesn't have the required permissions to update
other users' notes, please post a new note with a reference to both the issue
and the merge request.
-The release manager will [update the notes] in the regression issue as fixes are
-addressed.
-
-[8.3 Regressions]: https://gitlab.com/gitlab-org/gitlab-foss/issues/4127
-[update the notes]: https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue
+The release manager will
+[update the notes](https://gitlab.com/gitlab-org/release-tools/blob/master/doc/pro-tips.md#update-the-regression-issue)
+in the regression issue as fixes are addressed.
## Technical and UX debt
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index deb86569879..0007f6d6e2f 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -1349,11 +1349,9 @@ Replace `reconfigure` with `restart` where appropriate.
In [step 2 of the installation guide](../../install/installation.md#2-ruby),
we install Ruby from source. Whenever there is a new version that needs to
be updated, remember to change it throughout the codeblock and also replace
-the sha256sum (it can be found in the [downloads page][ruby-dl] of the Ruby
+the sha256sum (it can be found in the [downloads page](https://www.ruby-lang.org/en/downloads/) of the Ruby
website).
-[ruby-dl]: https://www.ruby-lang.org/en/downloads/ "Ruby download website"
-
### Configuration documentation for source and Omnibus installations
GitLab currently officially supports two installation methods: installations
@@ -1380,7 +1378,7 @@ the style below as a guide:
external_url "https://gitlab.example.com"
```
-1. Save the file and [reconfigure] GitLab for the changes to take effect.
+1. Save the file and [reconfigure](path/to/administration/restart_gitlab.md#omnibus-gitlab-reconfigure) GitLab for the changes to take effect.
---
@@ -1393,10 +1391,7 @@ the style below as a guide:
host: "gitlab.example.com"
```
-1. Save the file and [restart] GitLab for the changes to take effect.
-
-[reconfigure]: path/to/administration/restart_gitlab.md#omnibus-gitlab-reconfigure
-[restart]: path/to/administration/restart_gitlab.md#installations-from-source
+1. Save the file and [restart](path/to/administration/restart_gitlab.md#installations-from-source) GitLab for the changes to take effect.
````
In this case:
diff --git a/doc/development/ee_features.md b/doc/development/ee_features.md
index b386d0e78ff..bd70d5b87ba 100644
--- a/doc/development/ee_features.md
+++ b/doc/development/ee_features.md
@@ -9,7 +9,8 @@
## Act as CE when unlicensed
-Since the implementation of [GitLab CE features to work with unlicensed EE instance][ee-as-ce]
+Since the implementation of
+[GitLab CE features to work with unlicensed EE instance](https://gitlab.com/gitlab-org/gitlab/issues/2500)
GitLab Enterprise Edition should work like GitLab Community Edition
when no license is active. So EE features always should be guarded by
`project.feature_available?` or `group.feature_available?` (or
@@ -24,8 +25,6 @@ setting the [`FOSS_ONLY` environment variable](https://gitlab.com/gitlab-org/git
to something that evaluates as `true`. The same works for running tests
(for example `FOSS_ONLY=1 yarn jest`).
-[ee-as-ce]: https://gitlab.com/gitlab-org/gitlab/issues/2500
-
## Separation of EE code
All EE code should be put inside the `ee/` top-level directory. The
@@ -53,11 +52,9 @@ is applied not only to models. Here's a list of other examples:
- `ee/app/views/foo/_bar.html.haml`
This works because for every path that is present in CE's eager-load/auto-load
-paths, we add the same `ee/`-prepended path in [`config/application.rb`].
+paths, we add the same `ee/`-prepended path in [`config/application.rb`](https://gitlab.com/gitlab-org/gitlab/blob/925d3d4ebc7a2c72964ce97623ae41b8af12538d/config/application.rb#L42-52).
This also applies to views.
-[`config/application.rb`]: https://gitlab.com/gitlab-org/gitlab/blob/925d3d4ebc7a2c72964ce97623ae41b8af12538d/config/application.rb#L42-52
-
### EE features based on CE features
For features that build on existing CE features, write a module in the `EE`
diff --git a/doc/development/feature_flags/controls.md b/doc/development/feature_flags/controls.md
index fa9942e8d81..aa32285b27b 100644
--- a/doc/development/feature_flags/controls.md
+++ b/doc/development/feature_flags/controls.md
@@ -29,6 +29,11 @@ Monitor stage, Health group.
For all production environment Chatops commands, use the `#production` channel.
+As per the template, where a feature would have a (potentially) significant user
+impact and the feature is being enabled instance wide prior to release, please copy
+the Slack message and repost in the `#support_gitlab-com` channel for added visibility
+and awareness, preferably with a link to the issue, MR, or docs.
+
Regardless of the channel in which the Chatops command is ran, any feature flag change that affects GitLab.com will automatically be logged in an issue.
The issue is created in the [gl-infra/feature-flag-log](https://gitlab.com/gitlab-com/gl-infra/feature-flag-log/issues?scope=all&utf8=%E2%9C%93&state=closed) project, and it will at minimum log the Slack handle of person enabling a feature flag, the time, and the name of the flag being changed.
diff --git a/doc/development/file_storage.md b/doc/development/file_storage.md
index e16fe7eba5b..230288844d7 100644
--- a/doc/development/file_storage.md
+++ b/doc/development/file_storage.md
@@ -1,6 +1,6 @@
# File Storage in GitLab
-We use the [CarrierWave] gem to handle file upload, store and retrieval.
+We use the [CarrierWave](https://github.com/carrierwaveuploader/carrierwave) gem to handle file upload, store and retrieval.
File uploads should be accelerated by workhorse, for details please refer to [uploads development documentation](uploads.md).
@@ -46,14 +46,14 @@ they are still not 100% standardized. You can see them below:
CI Artifacts and LFS Objects behave differently in CE and EE. In CE they inherit the `GitlabUploader`
while in EE they inherit the `ObjectStorage` and store files in and S3 API compatible object store.
-In the case of Issues/MR/Notes Markdown attachments, there is a different approach using the [Hashed Storage] layout,
+In the case of Issues/MR/Notes Markdown attachments, there is a different approach using the [Hashed Storage](../administration/repository_storage_types.md) layout,
instead of basing the path into a mutable variable `:project_path_with_namespace`, it's possible to use the
hash of the project ID instead, if project migrates to the new approach (introduced in 10.2).
-> Note: We provide an [all-in-one Rake task] to migrate all uploads to object
+> Note: We provide an [all-in-one Rake task](../administration/raketasks/uploads/migrate.md) to migrate all uploads to object
> storage in one go. If a new Uploader class or model type is introduced, make
-> sure you add a Rake task invocation corresponding to it to the [category
-> list].
+> sure you add a Rake task invocation corresponding to it to the
+> [category list](https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/uploads/migrate.rake).
### Path segments
@@ -144,8 +144,3 @@ class Thing < ActiveRecord::Base
...
end
```
-
-[CarrierWave]: https://github.com/carrierwaveuploader/carrierwave
-[Hashed Storage]: ../administration/repository_storage_types.md
-[all-in-one rake task]: ../administration/raketasks/uploads/migrate.md
-[category list]: https://gitlab.com/gitlab-org/gitlab/blob/master/lib/tasks/gitlab/uploads/migrate.rake
diff --git a/doc/development/interacting_components.md b/doc/development/interacting_components.md
index 3db260d5f85..4639bd7cc20 100644
--- a/doc/development/interacting_components.md
+++ b/doc/development/interacting_components.md
@@ -9,7 +9,7 @@ when making _backend_ changes that might involve multiple features or [component
## Uploads
-GitLab supports uploads to [object storage]. That means every feature and
+GitLab supports uploads to [object storage](https://docs.gitlab.com/charts/advanced/external-object-storage/). That means every feature and
change that affects uploads should also be tested against [object storage],
which is _not_ enabled by default in [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit).
@@ -25,5 +25,3 @@ See also [File Storage in GitLab](file_storage.md).
GitLab supports a great amount of features for [merge requests](../user/project/merge_requests/index.md). One
of them is the ability to create merge requests from and to [forks](../gitlab-basics/fork-project.md),
which should also be highly considered and tested upon development phase.
-
-[object storage]: https://docs.gitlab.com/charts/advanced/external-object-storage/
diff --git a/doc/development/performance.md b/doc/development/performance.md
index a7ae283432f..5068103ff16 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -8,7 +8,7 @@ consistent performance of GitLab.
The process of solving performance problems is roughly as follows:
1. Make sure there's an issue open somewhere (for example, on the GitLab CE issue
- tracker), and create one if there is not. See [#15607][#15607] for an example.
+ tracker), and create one if there is not. See [#15607](https://gitlab.com/gitlab-org/gitlab-foss/issues/15607) for an example.
1. Measure the performance of the code in a production environment such as
GitLab.com (see the [Tooling](#tooling) section below). Performance should be
measured over a period of _at least_ 24 hours.
@@ -495,7 +495,7 @@ just memory but also unnecessary time spent in CPU and I/O for processing lines
## Anti-Patterns
-This is a collection of [anti-patterns][anti-pattern] that should be avoided
+This is a collection of [anti-patterns](https://en.wikipedia.org/wiki/Anti-pattern) that should be avoided
unless these changes have a measurable, significant, and positive impact on
production environments.
@@ -539,6 +539,3 @@ Assuming you are working with ActiveRecord models, you might also find these lin
You may find some useful examples in this snippet:
<https://gitlab.com/gitlab-org/gitlab-foss/snippets/33946>
-
-[#15607]: https://gitlab.com/gitlab-org/gitlab-foss/issues/15607
-[anti-pattern]: https://en.wikipedia.org/wiki/Anti-pattern
diff --git a/doc/install/aws/index.md b/doc/install/aws/index.md
index 109cd635dc0..d510dff82dd 100644
--- a/doc/install/aws/index.md
+++ b/doc/install/aws/index.md
@@ -205,7 +205,7 @@ On the EC2 dashboard, look for Load Balancer in the left navigation bar:
1. Click **Configure Health Check** and set up a health check for your EC2 instances.
1. For **Ping Protocol**, select HTTP.
1. For **Ping Port**, enter 80.
- 1. For **Ping Path**, enter `/explore`. (We use `/explore` as it's a public endpoint that does
+ 1. For **Ping Path**, enter `/users/sign_in`. (We use `/users/sign_in` as it's a public endpoint that does
not require authorization.)
1. Keep the default **Advanced Details** or adjust them according to your needs.
1. Click **Add EC2 Instances** but, as we don't have any instances to add yet, come back
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index d7b2222fa06..0ca2da1db63 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -69,6 +69,16 @@ you are privileged to.
If the public level is restricted, user profiles are only visible to logged in users.
+## Visibility of pages
+
+By default, the following directories are visible to unauthenticated users:
+
+- Public access (`/public`).
+- Explore (`/explore`).
+- Help (`/help`).
+
+However, if the access level of the `/public` directory is restricted, these directories are visible only to logged in users.
+
## Restricting the use of public or internal projects
You can restrict the use of visibility levels for users when they create a project or a
diff --git a/doc/user/admin_area/settings/visibility_and_access_controls.md b/doc/user/admin_area/settings/visibility_and_access_controls.md
index 704dd89ede2..f827fed833b 100644
--- a/doc/user/admin_area/settings/visibility_and_access_controls.md
+++ b/doc/user/admin_area/settings/visibility_and_access_controls.md
@@ -91,7 +91,7 @@ For more details on group visibility, see [Public access](../../../public_access
## Restricted visibility levels
-To set the available visibility levels for new projects and snippets:
+To set the available visibility levels for projects, snippets, and selected pages:
1. Check the desired visibility levels.
1. Click **Save changes**.
diff --git a/doc/user/project/import/img/jira/import_issues_from_jira_button_v12_10.png b/doc/user/project/import/img/jira/import_issues_from_jira_button_v12_10.png
new file mode 100644
index 00000000000..8983d685a24
--- /dev/null
+++ b/doc/user/project/import/img/jira/import_issues_from_jira_button_v12_10.png
Binary files differ
diff --git a/doc/user/project/import/img/jira/import_issues_from_jira_form_v12_10.png b/doc/user/project/import/img/jira/import_issues_from_jira_form_v12_10.png
new file mode 100644
index 00000000000..0ac5e9bdb91
--- /dev/null
+++ b/doc/user/project/import/img/jira/import_issues_from_jira_form_v12_10.png
Binary files differ
diff --git a/doc/user/project/import/img/jira/import_issues_from_jira_projects_v12_10.png b/doc/user/project/import/img/jira/import_issues_from_jira_projects_v12_10.png
new file mode 100644
index 00000000000..cf5f0dd59cd
--- /dev/null
+++ b/doc/user/project/import/img/jira/import_issues_from_jira_projects_v12_10.png
Binary files differ
diff --git a/doc/user/project/import/index.md b/doc/user/project/import/index.md
index a114e23b3e2..a0da68eb513 100644
--- a/doc/user/project/import/index.md
+++ b/doc/user/project/import/index.md
@@ -15,6 +15,7 @@
1. [By uploading a manifest file (AOSP)](manifest.md)
1. [From Gemnasium](gemnasium.md)
1. [From Phabricator](phabricator.md)
+1. [From Jira (issues only)](jira.md)
In addition to the specific migration documentation above, you can import any
Git repository via HTTP from the New Project page. Be aware that if the
diff --git a/doc/user/project/import/jira.md b/doc/user/project/import/jira.md
new file mode 100644
index 00000000000..49224001fe6
--- /dev/null
+++ b/doc/user/project/import/jira.md
@@ -0,0 +1,57 @@
+# Import your Jira project issues to GitLab
+
+> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/2766) in GitLab 12.10.
+
+Using GitLab Jira importer, you can import your Jira issues to GitLab.com or to
+your self-managed GitLab instance.
+
+Jira issues import is an MVC, project-level feature, meaning that issues from multiple
+Jira projects can be imported into a GitLab project. MVC version imports issue title and description
+as well as some other issue metadata as a section in the issue description.
+
+## Prerequisites
+
+### Permissions
+
+In order to be able to import issues from a Jira project you need to have read access on Jira
+issues and a [Maintainer or higher](../../permissions.md#project-members-permissions) role in the
+GitLab project that you wish to import into.
+
+### Jira integration
+
+This feature uses the existing GitLab [Jira integration](../integrations/jira.md).
+
+Make sure you have the integration set up before trying to import Jira issues.
+
+## Import Jira issues to GitLab
+
+To import Jira issues to a GitLab project, follow the steps below.
+
+NOTE: **Note:**
+Importing Jira issues is done as an asynchronous background job, which
+may result in delays based on import queues load, system load, or other factors.
+Importing large projects may take several minutes depending on the size of the import.
+
+1. On the **{issues}** **Issues** page, click the **Import Issues** (**{import}**) button.
+1. Select **Import from Jira**.
+
+ ![Import issues from Jira button](img/jira/import_issues_from_jira_button_v12_10.png)
+
+ The following form appears.
+
+ ![Import issues from Jira form](img/jira/import_issues_from_jira_form_v12_10.png)
+
+ If you've previously set up the [Jira integration](../integrations/jira.md), you now see the Jira
+ projects that you have access to in the dropdown.
+
+1. Select the Jira project that you wish to import issues from.
+
+ ![Import issues from Jira form](img/jira/import_issues_from_jira_projects_v12_10.png)
+
+1. Click **Import Issues**. You're presented with a confirmation that import has started.
+ While the import is running in the background, you can navigate away from the import status page
+ to the issues page, and you'll see the new issues appearing in the issues list.
+
+1. To check the status of your import, go back to the Jira import page.
+
+ ![Import issues from Jira button](img/jira/import_issues_from_jira_button_v12_10.png)
diff --git a/lib/api/helpers/rate_limiter.rb b/lib/api/helpers/rate_limiter.rb
new file mode 100644
index 00000000000..5a531b5324a
--- /dev/null
+++ b/lib/api/helpers/rate_limiter.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+module API
+ module Helpers
+ module RateLimiter
+ def check_rate_limit!(key, scope)
+ if rate_limiter.throttled?(key, scope: scope)
+ log_request(key)
+ render_exceeded_limit_error!
+ end
+ end
+
+ private
+
+ def rate_limiter
+ ::Gitlab::ApplicationRateLimiter
+ end
+
+ def render_exceeded_limit_error!
+ render_api_error!({ error: _('This endpoint has been requested too many times. Try again later.') }, 429)
+ end
+
+ def log_request(key)
+ rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user)
+ end
+ end
+ end
+end
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index a78202877fb..f27afd0055f 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -4,6 +4,7 @@ module API
class Issues < Grape::API
include PaginationParams
helpers Helpers::IssuesHelpers
+ helpers Helpers::RateLimiter
helpers ::Gitlab::IssuableMetadata
before { authenticate_non_get! }
@@ -211,6 +212,8 @@ module API
post ':id/issues' do
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42320')
+ check_rate_limit! :issues_create, [current_user, :issues_create]
+
authorize! :create_issue, user_project
params.delete(:created_at) unless current_user.can?(:set_issue_created_at, user_project)
diff --git a/lib/api/project_export.rb b/lib/api/project_export.rb
index ef6a8f1a396..9fd9d13a20c 100644
--- a/lib/api/project_export.rb
+++ b/lib/api/project_export.rb
@@ -2,15 +2,8 @@
module API
class ProjectExport < Grape::API
- helpers do
- def throttled?(action)
- rate_limiter.throttled?(action, scope: [current_user, action, user_project])
- end
+ helpers Helpers::RateLimiter
- def rate_limiter
- ::Gitlab::ApplicationRateLimiter
- end
- end
before do
not_found! unless Gitlab::CurrentSettings.project_export_enabled?
authorize_admin_project
@@ -32,9 +25,7 @@ module API
detail 'This feature was introduced in GitLab 10.6.'
end
get ':id/export/download' do
- if throttled?(:project_download_export)
- render_api_error!({ error: 'This endpoint has been requested too many times. Try again later.' }, 429)
- end
+ check_rate_limit! :project_download_export, [current_user, :project_download_export, user_project]
if user_project.export_file_exists?
present_carrierwave_file!(user_project.export_file)
@@ -54,9 +45,7 @@ module API
end
end
post ':id/export' do
- if throttled?(:project_export)
- render_api_error!({ error: 'This endpoint has been requested too many times. Try again later.' }, 429)
- end
+ check_rate_limit! :project_export, [current_user, :project_export, user_project]
project_export_params = declared_params(include_missing: false)
after_export_params = project_export_params.delete(:upload) || {}
diff --git a/lib/api/project_import.rb b/lib/api/project_import.rb
index ffa9dd13754..0e83686cab2 100644
--- a/lib/api/project_import.rb
+++ b/lib/api/project_import.rb
@@ -8,19 +8,12 @@ module API
helpers Helpers::ProjectsHelpers
helpers Helpers::FileUploadHelpers
+ helpers Helpers::RateLimiter
helpers do
def import_params
declared_params(include_missing: false)
end
-
- def throttled?(key, scope)
- rate_limiter.throttled?(key, scope: scope)
- end
-
- def rate_limiter
- ::Gitlab::ApplicationRateLimiter
- end
end
before do
@@ -69,13 +62,7 @@ module API
post 'import' do
require_gitlab_workhorse!
- key = "project_import".to_sym
-
- if throttled?(key, [current_user, key])
- rate_limiter.log_request(request, "#{key}_request_limit".to_sym, current_user)
-
- render_api_error!({ error: _('This endpoint has been requested too many times. Try again later.') }, 429)
- end
+ check_rate_limit! :project_import, [current_user, :project_import]
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42437')
diff --git a/lib/constraints/admin_constrainer.rb b/lib/constraints/admin_constrainer.rb
new file mode 100644
index 00000000000..59c855a1b73
--- /dev/null
+++ b/lib/constraints/admin_constrainer.rb
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+module Constraints
+ class AdminConstrainer
+ def matches?(request)
+ if Feature.enabled?(:user_mode_in_session)
+ admin_mode_enabled?(request)
+ else
+ user_is_admin?(request)
+ end
+ end
+
+ private
+
+ def user_is_admin?(request)
+ request.env['warden'].authenticate? && request.env['warden'].user.admin?
+ end
+
+ def admin_mode_enabled?(request)
+ Gitlab::Session.with_session(request.session) do
+ request.env['warden'].authenticate? && Gitlab::Auth::CurrentUserMode.new(request.env['warden'].user).admin_mode?
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/import_export/group/tree_saver.rb b/lib/gitlab/import_export/group/legacy_tree_saver.rb
index fd1eb329ad2..3776ef0d8f5 100644
--- a/lib/gitlab/import_export/group/tree_saver.rb
+++ b/lib/gitlab/import_export/group/legacy_tree_saver.rb
@@ -3,7 +3,7 @@
module Gitlab
module ImportExport
module Group
- class TreeSaver
+ class LegacyTreeSaver
attr_reader :full_path, :shared
def initialize(group:, current_user:, shared:, params: {})
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9965f8c7d47..49a064da6f8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -788,12 +788,18 @@ msgstr ""
msgid "<code>\"johnsmith@example.com\": \"johnsmith@example.com\"</code> will add \"By <a href=\"#\">johnsmith@example.com</a>\" to all issues and comments originally created by johnsmith@example.com. By default, the email address or username is masked to ensure the user's privacy. Use this option if you want to show the full email address."
msgstr ""
+msgid "<namespace / project>"
+msgstr ""
+
msgid "<no name set>"
msgstr ""
msgid "<no scopes selected>"
msgstr ""
+msgid "<project name>"
+msgstr ""
+
msgid "<strong>%{group_name}</strong> group members"
msgstr ""
@@ -5456,6 +5462,9 @@ msgstr ""
msgid "Container repositories sync capacity"
msgstr ""
+msgid "ContainerRegistry| Please visit the %{linkStart}administration settings%{linkEnd} to enable this feature."
+msgstr ""
+
msgid "ContainerRegistry|%{imageName} tags"
msgstr ""
@@ -5471,6 +5480,9 @@ msgstr ""
msgid "ContainerRegistry|Container Registry"
msgstr ""
+msgid "ContainerRegistry|Container Registry tag expiration and retention policy is disabled"
+msgstr ""
+
msgid "ContainerRegistry|Copy build command"
msgstr ""
@@ -5480,9 +5492,6 @@ msgstr ""
msgid "ContainerRegistry|Copy push command"
msgstr ""
-msgid "ContainerRegistry|Currently, the Container Registry tag expiration feature is not available for projects created before GitLab version 12.8. For updates and more information, visit Issue %{linkStart}#196124%{linkEnd}"
-msgstr ""
-
msgid "ContainerRegistry|Docker connection error"
msgstr ""
@@ -5531,6 +5540,9 @@ msgstr ""
msgid "ContainerRegistry|Number of tags to retain:"
msgstr ""
+msgid "ContainerRegistry|Please contact your administrator."
+msgstr ""
+
msgid "ContainerRegistry|Push an image"
msgstr ""
@@ -5587,6 +5599,9 @@ msgstr ""
msgid "ContainerRegistry|Tags deleted successfully"
msgstr ""
+msgid "ContainerRegistry|The Container Registry tag expiration and retention policies for this project have not been enabled."
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
diff --git a/spec/controllers/explore/groups_controller_spec.rb b/spec/controllers/explore/groups_controller_spec.rb
index 5a32d8ca0d3..eccbd7fa14d 100644
--- a/spec/controllers/explore/groups_controller_spec.rb
+++ b/spec/controllers/explore/groups_controller_spec.rb
@@ -22,4 +22,18 @@ describe Explore::GroupsController do
expect(assigns(:groups)).to contain_exactly(member_of_group, public_group)
end
+
+ context 'restricted visibility level is public' do
+ before do
+ sign_out(user)
+
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'redirects to login page' do
+ get :index
+
+ expect(response).to redirect_to new_user_session_path
+ end
+ end
end
diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb
index c2cd29eb036..00cc2d5a81c 100644
--- a/spec/controllers/explore/projects_controller_spec.rb
+++ b/spec/controllers/explore/projects_controller_spec.rb
@@ -171,5 +171,17 @@ describe Explore::ProjectsController do
get :index, params: { sort: sorting_param }
end
end
+
+ context 'restricted visibility level is public' do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'redirects to login page' do
+ get :index
+
+ expect(response).to redirect_to new_user_session_path
+ end
+ end
end
end
diff --git a/spec/controllers/help_controller_spec.rb b/spec/controllers/help_controller_spec.rb
index e010cac2f73..f03fee8d3ae 100644
--- a/spec/controllers/help_controller_spec.rb
+++ b/spec/controllers/help_controller_spec.rb
@@ -79,6 +79,20 @@ describe HelpController do
expect(assigns[:help_index]).to eq '[protocol-relative](//example.com)'
end
end
+
+ context 'restricted visibility set to public' do
+ before do
+ sign_out(user)
+
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'redirects to sign_in path' do
+ get :index
+
+ expect(response).to redirect_to(new_user_session_path)
+ end
+ end
end
describe 'GET #show' do
diff --git a/spec/features/explore/groups_spec.rb b/spec/features/explore/groups_spec.rb
index eff63d6a788..50ec44580d2 100644
--- a/spec/features/explore/groups_spec.rb
+++ b/spec/features/explore/groups_spec.rb
@@ -89,5 +89,17 @@ describe 'Explore Groups', :js do
end
it_behaves_like 'renders group in public groups area'
+
+ context 'when visibility is restricted to public' do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ end
+
+ it 'redirects to the sign in page' do
+ visit explore_groups_path
+
+ expect(page).to have_current_path(new_user_session_path)
+ end
+ end
end
end
diff --git a/spec/features/explore/user_explores_projects_spec.rb b/spec/features/explore/user_explores_projects_spec.rb
index c64709c0b55..6adf51a1cf6 100644
--- a/spec/features/explore/user_explores_projects_spec.rb
+++ b/spec/features/explore/user_explores_projects_spec.rb
@@ -16,6 +16,17 @@ describe 'User explores projects' do
include_examples 'shows public projects'
end
+
+ context 'when visibility is restricted to public' do
+ before do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+ visit(explore_projects_path)
+ end
+
+ it 'redirects to login page' do
+ expect(page).to have_current_path(new_user_session_path)
+ end
+ end
end
context 'when signed in' do
diff --git a/spec/frontend/registry/settings/components/registry_settings_app_spec.js b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
index c83cc0c00dd..95f784c9727 100644
--- a/spec/frontend/registry/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -1,10 +1,11 @@
import { shallowMount } from '@vue/test-utils';
-import { GlAlert } from '@gitlab/ui';
+import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import component from '~/registry/settings/components/registry_settings_app.vue';
import SettingsForm from '~/registry/settings/components/settings_form.vue';
import { createStore } from '~/registry/settings/store/';
-import { SET_IS_DISABLED } from '~/registry/settings/store/mutation_types';
+import { SET_SETTINGS, SET_INITIAL_STATE } from '~/registry/settings/store/mutation_types';
import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/shared/constants';
+import { stringifiedFormOptions } from '../../shared/mock_data';
describe('Registry Settings App', () => {
let wrapper;
@@ -13,14 +14,14 @@ describe('Registry Settings App', () => {
const findSettingsComponent = () => wrapper.find(SettingsForm);
const findAlert = () => wrapper.find(GlAlert);
- const mountComponent = ({ dispatchMock = 'mockResolvedValue', isDisabled = false } = {}) => {
- store = createStore();
- store.commit(SET_IS_DISABLED, isDisabled);
+ const mountComponent = ({ dispatchMock = 'mockResolvedValue' } = {}) => {
const dispatchSpy = jest.spyOn(store, 'dispatch');
- if (dispatchMock) {
- dispatchSpy[dispatchMock]();
- }
+ dispatchSpy[dispatchMock]();
+
wrapper = shallowMount(component, {
+ stubs: {
+ GlSprintf,
+ },
mocks: {
$toast: {
show: jest.fn(),
@@ -30,11 +31,16 @@ describe('Registry Settings App', () => {
});
};
+ beforeEach(() => {
+ store = createStore();
+ });
+
afterEach(() => {
wrapper.destroy();
});
it('renders', () => {
+ store.commit(SET_SETTINGS, { foo: 'bar' });
mountComponent();
expect(wrapper.element).toMatchSnapshot();
});
@@ -45,13 +51,15 @@ describe('Registry Settings App', () => {
});
it('renders the setting form', () => {
+ store.commit(SET_SETTINGS, { foo: 'bar' });
mountComponent();
expect(findSettingsComponent().exists()).toBe(true);
});
- describe('isDisabled', () => {
+ describe('the form is disabled', () => {
beforeEach(() => {
- mountComponent({ isDisabled: true });
+ store.commit(SET_SETTINGS, undefined);
+ mountComponent();
});
it('the form is hidden', () => {
@@ -59,9 +67,27 @@ describe('Registry Settings App', () => {
});
it('shows an alert', () => {
- expect(findAlert().html()).toContain(
- 'Currently, the Container Registry tag expiration feature is not available',
+ const text = findAlert().text();
+ expect(text).toContain(
+ 'The Container Registry tag expiration and retention policies for this project have not been enabled.',
);
+ expect(text).toContain('Please contact your administrator.');
+ });
+
+ describe('an admin is visiting the page', () => {
+ beforeEach(() => {
+ store.commit(SET_INITIAL_STATE, {
+ ...stringifiedFormOptions,
+ isAdmin: true,
+ adminSettingsPath: 'foo',
+ });
+ });
+
+ it('shows the admin part of the alert message', () => {
+ const sprintf = findAlert().find(GlSprintf);
+ expect(sprintf.text()).toBe('administration settings');
+ expect(sprintf.find(GlLink).attributes('href')).toBe('foo');
+ });
});
});
diff --git a/spec/frontend/registry/settings/store/actions_spec.js b/spec/frontend/registry/settings/store/actions_spec.js
index 5038dc82416..f92d10d087f 100644
--- a/spec/frontend/registry/settings/store/actions_spec.js
+++ b/spec/frontend/registry/settings/store/actions_spec.js
@@ -20,7 +20,7 @@ describe('Actions Registry Store', () => {
);
describe('receiveSettingsSuccess', () => {
- it('calls SET_SETTINGS when data is present', () => {
+ it('calls SET_SETTINGS', () => {
testAction(
actions.receiveSettingsSuccess,
'foo',
@@ -29,15 +29,6 @@ describe('Actions Registry Store', () => {
[],
);
});
- it('calls SET_IS_DISABLED when data is not present', () => {
- testAction(
- actions.receiveSettingsSuccess,
- null,
- {},
- [{ type: types.SET_IS_DISABLED, payload: true }],
- [],
- );
- });
});
describe('fetchSettings', () => {
diff --git a/spec/frontend/registry/settings/store/getters_spec.js b/spec/frontend/registry/settings/store/getters_spec.js
index 44631b97a39..944057ebc9f 100644
--- a/spec/frontend/registry/settings/store/getters_spec.js
+++ b/spec/frontend/registry/settings/store/getters_spec.js
@@ -29,7 +29,7 @@ describe('Getters registry settings store', () => {
});
});
- describe('getIsDisabled', () => {
+ describe('getIsEdited', () => {
it('returns false when original is equal to settings', () => {
const same = { foo: 'bar' };
expect(getters.getIsEdited({ original: same, settings: same })).toBe(false);
@@ -41,4 +41,18 @@ describe('Getters registry settings store', () => {
);
});
});
+
+ describe('getIsDisabled', () => {
+ it.each`
+ original | enableHistoricEntries | result
+ ${undefined} | ${false} | ${true}
+ ${{ foo: 'bar' }} | ${undefined} | ${false}
+ ${{}} | ${false} | ${false}
+ `(
+ 'returns $result when original is $original and enableHistoricEntries is $enableHistoricEntries',
+ ({ original, enableHistoricEntries, result }) => {
+ expect(getters.getIsDisabled({ original, enableHistoricEntries })).toBe(result);
+ },
+ );
+ });
});
diff --git a/spec/frontend/registry/settings/store/mutations_spec.js b/spec/frontend/registry/settings/store/mutations_spec.js
index 8ab0196fd4d..1d85e38eb36 100644
--- a/spec/frontend/registry/settings/store/mutations_spec.js
+++ b/spec/frontend/registry/settings/store/mutations_spec.js
@@ -12,14 +12,19 @@ describe('Mutations Registry Store', () => {
describe('SET_INITIAL_STATE', () => {
it('should set the initial state', () => {
- const expectedState = { ...mockState, projectId: 'foo', formOptions };
- mutations[types.SET_INITIAL_STATE](mockState, {
+ const payload = {
projectId: 'foo',
+ enableHistoricEntries: false,
+ adminSettingsPath: 'foo',
+ isAdmin: true,
+ };
+ const expectedState = { ...mockState, ...payload, formOptions };
+ mutations[types.SET_INITIAL_STATE](mockState, {
+ ...payload,
...stringifiedFormOptions,
});
- expect(mockState.projectId).toEqual(expectedState.projectId);
- expect(mockState.formOptions).toEqual(expectedState.formOptions);
+ expect(mockState).toEqual(expectedState);
});
});
@@ -41,6 +46,13 @@ describe('Mutations Registry Store', () => {
expect(mockState.settings).toEqual(expectedState.settings);
expect(mockState.original).toEqual(expectedState.settings);
});
+
+ it('should keep the default state when settings is not present', () => {
+ const originalSettings = { ...mockState.settings };
+ mutations[types.SET_SETTINGS](mockState);
+ expect(mockState.settings).toEqual(originalSettings);
+ expect(mockState.original).toEqual(undefined);
+ });
});
describe('RESET_SETTINGS', () => {
@@ -50,6 +62,13 @@ describe('Mutations Registry Store', () => {
mutations[types.RESET_SETTINGS](mockState);
expect(mockState.settings).toEqual(mockState.original);
});
+
+ it('if original is undefined it should initialize to empty object', () => {
+ mockState.settings = { foo: 'bar' };
+ mockState.original = undefined;
+ mutations[types.RESET_SETTINGS](mockState);
+ expect(mockState.settings).toEqual({});
+ });
});
describe('TOGGLE_LOADING', () => {
@@ -58,11 +77,4 @@ describe('Mutations Registry Store', () => {
expect(mockState.isLoading).toEqual(true);
});
});
-
- describe('SET_IS_DISABLED', () => {
- it('should set isDisabled', () => {
- mutations[types.SET_IS_DISABLED](mockState, true);
- expect(mockState.isDisabled).toEqual(true);
- });
- });
});
diff --git a/spec/lib/constraints/admin_constrainer_spec.rb b/spec/lib/constraints/admin_constrainer_spec.rb
new file mode 100644
index 00000000000..da178f9e71a
--- /dev/null
+++ b/spec/lib/constraints/admin_constrainer_spec.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+#
+require 'spec_helper'
+
+describe Constraints::AdminConstrainer, :do_not_mock_admin_mode do
+ let(:user) { create(:user) }
+
+ let(:session) { {} }
+ let(:env) { { 'warden' => double(:warden, authenticate?: true, user: user) } }
+ let(:request) { double(:request, session: session, env: env) }
+
+ around do |example|
+ Gitlab::Session.with_session(session) do
+ example.run
+ end
+ end
+
+ describe '#matches' do
+ context 'feature flag :user_mode_in_session is enabled' do
+ context 'when user is a regular user' do
+ it 'forbids access' do
+ expect(subject.matches?(request)).to be(false)
+ end
+ end
+
+ context 'when user is an admin' do
+ let(:user) { create(:admin) }
+
+ context 'admin mode is disabled' do
+ it 'forbids access' do
+ expect(subject.matches?(request)).to be(false)
+ end
+ end
+
+ context 'admin mode is enabled' do
+ before do
+ current_user_mode = Gitlab::Auth::CurrentUserMode.new(user)
+ current_user_mode.request_admin_mode!
+ current_user_mode.enable_admin_mode!(password: user.password)
+ end
+
+ it 'allows access' do
+ expect(subject.matches?(request)).to be(true)
+ end
+ end
+ end
+ end
+
+ context 'feature flag :user_mode_in_session is disabled' do
+ before do
+ stub_feature_flags(user_mode_in_session: false)
+ end
+
+ context 'when user is a regular user' do
+ it 'forbids access' do
+ expect(subject.matches?(request)).to be(false)
+ end
+ end
+
+ context 'when user is an admin' do
+ let(:user) { create(:admin) }
+
+ it 'allows access' do
+ expect(subject.matches?(request)).to be(true)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/group/tree_saver_spec.rb b/spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb
index eb790662d8c..a0490c255aa 100644
--- a/spec/lib/gitlab/import_export/group/tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::ImportExport::Group::TreeSaver do
+describe Gitlab::ImportExport::Group::LegacyTreeSaver do
describe 'saves the group tree into a json object' do
let(:shared) { Gitlab::ImportExport::Shared.new(group) }
let(:group_tree_saver) { described_class.new(group: group, current_user: user, shared: shared) }
@@ -28,7 +28,7 @@ describe Gitlab::ImportExport::Group::TreeSaver do
# except:
# context 'with description override' do
# context 'group members' do
- # ^ These are specific for the Group::TreeSaver
+ # ^ These are specific for the Group::LegacyTreeSaver
context 'JSON' do
let(:saved_group_json) do
group_tree_saver.save
diff --git a/spec/requests/api/issues/post_projects_issues_spec.rb b/spec/requests/api/issues/post_projects_issues_spec.rb
index be48113c215..1444f43003f 100644
--- a/spec/requests/api/issues/post_projects_issues_spec.rb
+++ b/spec/requests/api/issues/post_projects_issues_spec.rb
@@ -381,6 +381,20 @@ describe API::Issues do
end.not_to change { project.labels.count }
end
end
+
+ context 'when request exceeds the rate limit' do
+ before do
+ allow(::Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
+ end
+
+ it 'prevents users from creating more issues' do
+ post api("/projects/#{project.id}/issues", user),
+ params: { title: 'new issue', labels: 'label, label2', weight: 3, assignee_ids: [user2.id] }
+
+ expect(response).to have_gitlab_http_status(:too_many_requests)
+ expect(json_response['message']['error']).to eq('This endpoint has been requested too many times. Try again later.')
+ end
+ end
end
describe 'POST /projects/:id/issues with spam filtering' do
diff --git a/spec/services/groups/import_export/export_service_spec.rb b/spec/services/groups/import_export/export_service_spec.rb
index e026d2166d6..56c7121cc34 100644
--- a/spec/services/groups/import_export/export_service_spec.rb
+++ b/spec/services/groups/import_export/export_service_spec.rb
@@ -50,7 +50,7 @@ describe Groups::ImportExport::ExportService do
end
it 'saves the models' do
- expect(Gitlab::ImportExport::Group::TreeSaver).to receive(:new).and_call_original
+ expect(Gitlab::ImportExport::Group::LegacyTreeSaver).to receive(:new).and_call_original
service.execute
end