Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/api.js9
-rw-r--r--app/assets/javascripts/ci_variable_list/index.js8
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue28
-rw-r--r--app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue34
-rw-r--r--app/assets/javascripts/deploy_freeze/store/actions.js47
-rw-r--r--app/assets/javascripts/deploy_freeze/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/deploy_freeze/store/mutations.js11
-rw-r--r--app/assets/javascripts/deploy_freeze/store/state.js2
-rw-r--r--app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue5
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/index.js4
-rw-r--r--app/controllers/admin/application_settings_controller.rb4
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb2
-rw-r--r--app/serializers/build_artifact_entity.rb10
-rw-r--r--app/views/admin/application_settings/ci_cd.html.haml19
-rw-r--r--app/views/projects/_service_desk_settings.html.haml2
-rw-r--r--app/workers/concerns/application_worker.rb2
-rw-r--r--app/workers/concerns/cronjob_queue.rb2
-rw-r--r--changelogs/unreleased/205484-prj-set-ops-3-incidents.yml5
-rw-r--r--changelogs/unreleased/afontaine-edit-deploy-freeze.yml5
-rw-r--r--changelogs/unreleased/btn-default-sd-toggle.yml5
-rw-r--r--changelogs/unreleased/jivanvl-remove-ci-instance-variables-ui-ff.yml5
-rw-r--r--config/feature_flags/development/ci_instance_variables_ui.yml8
-rw-r--r--config/feature_flags/development/remove_duplicate_artifact_exposure_paths.yml8
-rw-r--r--doc/user/packages/composer_repository/index.md8
-rw-r--r--doc/user/project/img/issue_board_iteration_lists_v13_10.pngbin0 -> 61333 bytes
-rw-r--r--doc/user/project/issue_board.md44
-rw-r--r--doc/user/project/releases/img/deploy_freeze_v13_10.pngbin0 -> 15902 bytes
-rw-r--r--doc/user/project/releases/img/deploy_freeze_v13_2.pngbin33428 -> 0 bytes
-rw-r--r--doc/user/project/releases/index.md6
-rw-r--r--jest.config.base.js4
-rw-r--r--lib/api/admin/sidekiq.rb4
-rw-r--r--lib/gitlab/application_context.rb7
-rw-r--r--lib/gitlab/ci/features.rb8
-rw-r--r--lib/gitlab/gitaly_client.rb2
-rw-r--r--lib/gitlab/grape_logging/loggers/context_logger.rb2
-rw-r--r--lib/gitlab/sidekiq_queue.rb2
-rw-r--r--locale/gitlab.pot14
-rw-r--r--spec/controllers/application_controller_spec.rb2
-rw-r--r--spec/controllers/sessions_controller_spec.rb10
-rw-r--r--spec/frontend/api_spec.js32
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js71
-rw-r--r--spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js24
-rw-r--r--spec/frontend/deploy_freeze/store/actions_spec.js82
-rw-r--r--spec/frontend/deploy_freeze/store/mutations_spec.js15
-rw-r--r--spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap4
-rw-r--r--spec/frontend_integration/test_helpers/mock_server/index.js2
-rw-r--r--spec/lib/gitlab/application_context_spec.rb16
-rw-r--r--spec/lib/gitlab/metrics/background_transaction_spec.rb4
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb2
-rw-r--r--spec/requests/api/api_spec.rb4
-rw-r--r--spec/serializers/build_artifact_entity_spec.rb29
-rw-r--r--spec/spec_helper.rb18
-rw-r--r--spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb4
-rw-r--r--spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb12
-rw-r--r--spec/workers/background_migration_worker_spec.rb2
-rw-r--r--spec/workers/concerns/worker_context_spec.rb2
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/C++.gitignore0
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/Java.gitignore0
59 files changed, 525 insertions, 139 deletions
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 48005787d81..8dc44231e26 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -79,6 +79,7 @@ const Api = {
issuePath: '/api/:version/projects/:id/issues/:issue_iid',
tagsPath: '/api/:version/projects/:id/repository/tags',
freezePeriodsPath: '/api/:version/projects/:id/freeze_periods',
+ freezePeriodPath: '/api/:version/projects/:id/freeze_periods/:freeze_period_id',
usageDataIncrementCounterPath: '/api/:version/usage_data/increment_counter',
usageDataIncrementUniqueUsersPath: '/api/:version/usage_data/increment_unique_users',
featureFlagUserLists: '/api/:version/projects/:id/feature_flags_user_lists',
@@ -832,6 +833,14 @@ const Api = {
return axios.post(url, freezePeriod);
},
+ updateFreezePeriod(id, freezePeriod = {}) {
+ const url = Api.buildUrl(this.freezePeriodPath)
+ .replace(':id', encodeURIComponent(id))
+ .replace(':freeze_period_id', encodeURIComponent(freezePeriod.id));
+
+ return axios.put(url, freezePeriod);
+ },
+
trackRedisCounterEvent(event) {
if (!gon.features?.usageDataApi) {
return null;
diff --git a/app/assets/javascripts/ci_variable_list/index.js b/app/assets/javascripts/ci_variable_list/index.js
index 37b5f7e6df7..08bfabc05bc 100644
--- a/app/assets/javascripts/ci_variable_list/index.js
+++ b/app/assets/javascripts/ci_variable_list/index.js
@@ -3,8 +3,7 @@ import { parseBoolean } from '~/lib/utils/common_utils';
import CiVariableSettings from './components/ci_variable_settings.vue';
import createStore from './store';
-export default (containerId = 'js-ci-project-variables') => {
- const containerEl = document.getElementById(containerId);
+const mountCiVariableListApp = (containerEl) => {
const {
endpoint,
projectId,
@@ -43,3 +42,8 @@ export default (containerId = 'js-ci-project-variables') => {
},
});
};
+
+export default () => {
+ const el = document.querySelector('#js-ci-project-variables');
+ return !el ? {} : mountCiVariableListApp(el);
+};
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
index d05a0761ae3..051ab710e5f 100644
--- a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_modal.vue
@@ -18,7 +18,6 @@ export default {
modalOptions: {
ref: 'modal',
modalId: 'deploy-freeze-modal',
- title: __('Add deploy freeze'),
actionCancel: {
text: __('Cancel'),
},
@@ -30,10 +29,13 @@ export default {
cronSyntaxInstructions: __(
'Define a custom deploy freeze pattern with %{cronSyntaxStart}cron syntax%{cronSyntaxEnd}',
),
+ addTitle: __('Add deploy freeze'),
+ editTitle: __('Edit deploy freeze'),
},
computed: {
...mapState([
'projectId',
+ 'selectedId',
'selectedTimezone',
'timezoneData',
'freezeStartCron',
@@ -45,9 +47,9 @@ export default {
]),
addDeployFreezeButton() {
return {
- text: __('Add deploy freeze'),
+ text: this.isEditing ? __('Save deploy freeze') : __('Add deploy freeze'),
attributes: [
- { variant: 'success' },
+ { variant: 'confirm' },
{
disabled:
!isValidCron(this.freezeStartCron) ||
@@ -77,9 +79,17 @@ export default {
this.setSelectedTimezone(selectedTimezone);
},
},
+ isEditing() {
+ return Boolean(this.selectedId);
+ },
+ modalTitle() {
+ return this.isEditing
+ ? this.$options.translations.editTitle
+ : this.$options.translations.addTitle;
+ },
},
methods: {
- ...mapActions(['addFreezePeriod', 'setSelectedTimezone', 'resetModal']),
+ ...mapActions(['addFreezePeriod', 'updateFreezePeriod', 'setSelectedTimezone', 'resetModal']),
resetModalHandler() {
this.resetModal();
},
@@ -89,6 +99,13 @@ export default {
}
return '';
},
+ submit() {
+ if (this.isEditing) {
+ this.updateFreezePeriod();
+ } else {
+ this.addFreezePeriod();
+ }
+ },
},
};
</script>
@@ -96,8 +113,9 @@ export default {
<template>
<gl-modal
v-bind="$options.modalOptions"
+ :title="modalTitle"
:action-primary="addDeployFreezeButton"
- @primary="addFreezePeriod"
+ @primary="submit"
@canceled="resetModalHandler"
>
<p>
diff --git a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
index 0d6657973c3..6ce934dbaea 100644
--- a/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
+++ b/app/assets/javascripts/deploy_freeze/components/deploy_freeze_table.vue
@@ -1,7 +1,7 @@
<script>
import { GlTable, GlButton, GlModalDirective, GlSprintf } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
-import { s__, __ } from '~/locale';
+import { s__ } from '~/locale';
export default {
fields: [
@@ -17,9 +17,16 @@ export default {
key: 'cronTimezone',
label: s__('DeployFreeze|Time zone'),
},
+ {
+ key: 'edit',
+ label: s__('DeployFreeze|Edit'),
+ },
],
translations: {
- addDeployFreeze: __('Add deploy freeze'),
+ addDeployFreeze: s__('DeployFreeze|Add deploy freeze'),
+ emptyStateText: s__(
+ 'DeployFreeze|No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd}',
+ ),
},
components: {
GlTable,
@@ -39,7 +46,7 @@ export default {
this.fetchFreezePeriods();
},
methods: {
- ...mapActions(['fetchFreezePeriods']),
+ ...mapActions(['fetchFreezePeriods', 'setFreezePeriod']),
},
};
</script>
@@ -53,15 +60,20 @@ export default {
show-empty
stacked="lg"
>
+ <template #cell(cronTimezone)="{ item }">
+ {{ item.cronTimezone.formattedTimezone }}
+ </template>
+ <template #cell(edit)="{ item }">
+ <gl-button
+ v-gl-modal.deploy-freeze-modal
+ icon="pencil"
+ data-testid="edit-deploy-freeze"
+ @click="setFreezePeriod(item)"
+ />
+ </template>
<template #empty>
<p data-testid="empty-freeze-periods" class="gl-text-center text-plain">
- <gl-sprintf
- :message="
- s__(
- 'DeployFreeze|No deploy freezes exist for this project. To add one, click %{strongStart}Add deploy freeze%{strongEnd}',
- )
- "
- >
+ <gl-sprintf :message="$options.translations.emptyStateText">
<template #strong="{ content }">
<strong>{{ content }}</strong>
</template>
@@ -73,7 +85,7 @@ export default {
v-gl-modal.deploy-freeze-modal
data-testid="add-deploy-freeze"
category="primary"
- variant="success"
+ variant="confirm"
>
{{ $options.translations.addDeployFreeze }}
</gl-button>
diff --git a/app/assets/javascripts/deploy_freeze/store/actions.js b/app/assets/javascripts/deploy_freeze/store/actions.js
index 62045d2517d..56e45595dc5 100644
--- a/app/assets/javascripts/deploy_freeze/store/actions.js
+++ b/app/assets/javascripts/deploy_freeze/store/actions.js
@@ -3,37 +3,53 @@ import { deprecatedCreateFlash as createFlash } from '~/flash';
import { __ } from '~/locale';
import * as types from './mutation_types';
-export const requestAddFreezePeriod = ({ commit }) => {
+export const requestFreezePeriod = ({ commit }) => {
commit(types.REQUEST_ADD_FREEZE_PERIOD);
};
-export const receiveAddFreezePeriodSuccess = ({ commit }) => {
+export const receiveFreezePeriodSuccess = ({ commit }) => {
commit(types.RECEIVE_ADD_FREEZE_PERIOD_SUCCESS);
};
-export const receiveAddFreezePeriodError = ({ commit }, error) => {
+export const receiveFreezePeriodError = ({ commit }, error) => {
commit(types.RECEIVE_ADD_FREEZE_PERIOD_ERROR, error);
};
-export const addFreezePeriod = ({ state, dispatch, commit }) => {
- dispatch('requestAddFreezePeriod');
+const receiveFreezePeriod = (store, request) => {
+ const { dispatch, commit } = store;
+ dispatch('requestFreezePeriod');
- return Api.createFreezePeriod(state.projectId, {
- freeze_start: state.freezeStartCron,
- freeze_end: state.freezeEndCron,
- cron_timezone: state.selectedTimezoneIdentifier,
- })
+ request(store)
.then(() => {
- dispatch('receiveAddFreezePeriodSuccess');
+ dispatch('receiveFreezePeriodSuccess');
commit(types.RESET_MODAL);
dispatch('fetchFreezePeriods');
})
.catch((error) => {
createFlash(__('Error: Unable to create deploy freeze'));
- dispatch('receiveAddFreezePeriodError', error);
+ dispatch('receiveFreezePeriodError', error);
});
};
+export const addFreezePeriod = (store) =>
+ receiveFreezePeriod(store, ({ state }) =>
+ Api.createFreezePeriod(state.projectId, {
+ freeze_start: state.freezeStartCron,
+ freeze_end: state.freezeEndCron,
+ cron_timezone: state.selectedTimezoneIdentifier,
+ }),
+ );
+
+export const updateFreezePeriod = (store) =>
+ receiveFreezePeriod(store, ({ state }) =>
+ Api.updateFreezePeriod(state.projectId, {
+ id: state.selectedId,
+ freeze_start: state.freezeStartCron,
+ freeze_end: state.freezeEndCron,
+ cron_timezone: state.selectedTimezoneIdentifier,
+ }),
+ );
+
export const fetchFreezePeriods = ({ commit, state }) => {
commit(types.REQUEST_FREEZE_PERIODS);
@@ -46,6 +62,13 @@ export const fetchFreezePeriods = ({ commit, state }) => {
});
};
+export const setFreezePeriod = ({ commit }, freezePeriod) => {
+ commit(types.SET_SELECTED_ID, freezePeriod.id);
+ commit(types.SET_SELECTED_TIMEZONE, freezePeriod.cronTimezone);
+ commit(types.SET_FREEZE_START_CRON, freezePeriod.freezeStart);
+ commit(types.SET_FREEZE_END_CRON, freezePeriod.freezeEnd);
+};
+
export const setSelectedTimezone = ({ commit }, timezone) => {
commit(types.SET_SELECTED_TIMEZONE, timezone);
};
diff --git a/app/assets/javascripts/deploy_freeze/store/mutation_types.js b/app/assets/javascripts/deploy_freeze/store/mutation_types.js
index 47a4874a5cf..8e6fdfd4443 100644
--- a/app/assets/javascripts/deploy_freeze/store/mutation_types.js
+++ b/app/assets/javascripts/deploy_freeze/store/mutation_types.js
@@ -6,6 +6,7 @@ export const RECEIVE_ADD_FREEZE_PERIOD_SUCCESS = 'RECEIVE_ADD_FREEZE_PERIOD_SUCC
export const RECEIVE_ADD_FREEZE_PERIOD_ERROR = 'RECEIVE_ADD_FREEZE_PERIOD_ERROR';
export const SET_SELECTED_TIMEZONE = 'SET_SELECTED_TIMEZONE';
+export const SET_SELECTED_ID = 'SET_SELECTED_ID';
export const SET_FREEZE_START_CRON = 'SET_FREEZE_START_CRON';
export const SET_FREEZE_END_CRON = 'SET_FREEZE_END_CRON';
diff --git a/app/assets/javascripts/deploy_freeze/store/mutations.js b/app/assets/javascripts/deploy_freeze/store/mutations.js
index 3b34f3950e6..e62000c007c 100644
--- a/app/assets/javascripts/deploy_freeze/store/mutations.js
+++ b/app/assets/javascripts/deploy_freeze/store/mutations.js
@@ -4,7 +4,11 @@ import * as types from './mutation_types';
const formatTimezoneName = (freezePeriod, timezoneList) =>
convertObjectPropsToCamelCase({
...freezePeriod,
- cron_timezone: timezoneList.find((tz) => tz.identifier === freezePeriod.cron_timezone)?.name,
+ cron_timezone: {
+ formattedTimezone: timezoneList.find((tz) => tz.identifier === freezePeriod.cron_timezone)
+ ?.name,
+ identifier: freezePeriod.cronTimezone,
+ },
});
export default {
@@ -45,10 +49,15 @@ export default {
state.freezeEndCron = freezeEndCron;
},
+ [types.SET_SELECTED_ID](state, id) {
+ state.selectedId = id;
+ },
+
[types.RESET_MODAL](state) {
state.freezeStartCron = '';
state.freezeEndCron = '';
state.selectedTimezone = '';
state.selectedTimezoneIdentifier = '';
+ state.selectedId = '';
},
};
diff --git a/app/assets/javascripts/deploy_freeze/store/state.js b/app/assets/javascripts/deploy_freeze/store/state.js
index 4cc38c097b6..1b16b4c645b 100644
--- a/app/assets/javascripts/deploy_freeze/store/state.js
+++ b/app/assets/javascripts/deploy_freeze/store/state.js
@@ -6,6 +6,7 @@ export default ({
selectedTimezoneIdentifier = '',
freezeStartCron = '',
freezeEndCron = '',
+ selectedId = '',
}) => ({
projectId,
freezePeriods,
@@ -14,4 +15,5 @@ export default ({
selectedTimezoneIdentifier,
freezeStartCron,
freezeEndCron,
+ selectedId,
});
diff --git a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
index 9d5f37dc3b7..0746725153d 100644
--- a/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
+++ b/app/assets/javascripts/incidents_settings/components/incidents_settings_tabs.vue
@@ -26,7 +26,10 @@ export default {
class="settings no-animate qa-incident-management-settings"
>
<div class="settings-header">
- <h4 ref="sectionHeader">
+ <h4
+ ref="sectionHeader"
+ class="settings-title js-settings-toggle js-settings-toggle-trigger-only"
+ >
{{ $options.i18n.headerText }}
</h4>
<gl-button ref="toggleBtn" class="js-settings-toggle">{{
diff --git a/app/assets/javascripts/pages/admin/application_settings/index.js b/app/assets/javascripts/pages/admin/application_settings/index.js
index e3c6b0f6f5b..a6e3a7dc08a 100644
--- a/app/assets/javascripts/pages/admin/application_settings/index.js
+++ b/app/assets/javascripts/pages/admin/application_settings/index.js
@@ -4,9 +4,7 @@ import initSearchSettings from '~/search_settings';
import selfMonitor from '~/self_monitor';
import initSettingsPanels from '~/settings_panels';
-if (gon.features?.ciInstanceVariablesUi) {
- initVariableList('js-instance-variables');
-}
+initVariableList('js-instance-variables');
selfMonitor();
// Initialize expandable settings panels
initSettingsPanels();
diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb
index 5d507abdb6f..27f1e4a68cc 100644
--- a/app/controllers/admin/application_settings_controller.rb
+++ b/app/controllers/admin/application_settings_controller.rb
@@ -13,10 +13,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
before_action :disable_query_limiting, only: [:usage_data]
- before_action only: [:ci_cd] do
- push_frontend_feature_flag(:ci_instance_variables_ui, default_enabled: true)
- end
-
feature_category :not_owned, [
:general, :reporting, :metrics_and_profiling, :network,
:preferences, :update, :reset_health_check_token
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index bf1dfcd6416..32de4a0145c 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -462,7 +462,7 @@ class ApplicationController < ActionController::Base
feature_category: feature_category) do
yield
ensure
- @current_context = Labkit::Context.current.to_h
+ @current_context = Gitlab::ApplicationContext.current
end
end
diff --git a/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb b/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb
index 32ca6de9b96..ea1502d4b62 100644
--- a/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb
+++ b/app/graphql/mutations/admin/sidekiq_queues/delete_jobs.rb
@@ -8,7 +8,7 @@ module Mutations
ADMIN_MESSAGE = 'You must be an admin to use this mutation'
- Labkit::Context::KNOWN_KEYS.each do |key|
+ Gitlab::ApplicationContext::KNOWN_KEYS.each do |key|
argument key,
GraphQL::STRING_TYPE,
required: false,
diff --git a/app/serializers/build_artifact_entity.rb b/app/serializers/build_artifact_entity.rb
index 7a030372591..15458caa9f3 100644
--- a/app/serializers/build_artifact_entity.rb
+++ b/app/serializers/build_artifact_entity.rb
@@ -21,11 +21,17 @@ class BuildArtifactEntity < Grape::Entity
)
end
- expose :keep_path, if: -> (*) { artifact.expiring? } do |artifact|
+ expose :keep_path, if: -> (*) { artifact.expiring? && show_duplicated_paths?(artifact.project) } do |artifact|
fast_keep_project_job_artifacts_path(artifact.project, artifact.job)
end
- expose :browse_path do |artifact|
+ expose :browse_path, if: -> (*) { show_duplicated_paths?(artifact.project) } do |artifact|
fast_browse_project_job_artifacts_path(artifact.project, artifact.job)
end
+
+ private
+
+ def show_duplicated_paths?(project)
+ !Gitlab::Ci::Features.remove_duplicate_artifact_exposure_paths?(project)
+ end
end
diff --git a/app/views/admin/application_settings/ci_cd.html.haml b/app/views/admin/application_settings/ci_cd.html.haml
index 485fb71d111..28572fccb9d 100644
--- a/app/views/admin/application_settings/ci_cd.html.haml
+++ b/app/views/admin/application_settings/ci_cd.html.haml
@@ -2,16 +2,15 @@
- page_title _("CI/CD")
- @content_class = "limit-container-width" unless fluid_layout
-- if ::Gitlab::Ci::Features.instance_variables_ui_enabled?
- %section.settings.no-animate#js-ci-cd-variables{ class: ('expanded' if expanded_by_default?) }
- .settings-header
- = render 'admin/application_settings/ci/header', expanded: expanded_by_default?
- .settings-content
- - if ci_variable_protected_by_default?
- %p.settings-message.text-center
- - link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable') }
- = s_('Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
- #js-instance-variables{ data: { endpoint: admin_ci_variables_path, group: 'true', maskable_regex: ci_variable_maskable_regex, protected_by_default: ci_variable_protected_by_default?.to_s} }
+%section.settings.no-animate#js-ci-cd-variables{ class: ('expanded' if expanded_by_default?) }
+ .settings-header
+ = render 'admin/application_settings/ci/header', expanded: expanded_by_default?
+ .settings-content
+ - if ci_variable_protected_by_default?
+ %p.settings-message.text-center
+ - link_start = '<a href="%{url}">'.html_safe % { url: help_page_path('ci/variables/README', anchor: 'protect-a-custom-variable') }
+ = s_('Environment variables on this GitLab instance are configured to be %{link_start}protected%{link_end} by default.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
+ #js-instance-variables{ data: { endpoint: admin_ci_variables_path, group: 'true', maskable_regex: ci_variable_maskable_regex, protected_by_default: ci_variable_protected_by_default?.to_s} }
%section.settings.as-ci-cd.no-animate#js-ci-cd-settings{ class: ('expanded' if expanded_by_default?) }
.settings-header
diff --git a/app/views/projects/_service_desk_settings.html.haml b/app/views/projects/_service_desk_settings.html.haml
index 53b9e7f3d65..7b345941cf7 100644
--- a/app/views/projects/_service_desk_settings.html.haml
+++ b/app/views/projects/_service_desk_settings.html.haml
@@ -2,7 +2,7 @@
%section.settings.js-service-desk-setting-wrapper.no-animate#js-service-desk{ class: ('expanded' if expanded), data: { qa_selector: 'service_desk_settings_content' } }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Service Desk')
- %button.btn.gl-button.js-settings-toggle
+ %button.btn.gl-button.btn-default.js-settings-toggle
= expanded ? _('Collapse') : _('Expand')
- link_start = "<a href='#{help_page_path('user/project/service_desk')}' target='_blank' rel='noopener noreferrer'>".html_safe
%p= _('Enable and disable Service Desk. Some additional configuration might be required. %{link_start}Learn more%{link_end}.').html_safe % { link_start: link_start, link_end: '</a>'.html_safe }
diff --git a/app/workers/concerns/application_worker.rb b/app/workers/concerns/application_worker.rb
index d101ef100d8..0de26e27631 100644
--- a/app/workers/concerns/application_worker.rb
+++ b/app/workers/concerns/application_worker.rb
@@ -18,7 +18,7 @@ module ApplicationWorker
set_queue
def structured_payload(payload = {})
- context = Labkit::Context.current.to_h.merge(
+ context = Gitlab::ApplicationContext.current.merge(
'class' => self.class.name,
'job_status' => 'running',
'queue' => self.class.queue,
diff --git a/app/workers/concerns/cronjob_queue.rb b/app/workers/concerns/cronjob_queue.rb
index 955387b5ad4..b89d6bba72c 100644
--- a/app/workers/concerns/cronjob_queue.rb
+++ b/app/workers/concerns/cronjob_queue.rb
@@ -15,7 +15,7 @@ module CronjobQueue
# Cronjobs never get scheduled with arguments, so this is safe to
# override
def context_for_arguments(_args)
- return if Gitlab::ApplicationContext.current_context_include?('meta.caller_id')
+ return if Gitlab::ApplicationContext.current_context_include?(:caller_id)
Gitlab::ApplicationContext.new(caller_id: "Cronjob")
end
diff --git a/changelogs/unreleased/205484-prj-set-ops-3-incidents.yml b/changelogs/unreleased/205484-prj-set-ops-3-incidents.yml
new file mode 100644
index 00000000000..830bc130c76
--- /dev/null
+++ b/changelogs/unreleased/205484-prj-set-ops-3-incidents.yml
@@ -0,0 +1,5 @@
+---
+title: Project Settings Operations header Incidents expand/collapse on-click/on-tap
+merge_request: 56273
+author: Daniel Schömer
+type: changed
diff --git a/changelogs/unreleased/afontaine-edit-deploy-freeze.yml b/changelogs/unreleased/afontaine-edit-deploy-freeze.yml
new file mode 100644
index 00000000000..fdb1cf09c88
--- /dev/null
+++ b/changelogs/unreleased/afontaine-edit-deploy-freeze.yml
@@ -0,0 +1,5 @@
+---
+title: Add Ability to Edit Freeze Periods
+merge_request: 56407
+author:
+type: added
diff --git a/changelogs/unreleased/btn-default-sd-toggle.yml b/changelogs/unreleased/btn-default-sd-toggle.yml
new file mode 100644
index 00000000000..ded6ea651e7
--- /dev/null
+++ b/changelogs/unreleased/btn-default-sd-toggle.yml
@@ -0,0 +1,5 @@
+---
+title: Add btn-default class for Service Desk toggle in settings
+merge_request: 56195
+author: Yogi (@yo)
+type: changed
diff --git a/changelogs/unreleased/jivanvl-remove-ci-instance-variables-ui-ff.yml b/changelogs/unreleased/jivanvl-remove-ci-instance-variables-ui-ff.yml
new file mode 100644
index 00000000000..dfea1fa4875
--- /dev/null
+++ b/changelogs/unreleased/jivanvl-remove-ci-instance-variables-ui-ff.yml
@@ -0,0 +1,5 @@
+---
+title: Enable the instance variables UI
+merge_request: 56255
+author:
+type: other
diff --git a/config/feature_flags/development/ci_instance_variables_ui.yml b/config/feature_flags/development/ci_instance_variables_ui.yml
deleted file mode 100644
index 73bc0346818..00000000000
--- a/config/feature_flags/development/ci_instance_variables_ui.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-name: ci_instance_variables_ui
-introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33510
-rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/299879
-milestone: '13.1'
-type: development
-group: group::continuous integration
-default_enabled: true
diff --git a/config/feature_flags/development/remove_duplicate_artifact_exposure_paths.yml b/config/feature_flags/development/remove_duplicate_artifact_exposure_paths.yml
new file mode 100644
index 00000000000..3913590a6be
--- /dev/null
+++ b/config/feature_flags/development/remove_duplicate_artifact_exposure_paths.yml
@@ -0,0 +1,8 @@
+---
+name: remove_duplicate_artifact_exposure_paths
+introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54611
+rollout_issue_url:
+milestone: '13.10'
+type: development
+group: group::testing
+default_enabled: false
diff --git a/doc/user/packages/composer_repository/index.md b/doc/user/packages/composer_repository/index.md
index f935fa87d68..96b5a8513c5 100644
--- a/doc/user/packages/composer_repository/index.md
+++ b/doc/user/packages/composer_repository/index.md
@@ -268,7 +268,13 @@ To install a package:
Without the `gitlab-domains` definition in `composer.json`, Composer uses the GitLab token
as basic-auth, with the token as a username and a blank password. This results in a 401 error.
-Output indicates that the package has been successfully installed.
+1. With the `composer.json` and `auth.json` files configured, you can install the package by running:
+
+ ```shell
+ composer update
+ ```
+
+ If successful, you should see output indicating that the package installed successfully.
WARNING:
Never commit the `auth.json` file to your repository. To install packages from a CI/CD job,
diff --git a/doc/user/project/img/issue_board_iteration_lists_v13_10.png b/doc/user/project/img/issue_board_iteration_lists_v13_10.png
new file mode 100644
index 00000000000..be59c609a77
--- /dev/null
+++ b/doc/user/project/img/issue_board_iteration_lists_v13_10.png
Binary files differ
diff --git a/doc/user/project/issue_board.md b/doc/user/project/issue_board.md
index 98e75ba40e1..24eee5c3018 100644
--- a/doc/user/project/issue_board.md
+++ b/doc/user/project/issue_board.md
@@ -340,6 +340,31 @@ As in other list types, click the trash icon to remove a list.
![Milestone lists](img/issue_board_milestone_lists_v13_6.png)
+### Iteration lists **(PREMIUM)**
+
+> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/250479) in GitLab 13.10.
+> - It's [deployed behind the `board_new_lists` feature flag](../feature_flags.md), disabled by default.
+> - It's disabled on GitLab.com.
+> - It's recommended for production use.
+> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-new-add-list-form).
+
+WARNING:
+This feature might not be available to you. Check the **version history** note above for details.
+
+You're also able to create lists of an iteration.
+These are lists that filter issues by the assigned
+iteration. To add an iteration list:
+
+1. Select **Create list**.
+1. Select the **Iteration**.
+1. In the dropdown, select an iteration.
+1. Select **Add to board**.
+
+Like the milestone lists, you're able to [drag issues](#drag-issues-between-lists)
+to and from a iteration list to manipulate the iteration of the dragged issues.
+
+![Iteration lists](img/issue_board_iteration_lists_v13_10.png)
+
### Group issues in swimlanes **(PREMIUM)**
> - Grouping by epic [introduced](https://gitlab.com/groups/gitlab-org/-/epics/3352) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.6.
@@ -649,3 +674,22 @@ To disable it:
```ruby
Feature.disable(:add_issues_button)
```
+
+### Enable or disable new add list form **(FREE SELF)**
+
+The new form for adding lists is under development and not ready for production use. It is
+deployed behind a feature flag that is **disabled by default**.
+[GitLab administrators with access to the GitLab Rails console](../../administration/feature_flags.md)
+can enable it.
+
+To enable it:
+
+```ruby
+Feature.enable(:board_new_list)
+```
+
+To disable it:
+
+```ruby
+Feature.disable(:board_new_list)
+```
diff --git a/doc/user/project/releases/img/deploy_freeze_v13_10.png b/doc/user/project/releases/img/deploy_freeze_v13_10.png
new file mode 100644
index 00000000000..5c4b2d983dd
--- /dev/null
+++ b/doc/user/project/releases/img/deploy_freeze_v13_10.png
Binary files differ
diff --git a/doc/user/project/releases/img/deploy_freeze_v13_2.png b/doc/user/project/releases/img/deploy_freeze_v13_2.png
deleted file mode 100644
index 27d3a6044a1..00000000000
--- a/doc/user/project/releases/img/deploy_freeze_v13_2.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/releases/index.md b/doc/user/project/releases/index.md
index 7348e17a017..3aba5e7853f 100644
--- a/doc/user/project/releases/index.md
+++ b/doc/user/project/releases/index.md
@@ -217,11 +217,11 @@ To set a deploy freeze window in the UI, complete these steps:
1. Click **Add deploy freeze** to open the deploy freeze modal.
1. Enter the start time, end time, and timezone of the desired deploy freeze period.
1. Click **Add deploy freeze** in the modal.
-
-![Deploy freeze modal for setting a deploy freeze period](img/deploy_freeze_v13_2.png)
+1. After the deploy freeze is saved, you can edit it by selecting the edit button (**{pencil}**).
+ ![Deploy freeze modal for setting a deploy freeze period](img/deploy_freeze_v13_10.png)
WARNING:
-To edit or delete a deploy freeze, use the [Freeze Periods API](../../../api/freeze_periods.md).
+To delete a deploy freeze, use the [Freeze Periods API](../../../api/freeze_periods.md).
If a project contains multiple freeze periods, all periods apply. If they overlap, the freeze covers the
complete overlapping period.
diff --git a/jest.config.base.js b/jest.config.base.js
index 4e9b84d1d34..745a179af6d 100644
--- a/jest.config.base.js
+++ b/jest.config.base.js
@@ -45,7 +45,8 @@ module.exports = (path) => {
'emojis(/.*).json': '<rootDir>/fixtures/emojis$1.json',
'^spec/test_constants$': '<rootDir>/spec/frontend/__helpers__/test_constants',
'^jest/(.*)$': '<rootDir>/spec/frontend/$1',
- 'test_helpers(/.*)$': '<rootDir>/spec/frontend_integration/test_helpers$1',
+ '^test_helpers(/.*)$': '<rootDir>/spec/frontend_integration/test_helpers$1',
+ '^ee_else_ce_test_helpers(/.*)$': '<rootDir>/spec/frontend_integration/test_helpers$1',
};
const collectCoverageFrom = ['<rootDir>/app/assets/javascripts/**/*.{js,vue}'];
@@ -56,6 +57,7 @@ module.exports = (path) => {
'^ee(/.*)$': rootDirEE,
'^ee_component(/.*)$': rootDirEE,
'^ee_else_ce(/.*)$': rootDirEE,
+ '^ee_else_ce_test_helpers(/.*)$': '<rootDir>/ee/spec/frontend_integration/test_helpers$1',
'^ee_jest/(.*)$': '<rootDir>/ee/spec/frontend/$1',
[TEST_FIXTURES_PATTERN]: '<rootDir>/tmp/tests/frontend/fixtures-ee$1',
});
diff --git a/lib/api/admin/sidekiq.rb b/lib/api/admin/sidekiq.rb
index 7e561783685..d91d4a0d4d5 100644
--- a/lib/api/admin/sidekiq.rb
+++ b/lib/api/admin/sidekiq.rb
@@ -12,11 +12,11 @@ module API
namespace 'queues' do
desc 'Drop jobs matching the given metadata from the Sidekiq queue'
params do
- Labkit::Context::KNOWN_KEYS.each do |key|
+ Gitlab::ApplicationContext::KNOWN_KEYS.each do |key|
optional key, type: String, allow_blank: false
end
- at_least_one_of(*Labkit::Context::KNOWN_KEYS)
+ at_least_one_of(*Gitlab::ApplicationContext::KNOWN_KEYS)
end
delete ':queue_name' do
result =
diff --git a/lib/gitlab/application_context.rb b/lib/gitlab/application_context.rb
index a75da3a682b..ceda82cb6f6 100644
--- a/lib/gitlab/application_context.rb
+++ b/lib/gitlab/application_context.rb
@@ -8,6 +8,9 @@ module Gitlab
Attribute = Struct.new(:name, :type)
+ LOG_KEY = Labkit::Context::LOG_KEY
+ KNOWN_KEYS = Labkit::Context::KNOWN_KEYS
+
APPLICATION_ATTRIBUTES = [
Attribute.new(:project, Project),
Attribute.new(:namespace, Namespace),
@@ -24,6 +27,10 @@ module Gitlab
application_context.use(&block)
end
+ def self.with_raw_context(attributes = {}, &block)
+ Labkit::Context.with_context(attributes, &block)
+ end
+
def self.push(args)
application_context = new(**args)
Labkit::Context.push(application_context.to_lazy_hash)
diff --git a/lib/gitlab/ci/features.rb b/lib/gitlab/ci/features.rb
index c811ef211d6..79139ceb419 100644
--- a/lib/gitlab/ci/features.rb
+++ b/lib/gitlab/ci/features.rb
@@ -10,10 +10,6 @@ module Gitlab
::Feature.enabled?(:ci_artifacts_exclude, default_enabled: true)
end
- def self.instance_variables_ui_enabled?
- ::Feature.enabled?(:ci_instance_variables_ui, default_enabled: true)
- end
-
def self.pipeline_latest?
::Feature.enabled?(:ci_pipeline_latest, default_enabled: true)
end
@@ -71,6 +67,10 @@ module Gitlab
def self.ci_commit_pipeline_mini_graph_vue_enabled?(project)
::Feature.enabled?(:ci_commit_pipeline_mini_graph_vue, project, default_enabled: :yaml)
end
+
+ def self.remove_duplicate_artifact_exposure_paths?(project)
+ ::Feature.enabled?(:remove_duplicate_artifact_exposure_paths, project, default_enabled: :yaml)
+ end
end
end
end
diff --git a/lib/gitlab/gitaly_client.rb b/lib/gitlab/gitaly_client.rb
index e3788814dd5..f4a89edecd1 100644
--- a/lib/gitlab/gitaly_client.rb
+++ b/lib/gitlab/gitaly_client.rb
@@ -215,7 +215,7 @@ module Gitlab
'client_name' => CLIENT_NAME
}
- context_data = Labkit::Context.current&.to_h
+ context_data = Gitlab::ApplicationContext.current
feature_stack = Thread.current[:gitaly_feature_stack]
feature = feature_stack && feature_stack[0]
diff --git a/lib/gitlab/grape_logging/loggers/context_logger.rb b/lib/gitlab/grape_logging/loggers/context_logger.rb
index 0a8f0872fbe..468a296886e 100644
--- a/lib/gitlab/grape_logging/loggers/context_logger.rb
+++ b/lib/gitlab/grape_logging/loggers/context_logger.rb
@@ -6,7 +6,7 @@ module Gitlab
module Loggers
class ContextLogger < ::GrapeLogging::Loggers::Base
def parameters(_, _)
- Labkit::Context.current.to_h
+ Gitlab::ApplicationContext.current
end
end
end
diff --git a/lib/gitlab/sidekiq_queue.rb b/lib/gitlab/sidekiq_queue.rb
index 807c27a71ff..4b71dfc0c1b 100644
--- a/lib/gitlab/sidekiq_queue.rb
+++ b/lib/gitlab/sidekiq_queue.rb
@@ -21,7 +21,7 @@ module Gitlab
job_search_metadata =
search_metadata
.stringify_keys
- .slice(*Labkit::Context::KNOWN_KEYS)
+ .slice(*Gitlab::ApplicationContext::KNOWN_KEYS)
.transform_keys { |key| "meta.#{key}" }
.compact
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 9af2693ca1b..7e0d2eb2f6f 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10245,13 +10245,19 @@ msgstr ""
msgid "DeployFreeze|Add a freeze period to prevent unintended releases during a period of time for a given environment. You must update the deployment jobs in %{filename} according to the deploy freezes added here. %{freeze_period_link_start}Learn more.%{freeze_period_link_end}"
msgstr ""
+msgid "DeployFreeze|Add deploy freeze"
+msgstr ""
+
+msgid "DeployFreeze|Edit"
+msgstr ""
+
msgid "DeployFreeze|Freeze end"
msgstr ""
msgid "DeployFreeze|Freeze start"
msgstr ""
-msgid "DeployFreeze|No deploy freezes exist for this project. To add one, click %{strongStart}Add deploy freeze%{strongEnd}"
+msgid "DeployFreeze|No deploy freezes exist for this project. To add one, select %{strongStart}Add deploy freeze%{strongEnd}"
msgstr ""
msgid "DeployFreeze|Specify deploy freezes using %{cron_syntax_link_start}cron syntax%{cron_syntax_link_end}."
@@ -11191,6 +11197,9 @@ msgstr ""
msgid "Edit comment"
msgstr ""
+msgid "Edit deploy freeze"
+msgstr ""
+
msgid "Edit description"
msgstr ""
@@ -26436,6 +26445,9 @@ msgstr ""
msgid "Save comment"
msgstr ""
+msgid "Save deploy freeze"
+msgstr ""
+
msgid "Save password"
msgstr ""
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 4809a07f6e9..3d34db6c2c0 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -898,7 +898,7 @@ RSpec.describe ApplicationController do
feature_category :issue_tracking
def index
- Labkit::Context.with_context do |context|
+ Gitlab::ApplicationContext.with_raw_context do |context|
render json: context.to_h
end
end
diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index c31ba6fe156..5bee7698c3f 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -524,7 +524,7 @@ RSpec.describe SessionsController do
it 'sets the username and caller_id in the context' do
expect(controller).to receive(:destroy).and_wrap_original do |m, *args|
- expect(Labkit::Context.current.to_h)
+ expect(Gitlab::ApplicationContext.current)
.to include('meta.user' => user.username,
'meta.caller_id' => 'SessionsController#destroy')
@@ -538,9 +538,9 @@ RSpec.describe SessionsController do
context 'when not signed in' do
it 'sets the caller_id in the context' do
expect(controller).to receive(:new).and_wrap_original do |m, *args|
- expect(Labkit::Context.current.to_h)
+ expect(Gitlab::ApplicationContext.current)
.to include('meta.caller_id' => 'SessionsController#new')
- expect(Labkit::Context.current.to_h)
+ expect(Gitlab::ApplicationContext.current)
.not_to include('meta.user')
m.call(*args)
@@ -557,9 +557,9 @@ RSpec.describe SessionsController do
it 'sets the caller_id in the context' do
allow_any_instance_of(User).to receive(:lock_access!).and_wrap_original do |m, *args|
- expect(Labkit::Context.current.to_h)
+ expect(Gitlab::ApplicationContext.current)
.to include('meta.caller_id' => 'SessionsController#create')
- expect(Labkit::Context.current.to_h)
+ expect(Gitlab::ApplicationContext.current)
.not_to include('meta.user')
m.call(*args)
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index d6e1b170dd3..f875e3bdb07 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -1382,6 +1382,38 @@ describe('Api', () => {
});
});
+ describe('updateFreezePeriod', () => {
+ const options = {
+ id: 10,
+ freeze_start: '* * * * *',
+ freeze_end: '* * * * *',
+ cron_timezone: 'America/Juneau',
+ created_at: '2020-07-11T07:04:50.153Z',
+ updated_at: '2020-07-11T07:04:50.153Z',
+ };
+ const projectId = 8;
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectId}/freeze_periods/${options.id}`;
+
+ const expectedResult = {
+ id: 10,
+ freeze_start: '* * * * *',
+ freeze_end: '* * * * *',
+ cron_timezone: 'America/Juneau',
+ created_at: '2020-07-11T07:04:50.153Z',
+ updated_at: '2020-07-11T07:04:50.153Z',
+ };
+
+ describe('when the freeze period is successfully updated', () => {
+ it('resolves the Promise', () => {
+ mock.onPut(expectedUrl, options).replyOnce(httpStatus.OK, expectedResult);
+
+ return Api.updateFreezePeriod(projectId, options).then(({ data }) => {
+ expect(data).toStrictEqual(expectedResult);
+ });
+ });
+ });
+ });
+
describe('createPipeline', () => {
it('creates new pipeline', () => {
const redirectUrl = 'ci-project/-/pipelines/95';
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
index d8ce184940a..7c46c280d46 100644
--- a/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_modal_spec.js
@@ -1,13 +1,16 @@
import { GlButton, GlModal } from '@gitlab/ui';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
import Vuex from 'vuex';
+import Api from '~/api';
import DeployFreezeModal from '~/deploy_freeze/components/deploy_freeze_modal.vue';
import createStore from '~/deploy_freeze/store';
import TimezoneDropdown from '~/vue_shared/components/timezone_dropdown.vue';
import { freezePeriodsFixture, timezoneDataFixture } from '../helpers';
-const localVue = createLocalVue();
-localVue.use(Vuex);
+jest.mock('~/api');
+
+Vue.use(Vuex);
describe('Deploy freeze modal', () => {
let wrapper;
@@ -23,18 +26,19 @@ describe('Deploy freeze modal', () => {
stubs: {
GlModal,
},
- localVue,
store,
});
});
- const findModal = () => wrapper.find(GlModal);
- const addDeployFreezeButton = () => findModal().findAll(GlButton).at(1);
+ const findModal = () => wrapper.findComponent(GlModal);
+ const submitDeployFreezeButton = () => findModal().findAllComponents(GlButton).at(1);
- const setInput = (freezeStartCron, freezeEndCron, selectedTimezone) => {
+ const setInput = (freezeStartCron, freezeEndCron, selectedTimezone, id = '') => {
store.state.freezeStartCron = freezeStartCron;
store.state.freezeEndCron = freezeEndCron;
store.state.selectedTimezone = selectedTimezone;
+ store.state.selectedTimezoneIdentifier = selectedTimezone;
+ store.state.selectedId = id;
wrapper.find('#deploy-freeze-start').trigger('input');
wrapper.find('#deploy-freeze-end').trigger('input');
@@ -48,18 +52,36 @@ describe('Deploy freeze modal', () => {
describe('Basic interactions', () => {
it('button is disabled when freeze period is invalid', () => {
- expect(addDeployFreezeButton().attributes('disabled')).toBeTruthy();
+ expect(submitDeployFreezeButton().attributes('disabled')).toBeTruthy();
});
});
describe('Adding a new deploy freeze', () => {
+ const { freeze_start, freeze_end, cron_timezone } = freezePeriodsFixture[0];
+
beforeEach(() => {
- const { freeze_start, freeze_end, cron_timezone } = freezePeriodsFixture[0];
setInput(freeze_start, freeze_end, cron_timezone);
});
it('button is enabled when valid freeze period settings are present', () => {
- expect(addDeployFreezeButton().attributes('disabled')).toBeUndefined();
+ expect(submitDeployFreezeButton().attributes('disabled')).toBeUndefined();
+ });
+
+ it('should display Add deploy freeze', () => {
+ expect(findModal().props('title')).toBe('Add deploy freeze');
+ expect(submitDeployFreezeButton().text()).toBe('Add deploy freeze');
+ });
+
+ it('should call the add deploy freze API', () => {
+ Api.createFreezePeriod.mockResolvedValue();
+ findModal().vm.$emit('primary');
+
+ expect(Api.createFreezePeriod).toHaveBeenCalledTimes(1);
+ expect(Api.createFreezePeriod).toHaveBeenCalledWith(store.state.projectId, {
+ freeze_start,
+ freeze_end,
+ cron_timezone,
+ });
});
});
@@ -70,7 +92,7 @@ describe('Deploy freeze modal', () => {
});
it('disables the add deploy freeze button', () => {
- expect(addDeployFreezeButton().attributes('disabled')).toBeTruthy();
+ expect(submitDeployFreezeButton().attributes('disabled')).toBeTruthy();
});
});
@@ -81,7 +103,32 @@ describe('Deploy freeze modal', () => {
});
it('does not disable the submit button', () => {
- expect(addDeployFreezeButton().attributes('disabled')).toBeFalsy();
+ expect(submitDeployFreezeButton().attributes('disabled')).toBeFalsy();
+ });
+ });
+ });
+
+ describe('Editing an existing deploy freeze', () => {
+ const { freeze_start, freeze_end, cron_timezone, id } = freezePeriodsFixture[0];
+ beforeEach(() => {
+ setInput(freeze_start, freeze_end, cron_timezone, id);
+ });
+
+ it('should display Edit deploy freeze', () => {
+ expect(findModal().props('title')).toBe('Edit deploy freeze');
+ expect(submitDeployFreezeButton().text()).toBe('Save deploy freeze');
+ });
+
+ it('should call the update deploy freze API', () => {
+ Api.updateFreezePeriod.mockResolvedValue();
+ findModal().vm.$emit('primary');
+
+ expect(Api.updateFreezePeriod).toHaveBeenCalledTimes(1);
+ expect(Api.updateFreezePeriod).toHaveBeenCalledWith(store.state.projectId, {
+ id,
+ freeze_start,
+ freeze_end,
+ cron_timezone,
});
});
});
diff --git a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
index e4ee1b9ad26..168ddcfeacc 100644
--- a/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
+++ b/spec/frontend/deploy_freeze/components/deploy_freeze_table_spec.js
@@ -2,6 +2,7 @@ import { createLocalVue, mount } from '@vue/test-utils';
import Vuex from 'vuex';
import DeployFreezeTable from '~/deploy_freeze/components/deploy_freeze_table.vue';
import createStore from '~/deploy_freeze/store';
+import { RECEIVE_FREEZE_PERIODS_SUCCESS } from '~/deploy_freeze/store/mutation_types';
import { freezePeriodsFixture, timezoneDataFixture } from '../helpers';
const localVue = createLocalVue();
@@ -26,6 +27,7 @@ describe('Deploy freeze table', () => {
const findEmptyFreezePeriods = () => wrapper.find('[data-testid="empty-freeze-periods"]');
const findAddDeployFreezeButton = () => wrapper.find('[data-testid="add-deploy-freeze"]');
+ const findEditDeployFreezeButton = () => wrapper.find('[data-testid="edit-deploy-freeze"]');
const findDeployFreezeTable = () => wrapper.find('[data-testid="deploy-freeze-table"]');
beforeEach(() => {
@@ -45,17 +47,31 @@ describe('Deploy freeze table', () => {
it('displays empty', () => {
expect(findEmptyFreezePeriods().exists()).toBe(true);
expect(findEmptyFreezePeriods().text()).toBe(
- 'No deploy freezes exist for this project. To add one, click Add deploy freeze',
+ 'No deploy freezes exist for this project. To add one, select Add deploy freeze',
);
});
- it('displays data', () => {
- store.state.freezePeriods = freezePeriodsFixture;
+ describe('with data', () => {
+ beforeEach(async () => {
+ store.commit(RECEIVE_FREEZE_PERIODS_SUCCESS, freezePeriodsFixture);
+ await wrapper.vm.$nextTick();
+ });
- return wrapper.vm.$nextTick(() => {
+ it('displays data', () => {
const tableRows = findDeployFreezeTable().findAll('tbody tr');
expect(tableRows.length).toBe(freezePeriodsFixture.length);
expect(findEmptyFreezePeriods().exists()).toBe(false);
+ expect(findEditDeployFreezeButton().exists()).toBe(true);
+ });
+
+ it('allows user to edit deploy freeze', async () => {
+ findEditDeployFreezeButton().trigger('click');
+ await wrapper.vm.$nextTick();
+
+ expect(store.dispatch).toHaveBeenCalledWith(
+ 'setFreezePeriod',
+ store.state.freezePeriods[0],
+ );
});
});
});
diff --git a/spec/frontend/deploy_freeze/store/actions_spec.js b/spec/frontend/deploy_freeze/store/actions_spec.js
index f4d9802e39a..9c784f3c5a2 100644
--- a/spec/frontend/deploy_freeze/store/actions_spec.js
+++ b/spec/frontend/deploy_freeze/store/actions_spec.js
@@ -23,12 +23,46 @@ describe('deploy freeze store actions', () => {
});
Api.freezePeriods.mockResolvedValue({ data: freezePeriodsFixture });
Api.createFreezePeriod.mockResolvedValue();
+ Api.updateFreezePeriod.mockResolvedValue();
});
afterEach(() => {
mock.restore();
});
+ describe('setSelectedFreezePeriod', () => {
+ it('commits SET_SELECTED_TIMEZONE mutation', () => {
+ testAction(
+ actions.setFreezePeriod,
+ {
+ id: 3,
+ cronTimezone: 'UTC',
+ freezeStart: 'start',
+ freezeEnd: 'end',
+ },
+ {},
+ [
+ {
+ payload: 3,
+ type: types.SET_SELECTED_ID,
+ },
+ {
+ payload: 'UTC',
+ type: types.SET_SELECTED_TIMEZONE,
+ },
+ {
+ payload: 'start',
+ type: types.SET_FREEZE_START_CRON,
+ },
+ {
+ payload: 'end',
+ type: types.SET_FREEZE_END_CRON,
+ },
+ ],
+ );
+ });
+ });
+
describe('setSelectedTimezone', () => {
it('commits SET_SELECTED_TIMEZONE mutation', () => {
testAction(actions.setSelectedTimezone, {}, {}, [
@@ -68,10 +102,16 @@ describe('deploy freeze store actions', () => {
state,
[{ type: 'RESET_MODAL' }],
[
- { type: 'requestAddFreezePeriod' },
- { type: 'receiveAddFreezePeriodSuccess' },
+ { type: 'requestFreezePeriod' },
+ { type: 'receiveFreezePeriodSuccess' },
{ type: 'fetchFreezePeriods' },
],
+ () =>
+ expect(Api.createFreezePeriod).toHaveBeenCalledWith(state.projectId, {
+ freeze_start: state.freezeStartCron,
+ freeze_end: state.freezeEndCron,
+ cron_timezone: state.selectedTimezoneIdentifier,
+ }),
);
});
@@ -83,7 +123,43 @@ describe('deploy freeze store actions', () => {
{},
state,
[],
- [{ type: 'requestAddFreezePeriod' }, { type: 'receiveAddFreezePeriodError' }],
+ [{ type: 'requestFreezePeriod' }, { type: 'receiveFreezePeriodError' }],
+ () => expect(createFlash).toHaveBeenCalled(),
+ );
+ });
+ });
+
+ describe('updateFreezePeriod', () => {
+ it('dispatch correct actions on updating a freeze period', () => {
+ testAction(
+ actions.updateFreezePeriod,
+ {},
+ state,
+ [{ type: 'RESET_MODAL' }],
+ [
+ { type: 'requestFreezePeriod' },
+ { type: 'receiveFreezePeriodSuccess' },
+ { type: 'fetchFreezePeriods' },
+ ],
+ () =>
+ expect(Api.updateFreezePeriod).toHaveBeenCalledWith(state.projectId, {
+ id: state.selectedId,
+ freeze_start: state.freezeStartCron,
+ freeze_end: state.freezeEndCron,
+ cron_timezone: state.selectedTimezoneIdentifier,
+ }),
+ );
+ });
+
+ it('should show flash error and set error in state on add failure', () => {
+ Api.updateFreezePeriod.mockRejectedValue();
+
+ testAction(
+ actions.updateFreezePeriod,
+ {},
+ state,
+ [],
+ [{ type: 'requestFreezePeriod' }, { type: 'receiveFreezePeriodError' }],
() => expect(createFlash).toHaveBeenCalled(),
);
});
diff --git a/spec/frontend/deploy_freeze/store/mutations_spec.js b/spec/frontend/deploy_freeze/store/mutations_spec.js
index 54cbdfcb64c..ce75e3b89c3 100644
--- a/spec/frontend/deploy_freeze/store/mutations_spec.js
+++ b/spec/frontend/deploy_freeze/store/mutations_spec.js
@@ -33,7 +33,10 @@ describe('Deploy freeze mutations', () => {
const expectedFreezePeriods = freezePeriodsFixture.map((freezePeriod, index) => ({
...convertObjectPropsToCamelCase(freezePeriod),
- cronTimezone: timezoneNames[index],
+ cronTimezone: {
+ formattedTimezone: timezoneNames[index],
+ identifier: freezePeriod.cronTimezone,
+ },
}));
expect(stateCopy.freezePeriods).toMatchObject(expectedFreezePeriods);
@@ -62,11 +65,19 @@ describe('Deploy freeze mutations', () => {
});
});
- describe('SET_FREEZE_ENDT_CRON', () => {
+ describe('SET_FREEZE_END_CRON', () => {
it('should set freezeEndCron', () => {
mutations[types.SET_FREEZE_END_CRON](stateCopy, '5 0 * 8 *');
expect(stateCopy.freezeEndCron).toBe('5 0 * 8 *');
});
});
+
+ describe('SET_SELECTED_ID', () => {
+ it('should set selectedId', () => {
+ mutations[types.SET_SELECTED_ID](stateCopy, 5);
+
+ expect(stateCopy.selectedId).toBe(5);
+ });
+ });
});
diff --git a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
index 4398d568501..07f90a12f0f 100644
--- a/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
+++ b/spec/frontend/incidents_settings/components/__snapshots__/incidents_settings_tabs_spec.js.snap
@@ -9,7 +9,9 @@ exports[`IncidentsSettingTabs should render the component 1`] = `
<div
class="settings-header"
>
- <h4>
+ <h4
+ class="settings-title js-settings-toggle js-settings-toggle-trigger-only"
+ >
Incidents
diff --git a/spec/frontend_integration/test_helpers/mock_server/index.js b/spec/frontend_integration/test_helpers/mock_server/index.js
index 20cb441daa7..486c9452dbd 100644
--- a/spec/frontend_integration/test_helpers/mock_server/index.js
+++ b/spec/frontend_integration/test_helpers/mock_server/index.js
@@ -1,4 +1,5 @@
import { Server, Model, RestSerializer } from 'miragejs';
+import setupRoutes from 'ee_else_ce_test_helpers/mock_server/routes';
import {
getProject,
getEmptyProject,
@@ -11,7 +12,6 @@ import {
getBlobImage,
getBlobZip,
} from 'test_helpers/fixtures';
-import setupRoutes from './routes';
export const createMockServerOptions = () => ({
models: {
diff --git a/spec/lib/gitlab/application_context_spec.rb b/spec/lib/gitlab/application_context_spec.rb
index 0fbbc67ef6a..c4fe2ebaba9 100644
--- a/spec/lib/gitlab/application_context_spec.rb
+++ b/spec/lib/gitlab/application_context_spec.rb
@@ -27,6 +27,20 @@ RSpec.describe Gitlab::ApplicationContext do
end
end
+ describe '.with_raw_context' do
+ it 'yields the block' do
+ expect { |b| described_class.with_raw_context({}, &b) }.to yield_control
+ end
+
+ it 'passes the attributes unaltered on to labkit' do
+ attrs = { foo: :bar }
+
+ expect(Labkit::Context).to receive(:with_context).with(attrs)
+
+ described_class.with_raw_context(attrs) {}
+ end
+ end
+
describe '.push' do
it 'passes the expected context on to labkit' do
fake_proc = duck_type(:call)
@@ -138,7 +152,7 @@ RSpec.describe Gitlab::ApplicationContext do
it 'does not cause queries' do
context = described_class.new(project: create(:project), namespace: create(:group, :nested), user: create(:user))
- expect { context.use { Labkit::Context.current.to_h } }.not_to exceed_query_limit(0)
+ expect { context.use { Gitlab::ApplicationContext.current } }.not_to exceed_query_limit(0)
end
end
end
diff --git a/spec/lib/gitlab/metrics/background_transaction_spec.rb b/spec/lib/gitlab/metrics/background_transaction_spec.rb
index b31a2f7549a..15e52f7b6c8 100644
--- a/spec/lib/gitlab/metrics/background_transaction_spec.rb
+++ b/spec/lib/gitlab/metrics/background_transaction_spec.rb
@@ -30,7 +30,7 @@ RSpec.describe Gitlab::Metrics::BackgroundTransaction do
describe '#labels' do
it 'provides labels with endpoint_id and feature_category' do
- Labkit::Context.with_context(feature_category: 'projects', caller_id: 'TestWorker') do
+ Gitlab::ApplicationContext.with_raw_context(feature_category: 'projects', caller_id: 'TestWorker') do
expect(transaction.labels).to eq({ endpoint_id: 'TestWorker', feature_category: 'projects' })
end
end
@@ -41,7 +41,7 @@ RSpec.describe Gitlab::Metrics::BackgroundTransaction do
value = 1
expect(prometheus_metric).to receive(metric_method).with({ endpoint_id: 'TestWorker', feature_category: 'projects' }, value)
- Labkit::Context.with_context(feature_category: 'projects', caller_id: 'TestWorker') do
+ Gitlab::ApplicationContext.with_raw_context(feature_category: 'projects', caller_id: 'TestWorker') do
transaction.send(metric_method, :test_metric, value)
end
end
diff --git a/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb b/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
index ca473462d2e..f736a7db774 100644
--- a/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/worker_context/server_spec.rb
@@ -18,7 +18,7 @@ RSpec.describe Gitlab::SidekiqMiddleware::WorkerContext::Server do
worker_context user: nil
def perform(identifier, *args)
- self.class.contexts.merge!(identifier => Labkit::Context.current.to_h)
+ self.class.contexts.merge!(identifier => Gitlab::ApplicationContext.current)
end
end
end
diff --git a/spec/requests/api/api_spec.rb b/spec/requests/api/api_spec.rb
index 522030652bd..7e670724c11 100644
--- a/spec/requests/api/api_spec.rb
+++ b/spec/requests/api/api_spec.rb
@@ -105,7 +105,7 @@ RSpec.describe API::API do
it 'logs all application context fields' do
allow_any_instance_of(Gitlab::GrapeLogging::Loggers::ContextLogger).to receive(:parameters) do
- Labkit::Context.current.to_h.tap do |log_context|
+ Gitlab::ApplicationContext.current.tap do |log_context|
expect(log_context).to match('correlation_id' => an_instance_of(String),
'meta.caller_id' => '/api/:version/projects/:id/issues',
'meta.remote_ip' => an_instance_of(String),
@@ -122,7 +122,7 @@ RSpec.describe API::API do
it 'skips fields that do not apply' do
allow_any_instance_of(Gitlab::GrapeLogging::Loggers::ContextLogger).to receive(:parameters) do
- Labkit::Context.current.to_h.tap do |log_context|
+ Gitlab::ApplicationContext.current.tap do |log_context|
expect(log_context).to match('correlation_id' => an_instance_of(String),
'meta.caller_id' => '/api/:version/users',
'meta.remote_ip' => an_instance_of(String),
diff --git a/spec/serializers/build_artifact_entity_spec.rb b/spec/serializers/build_artifact_entity_spec.rb
index 02c172d723f..87c1874ec41 100644
--- a/spec/serializers/build_artifact_entity_spec.rb
+++ b/spec/serializers/build_artifact_entity_spec.rb
@@ -21,15 +21,30 @@ RSpec.describe BuildArtifactEntity do
expect(subject).to include(:expired, :expire_at)
end
- it 'contains paths to the artifacts' do
- expect(subject[:path])
- .to include "jobs/#{job.id}/artifacts/download?file_type=codequality"
+ it 'exposes the artifact download path' do
+ expect(subject[:path]).to include "jobs/#{job.id}/artifacts/download?file_type=codequality"
+ end
+
+ context 'with remove_duplicate_artifact_exposure_paths enabled' do
+ before do
+ stub_feature_flags(remove_duplicate_artifact_exposure_paths: true)
+ end
+
+ it 'has no keep or browse path' do
+ expect(subject).not_to include(:keep_path)
+ expect(subject).not_to include(:browse_path)
+ end
+ end
- expect(subject[:keep_path])
- .to include "jobs/#{job.id}/artifacts/keep"
+ context 'with remove_duplicate_artifact_exposure_paths disabled' do
+ before do
+ stub_feature_flags(remove_duplicate_artifact_exposure_paths: false)
+ end
- expect(subject[:browse_path])
- .to include "jobs/#{job.id}/artifacts/browse"
+ it 'has keep and browse paths' do
+ expect(subject[:keep_path]).to be_present
+ expect(subject[:browse_path]).to be_present
+ end
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b15d91b41e4..5f1513b1247 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -333,10 +333,20 @@ RSpec.configure do |config|
RequestStore.clear!
end
- config.around do |example|
- # Wrap each example in it's own context to make sure the contexts don't
- # leak
- Labkit::Context.with_context { example.run }
+ if ENV['SKIP_RSPEC_CONTEXT_WRAPPING']
+ config.around(:example, :context_aware) do |example|
+ # Wrap each example in it's own context to make sure the contexts don't
+ # leak
+ Gitlab::ApplicationContext.with_raw_context { example.run }
+ end
+ else
+ config.around do |example|
+ if [:controller, :request, :feature].include?(example.metadata[:type]) || example.metadata[:context_aware]
+ Gitlab::ApplicationContext.with_raw_context { example.run }
+ else
+ example.run
+ end
+ end
end
config.around do |example|
diff --git a/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb b/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb
index bdb0316bf5a..c775ca182e6 100644
--- a/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb
+++ b/spec/support/shared_examples/lib/api/ci/runner_shared_examples.rb
@@ -1,14 +1,14 @@
# frozen_string_literal: true
RSpec.shared_examples 'API::CI::Runner application context metadata' do |api_route|
- it 'contains correct context metadata' do
+ it 'contains correct context metadata', :context_aware do
# Avoids popping the context from the thread so we can
# check its content after the request.
allow(Labkit::Context).to receive(:pop)
send_request
- Labkit::Context.with_context do |context|
+ Gitlab::ApplicationContext.with_raw_context do |context|
expected_context = {
'meta.caller_id' => api_route,
'meta.user' => job.user.username,
diff --git a/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb b/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
index 4a71b696d57..57e28e6df57 100644
--- a/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
+++ b/spec/support/shared_examples/requests/api/logging_application_context_shared_examples.rb
@@ -1,21 +1,13 @@
# frozen_string_literal: true
RSpec.shared_examples 'storing arguments in the application context' do
- around do |example|
- Labkit::Context.with_context { example.run }
- end
-
- it 'places the expected params in the application context' do
+ it 'places the expected params in the application context', :context_aware do
# Stub the clearing of the context so we can validate it later
- # The `around` block above makes sure we do clean it up later
allow(Labkit::Context).to receive(:pop)
subject
- Labkit::Context.with_context do |context|
- expect(context.to_h)
- .to include(log_hash(expected_params))
- end
+ expect(Gitlab::ApplicationContext.current).to include(log_hash(expected_params))
end
def log_hash(hash)
diff --git a/spec/workers/background_migration_worker_spec.rb b/spec/workers/background_migration_worker_spec.rb
index 8094efcaf04..4575c270042 100644
--- a/spec/workers/background_migration_worker_spec.rb
+++ b/spec/workers/background_migration_worker_spec.rb
@@ -101,7 +101,7 @@ RSpec.describe BackgroundMigrationWorker, :clean_gitlab_redis_shared_state do
it 'sets the class that will be executed as the caller_id' do
expect(Gitlab::BackgroundMigration).to receive(:perform) do
- expect(Labkit::Context.current.to_h).to include('meta.caller_id' => 'Foo')
+ expect(Gitlab::ApplicationContext.current).to include('meta.caller_id' => 'Foo')
end
worker.perform('Foo', [10, 20])
diff --git a/spec/workers/concerns/worker_context_spec.rb b/spec/workers/concerns/worker_context_spec.rb
index 3de37b99aba..ebdb752d900 100644
--- a/spec/workers/concerns/worker_context_spec.rb
+++ b/spec/workers/concerns/worker_context_spec.rb
@@ -103,7 +103,7 @@ RSpec.describe WorkerContext do
describe '#with_context' do
it 'allows modifying context when the job is running' do
worker.new.with_context(user: build_stubbed(:user, username: 'jane-doe')) do
- expect(Labkit::Context.current.to_h).to include('meta.user' => 'jane-doe')
+ expect(Gitlab::ApplicationContext.current).to include('meta.user' => 'jane-doe')
end
end
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
index 259148fa18f..259148fa18f 100755..100644
--- a/vendor/gitignore/C++.gitignore
+++ b/vendor/gitignore/C++.gitignore
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
index a1c2a238a96..a1c2a238a96 100755..100644
--- a/vendor/gitignore/Java.gitignore
+++ b/vendor/gitignore/Java.gitignore