diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-26 09:08:36 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-11-26 09:08:36 +0000 |
commit | 23d237110e6a646dec08e1f5b4696d2d9c51cfef (patch) | |
tree | 3c568514c8e22203f50d38940cbb9865aad5bb02 | |
parent | 274dff4f027da636f62361c811285cbb5d5a7c0c (diff) | |
download | gitlab-ce-23d237110e6a646dec08e1f5b4696d2d9c51cfef.tar.gz |
Add latest changes from gitlab-org/gitlab@master
51 files changed, 622 insertions, 53 deletions
diff --git a/.rubocop.yml b/.rubocop.yml index 1d5cf7642c2..27dce2239d8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -56,7 +56,6 @@ Style/FrozenStringLiteralComment: - 'qa/**/*' - 'rubocop/**/*' - 'scripts/**/*' - - 'spec/lib/gitlab/**/*' RSpec/FilePath: Exclude: diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 19b85710710..8039a9a7602 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -1,5 +1,6 @@ <script> import { mapState, mapGetters, mapActions } from 'vuex'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import Icon from '~/vue_shared/components/icon.vue'; import { __ } from '~/locale'; import createFlash from '~/flash'; @@ -36,11 +37,20 @@ export default { GlLoadingIcon, PanelResizer, }, + mixins: [glFeatureFlagsMixin()], props: { endpoint: { type: String, required: true, }, + endpointMetadata: { + type: String, + required: true, + }, + endpointBatch: { + type: String, + required: true, + }, projectPath: { type: String, required: true, @@ -92,6 +102,7 @@ export default { computed: { ...mapState({ isLoading: state => state.diffs.isLoading, + isBatchLoading: state => state.diffs.isBatchLoading, diffFiles: state => state.diffs.diffFiles, diffViewType: state => state.diffs.diffViewType, mergeRequestDiffs: state => state.diffs.mergeRequestDiffs, @@ -153,6 +164,8 @@ export default { mounted() { this.setBaseConfig({ endpoint: this.endpoint, + endpointMetadata: this.endpointMetadata, + endpointBatch: this.endpointBatch, projectPath: this.projectPath, dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, @@ -185,6 +198,8 @@ export default { ...mapActions('diffs', [ 'setBaseConfig', 'fetchDiffFiles', + 'fetchDiffFilesMeta', + 'fetchDiffFilesBatch', 'startRenderDiffsQueue', 'assignDiscussionsToDiff', 'setHighlightedRow', @@ -196,24 +211,51 @@ export default { this.assignedDiscussions = false; this.fetchData(false); }, + isLatestVersion() { + return window.location.search.indexOf('diff_id') === -1; + }, fetchData(toggleTree = true) { - this.fetchDiffFiles() - .then(() => { - if (toggleTree) { - this.hideTreeListIfJustOneFile(); - } + if (this.isLatestVersion() && this.glFeatures.diffsBatchLoad) { + this.fetchDiffFilesMeta() + .then(() => { + if (toggleTree) this.hideTreeListIfJustOneFile(); + }) + .catch(() => { + createFlash(__('Something went wrong on our end. Please try again!')); + }); - requestIdleCallback( - () => { - this.setDiscussions(); - this.startRenderDiffsQueue(); - }, - { timeout: 1000 }, - ); - }) - .catch(() => { - createFlash(__('Something went wrong on our end. Please try again!')); - }); + this.fetchDiffFilesBatch() + .then(() => { + requestIdleCallback( + () => { + this.setDiscussions(); + this.startRenderDiffsQueue(); + }, + { timeout: 1000 }, + ); + }) + .catch(() => { + createFlash(__('Something went wrong on our end. Please try again!')); + }); + } else { + this.fetchDiffFiles() + .then(() => { + if (toggleTree) { + this.hideTreeListIfJustOneFile(); + } + + requestIdleCallback( + () => { + this.setDiscussions(); + this.startRenderDiffsQueue(); + }, + { timeout: 1000 }, + ); + }) + .catch(() => { + createFlash(__('Something went wrong on our end. Please try again!')); + }); + } if (!this.isNotesFetched) { eventHub.$emit('fetchNotesData'); @@ -324,7 +366,8 @@ export default { }" > <commit-widget v-if="commit" :commit="commit" /> - <template v-if="renderDiffFiles"> + <div v-if="isBatchLoading" class="loading"><gl-loading-icon /></div> + <template v-else-if="renderDiffFiles"> <diff-file v-for="file in diffFiles" :key="file.newPath" diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index d84e1af11f3..9de4c38bdf0 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -57,3 +57,4 @@ export const MIN_RENDERING_MS = 2; export const START_RENDERING_INDEX = 200; export const INLINE_DIFF_LINES_KEY = 'highlighted_diff_lines'; export const PARALLEL_DIFF_LINES_KEY = 'parallel_diff_lines'; +export const DIFFS_PER_PAGE = 10; diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index c9580e3d3b4..375ac80021f 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -67,6 +67,8 @@ export default function initDiffsApp(store) { return { endpoint: dataset.endpoint, + endpointMetadata: dataset.endpointMetadata || '', + endpointBatch: dataset.endpointBatch || '', projectPath: dataset.projectPath, helpPagePath: dataset.helpPagePath, currentUser: JSON.parse(dataset.currentUserData) || {}, @@ -100,6 +102,8 @@ export default function initDiffsApp(store) { return createElement('diffs-app', { props: { endpoint: this.endpoint, + endpointMetadata: this.endpointMetadata, + endpointBatch: this.endpointBatch, currentUser: this.currentUser, projectPath: this.projectPath, helpPagePath: this.helpPagePath, diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 6695d9fe96c..d4594399ff5 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -13,6 +13,7 @@ import { convertExpandLines, idleCallback, allDiscussionWrappersExpanded, + prepareDiffData, } from './utils'; import * as types from './mutation_types'; import { @@ -33,12 +34,27 @@ import { START_RENDERING_INDEX, INLINE_DIFF_LINES_KEY, PARALLEL_DIFF_LINES_KEY, + DIFFS_PER_PAGE, } from '../constants'; import { diffViewerModes } from '~/ide/constants'; export const setBaseConfig = ({ commit }, options) => { - const { endpoint, projectPath, dismissEndpoint, showSuggestPopover } = options; - commit(types.SET_BASE_CONFIG, { endpoint, projectPath, dismissEndpoint, showSuggestPopover }); + const { + endpoint, + endpointMetadata, + endpointBatch, + projectPath, + dismissEndpoint, + showSuggestPopover, + } = options; + commit(types.SET_BASE_CONFIG, { + endpoint, + endpointMetadata, + endpointBatch, + projectPath, + dismissEndpoint, + showSuggestPopover, + }); }; export const fetchDiffFiles = ({ state, commit }) => { @@ -67,6 +83,53 @@ export const fetchDiffFiles = ({ state, commit }) => { .catch(() => worker.terminate()); }; +export const fetchDiffFilesBatch = ({ commit, state }) => { + const baseUrl = `${state.endpointBatch}?per_page=${DIFFS_PER_PAGE}`; + const url = page => (page ? `${baseUrl}&page=${page}` : baseUrl); + + commit(types.SET_BATCH_LOADING, true); + + const getBatch = page => + axios + .get(url(page)) + .then(({ data: { pagination, diff_files } }) => { + commit(types.SET_DIFF_DATA_BATCH, { diff_files }); + commit(types.SET_BATCH_LOADING, false); + return pagination.next_page; + }) + .then(nextPage => nextPage && getBatch(nextPage)); + + return getBatch() + .then(handleLocationHash) + .catch(() => null); +}; + +export const fetchDiffFilesMeta = ({ commit, state }) => { + const worker = new TreeWorker(); + + commit(types.SET_LOADING, true); + + worker.addEventListener('message', ({ data }) => { + commit(types.SET_TREE_DATA, data); + + worker.terminate(); + }); + + return axios + .get(state.endpointMetadata) + .then(({ data }) => { + const strippedData = { ...data }; + strippedData.diff_files = []; + commit(types.SET_LOADING, false); + commit(types.SET_MERGE_REQUEST_DIFFS, data.merge_request_diffs || []); + commit(types.SET_DIFF_DATA, strippedData); + + prepareDiffData(data); + worker.postMessage(data.diff_files); + }) + .catch(() => worker.terminate()); +}; + export const setHighlightedRow = ({ commit }, lineCode) => { const fileHash = lineCode.split('_')[0]; commit(types.SET_HIGHLIGHTED_ROW, lineCode); diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index 6821c8445ea..8c52e3178e5 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -8,6 +8,7 @@ const defaultViewType = INLINE_DIFF_VIEW_TYPE; export default () => ({ isLoading: true, + isBatchLoading: false, addedLines: null, removedLines: null, endpoint: '', diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 9db56331faa..5a90d78b2bc 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -1,6 +1,8 @@ export const SET_BASE_CONFIG = 'SET_BASE_CONFIG'; export const SET_LOADING = 'SET_LOADING'; +export const SET_BATCH_LOADING = 'SET_BATCH_LOADING'; export const SET_DIFF_DATA = 'SET_DIFF_DATA'; +export const SET_DIFF_DATA_BATCH = 'SET_DIFF_DATA_BATCH'; export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE'; export const SET_MERGE_REQUEST_DIFFS = 'SET_MERGE_REQUEST_DIFFS'; export const TOGGLE_LINE_HAS_FORM = 'TOGGLE_LINE_HAS_FORM'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index a6915a46c00..de2f68d729c 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -12,14 +12,32 @@ import * as types from './mutation_types'; export default { [types.SET_BASE_CONFIG](state, options) { - const { endpoint, projectPath, dismissEndpoint, showSuggestPopover } = options; - Object.assign(state, { endpoint, projectPath, dismissEndpoint, showSuggestPopover }); + const { + endpoint, + endpointMetadata, + endpointBatch, + projectPath, + dismissEndpoint, + showSuggestPopover, + } = options; + Object.assign(state, { + endpoint, + endpointMetadata, + endpointBatch, + projectPath, + dismissEndpoint, + showSuggestPopover, + }); }, [types.SET_LOADING](state, isLoading) { Object.assign(state, { isLoading }); }, + [types.SET_BATCH_LOADING](state, isBatchLoading) { + Object.assign(state, { isBatchLoading }); + }, + [types.SET_DIFF_DATA](state, data) { prepareDiffData(data); @@ -28,6 +46,12 @@ export default { }); }, + [types.SET_DIFF_DATA_BATCH](state, data) { + prepareDiffData(data); + + state.diffFiles.push(...data.diff_files); + }, + [types.RENDER_FILE](state, file) { Object.assign(file, { renderIt: true, diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index d46bdea9b50..2326018b999 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -252,10 +252,11 @@ export function prepareDiffData(diffData) { showingLines += file.parallel_diff_lines.length; } + const name = (file.viewer && file.viewer.name) || diffViewerModes.text; + Object.assign(file, { renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY, - collapsed: - file.viewer.name === diffViewerModes.text && showingLines > MAX_LINES_TO_BE_RENDERED, + collapsed: name === diffViewerModes.text && showingLines > MAX_LINES_TO_BE_RENDERED, isShowingFullFile: false, isLoadingFullFile: false, discussions: [], diff --git a/app/assets/javascripts/environments/components/environment_item.vue b/app/assets/javascripts/environments/components/environment_item.vue index c94039326aa..dfd4d5474ff 100644 --- a/app/assets/javascripts/environments/components/environment_item.vue +++ b/app/assets/javascripts/environments/components/environment_item.vue @@ -6,6 +6,7 @@ import _ from 'underscore'; import { GlTooltipDirective } from '@gitlab/ui'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import Icon from '~/vue_shared/components/icon.vue'; +import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue'; import environmentItemMixin from 'ee_else_ce/environments/mixins/environment_item_mixin'; import ActionsComponent from './environment_actions.vue'; import ExternalUrlComponent from './environment_external_url.vue'; @@ -26,7 +27,6 @@ const timeagoInstance = new Timeago(); export default { components: { - UserAvatarLink, CommitComponent, Icon, ActionsComponent, @@ -35,6 +35,8 @@ export default { RollbackComponent, TerminalButtonComponent, MonitoringButtonComponent, + TooltipOnTruncate, + UserAvatarLink, }, directives: { GlTooltip: GlTooltipDirective, @@ -508,12 +510,16 @@ export default { </div> <div class="table-section section-15 d-none d-sm-none d-md-block" role="gridcell"> - <a - v-if="shouldRenderBuildName" - :href="buildPath" - class="build-link cgray flex-truncate-parent" - > - <span class="flex-truncate-child">{{ buildName }}</span> + <a v-if="shouldRenderBuildName" :href="buildPath" class="build-link cgray"> + <tooltip-on-truncate + :title="buildName" + truncate-target="child" + class="flex-truncate-parent" + > + <span class="flex-truncate-child"> + {{ buildName }} + </span> + </tooltip-on-truncate> </a> </div> diff --git a/app/assets/javascripts/environments/components/environments_app.vue b/app/assets/javascripts/environments/components/environments_app.vue index 81927d18f8b..50c667e6966 100644 --- a/app/assets/javascripts/environments/components/environments_app.vue +++ b/app/assets/javascripts/environments/components/environments_app.vue @@ -31,10 +31,6 @@ export default { type: Boolean, required: true, }, - cssContainerClass: { - type: String, - required: true, - }, newEnvironmentPath: { type: String, required: true, @@ -93,7 +89,7 @@ export default { }; </script> <template> - <div :class="cssContainerClass"> + <div> <stop-environment-modal :environment="environmentInStopModal" /> <confirm-rollback-modal :environment="environmentInRollbackModal" /> diff --git a/app/assets/javascripts/environments/index.js b/app/assets/javascripts/environments/index.js index dcdaf8731f8..9a68619d4f7 100644 --- a/app/assets/javascripts/environments/index.js +++ b/app/assets/javascripts/environments/index.js @@ -21,7 +21,6 @@ export default () => newEnvironmentPath: environmentsData.newEnvironmentPath, helpPagePath: environmentsData.helpPagePath, deployBoardsHelpPath: environmentsData.deployBoardsHelpPath, - cssContainerClass: environmentsData.cssClass, canCreateEnvironment: parseBoolean(environmentsData.canCreateEnvironment), canReadEnvironment: parseBoolean(environmentsData.canReadEnvironment), }; @@ -33,7 +32,6 @@ export default () => newEnvironmentPath: this.newEnvironmentPath, helpPagePath: this.helpPagePath, deployBoardsHelpPath: this.deployBoardsHelpPath, - cssContainerClass: this.cssContainerClass, canCreateEnvironment: this.canCreateEnvironment, canReadEnvironment: this.canReadEnvironment, ...this.canaryCalloutProps, diff --git a/app/controllers/clusters/clusters_controller.rb b/app/controllers/clusters/clusters_controller.rb index 673ead04709..9da8ad229fe 100644 --- a/app/controllers/clusters/clusters_controller.rb +++ b/app/controllers/clusters/clusters_controller.rb @@ -3,14 +3,14 @@ class Clusters::ClustersController < Clusters::BaseController include RoutableActions - before_action :cluster, only: [:cluster_status, :show, :update, :destroy] + before_action :cluster, only: [:cluster_status, :show, :update, :destroy, :clear_cache] before_action :generate_gcp_authorize_url, only: [:new] before_action :validate_gcp_token, only: [:new] before_action :gcp_cluster, only: [:new] before_action :user_cluster, only: [:new] before_action :authorize_create_cluster!, only: [:new, :authorize_aws_role, :revoke_aws_role, :aws_proxy] before_action :authorize_update_cluster!, only: [:update] - before_action :authorize_admin_cluster!, only: [:destroy] + before_action :authorize_admin_cluster!, only: [:destroy, :clear_cache] before_action :update_applications_status, only: [:cluster_status] before_action only: [:new, :create_gcp] do push_frontend_feature_flag(:create_eks_clusters) @@ -169,6 +169,12 @@ class Clusters::ClustersController < Clusters::BaseController render json: response.body, status: response.status end + def clear_cache + cluster.delete_cached_resources! + + redirect_to cluster.show_path, notice: _('Cluster cache cleared.') + end + private def destroy_params diff --git a/app/models/clusters/cluster.rb b/app/models/clusters/cluster.rb index 98e754a1370..62b2217a9af 100644 --- a/app/models/clusters/cluster.rb +++ b/app/models/clusters/cluster.rb @@ -267,6 +267,10 @@ module Clusters end end + def delete_cached_resources! + kubernetes_namespaces.delete_all(:delete_all) + end + private def unique_management_project_environment_scope diff --git a/app/presenters/clusterable_presenter.rb b/app/presenters/clusterable_presenter.rb index 2306f55f1f4..7677e6f026f 100644 --- a/app/presenters/clusterable_presenter.rb +++ b/app/presenters/clusterable_presenter.rb @@ -65,6 +65,10 @@ class ClusterablePresenter < Gitlab::View::Presenter::Delegated raise NotImplementedError end + def clear_cluster_cache_path(cluster) + raise NotImplementedError + end + def cluster_path(cluster, params = {}) raise NotImplementedError end diff --git a/app/presenters/group_clusterable_presenter.rb b/app/presenters/group_clusterable_presenter.rb index 54cea19b18e..21db2f6f96b 100644 --- a/app/presenters/group_clusterable_presenter.rb +++ b/app/presenters/group_clusterable_presenter.rb @@ -19,6 +19,11 @@ class GroupClusterablePresenter < ClusterablePresenter update_applications_group_cluster_path(clusterable, cluster, application) end + override :clear_cluster_cache_path + def clear_cluster_cache_path(cluster) + clear_cache_group_cluster_path(clusterable, cluster) + end + override :cluster_path def cluster_path(cluster, params = {}) group_cluster_path(clusterable, cluster, params) diff --git a/app/presenters/instance_clusterable_presenter.rb b/app/presenters/instance_clusterable_presenter.rb index c6572e8ce71..34d3f347689 100644 --- a/app/presenters/instance_clusterable_presenter.rb +++ b/app/presenters/instance_clusterable_presenter.rb @@ -37,6 +37,11 @@ class InstanceClusterablePresenter < ClusterablePresenter update_applications_admin_cluster_path(cluster, application) end + override :clear_cluster_cache_path + def clear_cluster_cache_path(cluster) + clear_cache_admin_cluster_path(cluster) + end + override :cluster_path def cluster_path(cluster, params = {}) admin_cluster_path(cluster, params) diff --git a/app/presenters/project_clusterable_presenter.rb b/app/presenters/project_clusterable_presenter.rb index 3fab69fff7a..5c56d42ed27 100644 --- a/app/presenters/project_clusterable_presenter.rb +++ b/app/presenters/project_clusterable_presenter.rb @@ -19,6 +19,11 @@ class ProjectClusterablePresenter < ClusterablePresenter update_applications_project_cluster_path(clusterable, cluster, application) end + override :clear_cluster_cache_path + def clear_cluster_cache_path(cluster) + clear_cache_project_cluster_path(clusterable, cluster) + end + override :cluster_path def cluster_path(cluster, params = {}) project_cluster_path(clusterable, cluster, params) diff --git a/app/serializers/diff_file_metadata_entity.rb b/app/serializers/diff_file_metadata_entity.rb index 500a844b170..05280518f39 100644 --- a/app/serializers/diff_file_metadata_entity.rb +++ b/app/serializers/diff_file_metadata_entity.rb @@ -7,4 +7,7 @@ class DiffFileMetadataEntity < Grape::Entity expose :old_path expose :new_file?, as: :new_file expose :deleted_file?, as: :deleted_file + expose :file_hash do |diff_file| + Digest::SHA1.hexdigest(diff_file.file_path) + end end diff --git a/app/views/clusters/clusters/_advanced_settings.html.haml b/app/views/clusters/clusters/_advanced_settings.html.haml index 59cdf2016fb..5e34b457231 100644 --- a/app/views/clusters/clusters/_advanced_settings.html.haml +++ b/app/views/clusters/clusters/_advanced_settings.html.haml @@ -28,6 +28,14 @@ .form-group = field.submit _('Save changes'), class: 'btn btn-success qa-save-domain' + - if @cluster.managed? + .sub-section.form-group + %h4 + = s_('ClusterIntegration|Clear cluster cache') + %p + = s_("ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts.") + = link_to(s_('ClusterIntegration|Clear cluster cache'), clusterable.clear_cluster_cache_path(@cluster), method: :delete, class: 'btn btn-primary') + .sub-section.form-group %h4.text-danger = s_('ClusterIntegration|Remove Kubernetes cluster integration') diff --git a/app/views/projects/merge_requests/show.html.haml b/app/views/projects/merge_requests/show.html.haml index dee6bc8bae4..c2bc5376fd7 100644 --- a/app/views/projects/merge_requests/show.html.haml +++ b/app/views/projects/merge_requests/show.html.haml @@ -78,6 +78,8 @@ = render 'projects/commit/pipelines_list', disable_initialization: true, endpoint: pipelines_project_merge_request_path(@project, @merge_request) #js-diffs-app.diffs.tab-pane{ data: { "is-locked" => @merge_request.discussion_locked?, endpoint: diffs_project_merge_request_path(@project, @merge_request, 'json', request.query_parameters), + endpoint_metadata: diffs_metadata_project_json_merge_request_path(@project, @merge_request, 'json', request.query_parameters), + endpoint_batch: diffs_batch_project_json_merge_request_path(@project, @merge_request, 'json', request.query_parameters), help_page_path: suggest_changes_help_path, current_user_data: @current_user_data, project_path: project_path(@merge_request.project), diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index d341520e4a2..5da86195243 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -6,7 +6,7 @@ .issues-filters{ class: ("w-100" if type == :boards_modal) } .issues-details-filters.filtered-search-block.d-flex.flex-column.flex-lg-row{ class: block_css_class, "v-pre" => type == :boards_modal } - .d-flex.flex-column.flex-md-row.flex-grow-1.mb-lg-0.mb-md-2.mb-sm-0 + .d-flex.flex-column.flex-md-row.flex-grow-1.mb-lg-0.mb-md-2.mb-sm-0.w-100 - if type == :boards = render "shared/boards/switcher", board: board = form_tag page_filter_path, method: :get, class: 'filter-form js-filter-form w-100' do @@ -162,8 +162,8 @@ %button.clear-search.hidden{ type: 'button' } = icon('times') .filter-dropdown-container.d-flex.flex-column.flex-md-row - #js-board-labels-toggle - if type == :boards + #js-board-labels-toggle .js-board-config{ data: { can_admin_list: user_can_admin_list, has_scope: board.scoped? } } - if user_can_admin_list = render 'shared/issuable/board_create_list_dropdown', board: board diff --git a/changelogs/unreleased/31759-clear-cluster-cache.yml b/changelogs/unreleased/31759-clear-cluster-cache.yml new file mode 100644 index 00000000000..29e0dda43ec --- /dev/null +++ b/changelogs/unreleased/31759-clear-cluster-cache.yml @@ -0,0 +1,5 @@ +--- +title: Add option to delete cached Kubernetes namespaces +merge_request: 20411 +author: +type: added diff --git a/changelogs/unreleased/32557-convert-generic-epic-error-banners-to-form-validation-messages.yml b/changelogs/unreleased/32557-convert-generic-epic-error-banners-to-form-validation-messages.yml new file mode 100644 index 00000000000..d40cfa2fce3 --- /dev/null +++ b/changelogs/unreleased/32557-convert-generic-epic-error-banners-to-form-validation-messages.yml @@ -0,0 +1,5 @@ +--- +title: Convert flash epic error to form validation error +merge_request: 20130 +author: +type: changed diff --git a/changelogs/unreleased/env-tooltips.yml b/changelogs/unreleased/env-tooltips.yml new file mode 100644 index 00000000000..f2d33bea1e5 --- /dev/null +++ b/changelogs/unreleased/env-tooltips.yml @@ -0,0 +1,5 @@ +--- +title: Fix tooltip hovers in environments table +merge_request: 20737 +author: +type: fixed diff --git a/config/routes.rb b/config/routes.rb index 9fb4d94f068..c98c0358336 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -166,6 +166,7 @@ Rails.application.routes.draw do end get :cluster_status, format: :json + delete :clear_cache end end end diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index 05b660ccdf6..ce3d6247d86 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -184,6 +184,17 @@ that the YAML parser knows to interpret the whole thing as a string rather than a "key: value" pair. Be careful when using special characters: `:`, `{`, `}`, `[`, `]`, `,`, `&`, `*`, `#`, `?`, `|`, `-`, `<`, `>`, `=`, `!`, `%`, `@`, `` ` ``. +If any of the script commands return an exit code different from zero, the job +will fail and further commands will not be executed. This behavior can be avoided by +storing the exit code in a variable: + +```yaml +job: + script: + - false && true; exit_code=$? + - if [ $exit_code -ne 0 ]; then echo "Previous command failed"; fi; +``` + #### YAML anchors for `script` > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/23005) in GitLab 12.5. diff --git a/doc/user/group/clusters/index.md b/doc/user/group/clusters/index.md index 1fe456902a2..2b36c3bdf5b 100644 --- a/doc/user/group/clusters/index.md +++ b/doc/user/group/clusters/index.md @@ -75,6 +75,21 @@ NOTE: **Note:** If you [install applications](#installing-applications) on your cluster, GitLab will create the resources required to run these even if you have chosen to manage your own cluster. +### Clearing the cluster cache + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/31759) in GitLab 12.6. + +If you choose to allow GitLab to manage your cluster for you, GitLab stores a cached +version of the namespaces and service accounts it creates for your projects. If you +modify these resources in your cluster manually, this cache can fall out of sync with +your cluster, which can cause deployment jobs to fail. + +To clear the cache: + +1. Navigate to your group’s **Kubernetes** page, and select your cluster. +1. Expand the **Advanced settings** section. +1. Click **Clear cluster cache**. + ## Base domain > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24580) in GitLab 11.8. diff --git a/doc/user/project/clusters/index.md b/doc/user/project/clusters/index.md index c5c2c2c07e7..2aa746fc596 100644 --- a/doc/user/project/clusters/index.md +++ b/doc/user/project/clusters/index.md @@ -132,6 +132,21 @@ NOTE: **Note:** If you [install applications](#installing-applications) on your cluster, GitLab will create the resources required to run these even if you have chosen to manage your own cluster. +#### Clearing the cluster cache + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/31759) in GitLab 12.6. + +If you choose to allow GitLab to manage your cluster for you, GitLab stores a cached +version of the namespaces and service accounts it creates for your projects. If you +modify these resources in your cluster manually, this cache can fall out of sync with +your cluster, which can cause deployment jobs to fail. + +To clear the cache: + +1. Navigate to your project’s **Operations > Kubernetes** page, and select your cluster. +1. Expand the **Advanced settings** section. +1. Click **Clear cluster cache**. + ### Base domain > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/24580) in GitLab 11.8. diff --git a/locale/gitlab.pot b/locale/gitlab.pot index e703e87f0d6..799612af9cd 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -3469,6 +3469,9 @@ msgstr "" msgid "Cluster Health" msgstr "" +msgid "Cluster cache cleared." +msgstr "" + msgid "ClusterIntegration| %{custom_domain_start}More information%{custom_domain_end}." msgstr "" @@ -3601,6 +3604,12 @@ msgstr "" msgid "ClusterIntegration|Choose which of your environments will use this cluster." msgstr "" +msgid "ClusterIntegration|Clear cluster cache" +msgstr "" + +msgid "ClusterIntegration|Clear the local cache of namespace and service accounts. This is necessary if your integration has become out of sync. The cache is repopulated during the next CI job that requires namespace and service accounts." +msgstr "" + msgid "ClusterIntegration|Cloud Run" msgstr "" @@ -6644,6 +6653,9 @@ msgstr "" msgid "Epic" msgstr "" +msgid "Epic cannot be found." +msgstr "" + msgid "Epic events" msgstr "" @@ -9611,6 +9623,9 @@ msgstr "" msgid "Issue board focus mode" msgstr "" +msgid "Issue cannot be found." +msgstr "" + msgid "Issue events" msgstr "" @@ -17678,6 +17693,9 @@ msgstr "" msgid "This environment has no deployments yet." msgstr "" +msgid "This epic already has the maximum number of child epics." +msgstr "" + msgid "This epic does not exist or you don't have sufficient permission." msgstr "" @@ -19487,12 +19505,6 @@ msgstr "" msgid "Want to see the data? Please ask an administrator for access." msgstr "" -msgid "We can't find an epic that matches what you are looking for." -msgstr "" - -msgid "We can't find an issue that matches what you are looking for." -msgstr "" - msgid "We could not determine the path to remove the epic" msgstr "" diff --git a/spec/controllers/admin/clusters_controller_spec.rb b/spec/controllers/admin/clusters_controller_spec.rb index ebae931764d..326d0808092 100644 --- a/spec/controllers/admin/clusters_controller_spec.rb +++ b/spec/controllers/admin/clusters_controller_spec.rb @@ -448,6 +448,33 @@ describe Admin::ClustersController do end end + describe 'DELETE clear cluster cache' do + let(:cluster) { create(:cluster, :instance) } + let!(:kubernetes_namespace) do + create(:cluster_kubernetes_namespace, + cluster: cluster, + project: create(:project) + ) + end + + def go + delete :clear_cache, params: { id: cluster } + end + + it 'deletes the namespaces associated with the cluster' do + expect { go }.to change { Clusters::KubernetesNamespace.count } + + expect(response).to redirect_to(admin_cluster_path(cluster)) + expect(cluster.kubernetes_namespaces).to be_empty + end + + describe 'security' do + it { expect { go }.to be_allowed_for(:admin) } + it { expect { go }.to be_denied_for(:user) } + it { expect { go }.to be_denied_for(:external) } + end + end + describe 'GET #cluster_status' do let(:cluster) { create(:cluster, :providing_by_gcp, :instance) } diff --git a/spec/controllers/groups/clusters_controller_spec.rb b/spec/controllers/groups/clusters_controller_spec.rb index d027405703b..d1669c84e3e 100644 --- a/spec/controllers/groups/clusters_controller_spec.rb +++ b/spec/controllers/groups/clusters_controller_spec.rb @@ -516,6 +516,42 @@ describe Groups::ClustersController do end end + describe 'DELETE clear cluster cache' do + let(:cluster) { create(:cluster, :group, groups: [group]) } + let!(:kubernetes_namespace) do + create(:cluster_kubernetes_namespace, + cluster: cluster, + project: create(:project) + ) + end + + def go + delete :clear_cache, + params: { + group_id: group, + id: cluster + } + end + + it 'deletes the namespaces associated with the cluster' do + expect { go }.to change { Clusters::KubernetesNamespace.count } + + expect(response).to redirect_to(group_cluster_path(group, cluster)) + expect(cluster.kubernetes_namespaces).to be_empty + end + + describe 'security' do + it { expect { go }.to be_allowed_for(:admin) } + it { expect { go }.to be_allowed_for(:owner).of(group) } + it { expect { go }.to be_allowed_for(:maintainer).of(group) } + it { expect { go }.to be_denied_for(:developer).of(group) } + it { expect { go }.to be_denied_for(:reporter).of(group) } + it { expect { go }.to be_denied_for(:guest).of(group) } + it { expect { go }.to be_denied_for(:user) } + it { expect { go }.to be_denied_for(:external) } + end + end + describe 'GET cluster_status' do let(:cluster) { create(:cluster, :providing_by_gcp, cluster_type: :group_type, groups: [group]) } diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb index 5a0512a042e..9c21b472c15 100644 --- a/spec/controllers/projects/clusters_controller_spec.rb +++ b/spec/controllers/projects/clusters_controller_spec.rb @@ -517,6 +517,38 @@ describe Projects::ClustersController do end end + describe 'DELETE clear cluster cache' do + let(:cluster) { create(:cluster, :project, projects: [project]) } + let!(:kubernetes_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster) } + + def go + delete :clear_cache, + params: { + namespace_id: project.namespace, + project_id: project, + id: cluster + } + end + + it 'deletes the namespaces associated with the cluster' do + expect { go }.to change { Clusters::KubernetesNamespace.count } + + expect(response).to redirect_to(project_cluster_path(project, cluster)) + expect(cluster.kubernetes_namespaces).to be_empty + end + + describe 'security' do + it { expect { go }.to be_allowed_for(:admin) } + it { expect { go }.to be_allowed_for(:owner).of(project) } + it { expect { go }.to be_allowed_for(:maintainer).of(project) } + it { expect { go }.to be_denied_for(:developer).of(project) } + it { expect { go }.to be_denied_for(:reporter).of(project) } + it { expect { go }.to be_denied_for(:guest).of(project) } + it { expect { go }.to be_denied_for(:user) } + it { expect { go }.to be_denied_for(:external) } + end + end + describe 'GET cluster_status' do let(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) } diff --git a/spec/features/merge_request/user_expands_diff_spec.rb b/spec/features/merge_request/user_expands_diff_spec.rb index ba7abd3af2c..9b040271468 100644 --- a/spec/features/merge_request/user_expands_diff_spec.rb +++ b/spec/features/merge_request/user_expands_diff_spec.rb @@ -8,6 +8,7 @@ describe 'User expands diff', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) allow(Gitlab::Git::Diff).to receive(:size_limit).and_return(100.kilobytes) allow(Gitlab::Git::Diff).to receive(:collapse_limit).and_return(10.kilobytes) @@ -20,7 +21,7 @@ describe 'User expands diff', :js do it_behaves_like 'rendering a single diff version' it 'allows user to expand diff' do - page.within find('[id="2f6fcd96b88b36ce98c38da085c795a27d92a3dd"]') do + page.within find('[id="6eb14e00385d2fb284765eb1cd8d420d33d63fc9"]') do click_link 'Click to expand it.' wait_for_requests diff --git a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb index 7cb46d90092..9cbea8a8466 100644 --- a/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb +++ b/spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb @@ -21,6 +21,7 @@ describe 'Merge request > User resolves diff notes and threads', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) end it_behaves_like 'rendering a single diff version' diff --git a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb index e882b401122..70afe056c64 100644 --- a/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb +++ b/spec/features/merge_request/user_sees_avatar_on_diff_notes_spec.rb @@ -22,6 +22,7 @@ describe 'Merge request > User sees avatars on diff notes', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) project.add_maintainer(user) sign_in user diff --git a/spec/features/merge_request/user_sees_diff_spec.rb b/spec/features/merge_request/user_sees_diff_spec.rb index 82dd779577c..de142344c26 100644 --- a/spec/features/merge_request/user_sees_diff_spec.rb +++ b/spec/features/merge_request/user_sees_diff_spec.rb @@ -11,6 +11,7 @@ describe 'Merge request > User sees diff', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) end it_behaves_like 'rendering a single diff version' diff --git a/spec/features/merge_request/user_sees_versions_spec.rb b/spec/features/merge_request/user_sees_versions_spec.rb index c3fce9761df..b3aef601c7b 100644 --- a/spec/features/merge_request/user_sees_versions_spec.rb +++ b/spec/features/merge_request/user_sees_versions_spec.rb @@ -17,6 +17,7 @@ describe 'Merge request > User sees versions', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) project.add_maintainer(user) sign_in(user) diff --git a/spec/features/merge_request/user_views_diffs_spec.rb b/spec/features/merge_request/user_views_diffs_spec.rb index 5a29477e597..313f438e23b 100644 --- a/spec/features/merge_request/user_views_diffs_spec.rb +++ b/spec/features/merge_request/user_views_diffs_spec.rb @@ -10,6 +10,7 @@ describe 'User views diffs', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) visit(diffs_project_merge_request_path(project, merge_request)) wait_for_requests diff --git a/spec/features/projects/view_on_env_spec.rb b/spec/features/projects/view_on_env_spec.rb index 832985f1a30..c2d4cefad12 100644 --- a/spec/features/projects/view_on_env_spec.rb +++ b/spec/features/projects/view_on_env_spec.rb @@ -10,6 +10,7 @@ describe 'View on environment', :js do before do stub_feature_flags(single_mr_diff_view: false) + stub_feature_flags(diffs_batch_load: false) project.add_maintainer(user) end diff --git a/spec/javascripts/diffs/components/app_spec.js b/spec/javascripts/diffs/components/app_spec.js index fdf8bcee756..52f7674a7b3 100644 --- a/spec/javascripts/diffs/components/app_spec.js +++ b/spec/javascripts/diffs/components/app_spec.js @@ -34,6 +34,8 @@ describe('diffs/components/app', () => { localVue, propsData: { endpoint: `${TEST_HOST}/diff/endpoint`, + endpointMetadata: `${TEST_HOST}/diff/endpointMetadata`, + endpointBatch: `${TEST_HOST}/diff/endpointBatch`, projectPath: 'namespace/project', currentUser: {}, changesEmptyStateIllustration: '', @@ -42,6 +44,11 @@ describe('diffs/components/app', () => { ...props, }, store, + methods: { + isLatestVersion() { + return true; + }, + }, }); } @@ -59,6 +66,58 @@ describe('diffs/components/app', () => { wrapper.destroy(); }); + describe('fetch diff methods', () => { + beforeEach(() => { + spyOn(window, 'requestIdleCallback').and.callFake(fn => fn()); + createComponent(); + spyOn(wrapper.vm, 'fetchDiffFiles').and.callFake(() => Promise.resolve()); + spyOn(wrapper.vm, 'fetchDiffFilesMeta').and.callFake(() => Promise.resolve()); + spyOn(wrapper.vm, 'fetchDiffFilesBatch').and.callFake(() => Promise.resolve()); + spyOn(wrapper.vm, 'setDiscussions'); + spyOn(wrapper.vm, 'startRenderDiffsQueue'); + }); + + it('calls fetchDiffFiles if diffsBatchLoad is not enabled', () => { + wrapper.vm.glFeatures.diffsBatchLoad = false; + wrapper.vm.fetchData(false); + + expect(wrapper.vm.fetchDiffFiles).toHaveBeenCalled(); + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.setDiscussions).toHaveBeenCalled(); + expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesMeta).not.toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled(); + }); + }); + + it('calls fetchDiffFiles if diffsBatchLoad is enabled, and not latest version', () => { + wrapper.vm.glFeatures.diffsBatchLoad = true; + wrapper.vm.isLatestVersion = () => false; + wrapper.vm.fetchData(false); + + expect(wrapper.vm.fetchDiffFiles).toHaveBeenCalled(); + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.setDiscussions).toHaveBeenCalled(); + expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesMeta).not.toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled(); + }); + }); + + it('calls batch methods if diffsBatchLoad is enabled, and latest version', () => { + wrapper.vm.glFeatures.diffsBatchLoad = true; + wrapper.vm.fetchData(false); + + expect(wrapper.vm.fetchDiffFiles).not.toHaveBeenCalled(); + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.setDiscussions).toHaveBeenCalled(); + expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled(); + expect(wrapper.vm.fetchDiffFilesBatch).toHaveBeenCalled(); + }); + }); + }); + it('adds container-limiting classes when showFileTree is false with inline diffs', () => { createComponent({}, ({ state }) => { state.diffs.showTreeList = false; @@ -93,6 +152,14 @@ describe('diffs/components/app', () => { expect(wrapper.contains(GlLoadingIcon)).toBe(true); }); + it('displays loading icon on batch loading', () => { + createComponent({}, ({ state }) => { + state.diffs.isBatchLoading = true; + }); + + expect(wrapper.contains(GlLoadingIcon)).toBe(true); + }); + it('displays diffs container when not loading', () => { createComponent(); diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js index 874891fcc6e..3235febe0dc 100644 --- a/spec/javascripts/diffs/store/actions_spec.js +++ b/spec/javascripts/diffs/store/actions_spec.js @@ -8,6 +8,8 @@ import { import actions, { setBaseConfig, fetchDiffFiles, + fetchDiffFilesBatch, + fetchDiffFilesMeta, assignDiscussionsToDiff, removeDiscussionsFromDiff, startRenderDiffsQueue, @@ -68,18 +70,41 @@ describe('DiffsStoreActions', () => { describe('setBaseConfig', () => { it('should set given endpoint and project path', done => { const endpoint = '/diffs/set/endpoint'; + const endpointMetadata = '/diffs/set/endpoint/metadata'; + const endpointBatch = '/diffs/set/endpoint/batch'; const projectPath = '/root/project'; const dismissEndpoint = '/-/user_callouts'; const showSuggestPopover = false; testAction( setBaseConfig, - { endpoint, projectPath, dismissEndpoint, showSuggestPopover }, - { endpoint: '', projectPath: '', dismissEndpoint: '', showSuggestPopover: true }, + { + endpoint, + endpointBatch, + endpointMetadata, + projectPath, + dismissEndpoint, + showSuggestPopover, + }, + { + endpoint: '', + endpointBatch: '', + endpointMetadata: '', + projectPath: '', + dismissEndpoint: '', + showSuggestPopover: true, + }, [ { type: types.SET_BASE_CONFIG, - payload: { endpoint, projectPath, dismissEndpoint, showSuggestPopover }, + payload: { + endpoint, + endpointMetadata, + endpointBatch, + projectPath, + dismissEndpoint, + showSuggestPopover, + }, }, ], [], @@ -114,6 +139,64 @@ describe('DiffsStoreActions', () => { }); }); + describe('fetchDiffFilesBatch', () => { + it('should fetch batch diff files', done => { + const endpointBatch = '/fetch/diffs_batch'; + const batch1 = `${endpointBatch}?per_page=10`; + const batch2 = `${endpointBatch}?per_page=10&page=2`; + const mock = new MockAdapter(axios); + const res1 = { diff_files: [], pagination: { next_page: 2 } }; + const res2 = { diff_files: [], pagination: {} }; + mock.onGet(batch1).reply(200, res1); + mock.onGet(batch2).reply(200, res2); + + testAction( + fetchDiffFilesBatch, + {}, + { endpointBatch }, + [ + { type: types.SET_BATCH_LOADING, payload: true }, + { type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res1.diff_files } }, + { type: types.SET_BATCH_LOADING, payload: false }, + { type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: [] } }, + { type: types.SET_BATCH_LOADING, payload: false }, + ], + [], + () => { + mock.restore(); + done(); + }, + ); + }); + }); + + describe('fetchDiffFilesMeta', () => { + it('should fetch diff meta information', done => { + const endpointMetadata = '/fetch/diffs_meta'; + const mock = new MockAdapter(axios); + const data = { diff_files: [] }; + const res = { data }; + mock.onGet(endpointMetadata).reply(200, res); + + testAction( + fetchDiffFilesMeta, + {}, + { endpointMetadata }, + [ + { type: types.SET_LOADING, payload: true }, + { type: types.SET_LOADING, payload: false }, + { type: types.SET_MERGE_REQUEST_DIFFS, payload: [] }, + { type: types.SET_DIFF_DATA, payload: { data, diff_files: [] } }, + ], + [], + () => { + mock.restore(); + done(); + }, + ); + }); + }); + describe('setHighlightedRow', () => { it('should mark currently selected diff and set lineHash and fileHash of highlightedRow', () => { testAction(setHighlightedRow, 'ABC_123', {}, [ diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js index 3e033b6c9dc..19bf5bdd592 100644 --- a/spec/javascripts/diffs/store/mutations_spec.js +++ b/spec/javascripts/diffs/store/mutations_spec.js @@ -28,6 +28,16 @@ describe('DiffsStoreMutations', () => { }); }); + describe('SET_BATCH_LOADING', () => { + it('should set loading state', () => { + const state = {}; + + mutations[types.SET_BATCH_LOADING](state, false); + + expect(state.isBatchLoading).toEqual(false); + }); + }); + describe('SET_DIFF_DATA', () => { it('should set diff data type properly', () => { const state = {}; @@ -45,6 +55,23 @@ describe('DiffsStoreMutations', () => { }); }); + describe('SET_DIFFSET_DIFF_DATA_BATCH_DATA', () => { + it('should set diff data batch type properly', () => { + const state = { diffFiles: [] }; + const diffMock = { + diff_files: [diffFileMockData], + }; + + mutations[types.SET_DIFF_DATA_BATCH](state, diffMock); + + const firstLine = state.diffFiles[0].parallel_diff_lines[0]; + + expect(firstLine.right.text).toBeUndefined(); + expect(state.diffFiles[0].renderIt).toEqual(true); + expect(state.diffFiles[0].collapsed).toEqual(false); + }); + }); + describe('SET_DIFF_VIEW_TYPE', () => { it('should set diff view type properly', () => { const state = {}; diff --git a/spec/javascripts/environments/environments_app_spec.js b/spec/javascripts/environments/environments_app_spec.js index 0dcd8868aba..10d37c86ea7 100644 --- a/spec/javascripts/environments/environments_app_spec.js +++ b/spec/javascripts/environments/environments_app_spec.js @@ -10,7 +10,6 @@ describe('Environment', () => { endpoint: 'environments.json', canCreateEnvironment: true, canReadEnvironment: true, - cssContainerClass: 'container', newEnvironmentPath: 'environments/new', helpPagePath: 'help', canaryDeploymentFeatureId: 'canary_deployment', diff --git a/spec/lib/gitlab/ci/build/context/build_spec.rb b/spec/lib/gitlab/ci/build/context/build_spec.rb index 3adde213f59..1b73b9a083d 100644 --- a/spec/lib/gitlab/ci/build/context/build_spec.rb +++ b/spec/lib/gitlab/ci/build/context/build_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Context::Build do diff --git a/spec/lib/gitlab/ci/build/context/global_spec.rb b/spec/lib/gitlab/ci/build/context/global_spec.rb index 6bc8f862779..65cc41ed3f9 100644 --- a/spec/lib/gitlab/ci/build/context/global_spec.rb +++ b/spec/lib/gitlab/ci/build/context/global_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Gitlab::Ci::Build::Context::Global do diff --git a/spec/models/clusters/cluster_spec.rb b/spec/models/clusters/cluster_spec.rb index 049db4f7013..7c419a195cd 100644 --- a/spec/models/clusters/cluster_spec.rb +++ b/spec/models/clusters/cluster_spec.rb @@ -960,4 +960,20 @@ describe Clusters::Cluster, :use_clean_rails_memory_store_caching do end end end + + describe '#delete_cached_resources!' do + let!(:cluster) { create(:cluster, :project) } + let!(:staging_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster, namespace: 'staging') } + let!(:production_namespace) { create(:cluster_kubernetes_namespace, cluster: cluster, namespace: 'production') } + + subject { cluster.delete_cached_resources! } + + it 'deletes associated namespace records' do + expect(cluster.kubernetes_namespaces).to match_array([staging_namespace, production_namespace]) + + subject + + expect(cluster.kubernetes_namespaces).to be_empty + end + end end diff --git a/spec/presenters/group_clusterable_presenter_spec.rb b/spec/presenters/group_clusterable_presenter_spec.rb index 11a8decc9cc..d40ca856f7b 100644 --- a/spec/presenters/group_clusterable_presenter_spec.rb +++ b/spec/presenters/group_clusterable_presenter_spec.rb @@ -83,6 +83,12 @@ describe GroupClusterablePresenter do it { is_expected.to eq(update_applications_group_cluster_path(group, cluster, application)) } end + describe '#clear_cluster_cache_path' do + subject { presenter.clear_cluster_cache_path(cluster) } + + it { is_expected.to eq(clear_cache_group_cluster_path(group, cluster)) } + end + describe '#cluster_path' do subject { presenter.cluster_path(cluster) } diff --git a/spec/presenters/instance_clusterable_presenter_spec.rb b/spec/presenters/instance_clusterable_presenter_spec.rb index 9f1268379f5..3e7ee7a0ff6 100644 --- a/spec/presenters/instance_clusterable_presenter_spec.rb +++ b/spec/presenters/instance_clusterable_presenter_spec.rb @@ -34,4 +34,10 @@ describe InstanceClusterablePresenter do it { is_expected.to eq(aws_proxy_admin_clusters_path(resource: resource)) } end + + describe '#clear_cluster_cache_path' do + subject { presenter.clear_cluster_cache_path(cluster) } + + it { is_expected.to eq(clear_cache_admin_cluster_path(cluster)) } + end end diff --git a/spec/presenters/project_clusterable_presenter_spec.rb b/spec/presenters/project_clusterable_presenter_spec.rb index 441c2a50fea..b3dad4abde5 100644 --- a/spec/presenters/project_clusterable_presenter_spec.rb +++ b/spec/presenters/project_clusterable_presenter_spec.rb @@ -83,6 +83,12 @@ describe ProjectClusterablePresenter do it { is_expected.to eq(update_applications_project_cluster_path(project, cluster, application)) } end + describe '#clear_cluster_cache_path' do + subject { presenter.clear_cluster_cache_path(cluster) } + + it { is_expected.to eq(clear_cache_project_cluster_path(project, cluster)) } + end + describe '#cluster_path' do subject { presenter.cluster_path(cluster) } diff --git a/spec/support/shared_examples/merge_requests_rendering_a_single_diff_version.rb b/spec/support/shared_examples/merge_requests_rendering_a_single_diff_version.rb index 80120629a32..18d025a4b07 100644 --- a/spec/support/shared_examples/merge_requests_rendering_a_single_diff_version.rb +++ b/spec/support/shared_examples/merge_requests_rendering_a_single_diff_version.rb @@ -3,6 +3,10 @@ # This pending test can be removed when `single_mr_diff_view` is enabled by default # disabling the feature flag above is then not needed anymore. RSpec.shared_examples 'rendering a single diff version' do |attribute| + before do + stub_feature_flags(diffs_batch_load: false) + end + pending 'allows editing diff settings single_mr_diff_view is enabled' do project = create(:project, :repository) user = project.creator |